

/* --- Start prototype.js --- */

/*  Prototype JavaScript framework, version 1.6.0
 *  (c) 2005-2007 Sam Stephenson
 *
 *  Prototype is freely distributable under the terms of an MIT-style license.
 *  For details, see the Prototype web site: http://www.prototypejs.org/
 *
 *--------------------------------------------------------------------------*/

var Prototype = {
  Version: '1.6.0',

  Browser: {
    IE:     !!(window.attachEvent && !window.opera),
    Opera:  !!window.opera,
    WebKit: navigator.userAgent.indexOf('AppleWebKit/') > -1,
    Gecko:  navigator.userAgent.indexOf('Gecko') > -1 && navigator.userAgent.indexOf('KHTML') == -1,
    MobileSafari: !!navigator.userAgent.match(/Apple.*Mobile.*Safari/)
  },

  BrowserFeatures: {
    XPath: !!document.evaluate,
    ElementExtensions: !!window.HTMLElement,
    SpecificElementExtensions:
      document.createElement('div').__proto__ &&
      document.createElement('div').__proto__ !==
        document.createElement('form').__proto__
  },

  ScriptFragment: '<script[^>]*>([\\S\\s]*?)<\/script>',
  JSONFilter: /^\/\*-secure-([\s\S]*)\*\/\s*$/,

  emptyFunction: function() { },
  K: function(x) { return x }
};

if (Prototype.Browser.MobileSafari)
  Prototype.BrowserFeatures.SpecificElementExtensions = false;

if (Prototype.Browser.WebKit)
  Prototype.BrowserFeatures.XPath = false;

/* Based on Alex Arnell's inheritance implementation. */
var Class = {
  create: function() {
    var parent = null, properties = $A(arguments);
    if (Object.isFunction(properties[0]))
      parent = properties.shift();

    function klass() {
      this.initialize.apply(this, arguments);
    }

    Object.extend(klass, Class.Methods);
    klass.superclass = parent;
    klass.subclasses = [];

    if (parent) {
      var subclass = function() { };
      subclass.prototype = parent.prototype;
      klass.prototype = new subclass;
      parent.subclasses.push(klass);
    }

    for (var i = 0; i < properties.length; i++)
      klass.addMethods(properties[i]);

    if (!klass.prototype.initialize)
      klass.prototype.initialize = Prototype.emptyFunction;

    klass.prototype.constructor = klass;

    return klass;
  }
};

Class.Methods = {
  addMethods: function(source) {
    var ancestor   = this.superclass && this.superclass.prototype;
    var properties = Object.keys(source);

    if (!Object.keys({ toString: true }).length)
      properties.push("toString", "valueOf");

    for (var i = 0, length = properties.length; i < length; i++) {
      var property = properties[i], value = source[property];
      if (ancestor && Object.isFunction(value) &&
          value.argumentNames().first() == "$super") {
        var method = value, value = Object.extend((function(m) {
          return function() { return ancestor[m].apply(this, arguments) };
        })(property).wrap(method), {
          valueOf:  function() { return method },
          toString: function() { return method.toString() }
        });
      }
      this.prototype[property] = value;
    }

    return this;
  }
};

var Abstract = { };

Object.extend = function(destination, source) {
  for (var property in source)
    destination[property] = source[property];
  return destination;
};

Object.extend(Object, {
  inspect: function(object) {
    try {
      if (object === undefined) return 'undefined';
      if (object === null) return 'null';
      return object.inspect ? object.inspect() : object.toString();
    } catch (e) {
      if (e instanceof RangeError) return '...';
      throw e;
    }
  },

  toJSON: function(object) {
    var type = typeof object;
    switch (type) {
      case 'undefined':
      case 'function':
      case 'unknown': return;
      case 'boolean': return object.toString();
    }

    if (object === null) return 'null';
    if (object.toJSON) return object.toJSON();
    if (Object.isElement(object)) return;

    var results = [];
    for (var property in object) {
      var value = Object.toJSON(object[property]);
      if (value !== undefined)
        results.push(property.toJSON() + ': ' + value);
    }

    return '{' + results.join(', ') + '}';
  },

  toQueryString: function(object) {
    return $H(object).toQueryString();
  },

  toHTML: function(object) {
    return object && object.toHTML ? object.toHTML() : String.interpret(object);
  },

  keys: function(object) {
    var keys = [];
    for (var property in object)
      keys.push(property);
    return keys;
  },

  values: function(object) {
    var values = [];
    for (var property in object)
      values.push(object[property]);
    return values;
  },

  clone: function(object) {
    return Object.extend({ }, object);
  },

  isElement: function(object) {
    return object && object.nodeType == 1;
  },

  isArray: function(object) {
    return object && object.constructor === Array;
  },

  isHash: function(object) {
    return object instanceof Hash;
  },

  isFunction: function(object) {
    return typeof object == "function";
  },

  isString: function(object) {
    return typeof object == "string";
  },

  isNumber: function(object) {
    return typeof object == "number";
  },

  isUndefined: function(object) {
    return typeof object == "undefined";
  }
});

Object.extend(Function.prototype, {
  argumentNames: function() {
    var names = this.toString().match(/^[\s\(]*function[^(]*\((.*?)\)/)[1].split(",").invoke("strip");
    return names.length == 1 && !names[0] ? [] : names;
  },

  bind: function() {
    if (arguments.length < 2 && arguments[0] === undefined) return this;
    var __method = this, args = $A(arguments), object = args.shift();
    return function() {
      return __method.apply(object, args.concat($A(arguments)));
    }
  },

  bindAsEventListener: function() {
    var __method = this, args = $A(arguments), object = args.shift();
    return function(event) {
      return __method.apply(object, [event || window.event].concat(args));
    }
  },

  curry: function() {
    if (!arguments.length) return this;
    var __method = this, args = $A(arguments);
    return function() {
      return __method.apply(this, args.concat($A(arguments)));
    }
  },

  delay: function() {
    var __method = this, args = $A(arguments), timeout = args.shift() * 1000;
    return window.setTimeout(function() {
      return __method.apply(__method, args);
    }, timeout);
  },

  wrap: function(wrapper) {
    var __method = this;
    return function() {
      return wrapper.apply(this, [__method.bind(this)].concat($A(arguments)));
    }
  },

  methodize: function() {
    if (this._methodized) return this._methodized;
    var __method = this;
    return this._methodized = function() {
      return __method.apply(null, [this].concat($A(arguments)));
    };
  }
});

Function.prototype.defer = Function.prototype.delay.curry(0.01);

Date.prototype.toJSON = function() {
  return '"' + this.getUTCFullYear() + '-' +
    (this.getUTCMonth() + 1).toPaddedString(2) + '-' +
    this.getUTCDate().toPaddedString(2) + 'T' +
    this.getUTCHours().toPaddedString(2) + ':' +
    this.getUTCMinutes().toPaddedString(2) + ':' +
    this.getUTCSeconds().toPaddedString(2) + 'Z"';
};

var Try = {
  these: function() {
    var returnValue;

    for (var i = 0, length = arguments.length; i < length; i++) {
      var lambda = arguments[i];
      try {
        returnValue = lambda();
        break;
      } catch (e) { }
    }

    return returnValue;
  }
};

RegExp.prototype.match = RegExp.prototype.test;

RegExp.escape = function(str) {
  return String(str).replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1');
};

/*--------------------------------------------------------------------------*/

var PeriodicalExecuter = Class.create({
  initialize: function(callback, frequency) {
    this.callback = callback;
    this.frequency = frequency;
    this.currentlyExecuting = false;

    this.registerCallback();
  },

  registerCallback: function() {
    this.timer = setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);
  },

  execute: function() {
    this.callback(this);
  },

  stop: function() {
    if (!this.timer) return;
    clearInterval(this.timer);
    this.timer = null;
  },

  onTimerEvent: function() {
    if (!this.currentlyExecuting) {
      try {
        this.currentlyExecuting = true;
        this.execute();
      } finally {
        this.currentlyExecuting = false;
      }
    }
  }
});
Object.extend(String, {
  interpret: function(value) {
    return value == null ? '' : String(value);
  },
  specialChar: {
    '\b': '\\b',
    '\t': '\\t',
    '\n': '\\n',
    '\f': '\\f',
    '\r': '\\r',
    '\\': '\\\\'
  }
});

Object.extend(String.prototype, {
  gsub: function(pattern, replacement) {
    var result = '', source = this, match;
    replacement = arguments.callee.prepareReplacement(replacement);

    while (source.length > 0) {
      if (match = source.match(pattern)) {
        result += source.slice(0, match.index);
        result += String.interpret(replacement(match));
        source  = source.slice(match.index + match[0].length);
      } else {
        result += source, source = '';
      }
    }
    return result;
  },

  sub: function(pattern, replacement, count) {
    replacement = this.gsub.prepareReplacement(replacement);
    count = count === undefined ? 1 : count;

    return this.gsub(pattern, function(match) {
      if (--count < 0) return match[0];
      return replacement(match);
    });
  },

  scan: function(pattern, iterator) {
    this.gsub(pattern, iterator);
    return String(this);
  },

  truncate: function(length, truncation) {
    length = length || 30;
    truncation = truncation === undefined ? '...' : truncation;
    return this.length > length ?
      this.slice(0, length - truncation.length) + truncation : String(this);
  },

  strip: function() {
    return this.replace(/^\s+/, '').replace(/\s+$/, '');
  },

  stripTags: function() {
    return this.replace(/<\/?[^>]+>/gi, '');
  },

  stripScripts: function() {
    return this.replace(new RegExp(Prototype.ScriptFragment, 'img'), '');
  },

  extractScripts: function() {
    var matchAll = new RegExp(Prototype.ScriptFragment, 'img');
    var matchOne = new RegExp(Prototype.ScriptFragment, 'im');
    return (this.match(matchAll) || []).map(function(scriptTag) {
      return (scriptTag.match(matchOne) || ['', ''])[1];
    });
  },

  evalScripts: function() {
    return this.extractScripts().map(function(script) { return eval(script) });
  },

  escapeHTML: function() {
    var self = arguments.callee;
    self.text.data = this;
    return self.div.innerHTML;
  },

  unescapeHTML: function() {
    var div = new Element('div');
    div.innerHTML = this.stripTags();
    return div.childNodes[0] ? (div.childNodes.length > 1 ?
      $A(div.childNodes).inject('', function(memo, node) { return memo+node.nodeValue }) :
      div.childNodes[0].nodeValue) : '';
  },

  toQueryParams: function(separator) {
    var match = this.strip().match(/([^?#]*)(#.*)?$/);
    if (!match) return { };

    return match[1].split(separator || '&').inject({ }, function(hash, pair) {
      if ((pair = pair.split('='))[0]) {
        var key = decodeURIComponent(pair.shift());
        var value = pair.length > 1 ? pair.join('=') : pair[0];
        if (value != undefined) value = decodeURIComponent(value);

        if (key in hash) {
          if (!Object.isArray(hash[key])) hash[key] = [hash[key]];
          hash[key].push(value);
        }
        else hash[key] = value;
      }
      return hash;
    });
  },

  toArray: function() {
    return this.split('');
  },

  succ: function() {
    return this.slice(0, this.length - 1) +
      String.fromCharCode(this.charCodeAt(this.length - 1) + 1);
  },

  times: function(count) {
    return count < 1 ? '' : new Array(count + 1).join(this);
  },

  camelize: function() {
    var parts = this.split('-'), len = parts.length;
    if (len == 1) return parts[0];

    var camelized = this.charAt(0) == '-'
      ? parts[0].charAt(0).toUpperCase() + parts[0].substring(1)
      : parts[0];

    for (var i = 1; i < len; i++)
      camelized += parts[i].charAt(0).toUpperCase() + parts[i].substring(1);

    return camelized;
  },

  capitalize: function() {
    return this.charAt(0).toUpperCase() + this.substring(1).toLowerCase();
  },

  underscore: function() {
    return this.gsub(/::/, '/').gsub(/([A-Z]+)([A-Z][a-z])/,'#{1}_#{2}').gsub(/([a-z\d])([A-Z])/,'#{1}_#{2}').gsub(/-/,'_').toLowerCase();
  },

  dasherize: function() {
    return this.gsub(/_/,'-');
  },

  inspect: function(useDoubleQuotes) {
    var escapedString = this.gsub(/[\x00-\x1f\\]/, function(match) {
      var character = String.specialChar[match[0]];
      return character ? character : '\\u00' + match[0].charCodeAt().toPaddedString(2, 16);
    });
    if (useDoubleQuotes) return '"' + escapedString.replace(/"/g, '\\"') + '"';
    return "'" + escapedString.replace(/'/g, '\\\'') + "'";
  },

  toJSON: function() {
    return this.inspect(true);
  },

  unfilterJSON: function(filter) {
    return this.sub(filter || Prototype.JSONFilter, '#{1}');
  },

  isJSON: function() {
    var str = this.replace(/\\./g, '@').replace(/"[^"\\\n\r]*"/g, '');
    return (/^[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]*$/).test(str);
  },

  evalJSON: function(sanitize) {
    var json = this.unfilterJSON();
    try {
      if (!sanitize || json.isJSON()) return eval('(' + json + ')');
    } catch (e) { }
    throw new SyntaxError('Badly formed JSON string: ' + this.inspect());
  },

  include: function(pattern) {
    return this.indexOf(pattern) > -1;
  },

  startsWith: function(pattern) {
    return this.indexOf(pattern) === 0;
  },

  endsWith: function(pattern) {
    var d = this.length - pattern.length;
    return d >= 0 && this.lastIndexOf(pattern) === d;
  },

  empty: function() {
    return this == '';
  },

  blank: function() {
    return /^\s*$/.test(this);
  },

  interpolate: function(object, pattern) {
    return new Template(this, pattern).evaluate(object);
  }
});

if (Prototype.Browser.WebKit || Prototype.Browser.IE) Object.extend(String.prototype, {
  escapeHTML: function() {
    return this.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');
  },
  unescapeHTML: function() {
    return this.replace(/&amp;/g,'&').replace(/&lt;/g,'<').replace(/&gt;/g,'>');
  }
});

String.prototype.gsub.prepareReplacement = function(replacement) {
  if (Object.isFunction(replacement)) return replacement;
  var template = new Template(replacement);
  return function(match) { return template.evaluate(match) };
};

String.prototype.parseQuery = String.prototype.toQueryParams;

Object.extend(String.prototype.escapeHTML, {
  div:  document.createElement('div'),
  text: document.createTextNode('')
});

with (String.prototype.escapeHTML) div.appendChild(text);

var Template = Class.create({
  initialize: function(template, pattern) {
    this.template = template.toString();
    this.pattern = pattern || Template.Pattern;
  },

  evaluate: function(object) {
    if (Object.isFunction(object.toTemplateReplacements))
      object = object.toTemplateReplacements();

    return this.template.gsub(this.pattern, function(match) {
      if (object == null) return '';

      var before = match[1] || '';
      if (before == '\\') return match[2];

      var ctx = object, expr = match[3];
      var pattern = /^([^.[]+|\[((?:.*?[^\\])?)\])(\.|\[|$)/, match = pattern.exec(expr);
      if (match == null) return before;

      while (match != null) {
        var comp = match[1].startsWith('[') ? match[2].gsub('\\\\]', ']') : match[1];
        ctx = ctx[comp];
        if (null == ctx || '' == match[3]) break;
        expr = expr.substring('[' == match[3] ? match[1].length : match[0].length);
        match = pattern.exec(expr);
      }

      return before + String.interpret(ctx);
    }.bind(this));
  }
});
Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/;

var $break = { };

var Enumerable = {
  each: function(iterator, context) {
    var index = 0;
    iterator = iterator.bind(context);
    try {
      this._each(function(value) {
        iterator(value, index++);
      });
    } catch (e) {
      if (e != $break) throw e;
    }
    return this;
  },

  eachSlice: function(number, iterator, context) {
    iterator = iterator ? iterator.bind(context) : Prototype.K;
    var index = -number, slices = [], array = this.toArray();
    while ((index += number) < array.length)
      slices.push(array.slice(index, index+number));
    return slices.collect(iterator, context);
  },

  all: function(iterator, context) {
    iterator = iterator ? iterator.bind(context) : Prototype.K;
    var result = true;
    this.each(function(value, index) {
      result = result && !!iterator(value, index);
      if (!result) throw $break;
    });
    return result;
  },

  any: function(iterator, context) {
    iterator = iterator ? iterator.bind(context) : Prototype.K;
    var result = false;
    this.each(function(value, index) {
      if (result = !!iterator(value, index))
        throw $break;
    });
    return result;
  },

  collect: function(iterator, context) {
    iterator = iterator ? iterator.bind(context) : Prototype.K;
    var results = [];
    this.each(function(value, index) {
      results.push(iterator(value, index));
    });
    return results;
  },

  detect: function(iterator, context) {
    iterator = iterator.bind(context);
    var result;
    this.each(function(value, index) {
      if (iterator(value, index)) {
        result = value;
        throw $break;
      }
    });
    return result;
  },

  findAll: function(iterator, context) {
    iterator = iterator.bind(context);
    var results = [];
    this.each(function(value, index) {
      if (iterator(value, index))
        results.push(value);
    });
    return results;
  },

  grep: function(filter, iterator, context) {
    iterator = iterator ? iterator.bind(context) : Prototype.K;
    var results = [];

    if (Object.isString(filter))
      filter = new RegExp(filter);

    this.each(function(value, index) {
      if (filter.match(value))
        results.push(iterator(value, index));
    });
    return results;
  },

  include: function(object) {
    if (Object.isFunction(this.indexOf))
      if (this.indexOf(object) != -1) return true;

    var found = false;
    this.each(function(value) {
      if (value == object) {
        found = true;
        throw $break;
      }
    });
    return found;
  },

  inGroupsOf: function(number, fillWith) {
    fillWith = fillWith === undefined ? null : fillWith;
    return this.eachSlice(number, function(slice) {
      while(slice.length < number) slice.push(fillWith);
      return slice;
    });
  },

  inject: function(memo, iterator, context) {
    iterator = iterator.bind(context);
    this.each(function(value, index) {
      memo = iterator(memo, value, index);
    });
    return memo;
  },

  invoke: function(method) {
    var args = $A(arguments).slice(1);
    return this.map(function(value) {
      return value[method].apply(value, args);
    });
  },

  max: function(iterator, context) {
    iterator = iterator ? iterator.bind(context) : Prototype.K;
    var result;
    this.each(function(value, index) {
      value = iterator(value, index);
      if (result == undefined || value >= result)
        result = value;
    });
    return result;
  },

  min: function(iterator, context) {
    iterator = iterator ? iterator.bind(context) : Prototype.K;
    var result;
    this.each(function(value, index) {
      value = iterator(value, index);
      if (result == undefined || value < result)
        result = value;
    });
    return result;
  },

  partition: function(iterator, context) {
    iterator = iterator ? iterator.bind(context) : Prototype.K;
    var trues = [], falses = [];
    this.each(function(value, index) {
      (iterator(value, index) ?
        trues : falses).push(value);
    });
    return [trues, falses];
  },

  pluck: function(property) {
    var results = [];
    this.each(function(value) {
      results.push(value[property]);
    });
    return results;
  },

  reject: function(iterator, context) {
    iterator = iterator.bind(context);
    var results = [];
    this.each(function(value, index) {
      if (!iterator(value, index))
        results.push(value);
    });
    return results;
  },

  sortBy: function(iterator, context) {
    iterator = iterator.bind(context);
    return this.map(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.map();
  },

  zip: function() {
    var iterator = Prototype.K, args = $A(arguments);
    if (Object.isFunction(args.last()))
      iterator = args.pop();

    var collections = [this].concat(args).map($A);
    return this.map(function(value, index) {
      return iterator(collections.pluck(index));
    });
  },

  size: function() {
    return this.toArray().length;
  },

  inspect: function() {
    return '#<Enumerable:' + this.toArray().inspect() + '>';
  }
};

Object.extend(Enumerable, {
  map:     Enumerable.collect,
  find:    Enumerable.detect,
  select:  Enumerable.findAll,
  filter:  Enumerable.findAll,
  member:  Enumerable.include,
  entries: Enumerable.toArray,
  every:   Enumerable.all,
  some:    Enumerable.any
});
function $A(iterable) {
  if (!iterable) return [];
  if (iterable.toArray) return iterable.toArray();
  var length = iterable.length, results = new Array(length);
  while (length--) results[length] = iterable[length];
  return results;
}

if (Prototype.Browser.WebKit) {
  function $A(iterable) {
    if (!iterable) return [];
    if (!(Object.isFunction(iterable) && iterable == '[object NodeList]') &&
        iterable.toArray) return iterable.toArray();
    var length = iterable.length, results = new Array(length);
    while (length--) results[length] = iterable[length];
    return results;
  }
}

Array.from = $A;

Object.extend(Array.prototype, Enumerable);

if (!Array.prototype._reverse) Array.prototype._reverse = Array.prototype.reverse;

Object.extend(Array.prototype, {
  _each: function(iterator) {
    for (var i = 0, length = this.length; i < 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 != null;
    });
  },

  flatten: function() {
    return this.inject([], function(array, value) {
      return array.concat(Object.isArray(value) ?
        value.flatten() : [value]);
    });
  },

  without: function() {
    var values = $A(arguments);
    return this.select(function(value) {
      return !values.include(value);
    });
  },

  reverse: function(inline) {
    return (inline !== false ? this : this.toArray())._reverse();
  },

  reduce: function() {
    return this.length > 1 ? this : this[0];
  },

  uniq: function(sorted) {
    return this.inject([], function(array, value, index) {
      if (0 == index || (sorted ? array.last() != value : !array.include(value)))
        array.push(value);
      return array;
    });
  },

  intersect: function(array) {
    return this.uniq().findAll(function(item) {
      return array.detect(function(value) { return item === value });
    });
  },

  clone: function() {
    return [].concat(this);
  },

  size: function() {
    return this.length;
  },

  inspect: function() {
    return '[' + this.map(Object.inspect).join(', ') + ']';
  },

  toJSON: function() {
    var results = [];
    this.each(function(object) {
      var value = Object.toJSON(object);
      if (value !== undefined) results.push(value);
    });
    return '[' + results.join(', ') + ']';
  }
});

// use native browser JS 1.6 implementation if available
if (Object.isFunction(Array.prototype.forEach))
  Array.prototype._each = Array.prototype.forEach;

if (!Array.prototype.indexOf) Array.prototype.indexOf = function(item, i) {
  i || (i = 0);
  var length = this.length;
  if (i < 0) i = length + i;
  for (; i < length; i++)
    if (this[i] === item) return i;
  return -1;
};

if (!Array.prototype.lastIndexOf) Array.prototype.lastIndexOf = function(item, i) {
  i = isNaN(i) ? this.length : (i < 0 ? this.length + i : i) + 1;
  var n = this.slice(0, i).reverse().indexOf(item);
  return (n < 0) ? n : i - n - 1;
};

Array.prototype.toArray = Array.prototype.clone;

function $w(string) {
  if (!Object.isString(string)) return [];
  string = string.strip();
  return string ? string.split(/\s+/) : [];
}

if (Prototype.Browser.Opera){
  Array.prototype.concat = function() {
    var array = [];
    for (var i = 0, length = this.length; i < length; i++) array.push(this[i]);
    for (var i = 0, length = arguments.length; i < length; i++) {
      if (Object.isArray(arguments[i])) {
        for (var j = 0, arrayLength = arguments[i].length; j < arrayLength; j++)
          array.push(arguments[i][j]);
      } else {
        array.push(arguments[i]);
      }
    }
    return array;
  };
}
Object.extend(Number.prototype, {
  toColorPart: function() {
    return this.toPaddedString(2, 16);
  },

  succ: function() {
    return this + 1;
  },

  times: function(iterator) {
    $R(0, this, true).each(iterator);
    return this;
  },

  toPaddedString: function(length, radix) {
    var string = this.toString(radix || 10);
    return '0'.times(length - string.length) + string;
  },

  toJSON: function() {
    return isFinite(this) ? this.toString() : 'null';
  }
});

$w('abs round ceil floor').each(function(method){
  Number.prototype[method] = Math[method].methodize();
});
function $H(object) {
  return new Hash(object);
};

var Hash = Class.create(Enumerable, (function() {
  if (function() {
    var i = 0, Test = function(value) { this.key = value };
    Test.prototype.key = 'foo';
    for (var property in new Test('bar')) i++;
    return i > 1;
  }()) {
    function each(iterator) {
      var cache = [];
      for (var key in this._object) {
        var value = this._object[key];
        if (cache.include(key)) continue;
        cache.push(key);
        var pair = [key, value];
        pair.key = key;
        pair.value = value;
        iterator(pair);
      }
    }
  } else {
    function each(iterator) {
      for (var key in this._object) {
        var value = this._object[key], pair = [key, value];
        pair.key = key;
        pair.value = value;
        iterator(pair);
      }
    }
  }

  function toQueryPair(key, value) {
    if (Object.isUndefined(value)) return key;
    return key + '=' + encodeURIComponent(String.interpret(value));
  }

  return {
    initialize: function(object) {
      this._object = Object.isHash(object) ? object.toObject() : Object.clone(object);
    },

    _each: each,

    set: function(key, value) {
      return this._object[key] = value;
    },

    get: function(key) {
      return this._object[key];
    },

    unset: function(key) {
      var value = this._object[key];
      delete this._object[key];
      return value;
    },

    toObject: function() {
      return Object.clone(this._object);
    },

    keys: function() {
      return this.pluck('key');
    },

    values: function() {
      return this.pluck('value');
    },

    index: function(value) {
      var match = this.detect(function(pair) {
        return pair.value === value;
      });
      return match && match.key;
    },

    merge: function(object) {
      return this.clone().update(object);
    },

    update: function(object) {
      return new Hash(object).inject(this, function(result, pair) {
        result.set(pair.key, pair.value);
        return result;
      });
    },

    toQueryString: function() {
      return this.map(function(pair) {
        var key = encodeURIComponent(pair.key), values = pair.value;

        if (values && typeof values == 'object') {
          if (Object.isArray(values))
            return values.map(toQueryPair.curry(key)).join('&');
        }
        return toQueryPair(key, values);
      }).join('&');
    },

    inspect: function() {
      return '#<Hash:{' + this.map(function(pair) {
        return pair.map(Object.inspect).join(': ');
      }).join(', ') + '}>';
    },

    toJSON: function() {
      return Object.toJSON(this.toObject());
    },

    clone: function() {
      return new Hash(this);
    }
  }
})());

Hash.prototype.toTemplateReplacements = Hash.prototype.toObject;
Hash.from = $H;
var ObjectRange = Class.create(Enumerable, {
  initialize: function(start, end, exclusive) {
    this.start = start;
    this.end = end;
    this.exclusive = exclusive;
  },

  _each: function(iterator) {
    var value = this.start;
    while (this.include(value)) {
      iterator(value);
      value = value.succ();
    }
  },

  include: function(value) {
    if (value < this.start)
      return false;
    if (this.exclusive)
      return value < this.end;
    return value <= this.end;
  }
});

var $R = function(start, end, exclusive) {
  return new ObjectRange(start, end, exclusive);
};

var Ajax = {
  getTransport: function() {
    return Try.these(
      function() {return new XMLHttpRequest()},
      function() {return new ActiveXObject('Msxml2.XMLHTTP')},
      function() {return new ActiveXObject('Microsoft.XMLHTTP')}
    ) || false;
  },

  activeRequestCount: 0
};

Ajax.Responders = {
  responders: [],

  _each: function(iterator) {
    this.responders._each(iterator);
  },

  register: function(responder) {
    if (!this.include(responder))
      this.responders.push(responder);
  },

  unregister: function(responder) {
    this.responders = this.responders.without(responder);
  },

  dispatch: function(callback, request, transport, json) {
    this.each(function(responder) {
      if (Object.isFunction(responder[callback])) {
        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 = Class.create({
  initialize: function(options) {
    this.options = {
      method:       'post',
      asynchronous: true,
      contentType:  'application/x-www-form-urlencoded',
      encoding:     'UTF-8',
      parameters:   '',
      evalJSON:     true,
      evalJS:       true
    };
    Object.extend(this.options, options || { });

    this.options.method = this.options.method.toLowerCase();
    if (Object.isString(this.options.parameters))
      this.options.parameters = this.options.parameters.toQueryParams();
  }
});

Ajax.Request = Class.create(Ajax.Base, {
  _complete: false,

  initialize: function($super, url, options) {
    $super(options);
    this.transport = Ajax.getTransport();
    this.request(url);
  },

  request: function(url) {
    this.url = url;
    this.method = this.options.method;
    var params = Object.clone(this.options.parameters);

    if (!['get', 'post'].include(this.method)) {
      // simulate other verbs over post
      params['_method'] = this.method;
      this.method = 'post';
    }

    this.parameters = params;

    if (params = Object.toQueryString(params)) {
      // when GET, append parameters to URL
      if (this.method == 'get')
        this.url += (this.url.include('?') ? '&' : '?') + params;
      else if (/Konqueror|Safari|KHTML/.test(navigator.userAgent))
        params += '&_=';
    }

    try {
      var response = new Ajax.Response(this);
      if (this.options.onCreate) this.options.onCreate(response);
      Ajax.Responders.dispatch('onCreate', this, response);

      this.transport.open(this.method.toUpperCase(), this.url,
        this.options.asynchronous);

      if (this.options.asynchronous) this.respondToReadyState.bind(this).defer(1);

      this.transport.onreadystatechange = this.onStateChange.bind(this);
      this.setRequestHeaders();

      this.body = this.method == 'post' ? (this.options.postBody || params) : null;
      this.transport.send(this.body);

      /* Force Firefox to handle ready state 4 for synchronous requests */
      if (!this.options.asynchronous && this.transport.overrideMimeType)
        this.onStateChange();

    }
    catch (e) {
      this.dispatchException(e);
    }
  },

  onStateChange: function() {
    var readyState = this.transport.readyState;
    if (readyState > 1 && !((readyState == 4) && this._complete))
      this.respondToReadyState(this.transport.readyState);
  },

  setRequestHeaders: function() {
    var headers = {
      'X-Requested-With': 'XMLHttpRequest',
      'X-Prototype-Version': Prototype.Version,
      'Accept': 'text/javascript, text/html, application/xml, text/xml, */*'
    };

    if (this.method == 'post') {
      headers['Content-type'] = this.options.contentType +
        (this.options.encoding ? '; charset=' + this.options.encoding : '');

      /* Force "Connection: close" for older Mozilla browsers to work
       * around a bug where XMLHttpRequest sends an incorrect
       * Content-length header. See Mozilla Bugzilla #246651.
       */
      if (this.transport.overrideMimeType &&
          (navigator.userAgent.match(/Gecko\/(\d{4})/) || [0,2005])[1] < 2005)
            headers['Connection'] = 'close';
    }

    // user-defined headers
    if (typeof this.options.requestHeaders == 'object') {
      var extras = this.options.requestHeaders;

      if (Object.isFunction(extras.push))
        for (var i = 0, length = extras.length; i < length; i += 2)
          headers[extras[i]] = extras[i+1];
      else
        $H(extras).each(function(pair) { headers[pair.key] = pair.value });
    }

    for (var name in headers)
      this.transport.setRequestHeader(name, headers[name]);
  },

  success: function() {
    var status = this.getStatus();
    return !status || (status >= 200 && status < 300);
  },

  getStatus: function() {
    try {
      return this.transport.status || 0;
    } catch (e) { return 0 }
  },

  respondToReadyState: function(readyState) {
    var state = Ajax.Request.Events[readyState], response = new Ajax.Response(this);

    if (state == 'Complete') {
      try {
        this._complete = true;
        (this.options['on' + response.status]
         || this.options['on' + (this.success() ? 'Success' : 'Failure')]
         || Prototype.emptyFunction)(response, response.headerJSON);
      } catch (e) {
        this.dispatchException(e);
      }

      var contentType = response.getHeader('Content-type');
      if (this.options.evalJS == 'force'
          || (this.options.evalJS && contentType
          && contentType.match(/^\s*(text|application)\/(x-)?(java|ecma)script(;.*)?\s*$/i)))
        this.evalResponse();
    }

    try {
      (this.options['on' + state] || Prototype.emptyFunction)(response, response.headerJSON);
      Ajax.Responders.dispatch('on' + state, this, response, response.headerJSON);
    } catch (e) {
      this.dispatchException(e);
    }

    if (state == 'Complete') {
      // avoid memory leak in MSIE: clean up
      this.transport.onreadystatechange = Prototype.emptyFunction;
    }
  },

  getHeader: function(name) {
    try {
      return this.transport.getResponseHeader(name);
    } catch (e) { return null }
  },

  evalResponse: function() {
    try {
      return eval((this.transport.responseText || '').unfilterJSON());
    } catch (e) {
      this.dispatchException(e);
    }
  },

  dispatchException: function(exception) {
    (this.options.onException || Prototype.emptyFunction)(this, exception);
    Ajax.Responders.dispatch('onException', this, exception);
  }
});

Ajax.Request.Events =
  ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete'];

Ajax.Response = Class.create({
  initialize: function(request){
    this.request = request;
    var transport  = this.transport  = request.transport,
        readyState = this.readyState = transport.readyState;

    if((readyState > 2 && !Prototype.Browser.IE) || readyState == 4) {
      this.status       = this.getStatus();
      this.statusText   = this.getStatusText();
      this.responseText = String.interpret(transport.responseText);
      this.headerJSON   = this._getHeaderJSON();
    }

    if(readyState == 4) {
      var xml = transport.responseXML;
      this.responseXML  = xml === undefined ? null : xml;
      this.responseJSON = this._getResponseJSON();
    }
  },

  status:      0,
  statusText: '',

  getStatus: Ajax.Request.prototype.getStatus,

  getStatusText: function() {
    try {
      return this.transport.statusText || '';
    } catch (e) { return '' }
  },

  getHeader: Ajax.Request.prototype.getHeader,

  getAllHeaders: function() {
    try {
      return this.getAllResponseHeaders();
    } catch (e) { return null }
  },

  getResponseHeader: function(name) {
    return this.transport.getResponseHeader(name);
  },

  getAllResponseHeaders: function() {
    return this.transport.getAllResponseHeaders();
  },

  _getHeaderJSON: function() {
    var json = this.getHeader('X-JSON');
    if (!json) return null;
    json = decodeURIComponent(escape(json));
    try {
      return json.evalJSON(this.request.options.sanitizeJSON);
    } catch (e) {
      this.request.dispatchException(e);
    }
  },

  _getResponseJSON: function() {
    var options = this.request.options;
    if (!options.evalJSON || (options.evalJSON != 'force' &&
      !(this.getHeader('Content-type') || '').include('application/json')))
        return null;
    try {
      return this.transport.responseText.evalJSON(options.sanitizeJSON);
    } catch (e) {
      this.request.dispatchException(e);
    }
  }
});

Ajax.Updater = Class.create(Ajax.Request, {
  initialize: function($super, container, url, options) {
    this.container = {
      success: (container.success || container),
      failure: (container.failure || (container.success ? null : container))
    };

    options = options || { };
    var onComplete = options.onComplete;
    options.onComplete = (function(response, param) {
      this.updateContent(response.responseText);
      if (Object.isFunction(onComplete)) onComplete(response, param);
    }).bind(this);

    $super(url, options);
  },

  updateContent: function(responseText) {
    var receiver = this.container[this.success() ? 'success' : 'failure'],
        options = this.options;

    if (!options.evalScripts) responseText = responseText.stripScripts();

    if (receiver = $(receiver)) {
      if (options.insertion) {
        if (Object.isString(options.insertion)) {
          var insertion = { }; insertion[options.insertion] = responseText;
          receiver.insert(insertion);
        }
        else options.insertion(receiver, responseText);
      }
      else receiver.update(responseText);
    }

    if (this.success()) {
      if (this.onComplete) this.onComplete.bind(this).defer();
    }
  }
});

Ajax.PeriodicalUpdater = Class.create(Ajax.Base, {
  initialize: function($super, container, url, options) {
    $super(options);
    this.onComplete = this.options.onComplete;

    this.frequency = (this.options.frequency || 2);
    this.decay = (this.options.decay || 1);

    this.updater = { };
    this.container = container;
    this.url = url;

    this.start();
  },

  start: function() {
    this.options.onComplete = this.updateComplete.bind(this);
    this.onTimerEvent();
  },

  stop: function() {
    this.updater.options.onComplete = undefined;
    clearTimeout(this.timer);
    (this.onComplete || Prototype.emptyFunction).apply(this, arguments);
  },

  updateComplete: function(response) {
    if (this.options.decay) {
      this.decay = (response.responseText == this.lastText ?
        this.decay * this.options.decay : 1);

      this.lastText = response.responseText;
    }
    this.timer = this.onTimerEvent.bind(this).delay(this.decay * this.frequency);
  },

  onTimerEvent: function() {
    this.updater = new Ajax.Updater(this.container, this.url, this.options);
  }
});
function $(element) {
  if (arguments.length > 1) {
    for (var i = 0, elements = [], length = arguments.length; i < length; i++)
      elements.push($(arguments[i]));
    return elements;
  }
  if (Object.isString(element))
    element = document.getElementById(element);
  return Element.extend(element);
}

if (Prototype.BrowserFeatures.XPath) {
  document._getElementsByXPath = function(expression, parentElement) {
    var results = [];
    var query = document.evaluate(expression, $(parentElement) || document,
      null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
    for (var i = 0, length = query.snapshotLength; i < length; i++)
      results.push(Element.extend(query.snapshotItem(i)));
    return results;
  };
}

/*--------------------------------------------------------------------------*/

if (!window.Node) var Node = { };

if (!Node.ELEMENT_NODE) {
  // DOM level 2 ECMAScript Language Binding
  Object.extend(Node, {
    ELEMENT_NODE: 1,
    ATTRIBUTE_NODE: 2,
    TEXT_NODE: 3,
    CDATA_SECTION_NODE: 4,
    ENTITY_REFERENCE_NODE: 5,
    ENTITY_NODE: 6,
    PROCESSING_INSTRUCTION_NODE: 7,
    COMMENT_NODE: 8,
    DOCUMENT_NODE: 9,
    DOCUMENT_TYPE_NODE: 10,
    DOCUMENT_FRAGMENT_NODE: 11,
    NOTATION_NODE: 12
  });
}

(function() {
  var element = this.Element;
  this.Element = function(tagName, attributes) {
    attributes = attributes || { };
    tagName = tagName.toLowerCase();
    var cache = Element.cache;
    if (Prototype.Browser.IE && attributes.name) {
      tagName = '<' + tagName + ' name="' + attributes.name + '">';
      delete attributes.name;
      return Element.writeAttribute(document.createElement(tagName), attributes);
    }
    if (!cache[tagName]) cache[tagName] = Element.extend(document.createElement(tagName));
    return Element.writeAttribute(cache[tagName].cloneNode(false), attributes);
  };
  Object.extend(this.Element, element || { });
}).call(window);

Element.cache = { };

Element.Methods = {
  visible: function(element) {
    return $(element).style.display != 'none';
  },

  toggle: function(element) {
    element = $(element);
    Element[Element.visible(element) ? 'hide' : 'show'](element);
    return element;
  },

  hide: function(element) {
    $(element).style.display = 'none';
    return element;
  },

  show: function(element) {
    $(element).style.display = '';
    return element;
  },

  remove: function(element) {
    element = $(element);
    element.parentNode.removeChild(element);
    return element;
  },

  update: function(element, content) {
    element = $(element);
    if (content && content.toElement) content = content.toElement();
    if (Object.isElement(content)) return element.update().insert(content);
    content = Object.toHTML(content);
    element.innerHTML = content.stripScripts();
    content.evalScripts.bind(content).defer();
    return element;
  },

  replace: function(element, content) {
    element = $(element);
    if (content && content.toElement) content = content.toElement();
    else if (!Object.isElement(content)) {
      content = Object.toHTML(content);
      var range = element.ownerDocument.createRange();
      range.selectNode(element);
      content.evalScripts.bind(content).defer();
      content = range.createContextualFragment(content.stripScripts());
    }
    element.parentNode.replaceChild(content, element);
    return element;
  },

  insert: function(element, insertions) {
    element = $(element);

    if (Object.isString(insertions) || Object.isNumber(insertions) ||
        Object.isElement(insertions) || (insertions && (insertions.toElement || insertions.toHTML)))
          insertions = {bottom:insertions};

    var content, t, range;

    for (position in insertions) {
      content  = insertions[position];
      position = position.toLowerCase();
      t = Element._insertionTranslations[position];

      if (content && content.toElement) content = content.toElement();
      if (Object.isElement(content)) {
        t.insert(element, content);
        continue;
      }

      content = Object.toHTML(content);

      range = element.ownerDocument.createRange();
      t.initializeRange(element, range);
      t.insert(element, range.createContextualFragment(content.stripScripts()));

      content.evalScripts.bind(content).defer();
    }

    return element;
  },

  wrap: function(element, wrapper, attributes) {
    element = $(element);
    if (Object.isElement(wrapper))
      $(wrapper).writeAttribute(attributes || { });
    else if (Object.isString(wrapper)) wrapper = new Element(wrapper, attributes);
    else wrapper = new Element('div', wrapper);
    if (element.parentNode)
      element.parentNode.replaceChild(wrapper, element);
    wrapper.appendChild(element);
    return wrapper;
  },

  inspect: function(element) {
    element = $(element);
    var result = '<' + element.tagName.toLowerCase();
    $H({'id': 'id', 'className': 'class'}).each(function(pair) {
      var property = pair.first(), attribute = pair.last();
      var value = (element[property] || '').toString();
      if (value) result += ' ' + attribute + '=' + value.inspect(true);
    });
    return result + '>';
  },

  recursivelyCollect: function(element, property) {
    element = $(element);
    var elements = [];
    while (element = element[property])
      if (element.nodeType == 1)
        elements.push(Element.extend(element));
    return elements;
  },

  ancestors: function(element) {
    return $(element).recursivelyCollect('parentNode');
  },

  descendants: function(element) {
    return $A($(element).getElementsByTagName('*')).each(Element.extend);
  },

  firstDescendant: function(element) {
    element = $(element).firstChild;
    while (element && element.nodeType != 1) element = element.nextSibling;
    return $(element);
  },

  immediateDescendants: function(element) {
    if (!(element = $(element).firstChild)) return [];
    while (element && element.nodeType != 1) element = element.nextSibling;
    if (element) return [element].concat($(element).nextSiblings());
    return [];
  },

  previousSiblings: function(element) {
    return $(element).recursivelyCollect('previousSibling');
  },

  nextSiblings: function(element) {
    return $(element).recursivelyCollect('nextSibling');
  },

  siblings: function(element) {
    element = $(element);
    return element.previousSiblings().reverse().concat(element.nextSiblings());
  },

  match: function(element, selector) {
    if (Object.isString(selector))
      selector = new Selector(selector);
    return selector.match($(element));
  },

  up: function(element, expression, index) {
    element = $(element);
    if (arguments.length == 1) return $(element.parentNode);
    var ancestors = element.ancestors();
    return expression ? Selector.findElement(ancestors, expression, index) :
      ancestors[index || 0];
  },

  down: function(element, expression, index) {
    element = $(element);
    if (arguments.length == 1) return element.firstDescendant();
    var descendants = element.descendants();
    return expression ? Selector.findElement(descendants, expression, index) :
      descendants[index || 0];
  },

  previous: function(element, expression, index) {
    element = $(element);
    if (arguments.length == 1) return $(Selector.handlers.previousElementSibling(element));
    var previousSiblings = element.previousSiblings();
    return expression ? Selector.findElement(previousSiblings, expression, index) :
      previousSiblings[index || 0];
  },

  next: function(element, expression, index) {
    element = $(element);
    if (arguments.length == 1) return $(Selector.handlers.nextElementSibling(element));
    var nextSiblings = element.nextSiblings();
    return expression ? Selector.findElement(nextSiblings, expression, index) :
      nextSiblings[index || 0];
  },

  select: function() {
    var args = $A(arguments), element = $(args.shift());
    return Selector.findChildElements(element, args);
  },

  adjacent: function() {
    var args = $A(arguments), element = $(args.shift());
    return Selector.findChildElements(element.parentNode, args).without(element);
  },

  identify: function(element) {
    element = $(element);
    var id = element.readAttribute('id'), self = arguments.callee;
    if (id) return id;
    do { id = 'anonymous_element_' + self.counter++ } while ($(id));
    element.writeAttribute('id', id);
    return id;
  },

  readAttribute: function(element, name) {
    element = $(element);
    if (Prototype.Browser.IE) {
      var t = Element._attributeTranslations.read;
      if (t.values[name]) return t.values[name](element, name);
      if (t.names[name]) name = t.names[name];
      if (name.include(':')) {
        return (!element.attributes || !element.attributes[name]) ? null :
         element.attributes[name].value;
      }
    }
    return element.getAttribute(name);
  },

  writeAttribute: function(element, name, value) {
    element = $(element);
    var attributes = { }, t = Element._attributeTranslations.write;

    if (typeof name == 'object') attributes = name;
    else attributes[name] = value === undefined ? true : value;

    for (var attr in attributes) {
      var name = t.names[attr] || attr, value = attributes[attr];
      if (t.values[attr]) name = t.values[attr](element, value);
      if (value === false || value === null)
        element.removeAttribute(name);
      else if (value === true)
        element.setAttribute(name, name);
      else element.setAttribute(name, value);
    }
    return element;
  },

  getHeight: function(element) {
    return $(element).getDimensions().height;
  },

  getWidth: function(element) {
    return $(element).getDimensions().width;
  },

  classNames: function(element) {
    return new Element.ClassNames(element);
  },

  hasClassName: function(element, className) {
    if (!(element = $(element))) return;
    var elementClassName = element.className;
    return (elementClassName.length > 0 && (elementClassName == className ||
      new RegExp("(^|\\s)" + className + "(\\s|$)").test(elementClassName)));
  },

  addClassName: function(element, className) {
    if (!(element = $(element))) return;
    if (!element.hasClassName(className))
      element.className += (element.className ? ' ' : '') + className;
    return element;
  },

  removeClassName: function(element, className) {
    if (!(element = $(element))) return;
    element.className = element.className.replace(
      new RegExp("(^|\\s+)" + className + "(\\s+|$)"), ' ').strip();
    return element;
  },

  toggleClassName: function(element, className) {
    if (!(element = $(element))) return;
    return element[element.hasClassName(className) ?
      'removeClassName' : 'addClassName'](className);
  },

  // removes whitespace-only text node children
  cleanWhitespace: function(element) {
    element = $(element);
    var node = element.firstChild;
    while (node) {
      var nextNode = node.nextSibling;
      if (node.nodeType == 3 && !/\S/.test(node.nodeValue))
        element.removeChild(node);
      node = nextNode;
    }
    return element;
  },

  empty: function(element) {
    return $(element).innerHTML.blank();
  },

  descendantOf: function(element, ancestor) {
    element = $(element), ancestor = $(ancestor);

    if (element.compareDocumentPosition)
      return (element.compareDocumentPosition(ancestor) & 8) === 8;

    if (element.sourceIndex && !Prototype.Browser.Opera) {
      var e = element.sourceIndex, a = ancestor.sourceIndex,
       nextAncestor = ancestor.nextSibling;
      if (!nextAncestor) {
        do { ancestor = ancestor.parentNode; }
        while (!(nextAncestor = ancestor.nextSibling) && ancestor.parentNode);
      }
      if (nextAncestor) return (e > a && e < nextAncestor.sourceIndex);
    }

    while (element = element.parentNode)
      if (element == ancestor) return true;
    return false;
  },

  scrollTo: function(element) {
    element = $(element);
    var pos = element.cumulativeOffset();
    window.scrollTo(pos[0], pos[1]);
    return element;
  },

  getStyle: function(element, style) {
    element = $(element);
    style = style == 'float' ? 'cssFloat' : style.camelize();
    var value = element.style[style];
    if (!value) {
      var css = document.defaultView.getComputedStyle(element, null);
      value = css ? css[style] : null;
    }
    if (style == 'opacity') return value ? parseFloat(value) : 1.0;
    return value == 'auto' ? null : value;
  },

  getOpacity: function(element) {
    return $(element).getStyle('opacity');
  },

  setStyle: function(element, styles) {
    element = $(element);
    var elementStyle = element.style, match;
    if (Object.isString(styles)) {
      element.style.cssText += ';' + styles;
      return styles.include('opacity') ?
        element.setOpacity(styles.match(/opacity:\s*(\d?\.?\d*)/)[1]) : element;
    }
    for (var property in styles)
      if (property == 'opacity') element.setOpacity(styles[property]);
      else
        elementStyle[(property == 'float' || property == 'cssFloat') ?
          (elementStyle.styleFloat === undefined ? 'cssFloat' : 'styleFloat') :
            property] = styles[property];

    return element;
  },

  setOpacity: function(element, value) {
    element = $(element);
    element.style.opacity = (value == 1 || value === '') ? '' :
      (value < 0.00001) ? 0 : value;
    return element;
  },

  getDimensions: function(element) {
    element = $(element);
    var display = $(element).getStyle('display');
    if (display != 'none' && display != null) // Safari bug
      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;
    var originalDisplay = els.display;
    els.visibility = 'hidden';
    els.position = 'absolute';
    els.display = 'block';
    var originalWidth = element.clientWidth;
    var originalHeight = element.clientHeight;
    els.display = originalDisplay;
    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;
      }
    }
    return element;
  },

  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 = '';
    }
    return element;
  },

  makeClipping: function(element) {
    element = $(element);
    if (element._overflow) return element;
    element._overflow = Element.getStyle(element, 'overflow') || 'auto';
    if (element._overflow !== 'hidden')
      element.style.overflow = 'hidden';
    return element;
  },

  undoClipping: function(element) {
    element = $(element);
    if (!element._overflow) return element;
    element.style.overflow = element._overflow == 'auto' ? '' : element._overflow;
    element._overflow = null;
    return element;
  },

  cumulativeOffset: function(element) {
    var valueT = 0, valueL = 0;
    do {
      valueT += element.offsetTop  || 0;
      valueL += element.offsetLeft || 0;
      element = element.offsetParent;
    } while (element);
    return Element._returnOffset(valueL, valueT);
  },

  positionedOffset: function(element) {
    var valueT = 0, valueL = 0;
    do {
      valueT += element.offsetTop  || 0;
      valueL += element.offsetLeft || 0;
      element = element.offsetParent;
      if (element) {
        if (element.tagName == 'BODY') break;
        var p = Element.getStyle(element, 'position');
        if (p == 'relative' || p == 'absolute') break;
      }
    } while (element);
    return Element._returnOffset(valueL, valueT);
  },

  absolutize: function(element) {
    element = $(element);
    if (element.getStyle('position') == 'absolute') return;
    // Position.prepare(); // To be done manually by Scripty when it needs it.

    var offsets = element.positionedOffset();
    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';
    return element;
  },

  relativize: function(element) {
    element = $(element);
    if (element.getStyle('position') == 'relative') return;
    // Position.prepare(); // To be done manually by Scripty when it needs it.

    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;
    return element;
  },

  cumulativeScrollOffset: function(element) {
    var valueT = 0, valueL = 0;
    do {
      valueT += element.scrollTop  || 0;
      valueL += element.scrollLeft || 0;
      element = element.parentNode;
    } while (element);
    return Element._returnOffset(valueL, valueT);
  },

  getOffsetParent: 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);
  },

  viewportOffset: 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 &&
        Element.getStyle(element, 'position') == 'absolute') break;

    } while (element = element.offsetParent);

    element = forElement;
    do {
      if (!Prototype.Browser.Opera || element.tagName == 'BODY') {
        valueT -= element.scrollTop  || 0;
        valueL -= element.scrollLeft || 0;
      }
    } while (element = element.parentNode);

    return Element._returnOffset(valueL, valueT);
  },

  clonePosition: function(element, source) {
    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 = source.viewportOffset();

    // find coordinate system to use
    element = $(element);
    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(element, 'position') == 'absolute') {
      parent = element.getOffsetParent();
      delta = parent.viewportOffset();
    }

    // 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)   element.style.left  = (p[0] - delta[0] + options.offsetLeft) + 'px';
    if (options.setTop)    element.style.top   = (p[1] - delta[1] + options.offsetTop) + 'px';
    if (options.setWidth)  element.style.width = source.offsetWidth + 'px';
    if (options.setHeight) element.style.height = source.offsetHeight + 'px';
    return element;
  }
};

Element.Methods.identify.counter = 1;

Object.extend(Element.Methods, {
  getElementsBySelector: Element.Methods.select,
  childElements: Element.Methods.immediateDescendants
});

Element._attributeTranslations = {
  write: {
    names: {
      className: 'class',
      htmlFor:   'for'
    },
    values: { }
  }
};


if (!document.createRange || Prototype.Browser.Opera) {
  Element.Methods.insert = function(element, insertions) {
    element = $(element);

    if (Object.isString(insertions) || Object.isNumber(insertions) ||
        Object.isElement(insertions) || (insertions && (insertions.toElement || insertions.toHTML)))
          insertions = { bottom: insertions };

    var t = Element._insertionTranslations, content, position, pos, tagName;

    for (position in insertions) {
      content  = insertions[position];
      position = position.toLowerCase();
      pos      = t[position];

      if (content && content.toElement) content = content.toElement();
      if (Object.isElement(content)) {
        pos.insert(element, content);
        continue;
      }

      content = Object.toHTML(content);
      tagName = ((position == 'before' || position == 'after')
        ? element.parentNode : element).tagName.toUpperCase();

      if (t.tags[tagName]) {
        var fragments = Element._getContentFromAnonymousElement(tagName, content.stripScripts());
        if (position == 'top' || position == 'after') fragments.reverse();
        fragments.each(pos.insert.curry(element));
      }
      else element.insertAdjacentHTML(pos.adjacency, content.stripScripts());

      content.evalScripts.bind(content).defer();
    }

    return element;
  };
}

if (Prototype.Browser.Opera) {
  Element.Methods._getStyle = Element.Methods.getStyle;
  Element.Methods.getStyle = function(element, style) {
    switch(style) {
      case 'left':
      case 'top':
      case 'right':
      case 'bottom':
        if (Element._getStyle(element, 'position') == 'static') return null;
      default: return Element._getStyle(element, style);
    }
  };
  Element.Methods._readAttribute = Element.Methods.readAttribute;
  Element.Methods.readAttribute = function(element, attribute) {
    if (attribute == 'title') return element.title;
    return Element._readAttribute(element, attribute);
  };
}

else if (Prototype.Browser.IE) {
  $w('positionedOffset getOffsetParent viewportOffset').each(function(method) {
    Element.Methods[method] = Element.Methods[method].wrap(
      function(proceed, element) {
        element = $(element);
        var position = element.getStyle('position');
        if (position != 'static') return proceed(element);
        element.setStyle({ position: 'relative' });
        var value = proceed(element);
        element.setStyle({ position: position });
        return value;
      }
    );
  });

  Element.Methods.getStyle = function(element, style) {
    element = $(element);
    style = (style == 'float' || style == 'cssFloat') ? 'styleFloat' : style.camelize();
    var value = element.style[style];
    if (!value && element.currentStyle) value = element.currentStyle[style];

    if (style == 'opacity') {
      if (value = (element.getStyle('filter') || '').match(/alpha\(opacity=(.*)\)/))
        if (value[1]) return parseFloat(value[1]) / 100;
      return 1.0;
    }

    if (value == 'auto') {
      if ((style == 'width' || style == 'height') && (element.getStyle('display') != 'none'))
        return element['offset' + style.capitalize()] + 'px';
      return null;
    }
    return value;
  };

  Element.Methods.setOpacity = function(element, value) {
    function stripAlpha(filter){
      return filter.replace(/alpha\([^\)]*\)/gi,'');
    }
    element = $(element);
    var currentStyle = element.currentStyle;
    if ((currentStyle && !currentStyle.hasLayout) ||
      (!currentStyle && element.style.zoom == 'normal'))
        element.style.zoom = 1;

    var filter = element.getStyle('filter'), style = element.style;
    if (value == 1 || value === '') {
      (filter = stripAlpha(filter)) ?
        style.filter = filter : style.removeAttribute('filter');
      return element;
    } else if (value < 0.00001) value = 0;
    style.filter = stripAlpha(filter) +
      'alpha(opacity=' + (value * 100) + ')';
    return element;
  };

  Element._attributeTranslations = {
    read: {
      names: {
        'class': 'className',
        'for':   'htmlFor'
      },
      values: {
        _getAttr: function(element, attribute) {
          return element.getAttribute(attribute, 2);
        },
        _getAttrNode: function(element, attribute) {
          var node = element.getAttributeNode(attribute);
          return node ? node.value : "";
        },
        _getEv: function(element, attribute) {
          var attribute = element.getAttribute(attribute);
          return attribute ? attribute.toString().slice(23, -2) : null;
        },
        _flag: function(element, attribute) {
          return $(element).hasAttribute(attribute) ? attribute : null;
        },
        style: function(element) {
          return element.style.cssText.toLowerCase();
        },
        title: function(element) {
          return element.title;
        }
      }
    }
  };

  Element._attributeTranslations.write = {
    names: Object.clone(Element._attributeTranslations.read.names),
    values: {
      checked: function(element, value) {
        element.checked = !!value;
      },

      style: function(element, value) {
        element.style.cssText = value ? value : '';
      }
    }
  };

  Element._attributeTranslations.has = {};

  $w('colSpan rowSpan vAlign dateTime accessKey tabIndex ' +
      'encType maxLength readOnly longDesc').each(function(attr) {
    Element._attributeTranslations.write.names[attr.toLowerCase()] = attr;
    Element._attributeTranslations.has[attr.toLowerCase()] = attr;
  });

  (function(v) {
    Object.extend(v, {
      href:        v._getAttr,
      src:         v._getAttr,
      type:        v._getAttr,
      action:      v._getAttrNode,
      disabled:    v._flag,
      checked:     v._flag,
      readonly:    v._flag,
      multiple:    v._flag,
      onload:      v._getEv,
      onunload:    v._getEv,
      onclick:     v._getEv,
      ondblclick:  v._getEv,
      onmousedown: v._getEv,
      onmouseup:   v._getEv,
      onmouseover: v._getEv,
      onmousemove: v._getEv,
      onmouseout:  v._getEv,
      onfocus:     v._getEv,
      onblur:      v._getEv,
      onkeypress:  v._getEv,
      onkeydown:   v._getEv,
      onkeyup:     v._getEv,
      onsubmit:    v._getEv,
      onreset:     v._getEv,
      onselect:    v._getEv,
      onchange:    v._getEv
    });
  })(Element._attributeTranslations.read.values);
}

else if (Prototype.Browser.Gecko && /rv:1\.8\.0/.test(navigator.userAgent)) {
  Element.Methods.setOpacity = function(element, value) {
    element = $(element);
    element.style.opacity = (value == 1) ? 0.999999 :
      (value === '') ? '' : (value < 0.00001) ? 0 : value;
    return element;
  };
}

else if (Prototype.Browser.WebKit) {
  Element.Methods.setOpacity = function(element, value) {
    element = $(element);
    element.style.opacity = (value == 1 || value === '') ? '' :
      (value < 0.00001) ? 0 : value;

    if (value == 1)
      if(element.tagName == 'IMG' && element.width) {
        element.width++; element.width--;
      } else try {
        var n = document.createTextNode(' ');
        element.appendChild(n);
        element.removeChild(n);
      } catch (e) { }

    return element;
  };

  // Safari returns margins on body which is incorrect if the child is absolutely
  // positioned.  For performance reasons, redefine Position.cumulativeOffset for
  // KHTML/WebKit only.
  Element.Methods.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 Element._returnOffset(valueL, valueT);
  };
}

if (Prototype.Browser.IE || Prototype.Browser.Opera) {
  // IE and Opera are missing .innerHTML support for TABLE-related and SELECT elements
  Element.Methods.update = function(element, content) {
    element = $(element);

    if (content && content.toElement) content = content.toElement();
    if (Object.isElement(content)) return element.update().insert(content);

    content = Object.toHTML(content);
    var tagName = element.tagName.toUpperCase();

    if (tagName in Element._insertionTranslations.tags) {
      $A(element.childNodes).each(function(node) { element.removeChild(node) });
      Element._getContentFromAnonymousElement(tagName, content.stripScripts())
        .each(function(node) { element.appendChild(node) });
    }
    else element.innerHTML = content.stripScripts();

    content.evalScripts.bind(content).defer();
    return element;
  };
}

if (document.createElement('div').outerHTML) {
  Element.Methods.replace = function(element, content) {
    element = $(element);

    if (content && content.toElement) content = content.toElement();
    if (Object.isElement(content)) {
      element.parentNode.replaceChild(content, element);
      return element;
    }

    content = Object.toHTML(content);
    var parent = element.parentNode, tagName = parent.tagName.toUpperCase();

    if (Element._insertionTranslations.tags[tagName]) {
      var nextSibling = element.next();
      var fragments = Element._getContentFromAnonymousElement(tagName, content.stripScripts());
      parent.removeChild(element);
      if (nextSibling)
        fragments.each(function(node) { parent.insertBefore(node, nextSibling) });
      else
        fragments.each(function(node) { parent.appendChild(node) });
    }
    else element.outerHTML = content.stripScripts();

    content.evalScripts.bind(content).defer();
    return element;
  };
}

Element._returnOffset = function(l, t) {
  var result = [l, t];
  result.left = l;
  result.top = t;
  return result;
};

Element._getContentFromAnonymousElement = function(tagName, html) {
  var div = new Element('div'), t = Element._insertionTranslations.tags[tagName];
  div.innerHTML = t[0] + html + t[1];
  t[2].times(function() { div = div.firstChild });
  return $A(div.childNodes);
};

Element._insertionTranslations = {
  before: {
    adjacency: 'beforeBegin',
    insert: function(element, node) {
      element.parentNode.insertBefore(node, element);
    },
    initializeRange: function(element, range) {
      range.setStartBefore(element);
    }
  },
  top: {
    adjacency: 'afterBegin',
    insert: function(element, node) {
      element.insertBefore(node, element.firstChild);
    },
    initializeRange: function(element, range) {
      range.selectNodeContents(element);
      range.collapse(true);
    }
  },
  bottom: {
    adjacency: 'beforeEnd',
    insert: function(element, node) {
      element.appendChild(node);
    }
  },
  after: {
    adjacency: 'afterEnd',
    insert: function(element, node) {
      element.parentNode.insertBefore(node, element.nextSibling);
    },
    initializeRange: function(element, range) {
      range.setStartAfter(element);
    }
  },
  tags: {
    TABLE:  ['<table>',                '</table>',                   1],
    TBODY:  ['<table><tbody>',         '</tbody></table>',           2],
    TR:     ['<table><tbody><tr>',     '</tr></tbody></table>',      3],
    TD:     ['<table><tbody><tr><td>', '</td></tr></tbody></table>', 4],
    SELECT: ['<select>',               '</select>',                  1]
  }
};

(function() {
  this.bottom.initializeRange = this.top.initializeRange;
  Object.extend(this.tags, {
    THEAD: this.tags.TBODY,
    TFOOT: this.tags.TBODY,
    TH:    this.tags.TD
  });
}).call(Element._insertionTranslations);

Element.Methods.Simulated = {
  hasAttribute: function(element, attribute) {
    attribute = Element._attributeTranslations.has[attribute] || attribute;
    var node = $(element).getAttributeNode(attribute);
    return node && node.specified;
  }
};

Element.Methods.ByTag = { };

Object.extend(Element, Element.Methods);

if (!Prototype.BrowserFeatures.ElementExtensions &&
    document.createElement('div').__proto__) {
  window.HTMLElement = { };
  window.HTMLElement.prototype = document.createElement('div').__proto__;
  Prototype.BrowserFeatures.ElementExtensions = true;
}

Element.extend = (function() {
  if (Prototype.BrowserFeatures.SpecificElementExtensions)
    return Prototype.K;

  var Methods = { }, ByTag = Element.Methods.ByTag;

  var extend = Object.extend(function(element) {
    if (!element || element._extendedByPrototype ||
        element.nodeType != 1 || element == window) return element;

    var methods = Object.clone(Methods),
      tagName = element.tagName, property, value;

    // extend methods for specific tags
    if (ByTag[tagName]) Object.extend(methods, ByTag[tagName]);

    for (property in methods) {
      value = methods[property];
      if (Object.isFunction(value) && !(property in element))
        element[property] = value.methodize();
    }

    element._extendedByPrototype = Prototype.emptyFunction;
    return element;

  }, {
    refresh: function() {
      // extend methods for all tags (Safari doesn't need this)
      if (!Prototype.BrowserFeatures.ElementExtensions) {
        Object.extend(Methods, Element.Methods);
        Object.extend(Methods, Element.Methods.Simulated);
      }
    }
  });

  extend.refresh();
  return extend;
})();

Element.hasAttribute = function(element, attribute) {
  if (element.hasAttribute) return element.hasAttribute(attribute);
  return Element.Methods.Simulated.hasAttribute(element, attribute);
};

Element.addMethods = function(methods) {
  var F = Prototype.BrowserFeatures, T = Element.Methods.ByTag;

  if (!methods) {
    Object.extend(Form, Form.Methods);
    Object.extend(Form.Element, Form.Element.Methods);
    Object.extend(Element.Methods.ByTag, {
      "FORM":     Object.clone(Form.Methods),
      "INPUT":    Object.clone(Form.Element.Methods),
      "SELECT":   Object.clone(Form.Element.Methods),
      "TEXTAREA": Object.clone(Form.Element.Methods)
    });
  }

  if (arguments.length == 2) {
    var tagName = methods;
    methods = arguments[1];
  }

  if (!tagName) Object.extend(Element.Methods, methods || { });
  else {
    if (Object.isArray(tagName)) tagName.each(extend);
    else extend(tagName);
  }

  function extend(tagName) {
    tagName = tagName.toUpperCase();
    if (!Element.Methods.ByTag[tagName])
      Element.Methods.ByTag[tagName] = { };
    Object.extend(Element.Methods.ByTag[tagName], methods);
  }

  function copy(methods, destination, onlyIfAbsent) {
    onlyIfAbsent = onlyIfAbsent || false;
    for (var property in methods) {
      var value = methods[property];
      if (!Object.isFunction(value)) continue;
      if (!onlyIfAbsent || !(property in destination))
        destination[property] = value.methodize();
    }
  }

  function findDOMClass(tagName) {
    var klass;
    var trans = {
      "OPTGROUP": "OptGroup", "TEXTAREA": "TextArea", "P": "Paragraph",
      "FIELDSET": "FieldSet", "UL": "UList", "OL": "OList", "DL": "DList",
      "DIR": "Directory", "H1": "Heading", "H2": "Heading", "H3": "Heading",
      "H4": "Heading", "H5": "Heading", "H6": "Heading", "Q": "Quote",
      "INS": "Mod", "DEL": "Mod", "A": "Anchor", "IMG": "Image", "CAPTION":
      "TableCaption", "COL": "TableCol", "COLGROUP": "TableCol", "THEAD":
      "TableSection", "TFOOT": "TableSection", "TBODY": "TableSection", "TR":
      "TableRow", "TH": "TableCell", "TD": "TableCell", "FRAMESET":
      "FrameSet", "IFRAME": "IFrame"
    };
    if (trans[tagName]) klass = 'HTML' + trans[tagName] + 'Element';
    if (window[klass]) return window[klass];
    klass = 'HTML' + tagName + 'Element';
    if (window[klass]) return window[klass];
    klass = 'HTML' + tagName.capitalize() + 'Element';
    if (window[klass]) return window[klass];

    window[klass] = { };
    window[klass].prototype = document.createElement(tagName).__proto__;
    return window[klass];
  }

  if (F.ElementExtensions) {
    copy(Element.Methods, HTMLElement.prototype);
    copy(Element.Methods.Simulated, HTMLElement.prototype, true);
  }

  if (F.SpecificElementExtensions) {
    for (var tag in Element.Methods.ByTag) {
      var klass = findDOMClass(tag);
      if (Object.isUndefined(klass)) continue;
      copy(T[tag], klass.prototype);
    }
  }

  Object.extend(Element, Element.Methods);
  delete Element.ByTag;

  if (Element.extend.refresh) Element.extend.refresh();
  Element.cache = { };
};

document.viewport = {
  getDimensions: function() {
    var dimensions = { };
    $w('width height').each(function(d) {
      var D = d.capitalize();
      dimensions[d] = self['inner' + D] ||
       (document.documentElement['client' + D] || document.body['client' + D]);
    });
    return dimensions;
  },

  getWidth: function() {
    return this.getDimensions().width;
  },

  getHeight: function() {
    return this.getDimensions().height;
  },

  getScrollOffsets: function() {
    return Element._returnOffset(
      window.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft,
      window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop);
  }
};
/* Portions of the Selector class are derived from Jack Slocum’s DomQuery,
 * part of YUI-Ext version 0.40, distributed under the terms of an MIT-style
 * license.  Please see http://www.yui-ext.com/ for more information. */

var Selector = Class.create({
  initialize: function(expression) {
    this.expression = expression.strip();
    this.compileMatcher();
  },

  compileMatcher: function() {
    // Selectors with namespaced attributes can't use the XPath version
    if (Prototype.BrowserFeatures.XPath && !(/(\[[\w-]*?:|:checked)/).test(this.expression))
      return this.compileXPathMatcher();

    var e = this.expression, ps = Selector.patterns, h = Selector.handlers,
        c = Selector.criteria, le, p, m;

    if (Selector._cache[e]) {
      this.matcher = Selector._cache[e];
      return;
    }

    this.matcher = ["this.matcher = function(root) {",
                    "var r = root, h = Selector.handlers, c = false, n;"];

    while (e && le != e && (/\S/).test(e)) {
      le = e;
      for (var i in ps) {
        p = ps[i];
        if (m = e.match(p)) {
          this.matcher.push(Object.isFunction(c[i]) ? c[i](m) :
    	      new Template(c[i]).evaluate(m));
          e = e.replace(m[0], '');
          break;
        }
      }
    }

    this.matcher.push("return h.unique(n);\n}");
    eval(this.matcher.join('\n'));
    Selector._cache[this.expression] = this.matcher;
  },

  compileXPathMatcher: function() {
    var e = this.expression, ps = Selector.patterns,
        x = Selector.xpath, le, m;

    if (Selector._cache[e]) {
      this.xpath = Selector._cache[e]; return;
    }

    this.matcher = ['.//*'];
    while (e && le != e && (/\S/).test(e)) {
      le = e;
      for (var i in ps) {
        if (m = e.match(ps[i])) {
          this.matcher.push(Object.isFunction(x[i]) ? x[i](m) :
            new Template(x[i]).evaluate(m));
          e = e.replace(m[0], '');
          break;
        }
      }
    }

    this.xpath = this.matcher.join('');
    Selector._cache[this.expression] = this.xpath;
  },

  findElements: function(root) {
    root = root || document;
    if (this.xpath) return document._getElementsByXPath(this.xpath, root);
    return this.matcher(root);
  },

  match: function(element) {
    this.tokens = [];

    var e = this.expression, ps = Selector.patterns, as = Selector.assertions;
    var le, p, m;

    while (e && le !== e && (/\S/).test(e)) {
      le = e;
      for (var i in ps) {
        p = ps[i];
        if (m = e.match(p)) {
          // use the Selector.assertions methods unless the selector
          // is too complex.
          if (as[i]) {
            this.tokens.push([i, Object.clone(m)]);
            e = e.replace(m[0], '');
          } else {
            // reluctantly do a document-wide search
            // and look for a match in the array
            return this.findElements(document).include(element);
          }
        }
      }
    }

    var match = true, name, matches;
    for (var i = 0, token; token = this.tokens[i]; i++) {
      name = token[0], matches = token[1];
      if (!Selector.assertions[name](element, matches)) {
        match = false; break;
      }
    }

    return match;
  },

  toString: function() {
    return this.expression;
  },

  inspect: function() {
    return "#<Selector:" + this.expression.inspect() + ">";
  }
});

Object.extend(Selector, {
  _cache: { },

  xpath: {
    descendant:   "//*",
    child:        "/*",
    adjacent:     "/following-sibling::*[1]",
    laterSibling: '/following-sibling::*',
    tagName:      function(m) {
      if (m[1] == '*') return '';
      return "[local-name()='" + m[1].toLowerCase() +
             "' or local-name()='" + m[1].toUpperCase() + "']";
    },
    className:    "[contains(concat(' ', @class, ' '), ' #{1} ')]",
    id:           "[@id='#{1}']",
    attrPresence: "[@#{1}]",
    attr: function(m) {
      m[3] = m[5] || m[6];
      return new Template(Selector.xpath.operators[m[2]]).evaluate(m);
    },
    pseudo: function(m) {
      var h = Selector.xpath.pseudos[m[1]];
      if (!h) return '';
      if (Object.isFunction(h)) return h(m);
      return new Template(Selector.xpath.pseudos[m[1]]).evaluate(m);
    },
    operators: {
      '=':  "[@#{1}='#{3}']",
      '!=': "[@#{1}!='#{3}']",
      '^=': "[starts-with(@#{1}, '#{3}')]",
      '$=': "[substring(@#{1}, (string-length(@#{1}) - string-length('#{3}') + 1))='#{3}']",
      '*=': "[contains(@#{1}, '#{3}')]",
      '~=': "[contains(concat(' ', @#{1}, ' '), ' #{3} ')]",
      '|=': "[contains(concat('-', @#{1}, '-'), '-#{3}-')]"
    },
    pseudos: {
      'first-child': '[not(preceding-sibling::*)]',
      'last-child':  '[not(following-sibling::*)]',
      'only-child':  '[not(preceding-sibling::* or following-sibling::*)]',
      'empty':       "[count(*) = 0 and (count(text()) = 0 or translate(text(), ' \t\r\n', '') = '')]",
      'checked':     "[@checked]",
      'disabled':    "[@disabled]",
      'enabled':     "[not(@disabled)]",
      'not': function(m) {
        var e = m[6], p = Selector.patterns,
            x = Selector.xpath, le, m, v;

        var exclusion = [];
        while (e && le != e && (/\S/).test(e)) {
          le = e;
          for (var i in p) {
            if (m = e.match(p[i])) {
              v = Object.isFunction(x[i]) ? x[i](m) : new Template(x[i]).evaluate(m);
              exclusion.push("(" + v.substring(1, v.length - 1) + ")");
              e = e.replace(m[0], '');
              break;
            }
          }
        }
        return "[not(" + exclusion.join(" and ") + ")]";
      },
      'nth-child':      function(m) {
        return Selector.xpath.pseudos.nth("(count(./preceding-sibling::*) + 1) ", m);
      },
      'nth-last-child': function(m) {
        return Selector.xpath.pseudos.nth("(count(./following-sibling::*) + 1) ", m);
      },
      'nth-of-type':    function(m) {
        return Selector.xpath.pseudos.nth("position() ", m);
      },
      'nth-last-of-type': function(m) {
        return Selector.xpath.pseudos.nth("(last() + 1 - position()) ", m);
      },
      'first-of-type':  function(m) {
        m[6] = "1"; return Selector.xpath.pseudos['nth-of-type'](m);
      },
      'last-of-type':   function(m) {
        m[6] = "1"; return Selector.xpath.pseudos['nth-last-of-type'](m);
      },
      'only-of-type':   function(m) {
        var p = Selector.xpath.pseudos; return p['first-of-type'](m) + p['last-of-type'](m);
      },
      nth: function(fragment, m) {
        var mm, formula = m[6], predicate;
        if (formula == 'even') formula = '2n+0';
        if (formula == 'odd')  formula = '2n+1';
        if (mm = formula.match(/^(\d+)$/)) // digit only
          return '[' + fragment + "= " + mm[1] + ']';
        if (mm = formula.match(/^(-?\d*)?n(([+-])(\d+))?/)) { // an+b
          if (mm[1] == "-") mm[1] = -1;
          var a = mm[1] ? Number(mm[1]) : 1;
          var b = mm[2] ? Number(mm[2]) : 0;
          predicate = "[((#{fragment} - #{b}) mod #{a} = 0) and " +
          "((#{fragment} - #{b}) div #{a} >= 0)]";
          return new Template(predicate).evaluate({
            fragment: fragment, a: a, b: b });
        }
      }
    }
  },

  criteria: {
    tagName:      'n = h.tagName(n, r, "#{1}", c);   c = false;',
    className:    'n = h.className(n, r, "#{1}", c); c = false;',
    id:           'n = h.id(n, r, "#{1}", c);        c = false;',
    attrPresence: 'n = h.attrPresence(n, r, "#{1}"); c = false;',
    attr: function(m) {
      m[3] = (m[5] || m[6]);
      return new Template('n = h.attr(n, r, "#{1}", "#{3}", "#{2}"); c = false;').evaluate(m);
    },
    pseudo: function(m) {
      if (m[6]) m[6] = m[6].replace(/"/g, '\\"');
      return new Template('n = h.pseudo(n, "#{1}", "#{6}", r, c); c = false;').evaluate(m);
    },
    descendant:   'c = "descendant";',
    child:        'c = "child";',
    adjacent:     'c = "adjacent";',
    laterSibling: 'c = "laterSibling";'
  },

  patterns: {
    // combinators must be listed first
    // (and descendant needs to be last combinator)
    laterSibling: /^\s*~\s*/,
    child:        /^\s*>\s*/,
    adjacent:     /^\s*\+\s*/,
    descendant:   /^\s/,

    // selectors follow
    tagName:      /^\s*(\*|[\w\-]+)(\b|$)?/,
    id:           /^#([\w\-\*]+)(\b|$)/,
    className:    /^\.([\w\-\*]+)(\b|$)/,
    pseudo:       /^:((first|last|nth|nth-last|only)(-child|-of-type)|empty|checked|(en|dis)abled|not)(\((.*?)\))?(\b|$|(?=\s)|(?=:))/,
    attrPresence: /^\[([\w]+)\]/,
    attr:         /\[((?:[\w-]*:)?[\w-]+)\s*(?:([!^$*~|]?=)\s*((['"])([^\4]*?)\4|([^'"][^\]]*?)))?\]/
  },

  // for Selector.match and Element#match
  assertions: {
    tagName: function(element, matches) {
      return matches[1].toUpperCase() == element.tagName.toUpperCase();
    },

    className: function(element, matches) {
      return Element.hasClassName(element, matches[1]);
    },

    id: function(element, matches) {
      return element.id === matches[1];
    },

    attrPresence: function(element, matches) {
      return Element.hasAttribute(element, matches[1]);
    },

    attr: function(element, matches) {
      var nodeValue = Element.readAttribute(element, matches[1]);
      return Selector.operators[matches[2]](nodeValue, matches[3]);
    }
  },

  handlers: {
    // UTILITY FUNCTIONS
    // joins two collections
    concat: function(a, b) {
      for (var i = 0, node; node = b[i]; i++)
        a.push(node);
      return a;
    },

    // marks an array of nodes for counting
    mark: function(nodes) {
      for (var i = 0, node; node = nodes[i]; i++)
        node._counted = true;
      return nodes;
    },

    unmark: function(nodes) {
      for (var i = 0, node; node = nodes[i]; i++)
        node._counted = undefined;
      return nodes;
    },

    // mark each child node with its position (for nth calls)
    // "ofType" flag indicates whether we're indexing for nth-of-type
    // rather than nth-child
    index: function(parentNode, reverse, ofType) {
      parentNode._counted = true;
      if (reverse) {
        for (var nodes = parentNode.childNodes, i = nodes.length - 1, j = 1; i >= 0; i--) {
          var node = nodes[i];
          if (node.nodeType == 1 && (!ofType || node._counted)) node.nodeIndex = j++;
        }
      } else {
        for (var i = 0, j = 1, nodes = parentNode.childNodes; node = nodes[i]; i++)
          if (node.nodeType == 1 && (!ofType || node._counted)) node.nodeIndex = j++;
      }
    },

    // filters out duplicates and extends all nodes
    unique: function(nodes) {
      if (nodes.length == 0) return nodes;
      var results = [], n;
      for (var i = 0, l = nodes.length; i < l; i++)
        if (!(n = nodes[i])._counted) {
          n._counted = true;
          results.push(Element.extend(n));
        }
      return Selector.handlers.unmark(results);
    },

    // COMBINATOR FUNCTIONS
    descendant: function(nodes) {
      var h = Selector.handlers;
      for (var i = 0, results = [], node; node = nodes[i]; i++)
        h.concat(results, node.getElementsByTagName('*'));
      return results;
    },

    child: function(nodes) {
      var h = Selector.handlers;
      for (var i = 0, results = [], node; node = nodes[i]; i++) {
        for (var j = 0, children = [], child; child = node.childNodes[j]; j++)
          if (child.nodeType == 1 && child.tagName != '!') results.push(child);
      }
      return results;
    },

    adjacent: function(nodes) {
      for (var i = 0, results = [], node; node = nodes[i]; i++) {
        var next = this.nextElementSibling(node);
        if (next) results.push(next);
      }
      return results;
    },

    laterSibling: function(nodes) {
      var h = Selector.handlers;
      for (var i = 0, results = [], node; node = nodes[i]; i++)
        h.concat(results, Element.nextSiblings(node));
      return results;
    },

    nextElementSibling: function(node) {
      while (node = node.nextSibling)
	      if (node.nodeType == 1) return node;
      return null;
    },

    previousElementSibling: function(node) {
      while (node = node.previousSibling)
        if (node.nodeType == 1) return node;
      return null;
    },

    // TOKEN FUNCTIONS
    tagName: function(nodes, root, tagName, combinator) {
      tagName = tagName.toUpperCase();
      var results = [], h = Selector.handlers;
      if (nodes) {
        if (combinator) {
          // fastlane for ordinary descendant combinators
          if (combinator == "descendant") {
            for (var i = 0, node; node = nodes[i]; i++)
              h.concat(results, node.getElementsByTagName(tagName));
            return results;
          } else nodes = this[combinator](nodes);
          if (tagName == "*") return nodes;
        }
        for (var i = 0, node; node = nodes[i]; i++)
          if (node.tagName.toUpperCase() == tagName) results.push(node);
        return results;
      } else return root.getElementsByTagName(tagName);
    },

    id: function(nodes, root, id, combinator) {
      var targetNode = $(id), h = Selector.handlers;
      if (!targetNode) return [];
      if (!nodes && root == document) return [targetNode];
      if (nodes) {
        if (combinator) {
          if (combinator == 'child') {
            for (var i = 0, node; node = nodes[i]; i++)
              if (targetNode.parentNode == node) return [targetNode];
          } else if (combinator == 'descendant') {
            for (var i = 0, node; node = nodes[i]; i++)
              if (Element.descendantOf(targetNode, node)) return [targetNode];
          } else if (combinator == 'adjacent') {
            for (var i = 0, node; node = nodes[i]; i++)
              if (Selector.handlers.previousElementSibling(targetNode) == node)
                return [targetNode];
          } else nodes = h[combinator](nodes);
        }
        for (var i = 0, node; node = nodes[i]; i++)
          if (node == targetNode) return [targetNode];
        return [];
      }
      return (targetNode && Element.descendantOf(targetNode, root)) ? [targetNode] : [];
    },

    className: function(nodes, root, className, combinator) {
      if (nodes && combinator) nodes = this[combinator](nodes);
      return Selector.handlers.byClassName(nodes, root, className);
    },

    byClassName: function(nodes, root, className) {
      if (!nodes) nodes = Selector.handlers.descendant([root]);
      var needle = ' ' + className + ' ';
      for (var i = 0, results = [], node, nodeClassName; node = nodes[i]; i++) {
        nodeClassName = node.className;
        if (nodeClassName.length == 0) continue;
        if (nodeClassName == className || (' ' + nodeClassName + ' ').include(needle))
          results.push(node);
      }
      return results;
    },

    attrPresence: function(nodes, root, attr) {
      if (!nodes) nodes = root.getElementsByTagName("*");
      var results = [];
      for (var i = 0, node; node = nodes[i]; i++)
        if (Element.hasAttribute(node, attr)) results.push(node);
      return results;
    },

    attr: function(nodes, root, attr, value, operator) {
      if (!nodes) nodes = root.getElementsByTagName("*");
      var handler = Selector.operators[operator], results = [];
      for (var i = 0, node; node = nodes[i]; i++) {
        var nodeValue = Element.readAttribute(node, attr);
        if (nodeValue === null) continue;
        if (handler(nodeValue, value)) results.push(node);
      }
      return results;
    },

    pseudo: function(nodes, name, value, root, combinator) {
      if (nodes && combinator) nodes = this[combinator](nodes);
      if (!nodes) nodes = root.getElementsByTagName("*");
      return Selector.pseudos[name](nodes, value, root);
    }
  },

  pseudos: {
    'first-child': function(nodes, value, root) {
      for (var i = 0, results = [], node; node = nodes[i]; i++) {
        if (Selector.handlers.previousElementSibling(node)) continue;
          results.push(node);
      }
      return results;
    },
    'last-child': function(nodes, value, root) {
      for (var i = 0, results = [], node; node = nodes[i]; i++) {
        if (Selector.handlers.nextElementSibling(node)) continue;
          results.push(node);
      }
      return results;
    },
    'only-child': function(nodes, value, root) {
      var h = Selector.handlers;
      for (var i = 0, results = [], node; node = nodes[i]; i++)
        if (!h.previousElementSibling(node) && !h.nextElementSibling(node))
          results.push(node);
      return results;
    },
    'nth-child':        function(nodes, formula, root) {
      return Selector.pseudos.nth(nodes, formula, root);
    },
    'nth-last-child':   function(nodes, formula, root) {
      return Selector.pseudos.nth(nodes, formula, root, true);
    },
    'nth-of-type':      function(nodes, formula, root) {
      return Selector.pseudos.nth(nodes, formula, root, false, true);
    },
    'nth-last-of-type': function(nodes, formula, root) {
      return Selector.pseudos.nth(nodes, formula, root, true, true);
    },
    'first-of-type':    function(nodes, formula, root) {
      return Selector.pseudos.nth(nodes, "1", root, false, true);
    },
    'last-of-type':     function(nodes, formula, root) {
      return Selector.pseudos.nth(nodes, "1", root, true, true);
    },
    'only-of-type':     function(nodes, formula, root) {
      var p = Selector.pseudos;
      return p['last-of-type'](p['first-of-type'](nodes, formula, root), formula, root);
    },

    // handles the an+b logic
    getIndices: function(a, b, total) {
      if (a == 0) return b > 0 ? [b] : [];
      return $R(1, total).inject([], function(memo, i) {
        if (0 == (i - b) % a && (i - b) / a >= 0) memo.push(i);
        return memo;
      });
    },

    // handles nth(-last)-child, nth(-last)-of-type, and (first|last)-of-type
    nth: function(nodes, formula, root, reverse, ofType) {
      if (nodes.length == 0) return [];
      if (formula == 'even') formula = '2n+0';
      if (formula == 'odd')  formula = '2n+1';
      var h = Selector.handlers, results = [], indexed = [], m;
      h.mark(nodes);
      for (var i = 0, node; node = nodes[i]; i++) {
        if (!node.parentNode._counted) {
          h.index(node.parentNode, reverse, ofType);
          indexed.push(node.parentNode);
        }
      }
      if (formula.match(/^\d+$/)) { // just a number
        formula = Number(formula);
        for (var i = 0, node; node = nodes[i]; i++)
          if (node.nodeIndex == formula) results.push(node);
      } else if (m = formula.match(/^(-?\d*)?n(([+-])(\d+))?/)) { // an+b
        if (m[1] == "-") m[1] = -1;
        var a = m[1] ? Number(m[1]) : 1;
        var b = m[2] ? Number(m[2]) : 0;
        var indices = Selector.pseudos.getIndices(a, b, nodes.length);
        for (var i = 0, node, l = indices.length; node = nodes[i]; i++) {
          for (var j = 0; j < l; j++)
            if (node.nodeIndex == indices[j]) results.push(node);
        }
      }
      h.unmark(nodes);
      h.unmark(indexed);
      return results;
    },

    'empty': function(nodes, value, root) {
      for (var i = 0, results = [], node; node = nodes[i]; i++) {
        // IE treats comments as element nodes
        if (node.tagName == '!' || (node.firstChild && !node.innerHTML.match(/^\s*$/))) continue;
        results.push(node);
      }
      return results;
    },

    'not': function(nodes, selector, root) {
      var h = Selector.handlers, selectorType, m;
      var exclusions = new Selector(selector).findElements(root);
      h.mark(exclusions);
      for (var i = 0, results = [], node; node = nodes[i]; i++)
        if (!node._counted) results.push(node);
      h.unmark(exclusions);
      return results;
    },

    'enabled': function(nodes, value, root) {
      for (var i = 0, results = [], node; node = nodes[i]; i++)
        if (!node.disabled) results.push(node);
      return results;
    },

    'disabled': function(nodes, value, root) {
      for (var i = 0, results = [], node; node = nodes[i]; i++)
        if (node.disabled) results.push(node);
      return results;
    },

    'checked': function(nodes, value, root) {
      for (var i = 0, results = [], node; node = nodes[i]; i++)
        if (node.checked) results.push(node);
      return results;
    }
  },

  operators: {
    '=':  function(nv, v) { return nv == v; },
    '!=': function(nv, v) { return nv != v; },
    '^=': function(nv, v) { return nv.startsWith(v); },
    '$=': function(nv, v) { return nv.endsWith(v); },
    '*=': function(nv, v) { return nv.include(v); },
    '~=': function(nv, v) { return (' ' + nv + ' ').include(' ' + v + ' '); },
    '|=': function(nv, v) { return ('-' + nv.toUpperCase() + '-').include('-' + v.toUpperCase() + '-'); }
  },

  matchElements: function(elements, expression) {
    var matches = new Selector(expression).findElements(), h = Selector.handlers;
    h.mark(matches);
    for (var i = 0, results = [], element; element = elements[i]; i++)
      if (element._counted) results.push(element);
    h.unmark(matches);
    return results;
  },

  findElement: function(elements, expression, index) {
    if (Object.isNumber(expression)) {
      index = expression; expression = false;
    }
    return Selector.matchElements(elements, expression || '*')[index || 0];
  },

  findChildElements: function(element, expressions) {
    var exprs = expressions.join(','), expressions = [];
    exprs.scan(/(([\w#:.~>+()\s-]+|\*|\[.*?\])+)\s*(,|$)/, function(m) {
      expressions.push(m[1].strip());
    });
    var results = [], h = Selector.handlers;
    for (var i = 0, l = expressions.length, selector; i < l; i++) {
      selector = new Selector(expressions[i].strip());
      h.concat(results, selector.findElements(element));
    }
    return (l > 1) ? h.unique(results) : results;
  }
});

function $$() {
  return Selector.findChildElements(document, $A(arguments));
}
var Form = {
  reset: function(form) {
    $(form).reset();
    return form;
  },

  serializeElements: function(elements, options) {
    if (typeof options != 'object') options = { hash: !!options };
    else if (options.hash === undefined) options.hash = true;
    var key, value, submitted = false, submit = options.submit;

    var data = elements.inject({ }, function(result, element) {
      if (!element.disabled && element.name) {
        key = element.name; value = $(element).getValue();
        if (value != null && (element.type != 'submit' || (!submitted &&
            submit !== false && (!submit || key == submit) && (submitted = true)))) {
          if (key in result) {
            // a key is already present; construct an array of values
            if (!Object.isArray(result[key])) result[key] = [result[key]];
            result[key].push(value);
          }
          else result[key] = value;
        }
      }
      return result;
    });

    return options.hash ? data : Object.toQueryString(data);
  }
};

Form.Methods = {
  serialize: function(form, options) {
    return Form.serializeElements(Form.getElements(form), options);
  },

  getElements: function(form) {
    return $A($(form).getElementsByTagName('*')).inject([],
      function(elements, child) {
        if (Form.Element.Serializers[child.tagName.toLowerCase()])
          elements.push(Element.extend(child));
        return elements;
      }
    );
  },

  getInputs: function(form, typeName, name) {
    form = $(form);
    var inputs = form.getElementsByTagName('input');

    if (!typeName && !name) return $A(inputs).map(Element.extend);

    for (var i = 0, matchingInputs = [], length = inputs.length; i < length; i++) {
      var input = inputs[i];
      if ((typeName && input.type != typeName) || (name && input.name != name))
        continue;
      matchingInputs.push(Element.extend(input));
    }

    return matchingInputs;
  },

  disable: function(form) {
    form = $(form);
    Form.getElements(form).invoke('disable');
    return form;
  },

  enable: function(form) {
    form = $(form);
    Form.getElements(form).invoke('enable');
    return form;
  },

  findFirstElement: function(form) {
    var elements = $(form).getElements().findAll(function(element) {
      return 'hidden' != element.type && !element.disabled;
    });
    var firstByIndex = elements.findAll(function(element) {
      return element.hasAttribute('tabIndex') && element.tabIndex >= 0;
    }).sortBy(function(element) { return element.tabIndex }).first();

    return firstByIndex ? firstByIndex : elements.find(function(element) {
      return ['input', 'select', 'textarea'].include(element.tagName.toLowerCase());
    });
  },

  focusFirstElement: function(form) {
    form = $(form);
    form.findFirstElement().activate();
    return form;
  },

  request: function(form, options) {
    form = $(form), options = Object.clone(options || { });

    var params = options.parameters, action = form.readAttribute('action') || '';
    if (action.blank()) action = window.location.href;
    options.parameters = form.serialize(true);

    if (params) {
      if (Object.isString(params)) params = params.toQueryParams();
      Object.extend(options.parameters, params);
    }

    if (form.hasAttribute('method') && !options.method)
      options.method = form.method;

    return new Ajax.Request(action, options);
  }
};

/*--------------------------------------------------------------------------*/

Form.Element = {
  focus: function(element) {
    $(element).focus();
    return element;
  },

  select: function(element) {
    $(element).select();
    return element;
  }
};

Form.Element.Methods = {
  serialize: function(element) {
    element = $(element);
    if (!element.disabled && element.name) {
      var value = element.getValue();
      if (value != undefined) {
        var pair = { };
        pair[element.name] = value;
        return Object.toQueryString(pair);
      }
    }
    return '';
  },

  getValue: function(element) {
    element = $(element);
    var method = element.tagName.toLowerCase();
    return Form.Element.Serializers[method](element);
  },

  setValue: function(element, value) {
    element = $(element);
    var method = element.tagName.toLowerCase();
    Form.Element.Serializers[method](element, value);
    return element;
  },

  clear: function(element) {
    $(element).value = '';
    return element;
  },

  present: function(element) {
    return $(element).value != '';
  },

  activate: function(element) {
    element = $(element);
    try {
      element.focus();
      if (element.select && (element.tagName.toLowerCase() != 'input' ||
          !['button', 'reset', 'submit'].include(element.type)))
        element.select();
    } catch (e) { }
    return element;
  },

  disable: function(element) {
    element = $(element);
    element.blur();
    element.disabled = true;
    return element;
  },

  enable: function(element) {
    element = $(element);
    element.disabled = false;
    return element;
  }
};

/*--------------------------------------------------------------------------*/

var Field = Form.Element;
var $F = Form.Element.Methods.getValue;

/*--------------------------------------------------------------------------*/

Form.Element.Serializers = {
  input: function(element, value) {
    switch (element.type.toLowerCase()) {
      case 'checkbox':
      case 'radio':
        return Form.Element.Serializers.inputSelector(element, value);
      default:
        return Form.Element.Serializers.textarea(element, value);
    }
  },

  inputSelector: function(element, value) {
    if (value === undefined) return element.checked ? element.value : null;
    else element.checked = !!value;
  },

  textarea: function(element, value) {
    if (value === undefined) return element.value;
    else element.value = value;
  },

  select: function(element, index) {
    if (index === undefined)
      return this[element.type == 'select-one' ?
        'selectOne' : 'selectMany'](element);
    else {
      var opt, value, single = !Object.isArray(index);
      for (var i = 0, length = element.length; i < length; i++) {
        opt = element.options[i];
        value = this.optionValue(opt);
        if (single) {
          if (value == index) {
            opt.selected = true;
            return;
          }
        }
        else opt.selected = index.include(value);
      }
    }
  },

  selectOne: function(element) {
    var index = element.selectedIndex;
    return index >= 0 ? this.optionValue(element.options[index]) : null;
  },

  selectMany: function(element) {
    var values, length = element.length;
    if (!length) return null;

    for (var i = 0, values = []; i < length; i++) {
      var opt = element.options[i];
      if (opt.selected) values.push(this.optionValue(opt));
    }
    return values;
  },

  optionValue: function(opt) {
    // extend element because hasAttribute may not be native
    return Element.extend(opt).hasAttribute('value') ? opt.value : opt.text;
  }
};

/*--------------------------------------------------------------------------*/

Abstract.TimedObserver = Class.create(PeriodicalExecuter, {
  initialize: function($super, element, frequency, callback) {
    $super(callback, frequency);
    this.element   = $(element);
    this.lastValue = this.getValue();
  },

  execute: function() {
    var value = this.getValue();
    if (Object.isString(this.lastValue) && Object.isString(value) ?
        this.lastValue != value : String(this.lastValue) != String(value)) {
      this.callback(this.element, value);
      this.lastValue = value;
    }
  }
});

Form.Element.Observer = Class.create(Abstract.TimedObserver, {
  getValue: function() {
    return Form.Element.getValue(this.element);
  }
});

Form.Observer = Class.create(Abstract.TimedObserver, {
  getValue: function() {
    return Form.serialize(this.element);
  }
});

/*--------------------------------------------------------------------------*/

Abstract.EventObserver = Class.create({
  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() {
    Form.getElements(this.element).each(this.registerCallback, this);
  },

  registerCallback: function(element) {
    if (element.type) {
      switch (element.type.toLowerCase()) {
        case 'checkbox':
        case 'radio':
          Event.observe(element, 'click', this.onElementEvent.bind(this));
          break;
        default:
          Event.observe(element, 'change', this.onElementEvent.bind(this));
          break;
      }
    }
  }
});

Form.Element.EventObserver = Class.create(Abstract.EventObserver, {
  getValue: function() {
    return Form.Element.getValue(this.element);
  }
});

Form.EventObserver = Class.create(Abstract.EventObserver, {
  getValue: function() {
    return Form.serialize(this.element);
  }
});
if (!window.Event) var Event = { };

Object.extend(Event, {
  KEY_BACKSPACE: 8,
  KEY_TAB:       9,
  KEY_RETURN:   13,
  KEY_ESC:      27,
  KEY_LEFT:     37,
  KEY_UP:       38,
  KEY_RIGHT:    39,
  KEY_DOWN:     40,
  KEY_DELETE:   46,
  KEY_HOME:     36,
  KEY_END:      35,
  KEY_PAGEUP:   33,
  KEY_PAGEDOWN: 34,
  KEY_INSERT:   45,

  cache: { },

  relatedTarget: function(event) {
    var element;
    switch(event.type) {
      case 'mouseover': element = event.fromElement; break;
      case 'mouseout':  element = event.toElement;   break;
      default: return null;
    }
    return Element.extend(element);
  }
});

Event.Methods = (function() {
  var isButton;

  if (Prototype.Browser.IE) {
    var buttonMap = { 0: 1, 1: 4, 2: 2 };
    isButton = function(event, code) {
      return event.button == buttonMap[code];
    };

  } else if (Prototype.Browser.WebKit) {
    isButton = function(event, code) {
      switch (code) {
        case 0: return event.which == 1 && !event.metaKey;
        case 1: return event.which == 1 && event.metaKey;
        default: return false;
      }
    };

  } else {
    isButton = function(event, code) {
      return event.which ? (event.which === code + 1) : (event.button === code);
    };
  }

  return {
    isLeftClick:   function(event) { return isButton(event, 0) },
    isMiddleClick: function(event) { return isButton(event, 1) },
    isRightClick:  function(event) { return isButton(event, 2) },

    element: function(event) {
      var node = Event.extend(event).target;
      return Element.extend(node.nodeType == Node.TEXT_NODE ? node.parentNode : node);
    },

    findElement: function(event, expression) {
      var element = Event.element(event);
      return element.match(expression) ? element : element.up(expression);
    },

    pointer: function(event) {
      return {
        x: event.pageX || (event.clientX +
          (document.documentElement.scrollLeft || document.body.scrollLeft)),
        y: event.pageY || (event.clientY +
          (document.documentElement.scrollTop || document.body.scrollTop))
      };
    },

    pointerX: function(event) { return Event.pointer(event).x },
    pointerY: function(event) { return Event.pointer(event).y },

    stop: function(event) {
      Event.extend(event);
      event.preventDefault();
      event.stopPropagation();
      event.stopped = true;
    }
  };
})();

Event.extend = (function() {
  var methods = Object.keys(Event.Methods).inject({ }, function(m, name) {
    m[name] = Event.Methods[name].methodize();
    return m;
  });

  if (Prototype.Browser.IE) {
    Object.extend(methods, {
      stopPropagation: function() { this.cancelBubble = true },
      preventDefault:  function() { this.returnValue = false },
      inspect: function() { return "[object Event]" }
    });

    return function(event) {
      if (!event) return false;
      if (event._extendedByPrototype) return event;

      event._extendedByPrototype = Prototype.emptyFunction;
      var pointer = Event.pointer(event);
      Object.extend(event, {
        target: event.srcElement,
        relatedTarget: Event.relatedTarget(event),
        pageX:  pointer.x,
        pageY:  pointer.y
      });
      return Object.extend(event, methods);
    };

  } else {
    Event.prototype = Event.prototype || document.createEvent("HTMLEvents").__proto__;
    Object.extend(Event.prototype, methods);
    return Prototype.K;
  }
})();

Object.extend(Event, (function() {
  var cache = Event.cache;

  function getEventID(element) {
    if (element._eventID) return element._eventID;
    arguments.callee.id = arguments.callee.id || 1;
    return element._eventID = ++arguments.callee.id;
  }

  function getDOMEventName(eventName) {
    if (eventName && eventName.include(':')) return "dataavailable";
    return eventName;
  }

  function getCacheForID(id) {
    return cache[id] = cache[id] || { };
  }

  function getWrappersForEventName(id, eventName) {
    var c = getCacheForID(id);
    return c[eventName] = c[eventName] || [];
  }

  function createWrapper(element, eventName, handler) {
    var id = getEventID(element);
    var c = getWrappersForEventName(id, eventName);
    if (c.pluck("handler").include(handler)) return false;

    var wrapper = function(event) {
      if (!Event || !Event.extend ||
        (event.eventName && event.eventName != eventName))
          return false;

      Event.extend(event);
      handler.call(element, event)
    };

    wrapper.handler = handler;
    c.push(wrapper);
    return wrapper;
  }

  function findWrapper(id, eventName, handler) {
    var c = getWrappersForEventName(id, eventName);
    return c.find(function(wrapper) { return wrapper.handler == handler });
  }

  function destroyWrapper(id, eventName, handler) {
    var c = getCacheForID(id);
    if (!c[eventName]) return false;
    c[eventName] = c[eventName].without(findWrapper(id, eventName, handler));
  }

  function destroyCache() {
    for (var id in cache)
      for (var eventName in cache[id])
        cache[id][eventName] = null;
  }

  if (window.attachEvent) {
    window.attachEvent("onunload", destroyCache);
  }

  return {
    observe: function(element, eventName, handler) {
      element = $(element);
      var name = getDOMEventName(eventName);

      var wrapper = createWrapper(element, eventName, handler);
      if (!wrapper) return element;

      if (element.addEventListener) {
        element.addEventListener(name, wrapper, false);
      } else {
        element.attachEvent("on" + name, wrapper);
      }

      return element;
    },

    stopObserving: function(element, eventName, handler) {
      element = $(element);
      var id = getEventID(element), name = getDOMEventName(eventName);

      if (!handler && eventName) {
        getWrappersForEventName(id, eventName).each(function(wrapper) {
          element.stopObserving(eventName, wrapper.handler);
        });
        return element;

      } else if (!eventName) {
        Object.keys(getCacheForID(id)).each(function(eventName) {
          element.stopObserving(eventName);
        });
        return element;
      }

      var wrapper = findWrapper(id, eventName, handler);
      if (!wrapper) return element;

      if (element.removeEventListener) {
        element.removeEventListener(name, wrapper, false);
      } else {
        element.detachEvent("on" + name, wrapper);
      }

      destroyWrapper(id, eventName, handler);

      return element;
    },

    fire: function(element, eventName, memo) {
      element = $(element);
      if (element == document && document.createEvent && !element.dispatchEvent)
        element = document.documentElement;

      if (document.createEvent) {
        var event = document.createEvent("HTMLEvents");
        event.initEvent("dataavailable", true, true);
      } else {
        var event = document.createEventObject();
        event.eventType = "ondataavailable";
      }

      event.eventName = eventName;
      event.memo = memo || { };

      if (document.createEvent) {
        element.dispatchEvent(event);
      } else {
        element.fireEvent(event.eventType, event);
      }

      return event;
    }
  };
})());

Object.extend(Event, Event.Methods);

Element.addMethods({
  fire:          Event.fire,
  observe:       Event.observe,
  stopObserving: Event.stopObserving
});

Object.extend(document, {
  fire:          Element.Methods.fire.methodize(),
  observe:       Element.Methods.observe.methodize(),
  stopObserving: Element.Methods.stopObserving.methodize()
});

(function() {
  /* Support for the DOMContentLoaded event is based on work by Dan Webb,
     Matthias Miller, Dean Edwards and John Resig. */

  var timer, fired = false;

  function fireContentLoadedEvent() {
    if (fired) return;
    if (timer) window.clearInterval(timer);
    document.fire("dom:loaded");
    fired = true;
  }

  if (document.addEventListener) {
    if (Prototype.Browser.WebKit) {
      timer = window.setInterval(function() {
        if (/loaded|complete/.test(document.readyState))
          fireContentLoadedEvent();
      }, 0);

      Event.observe(window, "load", fireContentLoadedEvent);

    } else {
      document.addEventListener("DOMContentLoaded",
        fireContentLoadedEvent, false);
    }

  } else {
    document.write("<script id=__onDOMContentLoaded defer src=//:><\/script>");
    $("__onDOMContentLoaded").onreadystatechange = function() {
      if (this.readyState == "complete") {
        this.onreadystatechange = null;
        fireContentLoadedEvent();
      }
    };
  }
})();
/*------------------------------- DEPRECATED -------------------------------*/

Hash.toQueryString = Object.toQueryString;

var Toggle = { display: Element.toggle };

Element.Methods.childOf = Element.Methods.descendantOf;

var Insertion = {
  Before: function(element, content) {
    return Element.insert(element, {before:content});
  },

  Top: function(element, content) {
    return Element.insert(element, {top:content});
  },

  Bottom: function(element, content) {
    return Element.insert(element, {bottom:content});
  },

  After: function(element, content) {
    return Element.insert(element, {after:content});
  }
};

var $continue = new Error('"throw $continue" is deprecated, use "return" instead');

// This should be moved to script.aculo.us; notice the deprecated methods
// further below, that map to the newer Element methods.
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;
  },

  // 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 = Element.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 = Element.cumulativeScrollOffset(element);

    this.xcomp = x + offsetcache[0] - this.deltaX;
    this.ycomp = y + offsetcache[1] - this.deltaY;
    this.offset = Element.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;
  },

  // Deprecation layer -- use newer Element methods now (1.5.2).

  cumulativeOffset: Element.Methods.cumulativeOffset,

  positionedOffset: Element.Methods.positionedOffset,

  absolutize: function(element) {
    Position.prepare();
    return Element.absolutize(element);
  },

  relativize: function(element) {
    Position.prepare();
    return Element.relativize(element);
  },

  realOffset: Element.Methods.cumulativeScrollOffset,

  offsetParent: Element.Methods.getOffsetParent,

  page: Element.Methods.viewportOffset,

  clone: function(source, target, options) {
    options = options || { };
    return Element.clonePosition(target, source, options);
  }
};

/*--------------------------------------------------------------------------*/

if (!document.getElementsByClassName) document.getElementsByClassName = function(instanceMethods){
  function iter(name) {
    return name.blank() ? null : "[contains(concat(' ', @class, ' '), ' " + name + " ')]";
  }

  instanceMethods.getElementsByClassName = Prototype.BrowserFeatures.XPath ?
  function(element, className) {
    className = className.toString().strip();
    var cond = /\s/.test(className) ? $w(className).map(iter).join('') : iter(className);
    return cond ? document._getElementsByXPath('.//*' + cond, element) : [];
  } : function(element, className) {
    className = className.toString().strip();
    var elements = [], classNames = (/\s/.test(className) ? $w(className) : null);
    if (!classNames && !className) return elements;

    var nodes = $(element).getElementsByTagName('*');
    className = ' ' + className + ' ';

    for (var i = 0, child, cn; child = nodes[i]; i++) {
      if (child.className && (cn = ' ' + child.className + ' ') && (cn.include(className) ||
          (classNames && classNames.all(function(name) {
            return !name.toString().blank() && cn.include(' ' + name + ' ');
          }))))
        elements.push(Element.extend(child));
    }
    return elements;
  };

  return function(className, parentElement) {
    return $(parentElement || document.body).getElementsByClassName(className);
  };
}(Element.Methods);

/*--------------------------------------------------------------------------*/

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($A(this).concat(classNameToAdd).join(' '));
  },

  remove: function(classNameToRemove) {
    if (!this.include(classNameToRemove)) return;
    this.set($A(this).without(classNameToRemove).join(' '));
  },

  toString: function() {
    return $A(this).join(' ');
  }
};

Object.extend(Element.ClassNames.prototype, Enumerable);

/*--------------------------------------------------------------------------*/

Element.addMethods();

/* --- End prototype.js --- */
/* --- Start scriptaculous.js --- */

// script.aculo.us scriptaculous.js v1.8.0, Tue Nov 06 15:01:40 +0300 2007

// Copyright (c) 2005-2007 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
// 
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
// 
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
// For details, see the script.aculo.us web site: http://script.aculo.us/

var Scriptaculous = {
  Version: '1.8.0',
  require: function(libraryName) {
    // inserting via DOM fails in Safari 2.0, so brute force approach
    document.write('<script type="text/javascript" src="'+libraryName+'"><\/script>');
  },
  REQUIRED_PROTOTYPE: '1.6.0',
  load: function() {
    function convertVersionString(versionString){
      var r = versionString.split('.');
      return parseInt(r[0])*100000 + parseInt(r[1])*1000 + parseInt(r[2]);
    }
 
    if((typeof Prototype=='undefined') || 
       (typeof Element == 'undefined') || 
       (typeof Element.Methods=='undefined') ||
       (convertVersionString(Prototype.Version) < 
        convertVersionString(Scriptaculous.REQUIRED_PROTOTYPE)))
       throw("script.aculo.us requires the Prototype JavaScript framework >= " +
        Scriptaculous.REQUIRED_PROTOTYPE);
    
    $A(document.getElementsByTagName("script")).findAll( function(s) {
      return (s.src && s.src.match(/scriptaculous\.js(\?.*)?$/))
    }).each( function(s) {
      var path = s.src.replace(/scriptaculous\.js(\?.*)?$/,'');
      var includes = s.src.match(/\?.*load=([a-z,]*)/);
      (includes ? includes[1] : 'builder,effects,dragdrop,controls,slider,sound').split(',').each(
       function(include) { Scriptaculous.require(path+include+'.js') });
    });
  }
}

Scriptaculous.load();

/* --- End scriptaculous.js --- */
/* --- Start effects.js --- */

// script.aculo.us effects.js v1.8.0, Tue Nov 06 15:01:40 +0300 2007

// Copyright (c) 2005-2007 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
// Contributors:
//  Justin Palmer (http://encytemedia.com/)
//  Mark Pilgrim (http://diveintomark.org/)
//  Martin Bialasinki
// 
// script.aculo.us is freely distributable under the terms of an MIT-style license.
// For details, see the script.aculo.us web site: http://script.aculo.us/ 

// converts rgb() and #xxx to #xxxxxx format,  
// returns self (or first argument) if not convertable  
String.prototype.parseColor = function() {  
  var color = '#';
  if (this.slice(0,4) == 'rgb(') {  
    var cols = this.slice(4,this.length-1).split(',');  
    var i=0; do { color += parseInt(cols[i]).toColorPart() } while (++i<3);  
  } else {  
    if (this.slice(0,1) == '#') {  
      if (this.length==4) for(var i=1;i<4;i++) color += (this.charAt(i) + this.charAt(i)).toLowerCase();  
      if (this.length==7) color = this.toLowerCase();  
    }  
  }  
  return (color.length==7 ? color : (arguments[0] || this));  
};

/*--------------------------------------------------------------------------*/

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.collectTextNodesIgnoreClass(node, className) : ''));
  }).flatten().join('');
};

Element.setContentZoom = function(element, percent) {
  element = $(element);  
  element.setStyle({fontSize: (percent/100) + 'em'});   
  if (Prototype.Browser.WebKit) window.scrollBy(0,0);
  return element;
};

Element.getInlineOpacity = function(element){
  return $(element).style.opacity || '';
};

Element.forceRerendering = function(element) {
  try {
    element = $(element);
    var n = document.createTextNode(' ');
    element.appendChild(n);
    element.removeChild(n);
  } catch(e) { }
};

/*--------------------------------------------------------------------------*/

var Effect = {
  _elementDoesNotExistError: {
    name: 'ElementDoesNotExistError',
    message: 'The specified DOM element does not exist, but is required for this effect to operate'
  },
  Transitions: {
    linear: Prototype.K,
    sinoidal: function(pos) {
      return (-Math.cos(pos*Math.PI)/2) + 0.5;
    },
    reverse: function(pos) {
      return 1-pos;
    },
    flicker: function(pos) {
      var pos = ((-Math.cos(pos*Math.PI)/4) + 0.75) + Math.random()/4;
      return pos > 1 ? 1 : pos;
    },
    wobble: function(pos) {
      return (-Math.cos(pos*Math.PI*(9*pos))/2) + 0.5;
    },
    pulse: function(pos, pulses) { 
      pulses = pulses || 5; 
      return (
        ((pos % (1/pulses)) * pulses).round() == 0 ? 
              ((pos * pulses * 2) - (pos * pulses * 2).floor()) : 
          1 - ((pos * pulses * 2) - (pos * pulses * 2).floor())
        );
    },
    spring: function(pos) { 
      return 1 - (Math.cos(pos * 4.5 * Math.PI) * Math.exp(-pos * 6)); 
    },
    none: function(pos) {
      return 0;
    },
    full: function(pos) {
      return 1;
    }
  },
  DefaultOptions: {
    duration:   1.0,   // seconds
    fps:        100,   // 100= assume 66fps max.
    sync:       false, // true for combining
    from:       0.0,
    to:         1.0,
    delay:      0.0,
    queue:      'parallel'
  },
  tagifyText: function(element) {
    var tagifyStyle = 'position:relative';
    if (Prototype.Browser.IE) tagifyStyle += ';zoom:1';
    
    element = $(element);
    $A(element.childNodes).each( function(child) {
      if (child.nodeType==3) {
        child.nodeValue.toArray().each( function(character) {
          element.insertBefore(
            new Element('span', {style: tagifyStyle}).update(
              character == ' ' ? String.fromCharCode(160) : character), 
              child);
        });
        Element.remove(child);
      }
    });
  },
  multiple: function(element, effect) {
    var elements;
    if (((typeof element == 'object') || 
        Object.isFunction(element)) && 
       (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'), limit: 1 }
    }, arguments[2] || { });
    Effect[element.visible() ? 
      Effect.PAIRS[effect][1] : Effect.PAIRS[effect][0]](element, options);
  }
};

Effect.DefaultOptions.transition = Effect.Transitions.sinoidal;

/* ------------- core effects ------------- */

Effect.ScopedQueue = Class.create(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 = Object.isString(effect.options.queue) ? 
      effect.options.queue : effect.options.queue.position;
    
    switch(position) {
      case 'front':
        // move unstarted effects after this effect  
        this.effects.findAll(function(e){ return e.state=='idle' }).each( function(e) {
            e.startOn  += effect.finishOn;
            e.finishOn += effect.finishOn;
          });
        break;
      case 'with-last':
        timestamp = this.effects.pluck('startOn').max() || timestamp;
        break;
      case 'end':
        // start effect after last queued effect has finished
        timestamp = this.effects.pluck('finishOn').max() || timestamp;
        break;
    }
    
    effect.startOn  += timestamp;
    effect.finishOn += timestamp;

    if (!effect.options.queue.limit || (this.effects.length < effect.options.queue.limit))
      this.effects.push(effect);
    
    if (!this.interval)
      this.interval = setInterval(this.loop.bind(this), 15);
  },
  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();
    for(var i=0, len=this.effects.length;i<len;i++) 
      this.effects[i] && this.effects[i].loop(timePos);
  }
});

Effect.Queues = {
  instances: $H(),
  get: function(queueName) {
    if (!Object.isString(queueName)) return queueName;
    
    return this.instances.get(queueName) ||
      this.instances.set(queueName, new Effect.ScopedQueue());
  }
};
Effect.Queue = Effect.Queues.get('global');

Effect.Base = Class.create({
  position: null,
  start: function(options) {
    function codeForEvent(options,eventName){
      return (
        (options[eventName+'Internal'] ? 'this.options.'+eventName+'Internal(this);' : '') +
        (options[eventName] ? 'this.options.'+eventName+'(this);' : '')
      );
    }
    if (options && options.transition === false) options.transition = Effect.Transitions.linear;
    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.fromToDelta  = this.options.to-this.options.from;
    this.totalTime    = this.finishOn-this.startOn;
    this.totalFrames  = this.options.fps*this.options.duration;
    
    eval('this.render = function(pos){ '+
      'if (this.state=="idle"){this.state="running";'+
      codeForEvent(this.options,'beforeSetup')+
      (this.setup ? 'this.setup();':'')+ 
      codeForEvent(this.options,'afterSetup')+
      '};if (this.state=="running"){'+
      'pos=this.options.transition(pos)*'+this.fromToDelta+'+'+this.options.from+';'+
      'this.position=pos;'+
      codeForEvent(this.options,'beforeUpdate')+
      (this.update ? 'this.update(pos);':'')+
      codeForEvent(this.options,'afterUpdate')+
      '}}');
    
    this.event('beforeStart');
    if (!this.options.sync)
      Effect.Queues.get(Object.isString(this.options.queue) ? 
        '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.totalTime,
          frame = (pos * this.totalFrames).round();
      if (frame > this.currentFrame) {
        this.render(pos);
        this.currentFrame = frame;
      }
    }
  },
  cancel: function() {
    if (!this.options.sync)
      Effect.Queues.get(Object.isString(this.options.queue) ? 
        '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() {
    var data = $H();
    for(property in this)
      if (!Object.isFunction(this[property])) data.set(property, this[property]);
    return '#<Effect:' + data.inspect() + ',options:' + $H(this.options).inspect() + '>';
  }
});

Effect.Parallel = Class.create(Effect.Base, {
  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.Tween = Class.create(Effect.Base, {
  initialize: function(object, from, to) {
    object = Object.isString(object) ? $(object) : object;
    var args = $A(arguments), method = args.last(), 
      options = args.length == 5 ? args[3] : null;
    this.method = Object.isFunction(method) ? method.bind(object) :
      Object.isFunction(object[method]) ? object[method].bind(object) : 
      function(value) { object[method] = value };
    this.start(Object.extend({ from: from, to: to }, options || { }));
  },
  update: function(position) {
    this.method(position);
  }
});

Effect.Event = Class.create(Effect.Base, {
  initialize: function() {
    this.start(Object.extend({ duration: 0 }, arguments[0] || { }));
  },
  update: Prototype.emptyFunction
});

Effect.Opacity = Class.create(Effect.Base, {
  initialize: function(element) {
    this.element = $(element);
    if (!this.element) throw(Effect._elementDoesNotExistError);
    // make this work on IE on elements without 'layout'
    if (Prototype.Browser.IE && (!this.element.currentStyle.hasLayout))
      this.element.setStyle({zoom: 1});
    var options = Object.extend({
      from: this.element.getOpacity() || 0.0,
      to:   1.0
    }, arguments[1] || { });
    this.start(options);
  },
  update: function(position) {
    this.element.setOpacity(position);
  }
});

Effect.Move = Class.create(Effect.Base, {
  initialize: function(element) {
    this.element = $(element);
    if (!this.element) throw(Effect._elementDoesNotExistError);
    var options = Object.extend({
      x:    0,
      y:    0,
      mode: 'relative'
    }, arguments[1] || { });
    this.start(options);
  },
  setup: function() {
    this.element.makePositioned();
    this.originalLeft = parseFloat(this.element.getStyle('left') || '0');
    this.originalTop  = parseFloat(this.element.getStyle('top')  || '0');
    if (this.options.mode == 'absolute') {
      this.options.x = this.options.x - this.originalLeft;
      this.options.y = this.options.y - this.originalTop;
    }
  },
  update: function(position) {
    this.element.setStyle({
      left: (this.options.x  * position + this.originalLeft).round() + 'px',
      top:  (this.options.y  * position + this.originalTop).round()  + '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(Effect.Base, {
  initialize: function(element, percent) {
    this.element = $(element);
    if (!this.element) throw(Effect._elementDoesNotExistError);
    var options = Object.extend({
      scaleX: true,
      scaleY: true,
      scaleContent: true,
      scaleFromCenter: false,
      scaleMode: 'box',        // 'box' or 'contents' or { } with provided values
      scaleFrom: 100.0,
      scaleTo:   percent
    }, arguments[2] || { });
    this.start(options);
  },
  setup: function() {
    this.restoreAfterFinish = this.options.restoreAfterFinish || false;
    this.elementPositioning = this.element.getStyle('position');
    
    this.originalStyle = { };
    ['top','left','width','height','fontSize'].each( function(k) {
      this.originalStyle[k] = this.element.style[k];
    }.bind(this));
      
    this.originalTop  = this.element.offsetTop;
    this.originalLeft = this.element.offsetLeft;
    
    var fontSize = this.element.getStyle('font-size') || '100%';
    ['em','px','%','pt'].each( function(fontSizeType) {
      if (fontSize.indexOf(fontSizeType)>0) {
        this.fontSize     = parseFloat(fontSize);
        this.fontSizeType = fontSizeType;
      }
    }.bind(this));
    
    this.factor = (this.options.scaleTo - this.options.scaleFrom)/100;
    
    this.dims = null;
    if (this.options.scaleMode=='box')
      this.dims = [this.element.offsetHeight, this.element.offsetWidth];
    if (/^content/.test(this.options.scaleMode))
      this.dims = [this.element.scrollHeight, this.element.scrollWidth];
    if (!this.dims)
      this.dims = [this.options.scaleMode.originalHeight,
                   this.options.scaleMode.originalWidth];
  },
  update: function(position) {
    var currentScale = (this.options.scaleFrom/100.0) + (this.factor * position);
    if (this.options.scaleContent && this.fontSize)
      this.element.setStyle({fontSize: this.fontSize * currentScale + this.fontSizeType });
    this.setDimensions(this.dims[0] * currentScale, this.dims[1] * currentScale);
  },
  finish: function(position) {
    if (this.restoreAfterFinish) this.element.setStyle(this.originalStyle);
  },
  setDimensions: function(height, width) {
    var d = { };
    if (this.options.scaleX) d.width = width.round() + 'px';
    if (this.options.scaleY) d.height = height.round() + 'px';
    if (this.options.scaleFromCenter) {
      var topd  = (height - this.dims[0])/2;
      var leftd = (width  - this.dims[1])/2;
      if (this.elementPositioning == 'absolute') {
        if (this.options.scaleY) d.top = this.originalTop-topd + 'px';
        if (this.options.scaleX) d.left = this.originalLeft-leftd + 'px';
      } else {
        if (this.options.scaleY) d.top = -topd + 'px';
        if (this.options.scaleX) d.left = -leftd + 'px';
      }
    }
    this.element.setStyle(d);
  }
});

Effect.Highlight = Class.create(Effect.Base, {
  initialize: function(element) {
    this.element = $(element);
    if (!this.element) throw(Effect._elementDoesNotExistError);
    var options = Object.extend({ startcolor: '#ffff99' }, arguments[1] || { });
    this.start(options);
  },
  setup: function() {
    // Prevent executing on elements not in the layout flow
    if (this.element.getStyle('display')=='none') { this.cancel(); return; }
    // Disable background image during the effect
    this.oldStyle = { };
    if (!this.options.keepBackgroundImage) {
      this.oldStyle.backgroundImage = this.element.getStyle('background-image');
      this.element.setStyle({backgroundImage: 'none'});
    }
    if (!this.options.endcolor)
      this.options.endcolor = this.element.getStyle('background-color').parseColor('#ffffff');
    if (!this.options.restorecolor)
      this.options.restorecolor = this.element.getStyle('background-color');
    // init color calculations
    this._base  = $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) {
    this.element.setStyle({backgroundColor: $R(0,2).inject('#',function(m,v,i){
      return m+((this._base[i]+(this._delta[i]*position)).round().toColorPart()); }.bind(this)) });
  },
  finish: function() {
    this.element.setStyle(Object.extend(this.oldStyle, {
      backgroundColor: this.options.restorecolor
    }));
  }
});

Effect.ScrollTo = function(element) {
  var options = arguments[1] || { },
    scrollOffsets = document.viewport.getScrollOffsets(),
    elementOffsets = $(element).cumulativeOffset(),
    max = (window.height || document.body.scrollHeight) - document.viewport.getHeight();  

  if (options.offset) elementOffsets[1] += options.offset;

  return new Effect.Tween(null,
    scrollOffsets.top,
    elementOffsets[1] > max ? max : elementOffsets[1],
    options,
    function(p){ scrollTo(scrollOffsets.left, p.round()) }
  );
};

/* ------------- combination effects ------------- */

Effect.Fade = function(element) {
  element = $(element);
  var oldOpacity = element.getInlineOpacity();
  var options = Object.extend({
    from: element.getOpacity() || 1.0,
    to:   0.0,
    afterFinishInternal: function(effect) { 
      if (effect.options.to!=0) return;
      effect.element.hide().setStyle({opacity: oldOpacity}); 
    }
  }, arguments[1] || { });
  return new Effect.Opacity(element,options);
};

Effect.Appear = function(element) {
  element = $(element);
  var options = Object.extend({
  from: (element.getStyle('display') == 'none' ? 0.0 : element.getOpacity() || 0.0),
  to:   1.0,
  // force Safari to render floated elements properly
  afterFinishInternal: function(effect) {
    effect.element.forceRerendering();
  },
  beforeSetup: function(effect) {
    effect.element.setOpacity(effect.options.from).show(); 
  }}, arguments[1] || { });
  return new Effect.Opacity(element,options);
};

Effect.Puff = function(element) {
  element = $(element);
  var oldStyle = { 
    opacity: element.getInlineOpacity(), 
    position: element.getStyle('position'),
    top:  element.style.top,
    left: element.style.left,
    width: element.style.width,
    height: element.style.height
  };
  return new 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) {
        Position.absolutize(effect.effects[0].element)
      },
      afterFinishInternal: function(effect) {
         effect.effects[0].element.hide().setStyle(oldStyle); }
     }, arguments[1] || { })
   );
};

Effect.BlindUp = function(element) {
  element = $(element);
  element.makeClipping();
  return new Effect.Scale(element, 0,
    Object.extend({ scaleContent: false, 
      scaleX: false, 
      restoreAfterFinish: true,
      afterFinishInternal: function(effect) {
        effect.element.hide().undoClipping();
      } 
    }, arguments[1] || { })
  );
};

Effect.BlindDown = function(element) {
  element = $(element);
  var elementDimensions = element.getDimensions();
  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) {
      effect.element.makeClipping().setStyle({height: '0px'}).show(); 
    },  
    afterFinishInternal: function(effect) {
      effect.element.undoClipping();
    }
  }, arguments[1] || { }));
};

Effect.SwitchOff = function(element) {
  element = $(element);
  var oldOpacity = element.getInlineOpacity();
  return new Effect.Appear(element, Object.extend({
    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) { 
          effect.element.makePositioned().makeClipping();
        },
        afterFinishInternal: function(effect) {
          effect.element.hide().undoClipping().undoPositioned().setStyle({opacity: oldOpacity});
        }
      })
    }
  }, arguments[1] || { }));
};

Effect.DropOut = function(element) {
  element = $(element);
  var oldStyle = {
    top: element.getStyle('top'),
    left: element.getStyle('left'),
    opacity: element.getInlineOpacity() };
  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) {
          effect.effects[0].element.makePositioned(); 
        },
        afterFinishInternal: function(effect) {
          effect.effects[0].element.hide().undoPositioned().setStyle(oldStyle);
        } 
      }, arguments[1] || { }));
};

Effect.Shake = function(element) {
  element = $(element);
  var options = Object.extend({
    distance: 20,
    duration: 0.5
  }, arguments[1] || {});
  var distance = parseFloat(options.distance);
  var split = parseFloat(options.duration) / 10.0;
  var oldStyle = {
    top: element.getStyle('top'),
    left: element.getStyle('left') };
    return new Effect.Move(element,
      { x:  distance, y: 0, duration: split, afterFinishInternal: function(effect) {
    new Effect.Move(effect.element,
      { x: -distance*2, y: 0, duration: split*2,  afterFinishInternal: function(effect) {
    new Effect.Move(effect.element,
      { x:  distance*2, y: 0, duration: split*2,  afterFinishInternal: function(effect) {
    new Effect.Move(effect.element,
      { x: -distance*2, y: 0, duration: split*2,  afterFinishInternal: function(effect) {
    new Effect.Move(effect.element,
      { x:  distance*2, y: 0, duration: split*2,  afterFinishInternal: function(effect) {
    new Effect.Move(effect.element,
      { x: -distance, y: 0, duration: split, afterFinishInternal: function(effect) {
        effect.element.undoPositioned().setStyle(oldStyle);
  }}) }}) }}) }}) }}) }});
};

Effect.SlideDown = function(element) {
  element = $(element).cleanWhitespace();
  // SlideDown need to have the content of the element wrapped in a container element with fixed height!
  var oldInnerBottom = element.down().getStyle('bottom');
  var elementDimensions = element.getDimensions();
  return new Effect.Scale(element, 100, Object.extend({ 
    scaleContent: false, 
    scaleX: false, 
    scaleFrom: window.opera ? 0 : 1,
    scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width},
    restoreAfterFinish: true,
    afterSetup: function(effect) {
      effect.element.makePositioned();
      effect.element.down().makePositioned();
      if (window.opera) effect.element.setStyle({top: ''});
      effect.element.makeClipping().setStyle({height: '0px'}).show(); 
    },
    afterUpdateInternal: function(effect) {
      effect.element.down().setStyle({bottom:
        (effect.dims[0] - effect.element.clientHeight) + 'px' }); 
    },
    afterFinishInternal: function(effect) {
      effect.element.undoClipping().undoPositioned();
      effect.element.down().undoPositioned().setStyle({bottom: oldInnerBottom}); }
    }, arguments[1] || { })
  );
};

Effect.SlideUp = function(element) {
  element = $(element).cleanWhitespace();
  var oldInnerBottom = element.down().getStyle('bottom');
  var elementDimensions = element.getDimensions();
  return new Effect.Scale(element, window.opera ? 0 : 1,
   Object.extend({ scaleContent: false, 
    scaleX: false, 
    scaleMode: 'box',
    scaleFrom: 100,
    scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width},
    restoreAfterFinish: true,
    afterSetup: function(effect) {
      effect.element.makePositioned();
      effect.element.down().makePositioned();
      if (window.opera) effect.element.setStyle({top: ''});
      effect.element.makeClipping().show();
    },  
    afterUpdateInternal: function(effect) {
      effect.element.down().setStyle({bottom:
        (effect.dims[0] - effect.element.clientHeight) + 'px' });
    },
    afterFinishInternal: function(effect) {
      effect.element.hide().undoClipping().undoPositioned();
      effect.element.down().undoPositioned().setStyle({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) {
      effect.element.makeClipping(); 
    },  
    afterFinishInternal: function(effect) {
      effect.element.hide().undoClipping(); 
    }
  });
};

Effect.Grow = function(element) {
  element = $(element);
  var options = Object.extend({
    direction: 'center',
    moveTransition: 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() };

  var dims = element.getDimensions();    
  var initialMoveX, initialMoveY;
  var moveX, moveY;
  
  switch (options.direction) {
    case 'top-left':
      initialMoveX = initialMoveY = moveX = moveY = 0; 
      break;
    case 'top-right':
      initialMoveX = dims.width;
      initialMoveY = moveY = 0;
      moveX = -dims.width;
      break;
    case 'bottom-left':
      initialMoveX = moveX = 0;
      initialMoveY = dims.height;
      moveY = -dims.height;
      break;
    case 'bottom-right':
      initialMoveX = dims.width;
      initialMoveY = dims.height;
      moveX = -dims.width;
      moveY = -dims.height;
      break;
    case 'center':
      initialMoveX = dims.width / 2;
      initialMoveY = dims.height / 2;
      moveX = -dims.width / 2;
      moveY = -dims.height / 2;
      break;
  }
  
  return new Effect.Move(element, {
    x: initialMoveX,
    y: initialMoveY,
    duration: 0.01, 
    beforeSetup: function(effect) {
      effect.element.hide().makeClipping().makePositioned();
    },
    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) {
               effect.effects[0].element.setStyle({height: '0px'}).show(); 
             },
             afterFinishInternal: function(effect) {
               effect.effects[0].element.undoClipping().undoPositioned().setStyle(oldStyle); 
             }
           }, options)
      )
    }
  });
};

Effect.Shrink = function(element) {
  element = $(element);
  var options = Object.extend({
    direction: 'center',
    moveTransition: 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() };

  var dims = element.getDimensions();
  var moveX, moveY;
  
  switch (options.direction) {
    case 'top-left':
      moveX = moveY = 0;
      break;
    case 'top-right':
      moveX = dims.width;
      moveY = 0;
      break;
    case 'bottom-left':
      moveX = 0;
      moveY = dims.height;
      break;
    case 'bottom-right':
      moveX = dims.width;
      moveY = dims.height;
      break;
    case 'center':  
      moveX = dims.width / 2;
      moveY = dims.height / 2;
      break;
  }
  
  return new 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) {
           effect.effects[0].element.makePositioned().makeClipping(); 
         },
         afterFinishInternal: function(effect) {
           effect.effects[0].element.hide().undoClipping().undoPositioned().setStyle(oldStyle); }
       }, options)
  );
};

Effect.Pulsate = function(element) {
  element = $(element);
  var options    = arguments[1] || { };
  var oldOpacity = element.getInlineOpacity();
  var transition = options.transition || Effect.Transitions.sinoidal;
  var reverser   = function(pos){ return transition(1-Effect.Transitions.pulse(pos, options.pulses)) };
  reverser.bind(transition);
  return new Effect.Opacity(element, 
    Object.extend(Object.extend({  duration: 2.0, from: 0,
      afterFinishInternal: function(effect) { effect.element.setStyle({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();
  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) {
        effect.element.hide().undoClipping().setStyle(oldStyle);
      } });
  }}, arguments[1] || { }));
};

Effect.Morph = Class.create(Effect.Base, {
  initialize: function(element) {
    this.element = $(element);
    if (!this.element) throw(Effect._elementDoesNotExistError);
    var options = Object.extend({
      style: { }
    }, arguments[1] || { });
    
    if (!Object.isString(options.style)) this.style = $H(options.style);
    else {
      if (options.style.include(':'))
        this.style = options.style.parseStyle();
      else {
        this.element.addClassName(options.style);
        this.style = $H(this.element.getStyles());
        this.element.removeClassName(options.style);
        var css = this.element.getStyles();
        this.style = this.style.reject(function(style) {
          return style.value == css[style.key];
        });
        options.afterFinishInternal = function(effect) {
          effect.element.addClassName(effect.options.style);
          effect.transforms.each(function(transform) {
            effect.element.style[transform.style] = '';
          });
        }
      }
    }
    this.start(options);
  },
  
  setup: function(){
    function parseColor(color){
      if (!color || ['rgba(0, 0, 0, 0)','transparent'].include(color)) color = '#ffffff';
      color = color.parseColor();
      return $R(0,2).map(function(i){
        return parseInt( color.slice(i*2+1,i*2+3), 16 ) 
      });
    }
    this.transforms = this.style.map(function(pair){
      var property = pair[0], value = pair[1], unit = null;

      if (value.parseColor('#zzzzzz') != '#zzzzzz') {
        value = value.parseColor();
        unit  = 'color';
      } else if (property == 'opacity') {
        value = parseFloat(value);
        if (Prototype.Browser.IE && (!this.element.currentStyle.hasLayout))
          this.element.setStyle({zoom: 1});
      } else if (Element.CSS_LENGTH.test(value)) {
          var components = value.match(/^([\+\-]?[0-9\.]+)(.*)$/);
          value = parseFloat(components[1]);
          unit = (components.length == 3) ? components[2] : null;
      }

      var originalValue = this.element.getStyle(property);
      return { 
        style: property.camelize(), 
        originalValue: unit=='color' ? parseColor(originalValue) : parseFloat(originalValue || 0), 
        targetValue: unit=='color' ? parseColor(value) : value,
        unit: unit
      };
    }.bind(this)).reject(function(transform){
      return (
        (transform.originalValue == transform.targetValue) ||
        (
          transform.unit != 'color' &&
          (isNaN(transform.originalValue) || isNaN(transform.targetValue))
        )
      )
    });
  },
  update: function(position) {
    var style = { }, transform, i = this.transforms.length;
    while(i--)
      style[(transform = this.transforms[i]).style] = 
        transform.unit=='color' ? '#'+
          (Math.round(transform.originalValue[0]+
            (transform.targetValue[0]-transform.originalValue[0])*position)).toColorPart() +
          (Math.round(transform.originalValue[1]+
            (transform.targetValue[1]-transform.originalValue[1])*position)).toColorPart() +
          (Math.round(transform.originalValue[2]+
            (transform.targetValue[2]-transform.originalValue[2])*position)).toColorPart() :
        (transform.originalValue +
          (transform.targetValue - transform.originalValue) * position).toFixed(3) + 
            (transform.unit === null ? '' : transform.unit);
    this.element.setStyle(style, true);
  }
});

Effect.Transform = Class.create({
  initialize: function(tracks){
    this.tracks  = [];
    this.options = arguments[1] || { };
    this.addTracks(tracks);
  },
  addTracks: function(tracks){
    tracks.each(function(track){
      track = $H(track);
      var data = track.values().first();
      this.tracks.push($H({
        ids:     track.keys().first(),
        effect:  Effect.Morph,
        options: { style: data }
      }));
    }.bind(this));
    return this;
  },
  play: function(){
    return new Effect.Parallel(
      this.tracks.map(function(track){
        var ids = track.get('ids'), effect = track.get('effect'), options = track.get('options');
        var elements = [$(ids) || $$(ids)].flatten();
        return elements.map(function(e){ return new effect(e, Object.extend({ sync:true }, options)) });
      }).flatten(),
      this.options
    );
  }
});

Element.CSS_PROPERTIES = $w(
  'backgroundColor backgroundPosition borderBottomColor borderBottomStyle ' + 
  'borderBottomWidth borderLeftColor borderLeftStyle borderLeftWidth ' +
  'borderRightColor borderRightStyle borderRightWidth borderSpacing ' +
  'borderTopColor borderTopStyle borderTopWidth bottom clip color ' +
  'fontSize fontWeight height left letterSpacing lineHeight ' +
  'marginBottom marginLeft marginRight marginTop markerOffset maxHeight '+
  'maxWidth minHeight minWidth opacity outlineColor outlineOffset ' +
  'outlineWidth paddingBottom paddingLeft paddingRight paddingTop ' +
  'right textIndent top width wordSpacing zIndex');
  
Element.CSS_LENGTH = /^(([\+\-]?[0-9\.]+)(em|ex|px|in|cm|mm|pt|pc|\%))|0$/;

String.__parseStyleElement = document.createElement('div');
String.prototype.parseStyle = function(){
  var style, styleRules = $H();
  if (Prototype.Browser.WebKit)
    style = new Element('div',{style:this}).style;
  else {
    String.__parseStyleElement.innerHTML = '<div style="' + this + '"></div>';
    style = String.__parseStyleElement.childNodes[0].style;
  }
  
  Element.CSS_PROPERTIES.each(function(property){
    if (style[property]) styleRules.set(property, style[property]); 
  });
  
  if (Prototype.Browser.IE && this.include('opacity'))
    styleRules.set('opacity', this.match(/opacity:\s*((?:0|1)?(?:\.\d*)?)/)[1]);

  return styleRules;
};

if (document.defaultView && document.defaultView.getComputedStyle) {
  Element.getStyles = function(element) {
    var css = document.defaultView.getComputedStyle($(element), null);
    return Element.CSS_PROPERTIES.inject({ }, function(styles, property) {
      styles[property] = css[property];
      return styles;
    });
  };
} else {
  Element.getStyles = function(element) {
    element = $(element);
    var css = element.currentStyle, styles;
    styles = Element.CSS_PROPERTIES.inject({ }, function(hash, property) {
      hash.set(property, css[property]);
      return hash;
    });
    if (!styles.opacity) styles.set('opacity', element.getOpacity());
    return styles;
  };
};

Effect.Methods = {
  morph: function(element, style) {
    element = $(element);
    new Effect.Morph(element, Object.extend({ style: style }, arguments[2] || { }));
    return element;
  },
  visualEffect: function(element, effect, options) {
    element = $(element)
    var s = effect.dasherize().camelize(), klass = s.charAt(0).toUpperCase() + s.substring(1);
    new Effect[klass](element, options);
    return element;
  },
  highlight: function(element, options) {
    element = $(element);
    new Effect.Highlight(element, options);
    return element;
  }
};

$w('fade appear grow shrink fold blindUp blindDown slideUp slideDown '+
  'pulsate shake puff squish switchOff dropOut').each(
  function(effect) { 
    Effect.Methods[effect] = function(element, options){
      element = $(element);
      Effect[effect.charAt(0).toUpperCase() + effect.substring(1)](element, options);
      return element;
    }
  }
);

$w('getInlineOpacity forceRerendering setContentZoom collectTextNodes collectTextNodesIgnoreClass getStyles').each( 
  function(f) { Effect.Methods[f] = Element[f]; }
);

Element.addMethods(Effect.Methods);


/* --- End effects.js --- */
/* --- Start milonic_src.js --- */

/*

Milonic DHTML Menu - JavaScript Website Navigation System.
Version 5.790 - Built: Monday February 4 2008 - 12:20
Copyright 2008 (c) Milonic Solutions Limited. All Rights Reserved.
This is a commercial software product, please visit http://www.milonic.com/ for more information.
See http://www.milonic.com/license.php for Commercial License Agreement
All Copyright statements must always remain in place in all files at all times

*******  PLEASE NOTE: THIS IS NOT FREE SOFTWARE, IT MUST BE LICENSED FOR ALL USE  ******* 

License Details:
 Number: 207360
    URL: www.villagevoicemedia.com
   Type: Worldwide
  Dated: Wednesday January 30 2008

*/

lNum=207360;lURL="www.villagevoicemedia.com";lVer="5.790";_$t_="Please visit www.milonic.com for details on how to remove this evaluation message";_mD=2;_d=document;_dB=_d.body;_n=navigator;_L=location;_nv=$tL(_n.appVersion);_nu=$tL(_n.userAgent);_ps=parseInt(_n.productSub);_cls=_toL=X_=Y_=_n=null;_W=window;_wp=_W.createPopup;ie=(_d.all)?1:0;ie4=(!_d.getElementById&&ie)?1:0;ie5=(!ie4&&ie&&!_wp)?1:0;ie55=(!ie4&&ie&&_wp)?1:0;ie7=(_nu.indexOf("msie 7")!=-1)?1:0;ns6=(_nu.indexOf("gecko")!=-1)?1:0;konq=(_nu.indexOf("konqueror")!=-1)?1:0;sfri=(_nu.indexOf("safari")!=-1)?1:0;if(sfri&&_d.evaluate)sfri=0;if(konq||sfri){_ps=0;ns6=0}ns4=(_d.layers)?1:0;ns61=(_ps>=20010726)?1:0;ns7=(_ps>=20020823)?1:0;ns72=(_ps>=20040804)?1:0;ff15=(_ps>=20060000)?1:0;op=(_W.opera)?1:0;if(op||konq){ie=0;ie7=0;}op5=(_nu.indexOf("opera 5")!=-1)?1:0;op6=(_nu.indexOf("opera 6")!=-1||_nu.indexOf("opera/6")!=-1)?1:0;op7=(_nu.indexOf("opera 7")!=-1||_nu.indexOf("opera/7")!=-1)?1:0;_OpV=(op&&_W.opera.version)?_W.opera.version():0;if(_OpV)op7=1;mac=(_nv.indexOf("mac")!=-1)?1:0;if(ns6||ns4||op||sfri)mac=0;ns60=0;if(ns6&&!ns61)ns60=1;if(op7)op=0;IEDtD=0;if(!op&&((_d.all||ns7)&&_d.compatMode=="CSS1Compat")||(mac&&_d.doctype&&_d.doctype.name.indexOf(".dtd")!=-1))IEDtD=1;_jv="javascript:;";inEditMode=_rstC=inDragMode=_d.dne=lcl=$R1=$mD=_mcnt=_sL=_sT=_ofMT=_oldbW=_bW=_oldbH=_bl=_el=_st=_en=_cKA=$BW=0;_mtX="";_startM=_c=1;_trueItemRef=focusedMenu=t_=_itemRef=_mn=-1;_zi=_aN=_bH=999;if(op)ie55=0;B$="absolute";$O="menu";$5="hidden";$_O="scroll";function $c(v){if(_d.getElementById)return _d.getElementById(v);if(_d.all)return _d.all[v]}function _StO(f,m){return setTimeout(f,m)}_m=[];_mi=[];_sm=[];_tsm=[];_cip=[];$S3="2E636F6D2F";$S4="646D2E706870";$S5=4048;_MT=_StO("",0);_oMT=_StO("",0);_cMT=_StO("",0);_mst=_StO("",0);_Mtip=_StO("",0);$u="undefined ";_Lhr=_L.href;$6="visible";if(op5){$5=$tU($5);$6=$tU($6)}function M_hideLayer(){}function _oTree(){}function mmMouseMove(){}function _TtM(){}function _IdM(){}function _ocURL(){}function mmClick(){}function autoOT(){}function _iF0C(){}function showtip(){}function isEditMode(){}function hidetip(){}function mmVisFunction(){}function doMenuResize(){}function _tMR(){}function _maxm(){}function $9(ap){if(ie55){try{if(ap.filters){return 1}}catch(e){}}else return false}function _p8(a,d){var t=[];for(_a=0;_a<a.length;_a++){if(a[_a]!=d){t[t.length]=a[_a]}}return t}function copyOf(w){for(_cO in w){this[_cO]=w[_cO]}}function $tL(v){if(v)return v.toLowerCase()}function $tU(v){if(v)return v.toUpperCase()}function $pU(v){if(v)return parseInt(v)}_lDd=0;function _gLd(){if(_d.readyState&&_d.readyState!="complete"){setTimeout("_gLd()",50);return}_lDd=1;_oldbH=0}if(!_d.readyState)_d.addEventListener('DOMContentLoaded',_gLd,false);else setTimeout("_gLd()",50);function drawMenus(){_startM=1;_oldbH=0;_oldbW=0;_baL=0;if(_W.buildAfterLoad)_baL=1;for(_y=_mcnt;_y<_m.length;_y++)o$(_y,1,_baL);if(_W._pageIsXML){var G=$c(_menuContainer);if(!G){G=_d.createElement("div");G.id=_menuContainer;_dB.appendChild(G)}G.innerHTML=_mtX}}_$S={menu:0,text:1,url:2,showmenu:3,status:4,onbgcolor:5,oncolor:6,offbgcolor:7,offcolor:8,offborder:9,separatorcolor:10,padding:11,fontsize:12,fontstyle:13,fontweight:14,fontfamily:15,high3dcolor:16,low3dcolor:17,pagecolor:18,pagebgcolor:19,headercolor:20,headerbgcolor:21,subimagepadding:22,subimageposition:23,subimage:24,onborder:25,ondecoration:26,separatorsize:27,itemheight:28,image:29,imageposition:30,imagealign:31,overimage:32,decoration:33,type:34,target:35,align:36,imageheight:37,imagewidth:38,openonclick:39,closeonclick:40,keepalive:41,onfunction:42,offfunction:43,onbold:44,onitalic:45,bgimage:46,overbgimage:47,onsubimage:48,separatorheight:49,separatorwidth:50,separatorpadding:51,separatoralign:52,onclass:53,offclass:54,itemwidth:55,pageimage:56,targetfeatures:57,visitedcolor:58,pointer:59,imagepadding:60,valign:61,clickfunction:62,bordercolor:63,borderstyle:64,borderwidth:65,overfilter:66,outfilter:67,margin:68,pagebgimage:69,swap3d:70,separatorimage:71,pageclass:72,menubgimage:73,headerborder:74,pageborder:75,title:76,pagematch:77,rawcss:78,fileimage:79,clickcolor:80,clickbgcolor:81,clickimage:82,clicksubimage:83,imageurl:84,pagesubimage:85,dragable:86,clickclass:87,clickbgimage:88,imageborderwidth:89,overseparatorimage:90,clickseparatorimage:91,pageseparatorimage:92,menubgcolor:93,opendelay:94,tooltip:95,disabled:96,dividespan:97,tipdelay:98,tipfollow:99,tipmenu:100,menustyle:101,pageoncolor:102,id:103,overpageimage:104,nowrap:105,overflow:106,hotkey:107,leftimage:108,rightimage:109,overleftimage:110,overrightimage:111,pageleftimage:112,pagerightimage:113,nobreadcrumb:114,custom:115,subimagecss:116,onsubimagecss:117};function mm_style(){for($i in _$S)this[$i]=_n;this.built=0}_$M={items:0,name:1,top:2,left:3,itemwidth:4,screenposition:5,style:6,alwaysvisible:7,align:8,orientation:9,keepalive:10,openstyle:11,margin:12,overflow:13,position:14,overfilter:15,outfilter:16,menuwidth:17,itemheight:18,followscroll:19,menualign:20,mm_callItem:21,mm_obj_ref:22,mm_built:23,menuheight:24,ignorecollision:25,divides:26,zindex:27,opendelay:28,resizable:29,minwidth:30,maxwidth:31,mm_fixheight:32,C:33,rawcss:34};function menuname(name){for($i in _$M)this[$i]=_n;this.name=$tL(name);_c=1;_mn++}function f_(i){_mi[_bl]=[];_mi[_bl][0]=_mn;i=i.split(";");_sc="";for(var a=0;a<i.length;a++){var p=i[a].indexOf("`");if(p!=-1){_sc=";";_tI=i[a];if(p==i[a].lastIndexOf("`")){for(var b=a;b<i.length;b++){if(i[b+1]){_tI+=";"+i[b+1];a++;if(i[b+1].indexOf("`")!=-1)b=i.length}}}i[a]=_tI.replace(/`/g,"")}p=i[a].indexOf("=");if(p==-1){if(i[a])_si=_si+";"+i[a]+_sc}else{_si=i[a].slice(p+1);_w=i[a].slice(0,p);if(_w=="showmenu")_si=$tL(_si)}if(i[a]&&_$S[_w])_mi[_bl][_$S[_w]]=_si}var S=_x[6];if(_mi[_bl][101])S=eval(_mi[_bl][101]);for($i in S)if(S[$i]){var v=_mi[_bl][_$S[$i]];if(!v&&v!="")_mi[_bl][_$S[$i]]=S[$i]}_m[_mn][0][_c-2]=_bl;_c++;_bl++}_c=0;function ami(t){_t=this;if(_c==1){_c++;_m[_mn]=[];_x=_m[_mn];for($i in _t)_x[_$M[$i]]=_t[$i];_x[21]=-1;_x[0]=[];if(!_x[12])_x[12]=0;var s=_m[_mn][6];var m=_m[_mn];if(m[15]==_n)m[15]=s.overfilter;if(m[16]==_n)m[16]=s.outfilter;if(m[13]==_n)m[13]=s.overflow;s[65]=(s.borderwidth)?$pU(s.borderwidth):0;s[64]=s.borderstyle;s[63]=s.bordercolor;if(_W.ignoreCollisions)m[25]=1;if(!s.built){_WzI=_zi;if(_W.menuZIndex){_WzI=_W.menuZIndex;_zi=_WzI}lcl++;var v=s.visitedcolor;if(v&&!_W._pageIsXML){_oC=s.offcolor;if(!_oC)_oC="#000000";if(!v)v="#ff0000";_d.write("<style>.g_"+lcl+":link{color:"+_oC+"}.g_"+lcl+":visited{color:"+v+"}</style>");s.g_="g_"+lcl}s.built=1}}f_(t)}menuname.prototype.aI=ami;


/* --- End milonic_src.js --- */
/* --- Start mmenudom.js --- */

/*

Milonic DHTML Menu - JavaScript Website Navigation System.
Version 5.790 - Built: Monday February 4 2008 - 12:20
Copyright 2008 (c) Milonic Solutions Limited. All Rights Reserved.
This is a commercial software product, please visit http://www.milonic.com/ for more information.
See http://www.milonic.com/license.php for Commercial License Agreement
All Copyright statements must always remain in place in all files at all times

*******  PLEASE NOTE: THIS IS NOT FREE SOFTWARE, IT MUST BE LICENSED FOR ALL USE  ******* 

License Details:
 Number: 207360
    URL: www.villagevoicemedia.com
   Type: Worldwide
  Dated: Wednesday January 30 2008

*/

function _p1(t){if(t._itemRef!=_itemRef)h$(t._itemRef)}function $P($){clearTimeout($);return _n}$7=0;$8=0;function _DC(){if(!_W.contextObject&&_trueItemRef==-1)$bb()}function _5($){return eval($)}function gMY(e){if(ns6){X_=e.pageX;Y_=e.pageY}else{e=event;X_=e.clientX;Y_=e.clientY}if(!op&&_d.all&&_dB){}mmMouseMove();_TtM();_IdM();doMenuResize(focusedMenu)}_dC=_DC;if(_d.onmousedown)_dC=_dC+_d.onmousedown;_d.onmousedown=_dC;_TbS="<table class=milonictable border=0 cellpadding=0 cellspacing=0 style='line-height:normal;padding:0px' ";function $_E(g,t,l,h,w){_px="px";var s=g.style;if(w<0)w=0;if(h<0)h=0;if(w+" "==$u)w=_n;if(h+" "==$u)h=_n;if(op){_px="";if(w!=_n)s.pixelWidth=w;if(h!=_n)s.pixelHeight=h}else{if(w!=_n)s.width=w+_px;if(h!=_n)s.height=h+_px;}if(!isNaN(t)&&t!=_n)s.top=t+_px;if(!isNaN(l)&&l!=_n)s.left=l+_px}function $D(g){if(!g)return;var h,w,o,t,l;h=g.offsetHeight;w=g.offsetWidth;if(op5){h=g.style.pixelHeight;w=g.style.pixelWidth}o=g;t=0;l=0;while(o!=_n){t+=o.offsetTop;l+=o.offsetLeft;o=o.offsetParent}if(sfri){l-=$8;t-=$7}if(mac&&_dB){_mcdb=_dB.currentStyle;_mcf=_mcdb.marginTop;if(_mcf)t=t+$pU(_mcf);_mcf=_mcdb.marginLeft;if(_mcf)l=l+$pU(_mcf)}return(new Array(t,l,h,w))}function $2(g,m){var s,f,i,x;if($9(g)){s=g.style;f=(s.visibility==$6)?_m[m][16]:_m[m][15];if(f){if(g.filters[0])g.filters[0].stop();i="";i="FILTER:";f=f.split(";");for(x=0;x<f.length;x++){i+=" progid:DXImageTransform.Microsoft."+f[x];if($tU(_nv).indexOf("MSIE 5.5")>0)x=_aN;}s.filter=i;g.filters[0].apply();}}}function $3(g,m){if($9(g)){_flt=(g.style.visibility==$6)?_m[m][15]:_m[m][16];if(_flt)g.filters[0].play()}}function $Y(){var o,s,X,v,D,g=arguments,t,g;D=g[0];v=g[1];o=$c($O+D);if(!o)return;s=o.style;_m[D][22]=o;if(v){M_hideLayer(D,v);X=_mLt*_fLm.length+" ";if(_kLm!=Math.ceil(X.substr(0,10)))_mi=[];if(!_startM)_m[D][23]=1;t=g[2]!=_n?g[2]:_n;l=g[3]!=_n?g[3]:_n;if(t||l)$_E(o,t,l);if(_m[D][5])p$(D);if(s.visibility!=$6){$2(o,D);if(!_m[D][27])s.zIndex=_zi;else s.zIndex=_m[D][27];s.visibility=$6;$3(o,D);$V(D,1);mmVisFunction(D,v);if(!_m[D][7])_m[D][21]=_itemRef;$mD++}$1(D)}else{if(_m[D][21]>-1&&_itemRef!=_m[D][21])d$(_m[D][21]);if(ns6||s.visibility==$6){if(!(ie||op7)&&_m[D][13]==$_O)s.overflow=$5;hmL(D);$V(D,0);mmVisFunction(D,v);$2(o,D);s.visibility=$5;if(!ie)s.top="-9999px";$3(o,D);$mD--}_m[D][21]=-1}}function $Z(){var g,a,M;if(inEditMode)return;g=arguments;if(t_>-1)d$(t_,1);t_=-1;_oMT=$P(_oMT);for(a=0;a<_m.length;a++){M=_m[a];if(M&&!M[7]&&!M[10]&&g[0]!=a){$Y(a);M_hideLayer(a,0)}else{hmL(a)}}_zi=_WzI;_itemRef=-1;$j=-1;if(_W.resetAutoOpen)_ocURL()}function $d(v){if(v+" "==$u)return-1;return _mi[v][0]}function $e(v){var t,x;t=$d(v);if(t==-1)return-1;for(x=0;x<_mi.length;x++)if(_mi[x]&&_mi[x][3]==_m[t][1])return _mi[x][0]}_mLt=8294.4;function $f(v){var t,x;t=$d(v);if(t==-1)return-1;for(x=0;x<_mi.length;x++)if(_mi[x][3]==_m[t][1])return x}function $h(v){v=$tL(v);for(var x=0;x<_m.length;x++)if(_m[x]&&v==_m[x][1])return x}_mot=0;function e$(){var g,i,I,b,H;g=arguments;i=g[0];I=_mi[i];if(I[96])return;H=$c("mmlink"+I[0]);hrs=H.style;_lnk=$c("lnk"+i);if(I[42]&&g[1])_5(I[42]);if((I[34]=="header"&&!I[2])||I[34]=="form"){$c($O+I[0]).onselectstart=_n;hrs.visibility=$5;return}_mot=$P(_mot);u_=$c("el"+i);if(u_.e$==1){$_E(H,u_.t,u_.l,u_.h,u_.w);hrs.visibility=$6;return}u_.e$=1;$y=_m[I[0]];if(!$y[9]&&mac){$1A=$D($c("pTR"+i));if(!$1A)$1A=$D(u_)}else $1A=$D(u_);_pm=$c($O+I[0]);k_=$D(_pm);if(H){H._itemRef=i;H.href=_jv;H.target="_self";if(I[34]!="disabled"){if(sfri)H.href=_n;if(I[2])H.href=I[2];H.title="";if(I[76])H.title=I[76];if(I[35])H.target=I[35];hrs.visibility=$6}hrs.zIndex=1;if(I[34]=="html"){hrs.zIndex=-1;hrs=u_.style}if((I[86]||I[34]=="dragable")&&inDragMode==0){if(_lnk)_lnk.href=_jv;drag_drop(I[0],i);hrs.zIndex=-1}if(u_.pt!=k_[0]||u_.pl!=k_[1]||u_.ph!=k_[2]||u_.pw!=k_[3]){_bwC=0;if(!H.border&&H.border!=I[25]){hrs.border=I[25];H.border=I[25];H.C=$pU(hrs.borderTopWidth)*2}if(H.C)_bwC=H.C;b=_m[I[0]][6][65];v_=0;if(mac)if(_m[I[0]][12])v_=_m[I[0]][12];if(konq||sfri||_OpV)v_-=b;u_.t=$1A[0]-k_[0]+v_;u_.l=$1A[1]-k_[1]+v_;if(ff15&&_m[I[0]][13]==$_O){u_.t=u_.t+(b);u_.l=u_.l+(b)}if(!IEDtD&&ie)_bwC=0;u_.h=$1A[2]-_bwC;u_.w=$1A[3]-_bwC;u_.pt=k_[0];u_.pl=k_[1];u_.ph=k_[2];u_.pw=k_[3]}$_E(H,u_.t,u_.l,u_.h,u_.w)}_Cr=(ns6)?_n:"";hrs.cursor=_Cr;if(I[59]){if(I[59]=="hand"&&ns6)I[59]="pointer";hrs.cursor=I[59]}if(I[32]&&I[29])$c("_img"+i).src=I[32];if(I[3]&&I[3]!="M_doc*"&&I[24]&&I[48])$c("simg"+i).src=I[48];if(_lnk&&!l_){_lnk.oC=_lnk.style.color;if(I[6])_lnk.style.color=I[6];if(I[26])_lnk.style.textDecoration=I[26]}if(I[53]){u_.className=I[53];if(_lnk)_lnk.className=I[53]}if(I[117]&&I[24]&&I[3])$c("simg"+i).className=I[117];if(!l_)if(I[5])u_.style.background=I[5];l_=0;if(I[1]&&I[47])u_.style.backgroundImage="url("+I[47]+")";if(I[110]){b=$c("li108"+i);if(I[1]&&b)b.src=I[110]}if(I[111]){b=$c("ri109"+i);if(I[1]&&b)b.src=I[111]}if(I[71]&&I[90])if($c("sep"+i))$c("sep"+i).style.backgroundImage="url('"+I[90]+"')";if(!mac){if(I[44])_lnk.style.fontWeight="bold";if(I[45])_lnk.style.fontStyle="italic"}showtip()}_kLm=_5($qe("6C4E756D"));function d$(){var g,i,I,n,H;g=arguments;i=g[0];if(i==-1)return;u_=$c("el"+i);if(!u_)return;if(!u_.e$)return;u_.e$=0;_trueItemRef=-1;_gs=u_.style;I=_mi[i];_tI=$c("_img"+i);if(_tI&&I[29])_tI.src=I[29];if(I[3]&&I[24]&&I[48])$c("simg"+i).src=I[24];_lnk=$c("lnk"+i);if(_lnk){if(_startM||op||sfri)_lnk.oC=I[8];if(I[34]!="header")_lnk.style.color=_lnk.oC;if(I[26])_lnk.style.textDecoration="none";if(I[33])_lnk.style.textDecoration=I[33]}if(I[116]&&I[24]&&I[3]){$c("simg"+i).className=I[116]}if(I[54]){u_.className=I[54];if(_lnk)_lnk.className=I[54]}if(I[7])_gs.background=I[7];if(I[9])_gs.border=I[9];if(I[46])_gs.backgroundImage="url("+I[46]+")";if(I[108]){b=$c("li108"+i);if(I[1]&&b)b.src=I[108]}if(I[109]){b=$c("ri109"+i);if(I[1]&&b)b.src=I[109]}if(I[71]){s_I=$c("sep"+i);if(s_I)s_I.style.backgroundImage="url("+I[71]+")"}if(!mac){n="normal";if(I[44]&&(I[14]==n||!I[14]))_lnk.style.fontWeight=n;if(I[45]&&(I[13]==n||!I[13]))_lnk.style.fontStyle=n}if(!_startM)hidetip()}function $1C(v){for(var a=0;a<v.length;a++){if(v[a]!=$m){_m3=_m[v[a]];if(_m3&&!(_m3[7]))$Y(v[a])}}}function f$(){_st=-1;_en=_sm.length;_mm=_iP;if(_iP==-1){if(_sm[0]!=$j)return _sm;_mm=$j}for(_b=0;_b<_sm.length;_b++){if(_sm[_b]==_mm)_st=_b+1;if(_sm[_b]==$m)_en=_b}if(_st>-1&&_en>-1){_tsm=_sm.slice(_st,_en)}return _tsm}function _cm3(){_tar=f$();$1C(_tar);for(_b=0;_b<_tar.length;_b++){if(_tar[_b]!=$m)_sm=_p8(_sm,_tar[_b])}}function $r(){_dB=_d.body;if(!_dB)return;$7=_dB.offsetTop;$8=_dB.offsetLeft;if(!op&&_d.all){_mc=_dB;if(IEDtD&&!mac&&!op7)_mc=_d.documentElement;if(!_mc)return;_bH=_mc.clientHeight;_bW=_mc.clientWidth;_sT=_mc.scrollTop;_sL=_mc.scrollLeft;if(konq)_bH=_W.innerHeight}else{_bH=_W.innerHeight;_bW=_W.innerWidth;if(ns6&&_d.documentElement.offsetWidth!=_bW)_bW=_bW-16;_sT=self.scrollY;_sL=self.scrollX;if(op){_sT=_dB.scrollTop;_sL=_dB.scrollleft}}}_fLm=_5($qe("6C55524C"));function $W(i){var I=_mi[i];if(I[3]){_p6=I[39];I[39]=0;_oldMD=_menuOpenDelay;_menuOpenDelay=0;_gm=$c($O+$h(I[3]));_ofMT=1;if(_gm.style.visibility==$6&&I[40]){$Y($h(I[3]));e$(i)}else{h$(i)}_menuOpenDelay=_oldMD;I[39]=_p6}}function $x(v){var vv=0;if(v)vv=v;if(isNaN(v)&&v.indexOf("offset=")==0)vv=$pU(v.substr(7,99));return vv}function popup(){var X,Y,g=arguments;_itemRef=-1;_MT=$P(_MT);_oMT=$P(_oMT);if(g[0]){$m=$h(g[0]);if($m>=0&&!_m[$m].tooltip)$Z($m);_M=_m[$m];if(!_M)return;if(!_M[23])g$($m);_gm=$c($O+$m);if(!_gm)return;j_=$D(_gm);_sm[_sm.length]=$m;$pS=0;if(!_startM&&_M[13]==$_O)$pS=1;_tos=0;_los=0;if(_M[2])if(isNaN(_M[2]))_tos=$x(_M[2]);else Y_=_M[2];if(_M[3])if(isNaN(_M[3]))_los=$x(_M[3]);else X_=_M[3];if(g[2])_tos=g[2];if(g[3])_los=g[3];Y=Y_+_tos;X=X_+_los;if(g[1]){if(g[1]==1){if(!ns6){if(!_M[3]||isNaN(_M[3]))X+=_sL;if(!_M[2]||isNaN(_M[2]))Y+=_sT}}else if(g[1]==2){Y=g[2];X=g[3]}else{_po=$c(g[1]);k_=$D(_po);Y=(k_[0]+k_[2]+_tos)+$7;X=(k_[1]+_los);if(g[4])_M.ttop=_ttop}if(!_M[25]&&!g[4]){if(Y+j_[2]+16>(_bH+_sT))Y=_bH-j_[2]+_sT-16;if(X+j_[3]+16>(_bW+_sL))X=_bW-j_[3]+_sL-16}}if(ns6&&_W.fixMozillaZIndex){X-=_sL;Y-=_sT}_zi=_zi+1;_oMT=$P(_oMT);_moD=(g[5])?g[5]:0;if(!_startM)_oMT=_StO("$Y("+$m+",1,"+Y+","+X+")",_moD);_M[21]=-1}}function popdown(){_ofMT=1;_MT=_StO("$Z()",_menuCloseDelay);_oMT=$P(_oMT)}function g$(m){if(op5||op6)return;if(_W.buildAfterLoad){if(!_lDd)return;createNewMenu(m)}_gm=$c($O+m);if(!_gm)return;if(!_m[m][23])$_E(_gm,-9999);_it=o$(m,0);_mcnt--;_gm.innerHTML=_it;$z(m)}$j=-1;function _colD(){}function h$(i,o){if(i<0)return;var I,_M;if(_itemRef>-1&&_itemRef!=i)hmL(_mi[_itemRef][0]);I=_mi[i];if(!I[65])I[65]=0;I[3]=$tL(I[3]);_mopen=I[3];$m=$h(_mopen);_M=_m[$m];if(_M){if(_M[21]>-1&&_M[21]!=i)d$(_M[21]);_M[21]=i}if(I[34]=="ToolTip")return;if(!I||_startM||inDragMode)return;$y=_m[I[0]];_MT=$P(_MT);if(_m[I[0]][7]&&$j!=I[0]&&!inEditMode){hmL($j);$1C(_sm);_oMT=$P(_oMT);_sm=[];if(!_W.resetAutoOpen)_DC()}if(_M&&!_M[23]&&_mopen){g$($m);if(!_lDd)return}if(t_>-1){_gm=0;if(I[3]){_gm=$c($O+$h(I[3]));if(_gm&&_gm.style.visibility==$6&&i==t_){e$(i,1);return}}if(t_!=i)k$(t_);_oMT=$P(_oMT)}_cMT=$P(_cMT);$m=-1;_itemRef=i;_trueItemRef=i;I=_mi[i];_moD=(_M&&_M[28])?_M[28]:_menuOpenDelay;if(I[94])_moD=I[94];$Q=0;if($y[9]){$Q=1;if(!_W.horizontalMenuDelay)_moD=0}_vq=_M?1:0;e$(i,1);if(_vq&&!_M)return;if(!_sm.length){_sm[0]=I[0];$j=I[0]}_iP=$d(i);if(_iP==-1)$j=I[0];_cMT=_StO("_cm3()",_moD);if(_mopen&&I[39]){_gm=$c($O+$m);if(_gm&&_gm.style.visibility==$6){_cMT=$P(_cMT);_tsm=_sm[_sm.length-1];if(_tsm!=$m)$Y(_tsm)}}if(_W.forgetClickValue)$R1=0;if(_mopen&&(!I[39]||$R1)&&I[34]!="tree"&&I[34]!="disabled"){_pm=$c($O+I[0]);k_=$D(_pm);$m=$h(_mopen);if(_M&&I[41])_M[10]=1;if($y.kAm!=_n&&$y.kAm+" "!=$u){_sm[_sm.length]=$y.kAm}$y.kAm=_n;if(_M&&_M[10]){$y.kAm=$m}if($m>-1){_mnO=$c($O+$m);_mp=$D(_mnO);u_=$c("el"+i);if(!$Q&&mac)u_=$c("pTR"+i);j_=$D(u_);if($Q){$l=j_[1];$k=k_[0]+k_[2]-I[65]}else{$l=k_[1]+k_[3]-I[65];$k=j_[0]}if(!$Q&&$y[13]==$_O&&!op){$k=(ns6&&!ns7)?$k-gevent:$k-_pm.scrollTop}_M=_m[$m];if(_M[2]!=_n)if(isNaN(_M[2])&&_M[2].indexOf("offset=")==0)$k=$k+$x(_M[2]);else $k=_M[2];if(_M[3]!=_n)if(isNaN(_M[3])&&_M[3].indexOf("offset=")==0)$l=$l+$x(_M[3]);else $l=_M[3];var S=0;if(!_M[25]){if(!$Q&&(!_M[2]||isNaN(_M[2]))){_hp=$k+_mp[2];if(_hp>_bH+_sT){$k=(_bH-_mp[2])+_sT-4}if(ns6){S=18;if(!window.scrollMaxX)S=0;if(_hp+S>_bH+_sT)$k=$k-S}}if($l+_mp[3]+3>_bW+_sL){if(!$Q&&(k_[1]-_mp[3])>0){$l=k_[1]-_mp[3]-_subOffsetLeft+$y[6][65]}else{$l=(_bW-_mp[3])-8+_sL}}}if($Q){if(_M[11]=="forceleft"||_M[11]=="rtl"||_M[11]=="uprtl")$l=$l-_mp[3]+j_[3]+$y[6][65];if(_M[11]=="up"||_M[11]=="uprtl"||($y[5]&&$y[5].indexOf("bottom")!=-1)){$k=k_[0]-_mp[2]-1-$x(_M[2])}}else{if(_M[11]=="forceleft"||_M[11]=="rtl"||_M[11]=="uprtl")$l=k_[1]-_mp[3]-(_subOffsetLeft*2);if(_M[11]=="up"||_M[11]=="uprtl"){$k=j_[0]-_mp[2]+j_[2]-$x(_M[2])}$k+=_subOffsetTop;$l+=_subOffsetLeft}if(ns60){$l-=$y[6][65];$k-=$y[6][65]}if(mac){$l-=$y[12]+$y[6][65];$k-=$y[12]+$y[6][65]}if(sfri&&$y[14]=="relative"){$l+=$8;$k+=$7}if(ns6&&_W.fixMozillaZIndex){if($y[14]!="fixed"){$l-=_sL;$k-=_sT}_gmt=$c("tbl"+$m);_gt=$D(_gmt);if($Q){if(_M[13]==$_O&&$k+_gt[2]>_bH)$k+=_sT}else{if($k+_gt[2]>_bH)$k=_bH-_gt[2]-S-2}}if($l<0)$l=0;if($k<0)$k=0;if(o){$Y($m)}else{_oMT=_StO("$Y("+$m+",1,"+$k+","+$l+")",_moD)}_zi++;if(_sm[_sm.length-1]!=$m)_sm[_sm.length]=$m}}isEditMode(i);if(!I[114])i$(_iP);t_=i;if(_ofMT==0)_oMT=$P(_oMT);_ofMT=0;if(_mopen&&_mopen.substr(0,5)=="ajax:")_maxm(_mopen)}_sBarW=0;function $1(m){var hm,hmT;if(op)return;_M=_m[m];if(!_M||_M[13]!="scroll")return;if(_M.ttop){_o4s=_M[2];_M[2]=_M.ttop}hm=$Q;if(_M[21]>-1){hmT=_m[_mi[_M[21]][0]];if(hmT[7]&&hmT[9])hm=1}_gm=$c($O+m);if(!_gm||_M[9])return;_mp=$D(_gm);if(!_M.sW)_M.sW=_mp[3];_gmt=$c("tbl"+m);_gt=$D(_gmt);_MS=_M[6];_Bw=_MS[65]*2;_Mw=_M[12]*2;_smt=_gt[2];if(hm)_smt=_gt[2]+_gt[0]-_sT;if(_smt<_bH-16){_gm.style.overflow="";$k=_n;if(!hm&&(_gt[0]+_gt[2]+16)>(_bH+_sT)){$k=(_bH-_gt[2])+_sT-6-$x(_M[2])}if(!_M[24])$_E(_gm,$k,_n,_gt[2],_gt[3]);if(!_M[24]){if(_M.ttop)_M[2]=_o4s;return}}_gm.style.overflow="auto";i_=_gt[3];if(!$BW){$_E(_gm,_n,_n,50,40);$BW=parseInt(_gm.style.width)-_gm.clientWidth;if(mac)$BW=18}$k=_n;if(hm){_ht=_bH-_gt[0]-8+_sT}else{_ht=_bH-_Mw-14;$k=6+_sT}$l=_n;if(!_M[25]&&_mp[1]+i_>(_bW+_sL))$l=(_bW-i_)-2;if(_M[2]&&!isNaN(_M[2])){$k=_M[2];_ht=(_bH+_sT)-$k-6;if(_ht>_gt[2])_ht=_gt[2]}if(_M[24])_ht=_M[24];i_+=$BW+_Mw;if(ns6&&!ns7)i_=_gt[3]+15;if(ns6){var S=18;if(!window.scrollMaxX)S=0;_hp=$k+_gt[2];if(_hp+S>_bH+_sT)_ht=_ht-S;if(_W.fixMozillaZIndex){if(hm)$k=_mp[0]-_sT;else $k=5}}if(_ht>0){if(_M[24])$k=_n;if(_M[11]=="up")_ht=_bH-$x(_M[2])-10;$_E(_gm,$k,$l,_ht+2-_M[12],i_);if(_M[24]&&!_M[25]){_mp=$D(_gm);if(_mp[0]+_mp[2]-_sT>_bH){$k=_mp[0]-_mp[2]}$_E(_gm,$k)}}if(_M.ttop)_M[2]=_o4s}function i$(p){var c,i;if(p>-1){c=_m[p][21];while(c>-1){i=_mi[c];if(i[34]!="tree")e$(c);if(c==_m[i[0]][21])return;c=_m[i[0]][21]}}}function $I(){if(_W.inResizeMode>-1)return;_mot=_StO('k$(this._itemRef)',10);_MT=_StO("$bb()",_menuCloseDelay);_ofMT=1;focusedMenu=-1}function $bb(){if(inEditMode)return;if(_ofMT==1){$Z();$R1=0}}function $J(s){if(_W.inResizeMode>-1)return;_mot=$P(_mot);_MT=$P(_MT);_ofMT=0;focusedMenu=s;doMenuResize(focusedMenu)}function $Cw(i){if(i[18])i[8]=i[18];if(i[19])i[7]=i[19];if(i[56])i[29]=i[56];if(i[69])i[46]=i[69];if(i[85]&&i[3])i[24]=i[85];if(i[72])i[54]=i[72];if(i[75])i[9]=i[75];if(i[92])i[71]=i[92];if(i[102])i[6]=i[102];if(i[104])i[32]=i[104];if(i[112])i[108]=i[112];if(i[113])i[109]=i[113];i.cpage=1}function $q(i){_hrF=_L.pathname+_L.search+_L.hash;_hx=_Lhr.split("/");_fNm="/"+_hx[_hx.length-1];var I,t,p,u,x;I=_mi[i];t=0;if(I[77]){p=I[77].split(",");for(x=0;x<p.length;x++)if(_hrF.indexOf(p[x])>-1)t=1}if(I[2]){u=I[2];if(_hrF==u||_hrF==u+"/"||u==_Lhr||u+"/"==_Lhr||_fNm=="/"+u)t=1}if(t==1){$Cw(I);_cip[_cip.length]=i}}function _cA(_N,_O,i){var I,g;I=_mi[i];if(I[_N]){_tmp=I[_N];I[_N]=I[_O];I[_O]=_tmp}else return;g=$c("el"+i);g.e$=1;if(_N==81&&I[7]){g.style.background=I[7];l_=1}if(_N==80&&I[8]&&I[1]){$c("lnk"+i).oC=I[8];$c("lnk"+i).style.color=I[8];l_=1}if(_N==87&&I[54]){g.className=I[54]}if(_N==88&&I[46]){g.style.backgroundImage="url("+I[88]+")";d$(i)}if(_N==91&&I[71]){$c("sep"+i).style.backgroundImage="url("+I[91]+")"}_gm=$c("simg"+i);if(_gm&&_N==83&&I[24]&&I[3])_gm.src=I[24];_gm=$c("_img"+i);if(_gm&&_N==82&&I[29])_gm.src=I[29]}function _caA(i){_cA(80,8,i);_cA(81,7,i);_cA(82,29,i);_cA(83,24,i);_cA(87,54,i);_cA(88,46,i);_cA(91,71,i)}function sCM(m,f){var a,M,i,I;for(a=0;a<_m[m][0].length;a++){i=_m[m][0][a];I=_mi[i];if(I[3]){M=$h(I[3]);if(M){_m[M][7]=0;eval(f);sCM(M,f)}}}}l_=0;function $K(i){var I,t,M,a;I=_mi[i];M=_m[I[0]];if(!_W.resetAutoOpen&&!I[34]&&!I[41]&&(I[2]||I[40]))$Z();if(M[11]=="tab"){t=$h(I[3]);sCM(I[0],"$Y(M)");if(t){if(M.Tm&&M.Tm!=t){_m[M.Tm][7]=0;$Y(M.Tm);$c("el"+M.Ti).e$=1;_caA(M.Ti);d$(M.Ti)}if(M.Tm!=t)_caA(i);M.Tm=t;M.Ti=i;if(M.Tm)_m[M.Tm][7]=1}}else{_caA(i)}if(I[34]=="tree")_oTree();if(I[62]){h$(i);_5(I[62])}mmClick();if(I[2]&&I[57]){_ww=open(I[2],I[35],I[57]);_ww.focus();return false}if(I[2]){if(I[34]=="html")_Lhr=I[2];if($c("mmlink"+I[0]).tagName=="DIV")_L.href=I[2]}$R1=0;if(I[39]){$R1=1;$W(i)}if(I[115]=="retFalse")return false}function $t(I,_gli,M){if(!I[1])return "";_Ltxt=I[1];_TiH=((I[34]=="header"||I[34]=="form"||I[34]=="dragable"||I[86]||!I[2])?1:0);_ofc=(I[8]?"color:"+I[8]:"");if(!_TiH&&I[58]&&!I.cpage)_ofc="";_fsize=(I[12]?";font-Size:"+I[12]:"");_fstyle=(I[13]?";font-Style:"+I[13]:";font-Style:normal");_fweight=(I[14]?";font-Weight:"+I[14]:";font-Weight:normal");_ffam=(I[15]?";font-Family:"+I[15]:"");_tdec=(I[33]?";text-Decoration:"+I[33]:";text-Decoration:none;");_disb=(I[34]=="disabled"?"disabled":"");_clss="";if(I[54]){_clss=" class='"+I[54]+"'";if(!I[33])_tdec="";if(!I[13])_fstyle="";if(!I[14])_fweight=""}else if(I[58]){_clss=" class='"+_m[_mi[_gli][0]][6].g_+"'"}m_ee=" ";if(!_TiH)m_ee=" onclick=\"return $K("+_gli+")\" ";_rawC=(I[78]?";"+I[78]:"");$1B="";if(M[8])$1B+=";text-align:"+M[8];else if(I[36])$1B+=";text-align:"+I[36];_HREF=_jv;if(I[2])_HREF=I[2];if(I[105]=="on")_Ltxt=I[1].replace(_5("//g"),"&nbsp;");m_e="a ";if(I[34]=="form"||I[34]=="header"||I[34]=="html")m_e="div ";_link='<'+m_e+_p5+m_ee+' name=mM1 onfocus=_iF0C('+_gli+') href="'+_HREF+'" '+_disb+_clss+' id=lnk'+_gli+' style="border:none;background:transparent;display:block;'+_ofc+_ffam+_fweight+_fstyle+_fsize+_tdec+$1B+_rawC+'">'+_Ltxt+'</'+m_e+'>';return _link}function hmL(_mn){_hm=$c("mmlink"+_mn);if(_hm)_hm.style.visibility=$5}function k$(i){var I=_mi[i];if(!I)return;_oMT=$P(_oMT);if(i>-1)hmL(I[0]);d$(i,1);o_IR=_itemRef;_itemRef=i;if(I&&I[43])_5(I[43]);_itemRef=o_IR}function _p2(M,t){t.style.width="auto";var m=_m[M];if(m[13]!=$_O){$z(M);if(m[5])p$(M)}m.Q=_StO("$1("+M+")",500)}function m$(i,_Tel){var I,_M,A,a,S;_it="";_el=_Tel;I=_mi[_el];$m=I[0];_M=_m[$m];if(_M[11]=="tab")I[39]=1;$q(_el);if(I[34]=="header"){if(I[20])I[8]=I[20];if(I[21])I[7]=I[21];if(I[74])I[9]=I[74]}_ofb=(I[46]?"background-image:url("+I[46]+");":"");if(!_ofb)_ofb=(I[7]?"background:"+I[7]+";":"");$n=" onmouseover=h$("+_Tel+") ";_link=$t(I,_el,_M);$o="";if(_M[18])$o="height:"+$pX(_M[18]);if(I[28])$o="height:"+$pX(I[28]);_clss="";if(I[54])_clss=" class='"+I[54]+"' ";if($Q){if(i==0)_it+="<tr>";if(I[50])I[27]=I[50]}else{if(I[49])I[27]=I[49];if(_M[26]&&!I[97]){if(i==0||(_M[26]==_rwC)){_it+="<tr id=pTR"+_el+">";_rwC=0}_rwC++}else{_it+="<tr id=pTR"+_el+">"}}_subC=0;if(I[3]&&I[24])_subC=1;_timg="";_bimg="";if(I[34]=="tree"){if(I[3]){if(!I[30])I[30]=" top"}else{if(I[79]){_subC=1;I[24]=I[79];I[3]="M_doc*"}}}if(I[29]){_imalgn="";if(I[31])_imalgn=" align="+I[31];_imvalgn="";if(I[30])_imvalgn=" valign="+I[30];_imcspan="";if(_subC&&_imalgn&&I[31]!="left")_imcspan=" colspan=2";_Iwid=(I[38])?"width:"+I[38]+"px;":"width:0;";_Ihgt=(I[37])?"height:"+I[37]+"px;":"";_impad=(I[60])?" style='padding:"+$pX(I[60])+"'":"";_alt=(I[76])?" alt='"+I[76]+"'":"";_timg="<td id=_imgO"+_el+" "+_imcspan+_imvalgn+_imalgn+_impad+">"+(I[84]?"<a href='"+I[84]+"'>":"")+"<img onload=_p2("+$m+",this) border="+(I[89]?I[89]:0)+" style='display:block;"+_Iwid+_Ihgt+"' "+_alt+" id=_img"+_el+" src='"+I[29]+"'>"+(I[84]?'</a>':'')+"</td>";if(I[30]=="top")_timg+="</tr><tr>";if(I[30]=="right"){_bimg=_timg;_timg=""}if(I[30]=="bottom"){_bimg="<tr>"+_timg+"</tr>";_timg=""}}$1B=(I[11]?";padding:"+$pX(I[11]):"");if(!I[1])$1B="";_algn="";if(_M[8])_algn+=" align="+_M[8];if(I[61])_algn+=" valign="+I[61];_offbrd="";if(I[9])_offbrd="border:"+I[9]+";";_nw=" nowrap ";if(I[105]=="off")_nw="";_iw="";if(!$Q&&_M[17])_iw=_M[17];if(_M[4])_iw=_M[4];if(I[55])_iw=I[55];if(I[55]!=_M[6].itemwidth)_iw=I[55];if($Q&&isNaN(_iw)&&_iw.indexOf("%")>-1)_iw=Math.ceil(100/_M[0].length)+"%";if(_M[31])_nw="";if(_iw){_nw="";_iw=" width="+_iw}if(I[97]){_iw+=" colspan="+I[97];_rwC=_M[26]}if(I[108]){_subC=1}if(_subC||I[29]){x_="";w_="";b_="";d_="";if(I[3]&&I[24]){A=0;if(IEDtD&&(_M[11]=="rtl"||_M[11]=="uprtl"))A=1;var C=I[116]?" class="+I[116]:"";_img="<img id=simg"+_el+" onload=_p2("+$m+",this) src='"+I[24]+"'"+C+" style='width:0px;'>";a_P="";if(I[22])a_P=";padding:"+$pX(I[22]);_imps="width=1";if(I[23]){_iA="width=1";_ivA="";_imP=I[23].split(" ");for(a=0;a<_imP.length;a++){if(_imP[a]=="left")A=1;if(_imP[a]=="right")A=0;if(_imP[a]=="top"||_imP[a]=="bottom"||_imP[a]=="middle"){_ivA="valign="+_imP[a];if(_imP[a]=="bottom")A=0}if(_imP[a]=="center"){b_="<tr>";d_="</tr>";_iA="align=center width=100%"}}_imps=_iA+" "+_ivA}_its=b_+"<td "+_imps+" style='font-size:1px"+a_P+";'>";_ite="</td>"+d_;if(A){x_=_its+_img+_ite}else{w_=_its+_img+_ite}}_it+="<td "+_iw+" id=el"+_el+$n+_clss+" style='padding:0px;"+_offbrd+_ofb+$o+";'>";_pw=" width=100% ";if(_W.noSubImageSpacing)_pw="";_it+=_TbS+_pw+" height=100% id=MTbl"+_el+">";_it+="<tr id=td"+_el+">";if(I[108])_it+="<td><img id=li108"+_el+" src="+I[108]+"></td>";_it+=x_;_it+=_timg;if(_link)_it+="<td "+_pw+_nw+_algn+" style='"+$1B+";'>"+_link+"</td>";_it+=_bimg;_it+=w_;if(I[109])_it+="<td><img id=ri109"+_el+" src="+I[109]+"></td>";_it+="</tr>";_it+="</table>";_it+="</td>"}else{if(_link)_it+="<td "+_iw+_clss+_nw+" id=el"+_el+$n+_algn+" style='"+$1B+_offbrd+$o+_ofb+";'>"+_link+"</td>"}S="";if((_M[0][i]!=_M[0][_M[0].length-1])&&I[27]>0){c$="";if(!I[10])I[10]=I[8];_sbg=";background:"+I[10];if(I[71])_sbg=";background-image:url("+I[71]+");";if($Q){if(I[49]){_sepA="middle";if(I[52])_sepA=I[52];S="";if(I[51])S="style=padding:"+$pX(I[51]);_it+="<td id=sep"+_el+" nowrap "+S+" valign="+_sepA+" align=left width=1px><div style='font-size:1px;width:"+$pX(I[27])+";height:"+$pX(I[49])+";"+c$+_sbg+";'></div></td>"}else{if(I[16]&&I[17]){_bwid=I[27]/2;if(_bwid<1)_bwid=1;q_=_bwid+"px solid ";c$+="border-right:"+q_+I[16]+";";c$+="border-left:"+q_+I[17]+";";c$="";_iT=_TbS+"><td></td></table>";if(ns6||ns7)_iT="";_it+="<td style='empty-cells:show;"+c$+";'>"+_iT+"</td>"}else{if(I[51])S="<td nowrap width="+$pX(I[51])+"></td>";_it+=S+"<td id=sep"+_el+" style='padding:0px;width:"+$pX(I[27])+c$+_sbg+";'>"+_TbS+" width="+I[27]+"><td style='padding:0px;'></td></table></td>"+S}}}else{if(I[16]&&I[17]){_bwid=I[27]/2;if(_bwid<1)_bwid=1;q_=_bwid+"px solid ";c$="border-bottom:"+q_+I[16]+";";c$+="border-top:"+q_+I[17]+";";if(mac||ns6||sfri||konq||IEDtD||op)I[27]=0}if(I[51])S="<tr><td height="+I[51]+"></td></tr>";_sepW="100%";if(I[50])_sepW=I[50];_sepA="center";if(I[52])_sepA=I[52];if(!mac)_sbg+=";overflow:hidden";_it+="</tr>"+S+"<tr><td style=padding:0px; id=sep"+_el+" align="+_sepA+"><div style='"+_sbg+";"+c$+"width:"+$pX(_sepW)+";padding:0px;height:"+$pX(I[27])+"font-size:1px;'></div></td></tr>"+S+""}}if(I[34]=="tree"){if(ie&&!mac){_it+="<tr id=OtI"+_el+" style='display:none;'><td></td></tr>"}else{_it+="<tr><td style='height:0px;' valign=top id=OtI"+_el+"></td></tr>"}}return _it}function $z(U){var M=_m[U];_gm=$c($O+U);if(_gm){_gmt=$c("tbl"+U);if(_gmt){$S=_gm.style;$T=_gmt.offsetWidth;if((M[14]=="relative"))if(!M[17])$S.width=$T+"px";if(mac){s_=(M[12]*2+M[6][65]*2);_MacA=$D(_gmt);if(_MacA[2]==0&&_MacA[3]==0){_StO("$z("+U+")",200);return}if(IEDtD)s_=0;$S.overflow=$5;$S.height=$pX(_MacA[2]+s_);$S.width=$pX(_MacA[3]+s_)}if(M[31]>0)if($T>M[31])$_E(_gm,_n,_n,_n,M[31])}}}gevent=0;function _p3(evt,$m){if(evt.target.tagName=="TD"){_egm=$c($O+$m);gevent=evt.layerY-(evt.pageY-$7)+_egm.offsetTop}}function $pX(){var g,x,p;g=arguments;x=g[1]?"":";";p=(!isNaN(g[0]))?g[0]+="px"+x:g[0]+x;return p}function _eMD(d){_it=d.split(":");return _it[1].replace(/;/g,"")}function createNewMenu(y){var M,o,b;_startM=0;M=_m[y];o=_d.createElement("div");o.id="menu"+y;o.onmouseout=new Function("$I()");o.onmouseover=new Function("$J("+y+")");o.onselectstart=new Function("return _f");if(_dB.appendChild){_dB.appendChild(o);o$(y,0);o.className=_cls;n=o.style;if(M[17])n.width=M[17]+"px";if(M[24])n.height=M[24]+"px";if(_ofb)n.background=_eMD(_ofb);if(p_)n.border=_eMD(p_);o.style.zindex=999;o.style.visibility=_visi;if(n_)n.position=_eMD(n_);if($k)n.top=_eMD($k);if($l)n.left=_eMD($l);if(_bgimg)n.backgroundImage=_eMD(_bgimg);if(_mbgc)n.background=_eMD(_mbgc);M[23]=0}}_fSz="'>";function o$(){var g,_M,bw,L,b,B,A;g=arguments;$m=g[0];B=g[1];_mcnt++;_M=_m[$m];_mt="";if(!_M)return;L=_M[0].length;A=g[2];if(A&&_M[7]==_n){for(b=0;b<L;b++)$q(_M[0][b]);return}if(_W.noTabIndex)_p5=" tabindex=-1 ";else _p5="";_MS=_M[6];y_="";$k="";$l="";if(_M[7]==0)_M[7]=_n;if((!_M[14])&&(!_M[7]))$k="top:-"+$pX(_aN);if(_M[2]!=_n)if(!isNaN(_M[2]))$k="top:"+$pX(_M[2]);if(_M[3]!=_n)if(!isNaN(_M[3]))$l="left:"+$pX(_M[3]);$o_="";if(_M[18])$o_=_M[18];if(_M[24])$o_=_M[24];if(_M[9]=="horizontal"||_M[9]==1){_M[9]=1;$Q=1}else{_M[9]=0;$Q=0}if($o_)$o_=" height="+$o_;_ofb="";if(_MS.offbgcolor)_ofb="background:"+_MS.offbgcolor;p_="";q_="";bw="";if(_MS[65]){_brdsty=_MS[64]?_MS[64]:"solid";_brdcol=_MS.offcolor?_MS.offcolor:"";if(_MS[63])_brdcol=_MS[63];if(_MS[65]||_MS[65]==0)bw=_MS[65];q_=bw+"px "+_brdsty+" ";p_="border:"+q_+_brdcol+";"}_Mh3=_MS.high3dcolor;_Ml3=_MS.low3dcolor;if(_Mh3&&_Ml3){_h3d=_Mh3;_l3d=_Ml3;if(_MS.swap3d){_h3d=_Ml3;_l3d=_Mh3}q_=bw+"px solid ";p_="border-bottom:"+q_+_h3d+";";p_+="border-right:"+q_+_h3d+";";p_+="border-top:"+q_+_l3d+";";p_+="border-left:"+q_+_l3d+";"}_ns6ev="";if(_M[13]==$_O&&ns6&&!ns7)_ns6ev="onmousemove='_p3(event,"+$m+")'";_bgimg=_MS.menubgimage?";background-image:url("+_MS.menubgimage+");":"";if(!_M[14]&&!_M[7]&&_W.fixMozillaZIndex&&ns6)_M[14]="fixed";n_=B$;if(_M[14]){n_=_M[14];if(_M[14]=="relative"){$k="";$l=""}if(_M[14]=="fixed"&&!ns6)n_=B$}$1B="padding:0px;";if(_M[12])$1B=";padding:"+$pX(_M[12]);_cls="mmenu";if(_MS.offclass)_cls=_MS.offclass;if(n_)n_="position:"+n_;_visi=$5;_mbgc="";if(B==1){_hght="";if(_M[17])_hght=";width:"+$pX(_M[17]);if(_M[24])_hght+=";height:"+$pX(_M[24]);if(_MS.menubgcolor)_mbgc=";background-color:"+_MS.menubgcolor;if(_M[11]=="rtl")$1B+="align:right;";_mali=_M[20]?";text-align:"+_M[20]:"";_rcss=_M[34]?_M[34]:"";_mt+="<div class=mmenucontainer onmouseout=$I() onmouseover=$J("+$m+") onselectstart='return 0' "+_ns6ev+" id=menu"+$m+" style='"+_rcss+$1B+_ofb+";"+p_+_hght+"z-index:999;visibility:"+_visi+";"+n_+";"+$k+";"+$l+_bgimg+_mbgc+_mali+"'>"}if(_M[7]||!_startM||(op5||op6)||_W.buildAllMenus){_M[23]=1;if(!(mac)&&ie)_fSz="font-size:999px;'>&nbsp;";_rwC=0;if($Q){if(_M[26]>1)_rwC=Math.ceil(_M[0].length/_M[26]);_rwT=_rwC}else{if(_M[4])y_=_M[4];if(_M[6].itemwidth)y_=_M[6].itemwidth}_mali="";if(_M[20])_mali=" align="+_M[20];if(y_)y_=" width="+y_;if(!_M[32])y_+=" "+$o_;_mt+=_TbS+y_+" id=tbl"+$m+_mali+">";for(b=0;b<_M[0].length;b++){_mt+=m$(b,_M[0][b]);_el++;if($Q&&_rwC>1){if(b+1==_rwT){_mt+="</tr><tr>";_rwT=_rwT+_rwC}}}if(mac&&!$Q)_mt+="<tr><td id=btm"+$m+"></td></tr>";_mt+="</table>"+" ";m_e=(_M[6].type=="div"||(ns61&&_M[6].type=="tree")?"div":"a");m_e+=_p5;_mt+="<"+m_e+" name=mM1 id=mmlink"+$m+" href=# onclick='return $K(this._itemRef)' onmouseover='_p1(this);_mot=$P(_mot)' style='outline:none;line-height:normal;background:transparent;text-decoration:none;height:1px;width:1px;overflow:hidden;position:"+B$+";"+_fSz+"</"+m_e+">"}else{if(B==1)for(b=0;b<L;b++){$q(_el);_el++}}if(B==1)_mt+="</div>";if(B==1){if(_W._pageIsXML)_mtX+=_mt;else _d.write(_mt)}else return _mt;if(_M[7]){_M[22]=$c($O+$m)}if(_M[19]){_M[19]=_M[19].toString();_fs=_M[19].split(",");if(!_fs[1])_fs[1]=50;if(!_fs[2])_fs[2]=2;_M[19]=_fs[0];$X($m,_fs[1],_fs[2])}if($m==_m.length-1||(A&&_M[7])){_mst=_StO("$N()",50);$p()}}$S2="6D696C6F6E6963";function $p(){if(!_W.disablePagePath){if(_cip.length>0){for(_c=0;_c<_cip.length;_c++){_ci=_cip[_c];_mni=$f(_ci);if(_mni==-1)_mni=_ci;if(_mni+" "!=$u){while(_mni!=-1){var I=_mi[_mni];$Cw(I);_gi=$c("el"+_mni);if(_gi)_gi.e$=1;d$(_mni);_omni=_mni;_mni=$f(_mni);if(_mni==_omni||_mni+" "==$u)_mni=-1}}}}}}function _p4(V,n){var S,m;S=[];if(isNaN(V[n])&&V[n].indexOf("offset=")==0){S[0]=V[n].substr(7,99);m=S[0].indexOf(";minimum=");if(m>-1){S[1]=S[0].substr(m+9,99);S[0]=S[0].substr(0,m)}V[n]=_n}return S}function p$(m){var M=_m[m];if(M[5]){_gm=$c($O+m);if(!_gm)return;j_=$D(_gm);_LoM=0;if(!_gm.leftOffset){_oSA=_p4(M,3);_gm.leftOffset=_oSA[0];_gm._LoM=_oSA[1]}_lft=_n;if(!M[3]){if(M[5].indexOf("left")!=-1)_lft=0;if(M[5].indexOf("center")!=-1)_lft=(_bW/2)-(j_[3]/2);if(M[5].indexOf("right")!=-1)_lft=(_bW-j_[3]);if(_gm.leftOffset)_lft=_lft+$pU(_gm.leftOffset)}_ToM=0;if(!_gm.topOffset){_oSA=_p4(M,2);_gm.topOffset=_oSA[0];_gm._ToM=_oSA[1]}m_=_n;if(!M[2]>=0){m_=_n;if(M[5].indexOf("top")!=-1)m_=0;if(M[5].indexOf("middle")!=-1)m_=(_bH/2)-(j_[2]/2);if(M[5].indexOf("bottom")!=-1)m_=_bH-j_[2];if(_gm.topOffset)m_=m_+$pU(_gm.topOffset)}if(_lft<0)_lft=0;if(_lft<_gm._LoM)_lft=_gm._LoM;if(m_)m_=$pU(m_);if(_lft)_lft=$pU(_lft);$_E(_gm,m_,_lft);if(M[19])M[19]=m_;if(M[7])$V(m,1);_gm.m_=m_}}function $X(m,c,r){if(!_startM&&!inDragMode){var M=_m[m];_fogm=M[22];h_=$D(_fogm);_tt=(_sT>M[2]-M[19])?_sT-(_sT-M[19]):M[2]-_sT;if(h_&&h_[0]-_sT!=_tt){diff=_sT+_tt;_rcor=(diff-h_[0]<1)?r:-r;_fv=$pU((diff-_rcor-h_[0])/r);if(r==1)_fv=$pU((diff-h_[0]));if(_fv!=0)diff=h_[0]+_fv;$_E(_fogm,diff);if(h_.m_)M[19]=h_.m_;if(ie55){_fogm=$c("ifM"+m);if(_fogm)$_E(_fogm,diff)}}}_fS=_StO("$X('"+m+"',"+c+","+r+")",c)}function $qe(s){var x,q,a;x=s.split("");q="";for(a=0;a<s.length;a++){q+="%"+x[a]+x[a+1];a++}return unescape(q)}$S1="687474703A2F2F7777772E";function $N(){var a;$r();if(_bH!=_oldbH||_bW!=_oldbW){_tMR();for(a=0;a<_m.length;a++){if(_m[a]&&_m[a][7]){$Y(a,1);$z(a)}}}if(_oldbH==0){_oldbH=_bH;if(!_W.disableMouseMove)_d.onmousemove=gMY}if(_startM){$mD=0;$J(-1);_ofMT=1}_startM=0;_oldbH=_bH;_oldbW=_bW;_mst=_StO("$N()",70)}getMenuByItem=$d;getParentMenuByItem=$e;getParentItemByItem=$f;_drawMenu=o$;BDMenu=g$;gmobj=$c;menuDisplay=$Y;gpos=$D;spos=$_E;_fixMenu=$z;getMenuByName=$h;itemOn=e$;itemOff=d$;_popi=h$;clickAction=$K;_setPosition=p$;closeAllMenus=$Z;function $V($m,_on){var _M,F,f,p,g,S;_M=_m[$m];if(ns6||_M.treemenu||_M[14]=="relative"||_W._CFix||!_M[22])return;if(ie55){if(_on){if(_M[7])F="iFM"+$m;else F="iF"+$mD;if(_M.ifr)f=_M.ifr;else f=$c(F);if(!f){if(!_lDd)return;f=_d.createElement("iframe");S=f.style;f.src="javascript:false";f.id=F;S.filter="Alpha(Opacity=0)";S.position=B$;S.className="mmenu";if(_dB.appendChild)_dB.appendChild(f)}p=$D(_M[22]);S=f.style;$_E(f,p[0],p[1],p[2],p[3]);S.visibility=$6;S.zIndex=_M[22].style.zIndex-2;_M.ifr=f}else{g=$c("iF"+($mD-1));if(g){$_E(g,-9999);g.style.visibility=$5;_M.ifr=_n}}}}


/* --- End mmenudom.js --- */
/* --- Start listmenus.js --- */

/*
   Milonic DHTML Menu HTML Unordered List Based Module version 2.3 - January 24 2008
   This module is only compatible with the Milonic DHTML Menu version 5.7 or higher

   Copyright 2008 (c) Milonic Solutions Limited. All Rights Reserved.
   This is a commercial software product, please visit http://www.milonic.com/ for more information.
   
   The object of this module is to enable data entered as a HTML un-ordered list to be used inside menus.
   Data for menu items is taken from HTML Lists and used for menus. Styles are created as normal DHTML Menus and referenced as a CSS classname.
*/

_lpss=0
_y3=new Array();
function buildListMenu(_mnu,_sty,_prps)
{	
	_lpss++
	if(_lpss==1)
	{
		_y5=0;
		_y1=0;
		for(_a=0;_a<_d.links.length;_a++){
		_y4=_d.links[_a];
			pE=_y4.parentNode;
			if(pE.tagName=="LI"){
				while(pE){
					if(pE.tagName=="UL"){
						if(!pE.menuId)
						{
							pE.menuId="mmenu"+_y5;
							if(pE.id==_mnu)pE.style.display="none"
							_y3[_y5]=new Array();
							if(_y1)_y3[_y1][_y3[_y1].length-1]+=";showmenu=listmenu"+_y5+";";
							if(pE.className)_y3[_y5].mS=pE.className

							if(pE.parentNode.tagName!="LI")
							{
								_y3[_y5].mM=1
								msMenu=pE.id
							}
							_y3[_y5].msMenu=msMenu							
							_y5++;
						}
						break;
					}
					pE=pE.parentNode;
				}
				if(pE)
				{
					_y1=pE.menuId.substr(5,3);
					if(sfri||ie)txt=_y4.innerHTML;else txt=_y4.text;
					_y3[_y1][_y3[_y1].length]="text="+txt.replace(/\"/g,"\\'")+";"
					_y7=""
					
					if(_y4.title)_y7="title="+_y4.title+";"
					if(_y4.target)_y7+="target="+_y4.target+";"
					if(_y4.href.substr(_y4.href.length-1,1)!="#")_y3[_y1][_y3[_y1].length-1]+="url="+_y4+";"+_y7
					
					
				}
			}
		}
	}
	_y6="";
	for(_a=0;_a<_y3.length;_a++){
		if(_y3[_a].msMenu==_mnu)
		{
			_mN="listmenu"+_a
			if(_y3[_a].mM)_mN=_mnu
			_y6+="with(milonic=new menuname('"+_mN+"')){"
			if(_y3[_a].mS)_y6+="style="+_y3[_a].mS+";";else _y6+="style="+_sty+";";
			if(_y3[_a].mM)_y6+=_prps;
			for(_b=0;_b<_y3[_a].length;_b++){_y6+="aI(\""+_y3[_a][_b].replace(/\"/g,"'")+";\");\n"}
			_y6+="}"
		}
	}
	_d.write("<script>"+_y6.replace(/\n/g,"")+"drawMenus();<\/script>")
}

/* --- End listmenus.js --- */
/* --- Start MenuStyle.js --- */

fixMozillaZIndex=true; //Fixes Z-Index problem  with Mozilla browsers but causes odd scrolling problem, toggle to see if it helps
_menuCloseDelay=500;
_menuOpenDelay=150;
_subOffsetTop=0;
_subOffsetLeft=-2;

with(Menu=new mm_style()){
  alwaysvisible  = 1;
  menuwidth      = "100%";
  menuheight     = "24px";
  align          = "center";
  styleid        = 1;
  bgimage        = "http://assets.westword.com/img/navbg_off.gif";
  fontfamily     = "trebuchet ms,times new roman,serif";
  fontsize       = "11px";
  fontstyle      = "normal";
  fontweight     = "bold";
  itemheight     = "18px";
  padding        = 3;
  offcolor       = "#ffffff";
  onbgcolor      = "#ffffff";
  oncolor        = "#000000";
  outfilter      = "fade(duration=0)";
  overbgimage    = "http://assets.westword.com/img/navbg_on.gif";
  overfilter     = "Fade(duration=0);Alpha(opacity=100);";
  separatorimage = "http://assets.westword.com/img/navsep.gif";
  separatorsize  = 1;
  rawcss         = "padding-left:12px;padding-right:12px;white-space:nowrap;text-transform:uppercase;";
};

with(SubMenu=new mm_style()){
  menuwidth      = "100%";
  align          = "left";
  bordercolor    = "#333333";
  borderstyle    = "solid";
  borderwidth    = 1;
  fontfamily     = "trebuchet ms,times new roman,serif";
  fontsize       = "11px";
  fontstyle      = "normal";
  fontweight     = "bold";
  itemheight     = "14px";
  keepalive      = "true";
  offbgcolor     = "#666666";
  offcolor       = "#ffffff";
  onbgcolor      = "#666666";
  oncolor        = "#ffffff";
  ondecoration   = "underline";
  outfilter      = "fade(duration=0)";
  overfilter     = "fade(duration=0);Alpha(opacity=95);";
  padding        = 1;
  rawcss         = "padding-left:4px;padding-right:4px;white-space:nowrap;";
  separatorcolor = "#333333";
  separatorsize  = 1;
};


/* --- End MenuStyle.js --- */
/* --- Start VVDOM.js --- */

/*
 *  VVDOM.js - DOM Compatibility scripts between IE/Firefox/etc
 *
 *  ************************************************************
 *  Note: Before adding any new functions into this class
 *        PLEASE check the prototype and scriptaculous libraries
 *        for duplicate functionality.
 *  ************************************************************
 */

function VVDOM() {

}

//-----------------------------------------------------------------------------
/**
 * VVMLoadManager class, should not instantiate instances of this, use the
 * instance instantiated below (loadMgr)
 */
//-----------------------------------------------------------------------------
function LoadManager()
{
    this.loadEvents = new Array();
    this.unLoadEvents = new Array();
    //-------------------------------------------------------------------------
    /**
     * Process load chain
     */
    this.processLoad = function()
    {
        var i = 0;
        for(i = 0; i < this.loadEvents.length; i++)
        {
            eval(this.loadEvents[i]);
        }
    }
    //-------------------------------------------------------------------------
    /**
     * Process unload chain
     */
    this.processUnload = function()
    {
        for(i = 0; i < this.unLoadEvents.length; i++)
        {
            eval(this.unLoadEvents[i]);
        }
    }
    //-------------------------------------------------------------------------
    /**
     * Add an event to the load chain
     *
     * @param string event - event to add, this will be eval'd in processLoad
     */
    this.addLoadEvent = function(event)
    {
        this.loadEvents.push(event);
    }
    //-------------------------------------------------------------------------
    /**
     * Add an event to the unload chain
     *
     * @param string event - event to add, this will be eval'd in processLoad
     */
    this.addUnloadEvent = function(event)
    {
        this.unLoadEvents.push(event);
    }
}
loadMgr = new LoadManager();
//-----------------------------------------------------------------------------

/* --- End VVDOM.js --- */
/* --- Start /home/httpd/app_frame/webroot/js/slider.js --- */

// script.aculo.us slider.js v1.8.0, Tue Nov 06 15:01:40 +0300 2007

// Copyright (c) 2005-2007 Marty Haught, Thomas Fuchs 
//
// script.aculo.us is freely distributable under the terms of an MIT-style license.
// For details, see the script.aculo.us web site: http://script.aculo.us/

if (!Control) var Control = { };

// options:
//  axis: 'vertical', or 'horizontal' (default)
//
// callbacks:
//  onChange(value)
//  onSlide(value)
Control.Slider = Class.create({
  initialize: function(handle, track, options) {
    var slider = this;
    
    if (Object.isArray(handle)) {
      this.handles = handle.collect( function(e) { return $(e) });
    } else {
      this.handles = [$(handle)];
    }
    
    this.track   = $(track);
    this.options = options || { };

    this.axis      = this.options.axis || 'horizontal';
    this.increment = this.options.increment || 1;
    this.step      = parseInt(this.options.step || '1');
    this.range     = this.options.range || $R(0,1);
    
    this.value     = 0; // assure backwards compat
    this.values    = this.handles.map( function() { return 0 });
    this.spans     = this.options.spans ? this.options.spans.map(function(s){ return $(s) }) : false;
    this.options.startSpan = $(this.options.startSpan || null);
    this.options.endSpan   = $(this.options.endSpan || null);

    this.restricted = this.options.restricted || false;

    this.maximum   = this.options.maximum || this.range.end;
    this.minimum   = this.options.minimum || this.range.start;

    // Will be used to align the handle onto the track, if necessary
    this.alignX = parseInt(this.options.alignX || '0');
    this.alignY = parseInt(this.options.alignY || '0');
    
    this.trackLength = this.maximumOffset() - this.minimumOffset();

    this.handleLength = this.isVertical() ? 
      (this.handles[0].offsetHeight != 0 ? 
        this.handles[0].offsetHeight : this.handles[0].style.height.replace(/px$/,"")) : 
      (this.handles[0].offsetWidth != 0 ? this.handles[0].offsetWidth : 
        this.handles[0].style.width.replace(/px$/,""));

    this.active   = false;
    this.dragging = false;
    this.disabled = false;

    if (this.options.disabled) this.setDisabled();

    // Allowed values array
    this.allowedValues = this.options.values ? this.options.values.sortBy(Prototype.K) : false;
    if (this.allowedValues) {
      this.minimum = this.allowedValues.min();
      this.maximum = this.allowedValues.max();
    }

    this.eventMouseDown = this.startDrag.bindAsEventListener(this);
    this.eventMouseUp   = this.endDrag.bindAsEventListener(this);
    this.eventMouseMove = this.update.bindAsEventListener(this);

    // Initialize handles in reverse (make sure first handle is active)
    this.handles.each( function(h,i) {
      i = slider.handles.length-1-i;
      slider.setValue(parseFloat(
        (Object.isArray(slider.options.sliderValue) ? 
          slider.options.sliderValue[i] : slider.options.sliderValue) || 
         slider.range.start), i);
      h.makePositioned().observe("mousedown", slider.eventMouseDown);
    });
    
    this.track.observe("mousedown", this.eventMouseDown);
    document.observe("mouseup", this.eventMouseUp);
    document.observe("mousemove", this.eventMouseMove);
    
    this.initialized = true;
  },
  dispose: function() {
    var slider = this;    
    Event.stopObserving(this.track, "mousedown", this.eventMouseDown);
    Event.stopObserving(document, "mouseup", this.eventMouseUp);
    Event.stopObserving(document, "mousemove", this.eventMouseMove);
    this.handles.each( function(h) {
      Event.stopObserving(h, "mousedown", slider.eventMouseDown);
    });
  },
  setDisabled: function(){
    this.disabled = true;
  },
  setEnabled: function(){
    this.disabled = false;
  },  
  getNearestValue: function(value){
    if (this.allowedValues){
      if (value >= this.allowedValues.max()) return(this.allowedValues.max());
      if (value <= this.allowedValues.min()) return(this.allowedValues.min());
      
      var offset = Math.abs(this.allowedValues[0] - value);
      var newValue = this.allowedValues[0];
      this.allowedValues.each( function(v) {
        var currentOffset = Math.abs(v - value);
        if (currentOffset <= offset){
          newValue = v;
          offset = currentOffset;
        } 
      });
      return newValue;
    }
    if (value > this.range.end) return this.range.end;
    if (value < this.range.start) return this.range.start;
    return value;
  },
  setValue: function(sliderValue, handleIdx){
    if (!this.active) {
      this.activeHandleIdx = handleIdx || 0;
      this.activeHandle    = this.handles[this.activeHandleIdx];
      this.updateStyles();
    }
    handleIdx = handleIdx || this.activeHandleIdx || 0;
    if (this.initialized && this.restricted) {
      if ((handleIdx>0) && (sliderValue<this.values[handleIdx-1]))
        sliderValue = this.values[handleIdx-1];
      if ((handleIdx < (this.handles.length-1)) && (sliderValue>this.values[handleIdx+1]))
        sliderValue = this.values[handleIdx+1];
    }
    sliderValue = this.getNearestValue(sliderValue);
    this.values[handleIdx] = sliderValue;
    this.value = this.values[0]; // assure backwards compat
    
    this.handles[handleIdx].style[this.isVertical() ? 'top' : 'left'] = 
      this.translateToPx(sliderValue);
    
    this.drawSpans();
    if (!this.dragging || !this.event) this.updateFinished();
  },
  setValueBy: function(delta, handleIdx) {
    this.setValue(this.values[handleIdx || this.activeHandleIdx || 0] + delta, 
      handleIdx || this.activeHandleIdx || 0);
  },
  translateToPx: function(value) {
    return Math.round(
      ((this.trackLength-this.handleLength)/(this.range.end-this.range.start)) * 
      (value - this.range.start)) + "px";
  },
  translateToValue: function(offset) {
    return ((offset/(this.trackLength-this.handleLength) * 
      (this.range.end-this.range.start)) + this.range.start);
  },
  getRange: function(range) {
    var v = this.values.sortBy(Prototype.K); 
    range = range || 0;
    return $R(v[range],v[range+1]);
  },
  minimumOffset: function(){
    return(this.isVertical() ? this.alignY : this.alignX);
  },
  maximumOffset: function(){
    return(this.isVertical() ? 
      (this.track.offsetHeight != 0 ? this.track.offsetHeight :
        this.track.style.height.replace(/px$/,"")) - this.alignY : 
      (this.track.offsetWidth != 0 ? this.track.offsetWidth : 
        this.track.style.width.replace(/px$/,"")) - this.alignX);
  },  
  isVertical:  function(){
    return (this.axis == 'vertical');
  },
  drawSpans: function() {
    var slider = this;
    if (this.spans)
      $R(0, this.spans.length-1).each(function(r) { slider.setSpan(slider.spans[r], slider.getRange(r)) });
    if (this.options.startSpan)
      this.setSpan(this.options.startSpan,
        $R(0, this.values.length>1 ? this.getRange(0).min() : this.value ));
    if (this.options.endSpan)
      this.setSpan(this.options.endSpan, 
        $R(this.values.length>1 ? this.getRange(this.spans.length-1).max() : this.value, this.maximum));
  },
  setSpan: function(span, range) {
    if (this.isVertical()) {
      span.style.top = this.translateToPx(range.start);
      span.style.height = this.translateToPx(range.end - range.start + this.range.start);
    } else {
      span.style.left = this.translateToPx(range.start);
      span.style.width = this.translateToPx(range.end - range.start + this.range.start);
    }
  },
  updateStyles: function() {
    this.handles.each( function(h){ Element.removeClassName(h, 'selected') });
    Element.addClassName(this.activeHandle, 'selected');
  },
  startDrag: function(event) {
    if (Event.isLeftClick(event)) {
      if (!this.disabled){
        this.active = true;
        
        var handle = Event.element(event);
        var pointer  = [Event.pointerX(event), Event.pointerY(event)];
        var track = handle;
        if (track==this.track) {
          var offsets  = Position.cumulativeOffset(this.track); 
          this.event = event;
          this.setValue(this.translateToValue( 
           (this.isVertical() ? pointer[1]-offsets[1] : pointer[0]-offsets[0])-(this.handleLength/2)
          ));
          var offsets  = Position.cumulativeOffset(this.activeHandle);
          this.offsetX = (pointer[0] - offsets[0]);
          this.offsetY = (pointer[1] - offsets[1]);
        } else {
          // find the handle (prevents issues with Safari)
          while((this.handles.indexOf(handle) == -1) && handle.parentNode) 
            handle = handle.parentNode;
            
          if (this.handles.indexOf(handle)!=-1) {
            this.activeHandle    = handle;
            this.activeHandleIdx = this.handles.indexOf(this.activeHandle);
            this.updateStyles();
            
            var offsets  = Position.cumulativeOffset(this.activeHandle);
            this.offsetX = (pointer[0] - offsets[0]);
            this.offsetY = (pointer[1] - offsets[1]);
          }
        }
      }
      Event.stop(event);
    }
  },
  update: function(event) {
   if (this.active) {
      if (!this.dragging) this.dragging = true;
      this.draw(event);
      if (Prototype.Browser.WebKit) window.scrollBy(0,0);
      Event.stop(event);
   }
  },
  draw: function(event) {
    var pointer = [Event.pointerX(event), Event.pointerY(event)];
    var offsets = Position.cumulativeOffset(this.track);
    pointer[0] -= this.offsetX + offsets[0];
    pointer[1] -= this.offsetY + offsets[1];
    this.event = event;
    this.setValue(this.translateToValue( this.isVertical() ? pointer[1] : pointer[0] ));
    if (this.initialized && this.options.onSlide)
      this.options.onSlide(this.values.length>1 ? this.values : this.value, this);
  },
  endDrag: function(event) {
    if (this.active && this.dragging) {
      this.finishDrag(event, true);
      Event.stop(event);
    }
    this.active = false;
    this.dragging = false;
  },  
  finishDrag: function(event, success) {
    this.active = false;
    this.dragging = false;
    this.updateFinished();
  },
  updateFinished: function() {
    if (this.initialized && this.options.onChange) 
      this.options.onChange(this.values.length>1 ? this.values : this.value, this);
    this.event = null;
  }
});


/* --- End /home/httpd/app_frame/webroot/js/slider.js --- */
/* --- Start /home/httpd/app_frame/webroot/js/dragdrop.js --- */

// script.aculo.us dragdrop.js v1.8.0, Tue Nov 06 15:01:40 +0300 2007

// Copyright (c) 2005-2007 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
//           (c) 2005-2007 Sammi Williams (http://www.oriontransfer.co.nz, sammi@oriontransfer.co.nz)
// 
// script.aculo.us is freely distributable under the terms of an MIT-style license.
// For details, see the script.aculo.us web site: http://script.aculo.us/

if(Object.isUndefined(Effect))
  throw("dragdrop.js requires including script.aculo.us' effects.js library");

var Droppables = {
  drops: [],

  remove: function(element) {
    this.drops = this.drops.reject(function(d) { return d.element==$(element) });
  },

  add: function(element) {
    element = $(element);
    var options = Object.extend({
      greedy:     true,
      hoverclass: null,
      tree:       false
    }, arguments[1] || { });

    // cache containers
    if(options.containment) {
      options._containers = [];
      var containment = options.containment;
      if(Object.isArray(containment)) {
        containment.each( function(c) { options._containers.push($(c)) });
      } else {
        options._containers.push($(containment));
      }
    }
    
    if(options.accept) options.accept = [options.accept].flatten();

    Element.makePositioned(element); // fix IE
    options.element = element;

    this.drops.push(options);
  },
  
  findDeepestChild: function(drops) {
    deepest = drops[0];
      
    for (i = 1; i < drops.length; ++i)
      if (Element.isParent(drops[i].element, deepest.element))
        deepest = drops[i];
    
    return deepest;
  },

  isContained: function(element, drop) {
    var containmentNode;
    if(drop.tree) {
      containmentNode = element.treeNode; 
    } else {
      containmentNode = element.parentNode;
    }
    return drop._containers.detect(function(c) { return containmentNode == c });
  },
  
  isAffected: function(point, element, drop) {
    return (
      (drop.element!=element) &&
      ((!drop._containers) ||
        this.isContained(element, drop)) &&
      ((!drop.accept) ||
        (Element.classNames(element).detect( 
          function(v) { return drop.accept.include(v) } ) )) &&
      Position.within(drop.element, point[0], point[1]) );
  },

  deactivate: function(drop) {
    if(drop.hoverclass)
      Element.removeClassName(drop.element, drop.hoverclass);
    this.last_active = null;
  },

  activate: function(drop) {
    if(drop.hoverclass)
      Element.addClassName(drop.element, drop.hoverclass);
    this.last_active = drop;
  },

  show: function(point, element) {
    if(!this.drops.length) return;
    var drop, affected = [];
    
    this.drops.each( function(drop) {
      if(Droppables.isAffected(point, element, drop))
        affected.push(drop);
    });
        
    if(affected.length>0)
      drop = Droppables.findDeepestChild(affected);

    if(this.last_active && this.last_active != drop) this.deactivate(this.last_active);
    if (drop) {
      Position.within(drop.element, point[0], point[1]);
      if(drop.onHover)
        drop.onHover(element, drop.element, Position.overlap(drop.overlap, drop.element));
      
      if (drop != this.last_active) Droppables.activate(drop);
    }
  },

  fire: function(event, element) {
    if(!this.last_active) return;
    Position.prepare();

    if (this.isAffected([Event.pointerX(event), Event.pointerY(event)], element, this.last_active))
      if (this.last_active.onDrop) {
        this.last_active.onDrop(element, this.last_active.element, event); 
        return true; 
      }
  },

  reset: function() {
    if(this.last_active)
      this.deactivate(this.last_active);
  }
}

var Draggables = {
  drags: [],
  observers: [],
  
  register: function(draggable) {
    if(this.drags.length == 0) {
      this.eventMouseUp   = this.endDrag.bindAsEventListener(this);
      this.eventMouseMove = this.updateDrag.bindAsEventListener(this);
      this.eventKeypress  = this.keyPress.bindAsEventListener(this);
      
      Event.observe(document, "mouseup", this.eventMouseUp);
      Event.observe(document, "mousemove", this.eventMouseMove);
      Event.observe(document, "keypress", this.eventKeypress);
    }
    this.drags.push(draggable);
  },
  
  unregister: function(draggable) {
    this.drags = this.drags.reject(function(d) { return d==draggable });
    if(this.drags.length == 0) {
      Event.stopObserving(document, "mouseup", this.eventMouseUp);
      Event.stopObserving(document, "mousemove", this.eventMouseMove);
      Event.stopObserving(document, "keypress", this.eventKeypress);
    }
  },
  
  activate: function(draggable) {
    if(draggable.options.delay) { 
      this._timeout = setTimeout(function() { 
        Draggables._timeout = null; 
        window.focus(); 
        Draggables.activeDraggable = draggable; 
      }.bind(this), draggable.options.delay); 
    } else {
      window.focus(); // allows keypress events if window isn't currently focused, fails for Safari
      this.activeDraggable = draggable;
    }
  },
  
  deactivate: function() {
    this.activeDraggable = null;
  },
  
  updateDrag: function(event) {
    if(!this.activeDraggable) return;
    var pointer = [Event.pointerX(event), Event.pointerY(event)];
    // Mozilla-based browsers fire successive mousemove events with
    // the same coordinates, prevent needless redrawing (moz bug?)
    if(this._lastPointer && (this._lastPointer.inspect() == pointer.inspect())) return;
    this._lastPointer = pointer;
    
    this.activeDraggable.updateDrag(event, pointer);
  },
  
  endDrag: function(event) {
    if(this._timeout) { 
      clearTimeout(this._timeout); 
      this._timeout = null; 
    }
    if(!this.activeDraggable) return;
    this._lastPointer = null;
    this.activeDraggable.endDrag(event);
    this.activeDraggable = null;
  },
  
  keyPress: function(event) {
    if(this.activeDraggable)
      this.activeDraggable.keyPress(event);
  },
  
  addObserver: function(observer) {
    this.observers.push(observer);
    this._cacheObserverCallbacks();
  },
  
  removeObserver: function(element) {  // element instead of observer fixes mem leaks
    this.observers = this.observers.reject( function(o) { return o.element==element });
    this._cacheObserverCallbacks();
  },
  
  notify: function(eventName, draggable, event) {  // 'onStart', 'onEnd', 'onDrag'
    if(this[eventName+'Count'] > 0)
      this.observers.each( function(o) {
        if(o[eventName]) o[eventName](eventName, draggable, event);
      });
    if(draggable.options[eventName]) draggable.options[eventName](draggable, event);
  },
  
  _cacheObserverCallbacks: function() {
    ['onStart','onEnd','onDrag'].each( function(eventName) {
      Draggables[eventName+'Count'] = Draggables.observers.select(
        function(o) { return o[eventName]; }
      ).length;
    });
  }
}

/*--------------------------------------------------------------------------*/

var Draggable = Class.create({
  initialize: function(element) {
    var defaults = {
      handle: false,
      reverteffect: function(element, top_offset, left_offset) {
        var dur = Math.sqrt(Math.abs(top_offset^2)+Math.abs(left_offset^2))*0.02;
        new Effect.Move(element, { x: -left_offset, y: -top_offset, duration: dur,
          queue: {scope:'_draggable', position:'end'}
        });
      },
      endeffect: function(element) {
        var toOpacity = Object.isNumber(element._opacity) ? element._opacity : 1.0;
        new Effect.Opacity(element, {duration:0.2, from:0.7, to:toOpacity, 
          queue: {scope:'_draggable', position:'end'},
          afterFinish: function(){ 
            Draggable._dragging[element] = false 
          }
        }); 
      },
      zindex: 1000,
      revert: false,
      quiet: false,
      scroll: false,
      scrollSensitivity: 20,
      scrollSpeed: 15,
      snap: false,  // false, or xy or [x,y] or function(x,y){ return [x,y] }
      delay: 0
    };
    
    if(!arguments[1] || Object.isUndefined(arguments[1].endeffect))
      Object.extend(defaults, {
        starteffect: function(element) {
          element._opacity = Element.getOpacity(element);
          Draggable._dragging[element] = true;
          new Effect.Opacity(element, {duration:0.2, from:element._opacity, to:0.7}); 
        }
      });
    
    var options = Object.extend(defaults, arguments[1] || { });

    this.element = $(element);
    
    if(options.handle && Object.isString(options.handle))
      this.handle = this.element.down('.'+options.handle, 0);
    
    if(!this.handle) this.handle = $(options.handle);
    if(!this.handle) this.handle = this.element;
    
    if(options.scroll && !options.scroll.scrollTo && !options.scroll.outerHTML) {
      options.scroll = $(options.scroll);
      this._isScrollChild = Element.childOf(this.element, options.scroll);
    }

    Element.makePositioned(this.element); // fix IE    

    this.options  = options;
    this.dragging = false;   

    this.eventMouseDown = this.initDrag.bindAsEventListener(this);
    Event.observe(this.handle, "mousedown", this.eventMouseDown);
    
    Draggables.register(this);
  },
  
  destroy: function() {
    Event.stopObserving(this.handle, "mousedown", this.eventMouseDown);
    Draggables.unregister(this);
  },
  
  currentDelta: function() {
    return([
      parseInt(Element.getStyle(this.element,'left') || '0'),
      parseInt(Element.getStyle(this.element,'top') || '0')]);
  },
  
  initDrag: function(event) {
    if(!Object.isUndefined(Draggable._dragging[this.element]) &&
      Draggable._dragging[this.element]) return;
    if(Event.isLeftClick(event)) {    
      // abort on form elements, fixes a Firefox issue
      var src = Event.element(event);
      if((tag_name = src.tagName.toUpperCase()) && (
        tag_name=='INPUT' ||
        tag_name=='SELECT' ||
        tag_name=='OPTION' ||
        tag_name=='BUTTON' ||
        tag_name=='TEXTAREA')) return;
        
      var pointer = [Event.pointerX(event), Event.pointerY(event)];
      var pos     = Position.cumulativeOffset(this.element);
      this.offset = [0,1].map( function(i) { return (pointer[i] - pos[i]) });
      
      Draggables.activate(this);
      Event.stop(event);
    }
  },
  
  startDrag: function(event) {
    this.dragging = true;
    if(!this.delta)
      this.delta = this.currentDelta();
    
    if(this.options.zindex) {
      this.originalZ = parseInt(Element.getStyle(this.element,'z-index') || 0);
      this.element.style.zIndex = this.options.zindex;
    }
    
    if(this.options.ghosting) {
      this._clone = this.element.cloneNode(true);
      this.element._originallyAbsolute = (this.element.getStyle('position') == 'absolute');
      if (!this.element._originallyAbsolute)
        Position.absolutize(this.element);
      this.element.parentNode.insertBefore(this._clone, this.element);
    }
    
    if(this.options.scroll) {
      if (this.options.scroll == window) {
        var where = this._getWindowScroll(this.options.scroll);
        this.originalScrollLeft = where.left;
        this.originalScrollTop = where.top;
      } else {
        this.originalScrollLeft = this.options.scroll.scrollLeft;
        this.originalScrollTop = this.options.scroll.scrollTop;
      }
    }
    
    Draggables.notify('onStart', this, event);
        
    if(this.options.starteffect) this.options.starteffect(this.element);
  },
  
  updateDrag: function(event, pointer) {
    if(!this.dragging) this.startDrag(event);
    
    if(!this.options.quiet){
      Position.prepare();
      Droppables.show(pointer, this.element);
    }
    
    Draggables.notify('onDrag', this, event);
    
    this.draw(pointer);
    if(this.options.change) this.options.change(this);
    
    if(this.options.scroll) {
      this.stopScrolling();
      
      var p;
      if (this.options.scroll == window) {
        with(this._getWindowScroll(this.options.scroll)) { p = [ left, top, left+width, top+height ]; }
      } else {
        p = Position.page(this.options.scroll);
        p[0] += this.options.scroll.scrollLeft + Position.deltaX;
        p[1] += this.options.scroll.scrollTop + Position.deltaY;
        p.push(p[0]+this.options.scroll.offsetWidth);
        p.push(p[1]+this.options.scroll.offsetHeight);
      }
      var speed = [0,0];
      if(pointer[0] < (p[0]+this.options.scrollSensitivity)) speed[0] = pointer[0]-(p[0]+this.options.scrollSensitivity);
      if(pointer[1] < (p[1]+this.options.scrollSensitivity)) speed[1] = pointer[1]-(p[1]+this.options.scrollSensitivity);
      if(pointer[0] > (p[2]-this.options.scrollSensitivity)) speed[0] = pointer[0]-(p[2]-this.options.scrollSensitivity);
      if(pointer[1] > (p[3]-this.options.scrollSensitivity)) speed[1] = pointer[1]-(p[3]-this.options.scrollSensitivity);
      this.startScrolling(speed);
    }
    
    // fix AppleWebKit rendering
    if(Prototype.Browser.WebKit) window.scrollBy(0,0);
    
    Event.stop(event);
  },
  
  finishDrag: function(event, success) {
    this.dragging = false;
    
    if(this.options.quiet){
      Position.prepare();
      var pointer = [Event.pointerX(event), Event.pointerY(event)];
      Droppables.show(pointer, this.element);
    }

    if(this.options.ghosting) {
      if (!this.element._originallyAbsolute)
        Position.relativize(this.element);
      delete this.element._originallyAbsolute;
      Element.remove(this._clone);
      this._clone = null;
    }

    var dropped = false; 
    if(success) { 
      dropped = Droppables.fire(event, this.element); 
      if (!dropped) dropped = false; 
    }
    if(dropped && this.options.onDropped) this.options.onDropped(this.element);
    Draggables.notify('onEnd', this, event);

    var revert = this.options.revert;
    if(revert && Object.isFunction(revert)) revert = revert(this.element);
    
    var d = this.currentDelta();
    if(revert && this.options.reverteffect) {
      if (dropped == 0 || revert != 'failure')
        this.options.reverteffect(this.element,
          d[1]-this.delta[1], d[0]-this.delta[0]);
    } else {
      this.delta = d;
    }

    if(this.options.zindex)
      this.element.style.zIndex = this.originalZ;

    if(this.options.endeffect) 
      this.options.endeffect(this.element);
      
    Draggables.deactivate(this);
    Droppables.reset();
  },
  
  keyPress: function(event) {
    if(event.keyCode!=Event.KEY_ESC) return;
    this.finishDrag(event, false);
    Event.stop(event);
  },
  
  endDrag: function(event) {
    if(!this.dragging) return;
    this.stopScrolling();
    this.finishDrag(event, true);
    Event.stop(event);
  },
  
  draw: function(point) {
    var pos = Position.cumulativeOffset(this.element);
    if(this.options.ghosting) {
      var r   = Position.realOffset(this.element);
      pos[0] += r[0] - Position.deltaX; pos[1] += r[1] - Position.deltaY;
    }
    
    var d = this.currentDelta();
    pos[0] -= d[0]; pos[1] -= d[1];
    
    if(this.options.scroll && (this.options.scroll != window && this._isScrollChild)) {
      pos[0] -= this.options.scroll.scrollLeft-this.originalScrollLeft;
      pos[1] -= this.options.scroll.scrollTop-this.originalScrollTop;
    }
    
    var p = [0,1].map(function(i){ 
      return (point[i]-pos[i]-this.offset[i]) 
    }.bind(this));
    
    if(this.options.snap) {
      if(Object.isFunction(this.options.snap)) {
        p = this.options.snap(p[0],p[1],this);
      } else {
      if(Object.isArray(this.options.snap)) {
        p = p.map( function(v, i) {
          return (v/this.options.snap[i]).round()*this.options.snap[i] }.bind(this))
      } else {
        p = p.map( function(v) {
          return (v/this.options.snap).round()*this.options.snap }.bind(this))
      }
    }}
    
    var style = this.element.style;
    if((!this.options.constraint) || (this.options.constraint=='horizontal'))
      style.left = p[0] + "px";
    if((!this.options.constraint) || (this.options.constraint=='vertical'))
      style.top  = p[1] + "px";
    
    if(style.visibility=="hidden") style.visibility = ""; // fix gecko rendering
  },
  
  stopScrolling: function() {
    if(this.scrollInterval) {
      clearInterval(this.scrollInterval);
      this.scrollInterval = null;
      Draggables._lastScrollPointer = null;
    }
  },
  
  startScrolling: function(speed) {
    if(!(speed[0] || speed[1])) return;
    this.scrollSpeed = [speed[0]*this.options.scrollSpeed,speed[1]*this.options.scrollSpeed];
    this.lastScrolled = new Date();
    this.scrollInterval = setInterval(this.scroll.bind(this), 10);
  },
  
  scroll: function() {
    var current = new Date();
    var delta = current - this.lastScrolled;
    this.lastScrolled = current;
    if(this.options.scroll == window) {
      with (this._getWindowScroll(this.options.scroll)) {
        if (this.scrollSpeed[0] || this.scrollSpeed[1]) {
          var d = delta / 1000;
          this.options.scroll.scrollTo( left + d*this.scrollSpeed[0], top + d*this.scrollSpeed[1] );
        }
      }
    } else {
      this.options.scroll.scrollLeft += this.scrollSpeed[0] * delta / 1000;
      this.options.scroll.scrollTop  += this.scrollSpeed[1] * delta / 1000;
    }
    
    Position.prepare();
    Droppables.show(Draggables._lastPointer, this.element);
    Draggables.notify('onDrag', this);
    if (this._isScrollChild) {
      Draggables._lastScrollPointer = Draggables._lastScrollPointer || $A(Draggables._lastPointer);
      Draggables._lastScrollPointer[0] += this.scrollSpeed[0] * delta / 1000;
      Draggables._lastScrollPointer[1] += this.scrollSpeed[1] * delta / 1000;
      if (Draggables._lastScrollPointer[0] < 0)
        Draggables._lastScrollPointer[0] = 0;
      if (Draggables._lastScrollPointer[1] < 0)
        Draggables._lastScrollPointer[1] = 0;
      this.draw(Draggables._lastScrollPointer);
    }
    
    if(this.options.change) this.options.change(this);
  },
  
  _getWindowScroll: function(w) {
    var T, L, W, H;
    with (w.document) {
      if (w.document.documentElement && documentElement.scrollTop) {
        T = documentElement.scrollTop;
        L = documentElement.scrollLeft;
      } else if (w.document.body) {
        T = body.scrollTop;
        L = body.scrollLeft;
      }
      if (w.innerWidth) {
        W = w.innerWidth;
        H = w.innerHeight;
      } else if (w.document.documentElement && documentElement.clientWidth) {
        W = documentElement.clientWidth;
        H = documentElement.clientHeight;
      } else {
        W = body.offsetWidth;
        H = body.offsetHeight
      }
    }
    return { top: T, left: L, width: W, height: H };
  }
});

Draggable._dragging = { };

/*--------------------------------------------------------------------------*/

var SortableObserver = Class.create({
  initialize: function(element, observer) {
    this.element   = $(element);
    this.observer  = observer;
    this.lastValue = Sortable.serialize(this.element);
  },
  
  onStart: function() {
    this.lastValue = Sortable.serialize(this.element);
  },
  
  onEnd: function() {
    Sortable.unmark();
    if(this.lastValue != Sortable.serialize(this.element))
      this.observer(this.element)
  }
});

var Sortable = {
  SERIALIZE_RULE: /^[^_\-](?:[A-Za-z0-9\-\_]*)[_](.*)$/,
  
  sortables: { },
  
  _findRootElement: function(element) {
    while (element.tagName.toUpperCase() != "BODY") {  
      if(element.id && Sortable.sortables[element.id]) return element;
      element = element.parentNode;
    }
  },

  options: function(element) {
    element = Sortable._findRootElement($(element));
    if(!element) return;
    return Sortable.sortables[element.id];
  },
  
  destroy: function(element){
    var s = Sortable.options(element);
    
    if(s) {
      Draggables.removeObserver(s.element);
      s.droppables.each(function(d){ Droppables.remove(d) });
      s.draggables.invoke('destroy');
      
      delete Sortable.sortables[s.element.id];
    }
  },

  create: function(element) {
    element = $(element);
    var options = Object.extend({ 
      element:     element,
      tag:         'li',       // assumes li children, override with tag: 'tagname'
      dropOnEmpty: false,
      tree:        false,
      treeTag:     'ul',
      overlap:     'vertical', // one of 'vertical', 'horizontal'
      constraint:  'vertical', // one of 'vertical', 'horizontal', false
      containment: element,    // also takes array of elements (or id's); or false
      handle:      false,      // or a CSS class
      only:        false,
      delay:       0,
      hoverclass:  null,
      ghosting:    false,
      quiet:       false, 
      scroll:      false,
      scrollSensitivity: 20,
      scrollSpeed: 15,
      format:      this.SERIALIZE_RULE,
      
      // these take arrays of elements or ids and can be 
      // used for better initialization performance
      elements:    false,
      handles:     false,
      
      onChange:    Prototype.emptyFunction,
      onUpdate:    Prototype.emptyFunction
    }, arguments[1] || { });

    // clear any old sortable with same element
    this.destroy(element);

    // build options for the draggables
    var options_for_draggable = {
      revert:      true,
      quiet:       options.quiet,
      scroll:      options.scroll,
      scrollSpeed: options.scrollSpeed,
      scrollSensitivity: options.scrollSensitivity,
      delay:       options.delay,
      ghosting:    options.ghosting,
      constraint:  options.constraint,
      handle:      options.handle };

    if(options.starteffect)
      options_for_draggable.starteffect = options.starteffect;

    if(options.reverteffect)
      options_for_draggable.reverteffect = options.reverteffect;
    else
      if(options.ghosting) options_for_draggable.reverteffect = function(element) {
        element.style.top  = 0;
        element.style.left = 0;
      };

    if(options.endeffect)
      options_for_draggable.endeffect = options.endeffect;

    if(options.zindex)
      options_for_draggable.zindex = options.zindex;

    // build options for the droppables  
    var options_for_droppable = {
      overlap:     options.overlap,
      containment: options.containment,
      tree:        options.tree,
      hoverclass:  options.hoverclass,
      onHover:     Sortable.onHover
    }
    
    var options_for_tree = {
      onHover:      Sortable.onEmptyHover,
      overlap:      options.overlap,
      containment:  options.containment,
      hoverclass:   options.hoverclass
    }

    // fix for gecko engine
    Element.cleanWhitespace(element); 

    options.draggables = [];
    options.droppables = [];

    // drop on empty handling
    if(options.dropOnEmpty || options.tree) {
      Droppables.add(element, options_for_tree);
      options.droppables.push(element);
    }

    (options.elements || this.findElements(element, options) || []).each( function(e,i) {
      var handle = options.handles ? $(options.handles[i]) :
        (options.handle ? $(e).select('.' + options.handle)[0] : e); 
      options.draggables.push(
        new Draggable(e, Object.extend(options_for_draggable, { handle: handle })));
      Droppables.add(e, options_for_droppable);
      if(options.tree) e.treeNode = element;
      options.droppables.push(e);      
    });
    
    if(options.tree) {
      (Sortable.findTreeElements(element, options) || []).each( function(e) {
        Droppables.add(e, options_for_tree);
        e.treeNode = element;
        options.droppables.push(e);
      });
    }

    // keep reference
    this.sortables[element.id] = options;

    // for onupdate
    Draggables.addObserver(new SortableObserver(element, options.onUpdate));

  },

  // return all suitable-for-sortable elements in a guaranteed order
  findElements: function(element, options) {
    return Element.findChildren(
      element, options.only, options.tree ? true : false, options.tag);
  },
  
  findTreeElements: function(element, options) {
    return Element.findChildren(
      element, options.only, options.tree ? true : false, options.treeTag);
  },

  onHover: function(element, dropon, overlap) {
    if(Element.isParent(dropon, element)) return;

    if(overlap > .33 && overlap < .66 && Sortable.options(dropon).tree) {
      return;
    } else if(overlap>0.5) {
      Sortable.mark(dropon, 'before');
      if(dropon.previousSibling != element) {
        var oldParentNode = element.parentNode;
        element.style.visibility = "hidden"; // fix gecko rendering
        dropon.parentNode.insertBefore(element, dropon);
        if(dropon.parentNode!=oldParentNode) 
          Sortable.options(oldParentNode).onChange(element);
        Sortable.options(dropon.parentNode).onChange(element);
      }
    } else {
      Sortable.mark(dropon, 'after');
      var nextElement = dropon.nextSibling || null;
      if(nextElement != element) {
        var oldParentNode = element.parentNode;
        element.style.visibility = "hidden"; // fix gecko rendering
        dropon.parentNode.insertBefore(element, nextElement);
        if(dropon.parentNode!=oldParentNode) 
          Sortable.options(oldParentNode).onChange(element);
        Sortable.options(dropon.parentNode).onChange(element);
      }
    }
  },
  
  onEmptyHover: function(element, dropon, overlap) {
    var oldParentNode = element.parentNode;
    var droponOptions = Sortable.options(dropon);
        
    if(!Element.isParent(dropon, element)) {
      var index;
      
      var children = Sortable.findElements(dropon, {tag: droponOptions.tag, only: droponOptions.only});
      var child = null;
            
      if(children) {
        var offset = Element.offsetSize(dropon, droponOptions.overlap) * (1.0 - overlap);
        
        for (index = 0; index < children.length; index += 1) {
          if (offset - Element.offsetSize (children[index], droponOptions.overlap) >= 0) {
            offset -= Element.offsetSize (children[index], droponOptions.overlap);
          } else if (offset - (Element.offsetSize (children[index], droponOptions.overlap) / 2) >= 0) {
            child = index + 1 < children.length ? children[index + 1] : null;
            break;
          } else {
            child = children[index];
            break;
          }
        }
      }
      
      dropon.insertBefore(element, child);
      
      Sortable.options(oldParentNode).onChange(element);
      droponOptions.onChange(element);
    }
  },

  unmark: function() {
    if(Sortable._marker) Sortable._marker.hide();
  },

  mark: function(dropon, position) {
    // mark on ghosting only
    var sortable = Sortable.options(dropon.parentNode);
    if(sortable && !sortable.ghosting) return; 

    if(!Sortable._marker) {
      Sortable._marker = 
        ($('dropmarker') || Element.extend(document.createElement('DIV'))).
          hide().addClassName('dropmarker').setStyle({position:'absolute'});
      document.getElementsByTagName("body").item(0).appendChild(Sortable._marker);
    }    
    var offsets = Position.cumulativeOffset(dropon);
    Sortable._marker.setStyle({left: offsets[0]+'px', top: offsets[1] + 'px'});
    
    if(position=='after')
      if(sortable.overlap == 'horizontal') 
        Sortable._marker.setStyle({left: (offsets[0]+dropon.clientWidth) + 'px'});
      else
        Sortable._marker.setStyle({top: (offsets[1]+dropon.clientHeight) + 'px'});
    
    Sortable._marker.show();
  },
  
  _tree: function(element, options, parent) {
    var children = Sortable.findElements(element, options) || [];
  
    for (var i = 0; i < children.length; ++i) {
      var match = children[i].id.match(options.format);

      if (!match) continue;
      
      var child = {
        id: encodeURIComponent(match ? match[1] : null),
        element: element,
        parent: parent,
        children: [],
        position: parent.children.length,
        container: $(children[i]).down(options.treeTag)
      }
      
      /* Get the element containing the children and recurse over it */
      if (child.container)
        this._tree(child.container, options, child)
      
      parent.children.push (child);
    }

    return parent; 
  },

  tree: function(element) {
    element = $(element);
    var sortableOptions = this.options(element);
    var options = Object.extend({
      tag: sortableOptions.tag,
      treeTag: sortableOptions.treeTag,
      only: sortableOptions.only,
      name: element.id,
      format: sortableOptions.format
    }, arguments[1] || { });
    
    var root = {
      id: null,
      parent: null,
      children: [],
      container: element,
      position: 0
    }
    
    return Sortable._tree(element, options, root);
  },

  /* Construct a [i] index for a particular node */
  _constructIndex: function(node) {
    var index = '';
    do {
      if (node.id) index = '[' + node.position + ']' + index;
    } while ((node = node.parent) != null);
    return index;
  },

  sequence: function(element) {
    element = $(element);
    var options = Object.extend(this.options(element), arguments[1] || { });
    
    return $(this.findElements(element, options) || []).map( function(item) {
      return item.id.match(options.format) ? item.id.match(options.format)[1] : '';
    });
  },

  setSequence: function(element, new_sequence) {
    element = $(element);
    var options = Object.extend(this.options(element), arguments[2] || { });
    
    var nodeMap = { };
    this.findElements(element, options).each( function(n) {
        if (n.id.match(options.format))
            nodeMap[n.id.match(options.format)[1]] = [n, n.parentNode];
        n.parentNode.removeChild(n);
    });
   
    new_sequence.each(function(ident) {
      var n = nodeMap[ident];
      if (n) {
        n[1].appendChild(n[0]);
        delete nodeMap[ident];
      }
    });
  },
  
  serialize: function(element) {
    element = $(element);
    var options = Object.extend(Sortable.options(element), arguments[1] || { });
    var name = encodeURIComponent(
      (arguments[1] && arguments[1].name) ? arguments[1].name : element.id);
    
    if (options.tree) {
      return Sortable.tree(element, arguments[1]).children.map( function (item) {
        return [name + Sortable._constructIndex(item) + "[id]=" + 
                encodeURIComponent(item.id)].concat(item.children.map(arguments.callee));
      }).flatten().join('&');
    } else {
      return Sortable.sequence(element, arguments[1]).map( function(item) {
        return name + "[]=" + encodeURIComponent(item);
      }).join('&');
    }
  }
}

// Returns true if child is contained within element
Element.isParent = function(child, element) {
  if (!child.parentNode || child == element) return false;
  if (child.parentNode == element) return true;
  return Element.isParent(child.parentNode, element);
}

Element.findChildren = function(element, only, recursive, tagName) {   
  if(!element.hasChildNodes()) return null;
  tagName = tagName.toUpperCase();
  if(only) only = [only].flatten();
  var elements = [];
  $A(element.childNodes).each( function(e) {
    if(e.tagName && e.tagName.toUpperCase()==tagName &&
      (!only || (Element.classNames(e).detect(function(v) { return only.include(v) }))))
        elements.push(e);
    if(recursive) {
      var grandchildren = Element.findChildren(e, only, recursive, tagName);
      if(grandchildren) elements.push(grandchildren);
    }
  });

  return (elements.length>0 ? elements.flatten() : []);
}

Element.offsetSize = function (element, type) {
  return element['offset' + ((type=='vertical' || type=='height') ? 'Height' : 'Width')];
}


/* --- End /home/httpd/app_frame/webroot/js/dragdrop.js --- */
/* --- Start /home/httpd/app_frame/webroot/js/unittest.js --- */

// script.aculo.us unittest.js v1.8.0, Tue Nov 06 15:01:40 +0300 2007

// Copyright (c) 2005-2007 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
//           (c) 2005-2007 Jon Tirsen (http://www.tirsen.com)
//           (c) 2005-2007 Michael Schuerig (http://www.schuerig.de/michael/)
//
// script.aculo.us is freely distributable under the terms of an MIT-style license.
// For details, see the script.aculo.us web site: http://script.aculo.us/

// experimental, Firefox-only
Event.simulateMouse = function(element, eventName) {
  var options = Object.extend({
    pointerX: 0,
    pointerY: 0,
    buttons:  0,
    ctrlKey:  false,
    altKey:   false,
    shiftKey: false,
    metaKey:  false
  }, arguments[2] || {});
  var oEvent = document.createEvent("MouseEvents");
  oEvent.initMouseEvent(eventName, true, true, document.defaultView, 
    options.buttons, options.pointerX, options.pointerY, options.pointerX, options.pointerY, 
    options.ctrlKey, options.altKey, options.shiftKey, options.metaKey, 0, $(element));
  
  if(this.mark) Element.remove(this.mark);
  this.mark = document.createElement('div');
  this.mark.appendChild(document.createTextNode(" "));
  document.body.appendChild(this.mark);
  this.mark.style.position = 'absolute';
  this.mark.style.top = options.pointerY + "px";
  this.mark.style.left = options.pointerX + "px";
  this.mark.style.width = "5px";
  this.mark.style.height = "5px;";
  this.mark.style.borderTop = "1px solid red;"
  this.mark.style.borderLeft = "1px solid red;"
  
  if(this.step)
    alert('['+new Date().getTime().toString()+'] '+eventName+'/'+Test.Unit.inspect(options));
  
  $(element).dispatchEvent(oEvent);
};

// Note: Due to a fix in Firefox 1.0.5/6 that probably fixed "too much", this doesn't work in 1.0.6 or DP2.
// You need to downgrade to 1.0.4 for now to get this working
// See https://bugzilla.mozilla.org/show_bug.cgi?id=289940 for the fix that fixed too much
Event.simulateKey = function(element, eventName) {
  var options = Object.extend({
    ctrlKey: false,
    altKey: false,
    shiftKey: false,
    metaKey: false,
    keyCode: 0,
    charCode: 0
  }, arguments[2] || {});

  var oEvent = document.createEvent("KeyEvents");
  oEvent.initKeyEvent(eventName, true, true, window, 
    options.ctrlKey, options.altKey, options.shiftKey, options.metaKey,
    options.keyCode, options.charCode );
  $(element).dispatchEvent(oEvent);
};

Event.simulateKeys = function(element, command) {
  for(var i=0; i<command.length; i++) {
    Event.simulateKey(element,'keypress',{charCode:command.charCodeAt(i)});
  }
};

var Test = {}
Test.Unit = {};

// security exception workaround
Test.Unit.inspect = Object.inspect;

Test.Unit.Logger = Class.create();
Test.Unit.Logger.prototype = {
  initialize: function(log) {
    this.log = $(log);
    if (this.log) {
      this._createLogTable();
    }
  },
  start: function(testName) {
    if (!this.log) return;
    this.testName = testName;
    this.lastLogLine = document.createElement('tr');
    this.statusCell = document.createElement('td');
    this.nameCell = document.createElement('td');
    this.nameCell.className = "nameCell";
    this.nameCell.appendChild(document.createTextNode(testName));
    this.messageCell = document.createElement('td');
    this.lastLogLine.appendChild(this.statusCell);
    this.lastLogLine.appendChild(this.nameCell);
    this.lastLogLine.appendChild(this.messageCell);
    this.loglines.appendChild(this.lastLogLine);
  },
  finish: function(status, summary) {
    if (!this.log) return;
    this.lastLogLine.className = status;
    this.statusCell.innerHTML = status;
    this.messageCell.innerHTML = this._toHTML(summary);
    this.addLinksToResults();
  },
  message: function(message) {
    if (!this.log) return;
    this.messageCell.innerHTML = this._toHTML(message);
  },
  summary: function(summary) {
    if (!this.log) return;
    this.logsummary.innerHTML = this._toHTML(summary);
  },
  _createLogTable: function() {
    this.log.innerHTML =
    '<div id="logsummary"></div>' +
    '<table id="logtable">' +
    '<thead><tr><th>Status</th><th>Test</th><th>Message</th></tr></thead>' +
    '<tbody id="loglines"></tbody>' +
    '</table>';
    this.logsummary = $('logsummary')
    this.loglines = $('loglines');
  },
  _toHTML: function(txt) {
    return txt.escapeHTML().replace(/\n/g,"<br/>");
  },
  addLinksToResults: function(){ 
    $$("tr.failed .nameCell").each( function(td){ // todo: limit to children of this.log
      td.title = "Run only this test"
      Event.observe(td, 'click', function(){ window.location.search = "?tests=" + td.innerHTML;});
    });
    $$("tr.passed .nameCell").each( function(td){ // todo: limit to children of this.log
      td.title = "Run all tests"
      Event.observe(td, 'click', function(){ window.location.search = "";});
    });
  }
}

Test.Unit.Runner = Class.create();
Test.Unit.Runner.prototype = {
  initialize: function(testcases) {
    this.options = Object.extend({
      testLog: 'testlog'
    }, arguments[1] || {});
    this.options.resultsURL = this.parseResultsURLQueryParameter();
    this.options.tests      = this.parseTestsQueryParameter();
    if (this.options.testLog) {
      this.options.testLog = $(this.options.testLog) || null;
    }
    if(this.options.tests) {
      this.tests = [];
      for(var i = 0; i < this.options.tests.length; i++) {
        if(/^test/.test(this.options.tests[i])) {
          this.tests.push(new Test.Unit.Testcase(this.options.tests[i], testcases[this.options.tests[i]], testcases["setup"], testcases["teardown"]));
        }
      }
    } else {
      if (this.options.test) {
        this.tests = [new Test.Unit.Testcase(this.options.test, testcases[this.options.test], testcases["setup"], testcases["teardown"])];
      } else {
        this.tests = [];
        for(var testcase in testcases) {
          if(/^test/.test(testcase)) {
            this.tests.push(
               new Test.Unit.Testcase(
                 this.options.context ? ' -> ' + this.options.titles[testcase] : testcase, 
                 testcases[testcase], testcases["setup"], testcases["teardown"]
               ));
          }
        }
      }
    }
    this.currentTest = 0;
    this.logger = new Test.Unit.Logger(this.options.testLog);
    setTimeout(this.runTests.bind(this), 1000);
  },
  parseResultsURLQueryParameter: function() {
    return window.location.search.parseQuery()["resultsURL"];
  },
  parseTestsQueryParameter: function(){
    if (window.location.search.parseQuery()["tests"]){
        return window.location.search.parseQuery()["tests"].split(',');
    };
  },
  // Returns:
  //  "ERROR" if there was an error,
  //  "FAILURE" if there was a failure, or
  //  "SUCCESS" if there was neither
  getResult: function() {
    var hasFailure = false;
    for(var i=0;i<this.tests.length;i++) {
      if (this.tests[i].errors > 0) {
        return "ERROR";
      }
      if (this.tests[i].failures > 0) {
        hasFailure = true;
      }
    }
    if (hasFailure) {
      return "FAILURE";
    } else {
      return "SUCCESS";
    }
  },
  postResults: function() {
    if (this.options.resultsURL) {
      new Ajax.Request(this.options.resultsURL, 
        { method: 'get', parameters: 'result=' + this.getResult(), asynchronous: false });
    }
  },
  runTests: function() {
    var test = this.tests[this.currentTest];
    if (!test) {
      // finished!
      this.postResults();
      this.logger.summary(this.summary());
      return;
    }
    if(!test.isWaiting) {
      this.logger.start(test.name);
    }
    test.run();
    if(test.isWaiting) {
      this.logger.message("Waiting for " + test.timeToWait + "ms");
      setTimeout(this.runTests.bind(this), test.timeToWait || 1000);
    } else {
      this.logger.finish(test.status(), test.summary());
      this.currentTest++;
      // tail recursive, hopefully the browser will skip the stackframe
      this.runTests();
    }
  },
  summary: function() {
    var assertions = 0;
    var failures = 0;
    var errors = 0;
    var messages = [];
    for(var i=0;i<this.tests.length;i++) {
      assertions +=   this.tests[i].assertions;
      failures   +=   this.tests[i].failures;
      errors     +=   this.tests[i].errors;
    }
    return (
      (this.options.context ? this.options.context + ': ': '') + 
      this.tests.length + " tests, " + 
      assertions + " assertions, " + 
      failures   + " failures, " +
      errors     + " errors");
  }
}

Test.Unit.Assertions = Class.create();
Test.Unit.Assertions.prototype = {
  initialize: function() {
    this.assertions = 0;
    this.failures   = 0;
    this.errors     = 0;
    this.messages   = [];
  },
  summary: function() {
    return (
      this.assertions + " assertions, " + 
      this.failures   + " failures, " +
      this.errors     + " errors" + "\n" +
      this.messages.join("\n"));
  },
  pass: function() {
    this.assertions++;
  },
  fail: function(message) {
    this.failures++;
    this.messages.push("Failure: " + message);
  },
  info: function(message) {
    this.messages.push("Info: " + message);
  },
  error: function(error) {
    this.errors++;
    this.messages.push(error.name + ": "+ error.message + "(" + Test.Unit.inspect(error) +")");
  },
  status: function() {
    if (this.failures > 0) return 'failed';
    if (this.errors > 0) return 'error';
    return 'passed';
  },
  assert: function(expression) {
    var message = arguments[1] || 'assert: got "' + Test.Unit.inspect(expression) + '"';
    try { expression ? this.pass() : 
      this.fail(message); }
    catch(e) { this.error(e); }
  },
  assertEqual: function(expected, actual) {
    var message = arguments[2] || "assertEqual";
    try { (expected == actual) ? this.pass() :
      this.fail(message + ': expected "' + Test.Unit.inspect(expected) + 
        '", actual "' + Test.Unit.inspect(actual) + '"'); }
    catch(e) { this.error(e); }
  },
  assertInspect: function(expected, actual) {
    var message = arguments[2] || "assertInspect";
    try { (expected == actual.inspect()) ? this.pass() :
      this.fail(message + ': expected "' + Test.Unit.inspect(expected) + 
        '", actual "' + Test.Unit.inspect(actual) + '"'); }
    catch(e) { this.error(e); }
  },
  assertEnumEqual: function(expected, actual) {
    var message = arguments[2] || "assertEnumEqual";
    try { $A(expected).length == $A(actual).length && 
      expected.zip(actual).all(function(pair) { return pair[0] == pair[1] }) ?
        this.pass() : this.fail(message + ': expected ' + Test.Unit.inspect(expected) + 
          ', actual ' + Test.Unit.inspect(actual)); }
    catch(e) { this.error(e); }
  },
  assertNotEqual: function(expected, actual) {
    var message = arguments[2] || "assertNotEqual";
    try { (expected != actual) ? this.pass() : 
      this.fail(message + ': got "' + Test.Unit.inspect(actual) + '"'); }
    catch(e) { this.error(e); }
  },
  assertIdentical: function(expected, actual) { 
    var message = arguments[2] || "assertIdentical"; 
    try { (expected === actual) ? this.pass() : 
      this.fail(message + ': expected "' + Test.Unit.inspect(expected) +  
        '", actual "' + Test.Unit.inspect(actual) + '"'); } 
    catch(e) { this.error(e); } 
  },
  assertNotIdentical: function(expected, actual) { 
    var message = arguments[2] || "assertNotIdentical"; 
    try { !(expected === actual) ? this.pass() : 
      this.fail(message + ': expected "' + Test.Unit.inspect(expected) +  
        '", actual "' + Test.Unit.inspect(actual) + '"'); } 
    catch(e) { this.error(e); } 
  },
  assertNull: function(obj) {
    var message = arguments[1] || 'assertNull'
    try { (obj==null) ? this.pass() : 
      this.fail(message + ': got "' + Test.Unit.inspect(obj) + '"'); }
    catch(e) { this.error(e); }
  },
  assertMatch: function(expected, actual) {
    var message = arguments[2] || 'assertMatch';
    var regex = new RegExp(expected);
    try { (regex.exec(actual)) ? this.pass() :
      this.fail(message + ' : regex: "' +  Test.Unit.inspect(expected) + ' did not match: ' + Test.Unit.inspect(actual) + '"'); }
    catch(e) { this.error(e); }
  },
  assertHidden: function(element) {
    var message = arguments[1] || 'assertHidden';
    this.assertEqual("none", element.style.display, message);
  },
  assertNotNull: function(object) {
    var message = arguments[1] || 'assertNotNull';
    this.assert(object != null, message);
  },
  assertType: function(expected, actual) {
    var message = arguments[2] || 'assertType';
    try { 
      (actual.constructor == expected) ? this.pass() : 
      this.fail(message + ': expected "' + Test.Unit.inspect(expected) +  
        '", actual "' + (actual.constructor) + '"'); }
    catch(e) { this.error(e); }
  },
  assertNotOfType: function(expected, actual) {
    var message = arguments[2] || 'assertNotOfType';
    try { 
      (actual.constructor != expected) ? this.pass() : 
      this.fail(message + ': expected "' + Test.Unit.inspect(expected) +  
        '", actual "' + (actual.constructor) + '"'); }
    catch(e) { this.error(e); }
  },
  assertInstanceOf: function(expected, actual) {
    var message = arguments[2] || 'assertInstanceOf';
    try { 
      (actual instanceof expected) ? this.pass() : 
      this.fail(message + ": object was not an instance of the expected type"); }
    catch(e) { this.error(e); } 
  },
  assertNotInstanceOf: function(expected, actual) {
    var message = arguments[2] || 'assertNotInstanceOf';
    try { 
      !(actual instanceof expected) ? this.pass() : 
      this.fail(message + ": object was an instance of the not expected type"); }
    catch(e) { this.error(e); } 
  },
  assertRespondsTo: function(method, obj) {
    var message = arguments[2] || 'assertRespondsTo';
    try {
      (obj[method] && typeof obj[method] == 'function') ? this.pass() : 
      this.fail(message + ": object doesn't respond to [" + method + "]"); }
    catch(e) { this.error(e); }
  },
  assertReturnsTrue: function(method, obj) {
    var message = arguments[2] || 'assertReturnsTrue';
    try {
      var m = obj[method];
      if(!m) m = obj['is'+method.charAt(0).toUpperCase()+method.slice(1)];
      m() ? this.pass() : 
      this.fail(message + ": method returned false"); }
    catch(e) { this.error(e); }
  },
  assertReturnsFalse: function(method, obj) {
    var message = arguments[2] || 'assertReturnsFalse';
    try {
      var m = obj[method];
      if(!m) m = obj['is'+method.charAt(0).toUpperCase()+method.slice(1)];
      !m() ? this.pass() : 
      this.fail(message + ": method returned true"); }
    catch(e) { this.error(e); }
  },
  assertRaise: function(exceptionName, method) {
    var message = arguments[2] || 'assertRaise';
    try { 
      method();
      this.fail(message + ": exception expected but none was raised"); }
    catch(e) {
      ((exceptionName == null) || (e.name==exceptionName)) ? this.pass() : this.error(e); 
    }
  },
  assertElementsMatch: function() {
    var expressions = $A(arguments), elements = $A(expressions.shift());
    if (elements.length != expressions.length) {
      this.fail('assertElementsMatch: size mismatch: ' + elements.length + ' elements, ' + expressions.length + ' expressions');
      return false;
    }
    elements.zip(expressions).all(function(pair, index) {
      var element = $(pair.first()), expression = pair.last();
      if (element.match(expression)) return true;
      this.fail('assertElementsMatch: (in index ' + index + ') expected ' + expression.inspect() + ' but got ' + element.inspect());
    }.bind(this)) && this.pass();
  },
  assertElementMatches: function(element, expression) {
    this.assertElementsMatch([element], expression);
  },
  benchmark: function(operation, iterations) {
    var startAt = new Date();
    (iterations || 1).times(operation);
    var timeTaken = ((new Date())-startAt);
    this.info((arguments[2] || 'Operation') + ' finished ' + 
       iterations + ' iterations in ' + (timeTaken/1000)+'s' );
    return timeTaken;
  },
  _isVisible: function(element) {
    element = $(element);
    if(!element.parentNode) return true;
    this.assertNotNull(element);
    if(element.style && Element.getStyle(element, 'display') == 'none')
      return false;
    
    return this._isVisible(element.parentNode);
  },
  assertNotVisible: function(element) {
    this.assert(!this._isVisible(element), Test.Unit.inspect(element) + " was not hidden and didn't have a hidden parent either. " + ("" || arguments[1]));
  },
  assertVisible: function(element) {
    this.assert(this._isVisible(element), Test.Unit.inspect(element) + " was not visible. " + ("" || arguments[1]));
  },
  benchmark: function(operation, iterations) {
    var startAt = new Date();
    (iterations || 1).times(operation);
    var timeTaken = ((new Date())-startAt);
    this.info((arguments[2] || 'Operation') + ' finished ' + 
       iterations + ' iterations in ' + (timeTaken/1000)+'s' );
    return timeTaken;
  }
}

Test.Unit.Testcase = Class.create();
Object.extend(Object.extend(Test.Unit.Testcase.prototype, Test.Unit.Assertions.prototype), {
  initialize: function(name, test, setup, teardown) {
    Test.Unit.Assertions.prototype.initialize.bind(this)();
    this.name           = name;
    
    if(typeof test == 'string') {
      test = test.gsub(/(\.should[^\(]+\()/,'#{0}this,');
      test = test.gsub(/(\.should[^\(]+)\(this,\)/,'#{1}(this)');
      this.test = function() {
        eval('with(this){'+test+'}');
      }
    } else {
      this.test = test || function() {};
    }
    
    this.setup          = setup || function() {};
    this.teardown       = teardown || function() {};
    this.isWaiting      = false;
    this.timeToWait     = 1000;
  },
  wait: function(time, nextPart) {
    this.isWaiting = true;
    this.test = nextPart;
    this.timeToWait = time;
  },
  run: function() {
    try {
      try {
        if (!this.isWaiting) this.setup.bind(this)();
        this.isWaiting = false;
        this.test.bind(this)();
      } finally {
        if(!this.isWaiting) {
          this.teardown.bind(this)();
        }
      }
    }
    catch(e) { this.error(e); }
  }
});

// *EXPERIMENTAL* BDD-style testing to please non-technical folk
// This draws many ideas from RSpec http://rspec.rubyforge.org/

Test.setupBDDExtensionMethods = function(){
  var METHODMAP = {
    shouldEqual:     'assertEqual',
    shouldNotEqual:  'assertNotEqual',
    shouldEqualEnum: 'assertEnumEqual',
    shouldBeA:       'assertType',
    shouldNotBeA:    'assertNotOfType',
    shouldBeAn:      'assertType',
    shouldNotBeAn:   'assertNotOfType',
    shouldBeNull:    'assertNull',
    shouldNotBeNull: 'assertNotNull',
    
    shouldBe:        'assertReturnsTrue',
    shouldNotBe:     'assertReturnsFalse',
    shouldRespondTo: 'assertRespondsTo'
  };
  var makeAssertion = function(assertion, args, object) { 
   	this[assertion].apply(this,(args || []).concat([object]));
  }
  
  Test.BDDMethods = {};   
  $H(METHODMAP).each(function(pair) { 
    Test.BDDMethods[pair.key] = function() { 
       var args = $A(arguments); 
       var scope = args.shift(); 
       makeAssertion.apply(scope, [pair.value, args, this]); }; 
  });
  
  [Array.prototype, String.prototype, Number.prototype, Boolean.prototype].each(
    function(p){ Object.extend(p, Test.BDDMethods) }
  );
}

Test.context = function(name, spec, log){
  Test.setupBDDExtensionMethods();
  
  var compiledSpec = {};
  var titles = {};
  for(specName in spec) {
    switch(specName){
      case "setup":
      case "teardown":
        compiledSpec[specName] = spec[specName];
        break;
      default:
        var testName = 'test'+specName.gsub(/\s+/,'-').camelize();
        var body = spec[specName].toString().split('\n').slice(1);
        if(/^\{/.test(body[0])) body = body.slice(1);
        body.pop();
        body = body.map(function(statement){ 
          return statement.strip()
        });
        compiledSpec[testName] = body.join('\n');
        titles[testName] = specName;
    }
  }
  new Test.Unit.Runner(compiledSpec, { titles: titles, testLog: log || 'testlog', context: name });
};

/* --- End /home/httpd/app_frame/webroot/js/unittest.js --- */
/* --- Start /home/httpd/app_frame/webroot/js/controls.js --- */

// script.aculo.us controls.js v1.8.0, Tue Nov 06 15:01:40 +0300 2007

// Copyright (c) 2005-2007 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
//           (c) 2005-2007 Ivan Krstic (http://blogs.law.harvard.edu/ivan)
//           (c) 2005-2007 Jon Tirsen (http://www.tirsen.com)
// Contributors:
//  Richard Livsey
//  Rahul Bhargava
//  Rob Wills
// 
// script.aculo.us is freely distributable under the terms of an MIT-style license.
// For details, see the script.aculo.us web site: http://script.aculo.us/

// Autocompleter.Base handles all the autocompletion functionality 
// that's independent of the data source for autocompletion. This
// includes drawing the autocompletion menu, observing keyboard
// and mouse events, and similar.
//
// Specific autocompleters need to provide, at the very least, 
// a getUpdatedChoices function that will be invoked every time
// the text inside the monitored textbox changes. This method 
// should get the text for which to provide autocompletion by
// invoking this.getToken(), NOT by directly accessing
// this.element.value. This is to allow incremental tokenized
// autocompletion. Specific auto-completion logic (AJAX, etc)
// belongs in getUpdatedChoices.
//
// Tokenized incremental autocompletion is enabled automatically
// when an autocompleter is instantiated with the 'tokens' option
// in the options parameter, e.g.:
// new Ajax.Autocompleter('id','upd', '/url/', { tokens: ',' });
// will incrementally autocomplete with a comma as the token.
// Additionally, ',' in the above example can be replaced with
// a token array, e.g. { tokens: [',', '\n'] } which
// enables autocompletion on multiple tokens. This is most 
// useful when one of the tokens is \n (a newline), as it 
// allows smart autocompletion after linebreaks.

if(typeof Effect == 'undefined')
  throw("controls.js requires including script.aculo.us' effects.js library");

var Autocompleter = { }
Autocompleter.Base = Class.create({
  baseInitialize: function(element, update, options) {
    element          = $(element)
    this.element     = element; 
    this.update      = $(update);  
    this.hasFocus    = false; 
    this.changed     = false; 
    this.active      = false; 
    this.index       = 0;     
    this.entryCount  = 0;
    this.oldElementValue = this.element.value;

    if(this.setOptions)
      this.setOptions(options);
    else
      this.options = options || { };

    this.options.paramName    = this.options.paramName || this.element.name;
    this.options.tokens       = this.options.tokens || [];
    this.options.frequency    = this.options.frequency || 0.4;
    this.options.minChars     = this.options.minChars || 1;
    this.options.onShow       = this.options.onShow || 
      function(element, update){ 
        if(!update.style.position || update.style.position=='absolute') {
          update.style.position = 'absolute';
          Position.clone(element, update, {
            setHeight: false, 
            offsetTop: element.offsetHeight
          });
        }
        Effect.Appear(update,{duration:0.15});
      };
    this.options.onHide = this.options.onHide || 
      function(element, update){ new Effect.Fade(update,{duration:0.15}) };

    if(typeof(this.options.tokens) == 'string') 
      this.options.tokens = new Array(this.options.tokens);
    // Force carriage returns as token delimiters anyway
    if (!this.options.tokens.include('\n'))
      this.options.tokens.push('\n');

    this.observer = null;
    
    this.element.setAttribute('autocomplete','off');

    Element.hide(this.update);

    Event.observe(this.element, 'blur', this.onBlur.bindAsEventListener(this));
    Event.observe(this.element, 'keypress', this.onKeyPress.bindAsEventListener(this));
  },

  show: function() {
    if(Element.getStyle(this.update, 'display')=='none') this.options.onShow(this.element, this.update);
    if(!this.iefix && 
      (Prototype.Browser.IE) &&
      (Element.getStyle(this.update, 'position')=='absolute')) {
      new Insertion.After(this.update, 
       '<iframe id="' + this.update.id + '_iefix" '+
       'style="display:none;position:absolute;filter:progid:DXImageTransform.Microsoft.Alpha(opacity=0);" ' +
       'src="javascript:false;" frameborder="0" scrolling="no"></iframe>');
      this.iefix = $(this.update.id+'_iefix');
    }
    if(this.iefix) setTimeout(this.fixIEOverlapping.bind(this), 50);
  },
  
  fixIEOverlapping: function() {
    Position.clone(this.update, this.iefix, {setTop:(!this.update.style.height)});
    this.iefix.style.zIndex = 1;
    this.update.style.zIndex = 2;
    Element.show(this.iefix);
  },

  hide: function() {
    this.stopIndicator();
    if(Element.getStyle(this.update, 'display')!='none') this.options.onHide(this.element, this.update);
    if(this.iefix) Element.hide(this.iefix);
  },

  startIndicator: function() {
    if(this.options.indicator) Element.show(this.options.indicator);
  },

  stopIndicator: function() {
    if(this.options.indicator) Element.hide(this.options.indicator);
  },

  onKeyPress: function(event) {
    if(this.active)
      switch(event.keyCode) {
       case Event.KEY_TAB:
       case Event.KEY_RETURN:
         this.selectEntry();
         Event.stop(event);
       case Event.KEY_ESC:
         this.hide();
         this.active = false;
         Event.stop(event);
         return;
       case Event.KEY_LEFT:
       case Event.KEY_RIGHT:
         return;
       case Event.KEY_UP:
         this.markPrevious();
         this.render();
         if(Prototype.Browser.WebKit) Event.stop(event);
         return;
       case Event.KEY_DOWN:
         this.markNext();
         this.render();
         if(Prototype.Browser.WebKit) Event.stop(event);
         return;
      }
     else 
       if(event.keyCode==Event.KEY_TAB || event.keyCode==Event.KEY_RETURN || 
         (Prototype.Browser.WebKit > 0 && event.keyCode == 0)) return;

    this.changed = true;
    this.hasFocus = true;

    if(this.observer) clearTimeout(this.observer);
      this.observer = 
        setTimeout(this.onObserverEvent.bind(this), this.options.frequency*1000);
  },

  activate: function() {
    this.changed = false;
    this.hasFocus = true;
    this.getUpdatedChoices();
  },

  onHover: function(event) {
    var element = Event.findElement(event, 'LI');
    if(this.index != element.autocompleteIndex) 
    {
        this.index = element.autocompleteIndex;
        this.render();
    }
    Event.stop(event);
  },
  
  onClick: function(event) {
    var element = Event.findElement(event, 'LI');
    this.index = element.autocompleteIndex;
    this.selectEntry();
    this.hide();
  },
  
  onBlur: function(event) {
    // needed to make click events working
    setTimeout(this.hide.bind(this), 250);
    this.hasFocus = false;
    this.active = false;     
  }, 
  
  render: function() {
    if(this.entryCount > 0) {
      for (var i = 0; i < this.entryCount; i++)
        this.index==i ? 
          Element.addClassName(this.getEntry(i),"selected") : 
          Element.removeClassName(this.getEntry(i),"selected");
      if(this.hasFocus) { 
        this.show();
        this.active = true;
      }
    } else {
      this.active = false;
      this.hide();
    }
  },
  
  markPrevious: function() {
    if(this.index > 0) this.index--
      else this.index = this.entryCount-1;
    this.getEntry(this.index).scrollIntoView(true);
  },
  
  markNext: function() {
    if(this.index < this.entryCount-1) this.index++
      else this.index = 0;
    this.getEntry(this.index).scrollIntoView(false);
  },
  
  getEntry: function(index) {
    return this.update.firstChild.childNodes[index];
  },
  
  getCurrentEntry: function() {
    return this.getEntry(this.index);
  },
  
  selectEntry: function() {
    this.active = false;
    this.updateElement(this.getCurrentEntry());
  },

  updateElement: function(selectedElement) {
    if (this.options.updateElement) {
      this.options.updateElement(selectedElement);
      return;
    }
    var value = '';
    if (this.options.select) {
      var nodes = $(selectedElement).select('.' + this.options.select) || [];
      if(nodes.length>0) value = Element.collectTextNodes(nodes[0], this.options.select);
    } else
      value = Element.collectTextNodesIgnoreClass(selectedElement, 'informal');
    
    var bounds = this.getTokenBounds();
    if (bounds[0] != -1) {
      var newValue = this.element.value.substr(0, bounds[0]);
      var whitespace = this.element.value.substr(bounds[0]).match(/^\s+/);
      if (whitespace)
        newValue += whitespace[0];
      this.element.value = newValue + value + this.element.value.substr(bounds[1]);
    } else {
      this.element.value = value;
    }
    this.oldElementValue = this.element.value;
    this.element.focus();
    
    if (this.options.afterUpdateElement)
      this.options.afterUpdateElement(this.element, selectedElement);
  },

  updateChoices: function(choices) {
    if(!this.changed && this.hasFocus) {
      this.update.innerHTML = choices;
      Element.cleanWhitespace(this.update);
      Element.cleanWhitespace(this.update.down());

      if(this.update.firstChild && this.update.down().childNodes) {
        this.entryCount = 
          this.update.down().childNodes.length;
        for (var i = 0; i < this.entryCount; i++) {
          var entry = this.getEntry(i);
          entry.autocompleteIndex = i;
          this.addObservers(entry);
        }
      } else { 
        this.entryCount = 0;
      }

      this.stopIndicator();
      this.index = 0;
      
      if(this.entryCount==1 && this.options.autoSelect) {
        this.selectEntry();
        this.hide();
      } else {
        this.render();
      }
    }
  },

  addObservers: function(element) {
    Event.observe(element, "mouseover", this.onHover.bindAsEventListener(this));
    Event.observe(element, "click", this.onClick.bindAsEventListener(this));
  },

  onObserverEvent: function() {
    this.changed = false;   
    this.tokenBounds = null;
    if(this.getToken().length>=this.options.minChars) {
      this.getUpdatedChoices();
    } else {
      this.active = false;
      this.hide();
    }
    this.oldElementValue = this.element.value;
  },

  getToken: function() {
    var bounds = this.getTokenBounds();
    return this.element.value.substring(bounds[0], bounds[1]).strip();
  },

  getTokenBounds: function() {
    if (null != this.tokenBounds) return this.tokenBounds;
    var value = this.element.value;
    if (value.strip().empty()) return [-1, 0];
    var diff = arguments.callee.getFirstDifferencePos(value, this.oldElementValue);
    var offset = (diff == this.oldElementValue.length ? 1 : 0);
    var prevTokenPos = -1, nextTokenPos = value.length;
    var tp;
    for (var index = 0, l = this.options.tokens.length; index < l; ++index) {
      tp = value.lastIndexOf(this.options.tokens[index], diff + offset - 1);
      if (tp > prevTokenPos) prevTokenPos = tp;
      tp = value.indexOf(this.options.tokens[index], diff + offset);
      if (-1 != tp && tp < nextTokenPos) nextTokenPos = tp;
    }
    return (this.tokenBounds = [prevTokenPos + 1, nextTokenPos]);
  }
});

Autocompleter.Base.prototype.getTokenBounds.getFirstDifferencePos = function(newS, oldS) {
  var boundary = Math.min(newS.length, oldS.length);
  for (var index = 0; index < boundary; ++index)
    if (newS[index] != oldS[index])
      return index;
  return boundary;
};

Ajax.Autocompleter = Class.create(Autocompleter.Base, {
  initialize: function(element, update, url, options) {
    this.baseInitialize(element, update, options);
    this.options.asynchronous  = true;
    this.options.onComplete    = this.onComplete.bind(this);
    this.options.defaultParams = this.options.parameters || null;
    this.url                   = url;
  },

  getUpdatedChoices: function() {
    this.startIndicator();
    
    var entry = encodeURIComponent(this.options.paramName) + '=' + 
      encodeURIComponent(this.getToken());

    this.options.parameters = this.options.callback ?
      this.options.callback(this.element, entry) : entry;

    if(this.options.defaultParams) 
      this.options.parameters += '&' + this.options.defaultParams;
    
    new Ajax.Request(this.url, this.options);
  },

  onComplete: function(request) {
    this.updateChoices(request.responseText);
  }
});

// The local array autocompleter. Used when you'd prefer to
// inject an array of autocompletion options into the page, rather
// than sending out Ajax queries, which can be quite slow sometimes.
//
// The constructor takes four parameters. The first two are, as usual,
// the id of the monitored textbox, and id of the autocompletion menu.
// The third is the array you want to autocomplete from, and the fourth
// is the options block.
//
// Extra local autocompletion options:
// - choices - How many autocompletion choices to offer
//
// - partialSearch - If false, the autocompleter will match entered
//                    text only at the beginning of strings in the 
//                    autocomplete array. Defaults to true, which will
//                    match text at the beginning of any *word* in the
//                    strings in the autocomplete array. If you want to
//                    search anywhere in the string, additionally set
//                    the option fullSearch to true (default: off).
//
// - fullSsearch - Search anywhere in autocomplete array strings.
//
// - partialChars - How many characters to enter before triggering
//                   a partial match (unlike minChars, which defines
//                   how many characters are required to do any match
//                   at all). Defaults to 2.
//
// - ignoreCase - Whether to ignore case when autocompleting.
//                 Defaults to true.
//
// It's possible to pass in a custom function as the 'selector' 
// option, if you prefer to write your own autocompletion logic.
// In that case, the other options above will not apply unless
// you support them.

Autocompleter.Local = Class.create(Autocompleter.Base, {
  initialize: function(element, update, array, options) {
    this.baseInitialize(element, update, options);
    this.options.array = array;
  },

  getUpdatedChoices: function() {
    this.updateChoices(this.options.selector(this));
  },

  setOptions: function(options) {
    this.options = Object.extend({
      choices: 10,
      partialSearch: true,
      partialChars: 2,
      ignoreCase: true,
      fullSearch: false,
      selector: function(instance) {
        var ret       = []; // Beginning matches
        var partial   = []; // Inside matches
        var entry     = instance.getToken();
        var count     = 0;

        for (var i = 0; i < instance.options.array.length &&  
          ret.length < instance.options.choices ; i++) { 

          var elem = instance.options.array[i];
          var foundPos = instance.options.ignoreCase ? 
            elem.toLowerCase().indexOf(entry.toLowerCase()) : 
            elem.indexOf(entry);

          while (foundPos != -1) {
            if (foundPos == 0 && elem.length != entry.length) { 
              ret.push("<li><strong>" + elem.substr(0, entry.length) + "</strong>" + 
                elem.substr(entry.length) + "</li>");
              break;
            } else if (entry.length >= instance.options.partialChars && 
              instance.options.partialSearch && foundPos != -1) {
              if (instance.options.fullSearch || /\s/.test(elem.substr(foundPos-1,1))) {
                partial.push("<li>" + elem.substr(0, foundPos) + "<strong>" +
                  elem.substr(foundPos, entry.length) + "</strong>" + elem.substr(
                  foundPos + entry.length) + "</li>");
                break;
              }
            }

            foundPos = instance.options.ignoreCase ? 
              elem.toLowerCase().indexOf(entry.toLowerCase(), foundPos + 1) : 
              elem.indexOf(entry, foundPos + 1);

          }
        }
        if (partial.length)
          ret = ret.concat(partial.slice(0, instance.options.choices - ret.length))
        return "<ul>" + ret.join('') + "</ul>";
      }
    }, options || { });
  }
});

// AJAX in-place editor and collection editor
// Full rewrite by Christophe Porteneuve <tdd@tddsworld.com> (April 2007).

// Use this if you notice weird scrolling problems on some browsers,
// the DOM might be a bit confused when this gets called so do this
// waits 1 ms (with setTimeout) until it does the activation
Field.scrollFreeActivate = function(field) {
  setTimeout(function() {
    Field.activate(field);
  }, 1);
}

Ajax.InPlaceEditor = Class.create({
  initialize: function(element, url, options) {
    this.url = url;
    this.element = element = $(element);
    this.prepareOptions();
    this._controls = { };
    arguments.callee.dealWithDeprecatedOptions(options); // DEPRECATION LAYER!!!
    Object.extend(this.options, options || { });
    if (!this.options.formId && this.element.id) {
      this.options.formId = this.element.id + '-inplaceeditor';
      if ($(this.options.formId))
        this.options.formId = '';
    }
    if (this.options.externalControl)
      this.options.externalControl = $(this.options.externalControl);
    if (!this.options.externalControl)
      this.options.externalControlOnly = false;
    this._originalBackground = this.element.getStyle('background-color') || 'transparent';
    this.element.title = this.options.clickToEditText;
    this._boundCancelHandler = this.handleFormCancellation.bind(this);
    this._boundComplete = (this.options.onComplete || Prototype.emptyFunction).bind(this);
    this._boundFailureHandler = this.handleAJAXFailure.bind(this);
    this._boundSubmitHandler = this.handleFormSubmission.bind(this);
    this._boundWrapperHandler = this.wrapUp.bind(this);
    this.registerListeners();
  },
  checkForEscapeOrReturn: function(e) {
    if (!this._editing || e.ctrlKey || e.altKey || e.shiftKey) return;
    if (Event.KEY_ESC == e.keyCode)
      this.handleFormCancellation(e);
    else if (Event.KEY_RETURN == e.keyCode)
      this.handleFormSubmission(e);
  },
  createControl: function(mode, handler, extraClasses) {
    var control = this.options[mode + 'Control'];
    var text = this.options[mode + 'Text'];
    if ('button' == control) {
      var btn = document.createElement('input');
      btn.type = 'submit';
      btn.value = text;
      btn.className = 'editor_' + mode + '_button';
      if ('cancel' == mode)
        btn.onclick = this._boundCancelHandler;
      this._form.appendChild(btn);
      this._controls[mode] = btn;
    } else if ('link' == control) {
      var link = document.createElement('a');
      link.href = '#';
      link.appendChild(document.createTextNode(text));
      link.onclick = 'cancel' == mode ? this._boundCancelHandler : this._boundSubmitHandler;
      link.className = 'editor_' + mode + '_link';
      if (extraClasses)
        link.className += ' ' + extraClasses;
      this._form.appendChild(link);
      this._controls[mode] = link;
    }
  },
  createEditField: function() {
    var text = (this.options.loadTextURL ? this.options.loadingText : this.getText());
    var fld;
    if (1 >= this.options.rows && !/\r|\n/.test(this.getText())) {
      fld = document.createElement('input');
      fld.type = 'text';
      var size = this.options.size || this.options.cols || 0;
      if (0 < size) fld.size = size;
    } else {
      fld = document.createElement('textarea');
      fld.rows = (1 >= this.options.rows ? this.options.autoRows : this.options.rows);
      fld.cols = this.options.cols || 40;
    }
    fld.name = this.options.paramName;
    fld.value = text; // No HTML breaks conversion anymore
    fld.className = 'editor_field';
    if (this.options.submitOnBlur)
      fld.onblur = this._boundSubmitHandler;
    this._controls.editor = fld;
    if (this.options.loadTextURL)
      this.loadExternalText();
    this._form.appendChild(this._controls.editor);
  },
  createForm: function() {
    var ipe = this;
    function addText(mode, condition) {
      var text = ipe.options['text' + mode + 'Controls'];
      if (!text || condition === false) return;
      ipe._form.appendChild(document.createTextNode(text));
    };
    this._form = $(document.createElement('form'));
    this._form.id = this.options.formId;
    this._form.addClassName(this.options.formClassName);
    this._form.onsubmit = this._boundSubmitHandler;
    this.createEditField();
    if ('textarea' == this._controls.editor.tagName.toLowerCase())
      this._form.appendChild(document.createElement('br'));
    if (this.options.onFormCustomization)
      this.options.onFormCustomization(this, this._form);
    addText('Before', this.options.okControl || this.options.cancelControl);
    this.createControl('ok', this._boundSubmitHandler);
    addText('Between', this.options.okControl && this.options.cancelControl);
    this.createControl('cancel', this._boundCancelHandler, 'editor_cancel');
    addText('After', this.options.okControl || this.options.cancelControl);
  },
  destroy: function() {
    if (this._oldInnerHTML)
      this.element.innerHTML = this._oldInnerHTML;
    this.leaveEditMode();
    this.unregisterListeners();
  },
  enterEditMode: function(e) {
    if (this._saving || this._editing) return;
    this._editing = true;
    this.triggerCallback('onEnterEditMode');
    if (this.options.externalControl)
      this.options.externalControl.hide();
    this.element.hide();
    this.createForm();
    this.element.parentNode.insertBefore(this._form, this.element);
    if (!this.options.loadTextURL)
      this.postProcessEditField();
    if (e) Event.stop(e);
  },
  enterHover: function(e) {
    if (this.options.hoverClassName)
      this.element.addClassName(this.options.hoverClassName);
    if (this._saving) return;
    this.triggerCallback('onEnterHover');
  },
  getText: function() {
    return this.element.innerHTML;
  },
  handleAJAXFailure: function(transport) {
    this.triggerCallback('onFailure', transport);
    if (this._oldInnerHTML) {
      this.element.innerHTML = this._oldInnerHTML;
      this._oldInnerHTML = null;
    }
  },
  handleFormCancellation: function(e) {
    this.wrapUp();
    if (e) Event.stop(e);
  },
  handleFormSubmission: function(e) {
    var form = this._form;
    var value = $F(this._controls.editor);
    this.prepareSubmission();
    var params = this.options.callback(form, value) || '';
    if (Object.isString(params))
      params = params.toQueryParams();
    params.editorId = this.element.id;
    if (this.options.htmlResponse) {
      var options = Object.extend({ evalScripts: true }, this.options.ajaxOptions);
      Object.extend(options, {
        parameters: params,
        onComplete: this._boundWrapperHandler,
        onFailure: this._boundFailureHandler
      });
      new Ajax.Updater({ success: this.element }, this.url, options);
    } else {
      var options = Object.extend({ method: 'get' }, this.options.ajaxOptions);
      Object.extend(options, {
        parameters: params,
        onComplete: this._boundWrapperHandler,
        onFailure: this._boundFailureHandler
      });
      new Ajax.Request(this.url, options);
    }
    if (e) Event.stop(e);
  },
  leaveEditMode: function() {
    this.element.removeClassName(this.options.savingClassName);
    this.removeForm();
    this.leaveHover();
    this.element.style.backgroundColor = this._originalBackground;
    this.element.show();
    if (this.options.externalControl)
      this.options.externalControl.show();
    this._saving = false;
    this._editing = false;
    this._oldInnerHTML = null;
    this.triggerCallback('onLeaveEditMode');
  },
  leaveHover: function(e) {
    if (this.options.hoverClassName)
      this.element.removeClassName(this.options.hoverClassName);
    if (this._saving) return;
    this.triggerCallback('onLeaveHover');
  },
  loadExternalText: function() {
    this._form.addClassName(this.options.loadingClassName);
    this._controls.editor.disabled = true;
    var options = Object.extend({ method: 'get' }, this.options.ajaxOptions);
    Object.extend(options, {
      parameters: 'editorId=' + encodeURIComponent(this.element.id),
      onComplete: Prototype.emptyFunction,
      onSuccess: function(transport) {
        this._form.removeClassName(this.options.loadingClassName);
        var text = transport.responseText;
        if (this.options.stripLoadedTextTags)
          text = text.stripTags();
        this._controls.editor.value = text;
        this._controls.editor.disabled = false;
        this.postProcessEditField();
      }.bind(this),
      onFailure: this._boundFailureHandler
    });
    new Ajax.Request(this.options.loadTextURL, options);
  },
  postProcessEditField: function() {
    var fpc = this.options.fieldPostCreation;
    if (fpc)
      $(this._controls.editor)['focus' == fpc ? 'focus' : 'activate']();
  },
  prepareOptions: function() {
    this.options = Object.clone(Ajax.InPlaceEditor.DefaultOptions);
    Object.extend(this.options, Ajax.InPlaceEditor.DefaultCallbacks);
    [this._extraDefaultOptions].flatten().compact().each(function(defs) {
      Object.extend(this.options, defs);
    }.bind(this));
  },
  prepareSubmission: function() {
    this._saving = true;
    this.removeForm();
    this.leaveHover();
    this.showSaving();
  },
  registerListeners: function() {
    this._listeners = { };
    var listener;
    $H(Ajax.InPlaceEditor.Listeners).each(function(pair) {
      listener = this[pair.value].bind(this);
      this._listeners[pair.key] = listener;
      if (!this.options.externalControlOnly)
        this.element.observe(pair.key, listener);
      if (this.options.externalControl)
        this.options.externalControl.observe(pair.key, listener);
    }.bind(this));
  },
  removeForm: function() {
    if (!this._form) return;
    this._form.remove();
    this._form = null;
    this._controls = { };
  },
  showSaving: function() {
    this._oldInnerHTML = this.element.innerHTML;
    this.element.innerHTML = this.options.savingText;
    this.element.addClassName(this.options.savingClassName);
    this.element.style.backgroundColor = this._originalBackground;
    this.element.show();
  },
  triggerCallback: function(cbName, arg) {
    if ('function' == typeof this.options[cbName]) {
      this.options[cbName](this, arg);
    }
  },
  unregisterListeners: function() {
    $H(this._listeners).each(function(pair) {
      if (!this.options.externalControlOnly)
        this.element.stopObserving(pair.key, pair.value);
      if (this.options.externalControl)
        this.options.externalControl.stopObserving(pair.key, pair.value);
    }.bind(this));
  },
  wrapUp: function(transport) {
    this.leaveEditMode();
    // Can't use triggerCallback due to backward compatibility: requires
    // binding + direct element
    this._boundComplete(transport, this.element);
  }
});

Object.extend(Ajax.InPlaceEditor.prototype, {
  dispose: Ajax.InPlaceEditor.prototype.destroy
});

Ajax.InPlaceCollectionEditor = Class.create(Ajax.InPlaceEditor, {
  initialize: function($super, element, url, options) {
    this._extraDefaultOptions = Ajax.InPlaceCollectionEditor.DefaultOptions;
    $super(element, url, options);
  },

  createEditField: function() {
    var list = document.createElement('select');
    list.name = this.options.paramName;
    list.size = 1;
    this._controls.editor = list;
    this._collection = this.options.collection || [];
    if (this.options.loadCollectionURL)
      this.loadCollection();
    else
      this.checkForExternalText();
    this._form.appendChild(this._controls.editor);
  },

  loadCollection: function() {
    this._form.addClassName(this.options.loadingClassName);
    this.showLoadingText(this.options.loadingCollectionText);
    var options = Object.extend({ method: 'get' }, this.options.ajaxOptions);
    Object.extend(options, {
      parameters: 'editorId=' + encodeURIComponent(this.element.id),
      onComplete: Prototype.emptyFunction,
      onSuccess: function(transport) {
        var js = transport.responseText.strip();
        if (!/^\[.*\]$/.test(js)) // TODO: improve sanity check
          throw 'Server returned an invalid collection representation.';
        this._collection = eval(js);
        this.checkForExternalText();
      }.bind(this),
      onFailure: this.onFailure
    });
    new Ajax.Request(this.options.loadCollectionURL, options);
  },

  showLoadingText: function(text) {
    this._controls.editor.disabled = true;
    var tempOption = this._controls.editor.firstChild;
    if (!tempOption) {
      tempOption = document.createElement('option');
      tempOption.value = '';
      this._controls.editor.appendChild(tempOption);
      tempOption.selected = true;
    }
    tempOption.update((text || '').stripScripts().stripTags());
  },

  checkForExternalText: function() {
    this._text = this.getText();
    if (this.options.loadTextURL)
      this.loadExternalText();
    else
      this.buildOptionList();
  },

  loadExternalText: function() {
    this.showLoadingText(this.options.loadingText);
    var options = Object.extend({ method: 'get' }, this.options.ajaxOptions);
    Object.extend(options, {
      parameters: 'editorId=' + encodeURIComponent(this.element.id),
      onComplete: Prototype.emptyFunction,
      onSuccess: function(transport) {
        this._text = transport.responseText.strip();
        this.buildOptionList();
      }.bind(this),
      onFailure: this.onFailure
    });
    new Ajax.Request(this.options.loadTextURL, options);
  },

  buildOptionList: function() {
    this._form.removeClassName(this.options.loadingClassName);
    this._collection = this._collection.map(function(entry) {
      return 2 === entry.length ? entry : [entry, entry].flatten();
    });
    var marker = ('value' in this.options) ? this.options.value : this._text;
    var textFound = this._collection.any(function(entry) {
      return entry[0] == marker;
    }.bind(this));
    this._controls.editor.update('');
    var option;
    this._collection.each(function(entry, index) {
      option = document.createElement('option');
      option.value = entry[0];
      option.selected = textFound ? entry[0] == marker : 0 == index;
      option.appendChild(document.createTextNode(entry[1]));
      this._controls.editor.appendChild(option);
    }.bind(this));
    this._controls.editor.disabled = false;
    Field.scrollFreeActivate(this._controls.editor);
  }
});

//**** DEPRECATION LAYER FOR InPlace[Collection]Editor! ****
//**** This only  exists for a while,  in order to  let ****
//**** users adapt to  the new API.  Read up on the new ****
//**** API and convert your code to it ASAP!            ****

Ajax.InPlaceEditor.prototype.initialize.dealWithDeprecatedOptions = function(options) {
  if (!options) return;
  function fallback(name, expr) {
    if (name in options || expr === undefined) return;
    options[name] = expr;
  };
  fallback('cancelControl', (options.cancelLink ? 'link' : (options.cancelButton ? 'button' :
    options.cancelLink == options.cancelButton == false ? false : undefined)));
  fallback('okControl', (options.okLink ? 'link' : (options.okButton ? 'button' :
    options.okLink == options.okButton == false ? false : undefined)));
  fallback('highlightColor', options.highlightcolor);
  fallback('highlightEndColor', options.highlightendcolor);
};

Object.extend(Ajax.InPlaceEditor, {
  DefaultOptions: {
    ajaxOptions: { },
    autoRows: 3,                                // Use when multi-line w/ rows == 1
    cancelControl: 'link',                      // 'link'|'button'|false
    cancelText: 'cancel',
    clickToEditText: 'Click to edit',
    externalControl: null,                      // id|elt
    externalControlOnly: false,
    fieldPostCreation: 'activate',              // 'activate'|'focus'|false
    formClassName: 'inplaceeditor-form',
    formId: null,                               // id|elt
    highlightColor: '#ffff99',
    highlightEndColor: '#ffffff',
    hoverClassName: '',
    htmlResponse: true,
    loadingClassName: 'inplaceeditor-loading',
    loadingText: 'Loading...',
    okControl: 'button',                        // 'link'|'button'|false
    okText: 'ok',
    paramName: 'value',
    rows: 1,                                    // If 1 and multi-line, uses autoRows
    savingClassName: 'inplaceeditor-saving',
    savingText: 'Saving...',
    size: 0,
    stripLoadedTextTags: false,
    submitOnBlur: false,
    textAfterControls: '',
    textBeforeControls: '',
    textBetweenControls: ''
  },
  DefaultCallbacks: {
    callback: function(form) {
      return Form.serialize(form);
    },
    onComplete: function(transport, element) {
      // For backward compatibility, this one is bound to the IPE, and passes
      // the element directly.  It was too often customized, so we don't break it.
      new Effect.Highlight(element, {
        startcolor: this.options.highlightColor, keepBackgroundImage: true });
    },
    onEnterEditMode: null,
    onEnterHover: function(ipe) {
      ipe.element.style.backgroundColor = ipe.options.highlightColor;
      if (ipe._effect)
        ipe._effect.cancel();
    },
    onFailure: function(transport, ipe) {
      alert('Error communication with the server: ' + transport.responseText.stripTags());
    },
    onFormCustomization: null, // Takes the IPE and its generated form, after editor, before controls.
    onLeaveEditMode: null,
    onLeaveHover: function(ipe) {
      ipe._effect = new Effect.Highlight(ipe.element, {
        startcolor: ipe.options.highlightColor, endcolor: ipe.options.highlightEndColor,
        restorecolor: ipe._originalBackground, keepBackgroundImage: true
      });
    }
  },
  Listeners: {
    click: 'enterEditMode',
    keydown: 'checkForEscapeOrReturn',
    mouseover: 'enterHover',
    mouseout: 'leaveHover'
  }
});

Ajax.InPlaceCollectionEditor.DefaultOptions = {
  loadingCollectionText: 'Loading options...'
};

// Delayed observer, like Form.Element.Observer, 
// but waits for delay after last key input
// Ideal for live-search fields

Form.Element.DelayedObserver = Class.create({
  initialize: function(element, delay, callback) {
    this.delay     = delay || 0.5;
    this.element   = $(element);
    this.callback  = callback;
    this.timer     = null;
    this.lastValue = $F(this.element); 
    Event.observe(this.element,'keyup',this.delayedListener.bindAsEventListener(this));
  },
  delayedListener: function(event) {
    if(this.lastValue == $F(this.element)) return;
    if(this.timer) clearTimeout(this.timer);
    this.timer = setTimeout(this.onTimerEvent.bind(this), this.delay * 1000);
    this.lastValue = $F(this.element);
  },
  onTimerEvent: function() {
    this.timer = null;
    this.callback(this.element, $F(this.element));
  }
});


/* --- End /home/httpd/app_frame/webroot/js/controls.js --- */
/* --- Start /home/httpd/app_frame/webroot/js/builder.js --- */

// script.aculo.us builder.js v1.8.0, Tue Nov 06 15:01:40 +0300 2007

// Copyright (c) 2005-2007 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
//
// script.aculo.us is freely distributable under the terms of an MIT-style license.
// For details, see the script.aculo.us web site: http://script.aculo.us/

var Builder = {
  NODEMAP: {
    AREA: 'map',
    CAPTION: 'table',
    COL: 'table',
    COLGROUP: 'table',
    LEGEND: 'fieldset',
    OPTGROUP: 'select',
    OPTION: 'select',
    PARAM: 'object',
    TBODY: 'table',
    TD: 'table',
    TFOOT: 'table',
    TH: 'table',
    THEAD: 'table',
    TR: 'table'
  },
  // note: For Firefox < 1.5, OPTION and OPTGROUP tags are currently broken,
  //       due to a Firefox bug
  node: function(elementName) {
    elementName = elementName.toUpperCase();
    
    // try innerHTML approach
    var parentTag = this.NODEMAP[elementName] || 'div';
    var parentElement = document.createElement(parentTag);
    try { // prevent IE "feature": http://dev.rubyonrails.org/ticket/2707
      parentElement.innerHTML = "<" + elementName + "></" + elementName + ">";
    } catch(e) {}
    var element = parentElement.firstChild || null;
      
    // see if browser added wrapping tags
    if(element && (element.tagName.toUpperCase() != elementName))
      element = element.getElementsByTagName(elementName)[0];
    
    // fallback to createElement approach
    if(!element) element = document.createElement(elementName);
    
    // abort if nothing could be created
    if(!element) return;

    // attributes (or text)
    if(arguments[1])
      if(this._isStringOrNumber(arguments[1]) ||
        (arguments[1] instanceof Array) ||
        arguments[1].tagName) {
          this._children(element, arguments[1]);
        } else {
          var attrs = this._attributes(arguments[1]);
          if(attrs.length) {
            try { // prevent IE "feature": http://dev.rubyonrails.org/ticket/2707
              parentElement.innerHTML = "<" +elementName + " " +
                attrs + "></" + elementName + ">";
            } catch(e) {}
            element = parentElement.firstChild || null;
            // workaround firefox 1.0.X bug
            if(!element) {
              element = document.createElement(elementName);
              for(attr in arguments[1]) 
                element[attr == 'class' ? 'className' : attr] = arguments[1][attr];
            }
            if(element.tagName.toUpperCase() != elementName)
              element = parentElement.getElementsByTagName(elementName)[0];
          }
        } 

    // text, or array of children
    if(arguments[2])
      this._children(element, arguments[2]);

     return element;
  },
  _text: function(text) {
     return document.createTextNode(text);
  },

  ATTR_MAP: {
    'className': 'class',
    'htmlFor': 'for'
  },

  _attributes: function(attributes) {
    var attrs = [];
    for(attribute in attributes)
      attrs.push((attribute in this.ATTR_MAP ? this.ATTR_MAP[attribute] : attribute) +
          '="' + attributes[attribute].toString().escapeHTML().gsub(/"/,'&quot;') + '"');
    return attrs.join(" ");
  },
  _children: function(element, children) {
    if(children.tagName) {
      element.appendChild(children);
      return;
    }
    if(typeof children=='object') { // array can hold nodes and text
      children.flatten().each( function(e) {
        if(typeof e=='object')
          element.appendChild(e)
        else
          if(Builder._isStringOrNumber(e))
            element.appendChild(Builder._text(e));
      });
    } else
      if(Builder._isStringOrNumber(children))
        element.appendChild(Builder._text(children));
  },
  _isStringOrNumber: function(param) {
    return(typeof param=='string' || typeof param=='number');
  },
  build: function(html) {
    var element = this.node('div');
    $(element).update(html.strip());
    return element.down();
  },
  dump: function(scope) { 
    if(typeof scope != 'object' && typeof scope != 'function') scope = window; //global scope 
  
    var tags = ("A ABBR ACRONYM ADDRESS APPLET AREA B BASE BASEFONT BDO BIG BLOCKQUOTE BODY " +
      "BR BUTTON CAPTION CENTER CITE CODE COL COLGROUP DD DEL DFN DIR DIV DL DT EM FIELDSET " +
      "FONT FORM FRAME FRAMESET H1 H2 H3 H4 H5 H6 HEAD HR HTML I IFRAME IMG INPUT INS ISINDEX "+
      "KBD LABEL LEGEND LI LINK MAP MENU META NOFRAMES NOSCRIPT OBJECT OL OPTGROUP OPTION P "+
      "PARAM PRE Q S SAMP SCRIPT SELECT SMALL SPAN STRIKE STRONG STYLE SUB SUP TABLE TBODY TD "+
      "TEXTAREA TFOOT TH THEAD TITLE TR TT U UL VAR").split(/\s+/);
  
    tags.each( function(tag){ 
      scope[tag] = function() { 
        return Builder.node.apply(Builder, [tag].concat($A(arguments)));  
      } 
    });
  }
}


/* --- End /home/httpd/app_frame/webroot/js/builder.js --- */
/* --- Start /home/httpd/app_frame/webroot/js/sound.js --- */

// script.aculo.us sound.js v1.8.0, Tue Nov 06 15:01:40 +0300 2007

// Copyright (c) 2005-2007 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
//
// Based on code created by Jules Gravinese (http://www.webveteran.com/)
//
// script.aculo.us is freely distributable under the terms of an MIT-style license.
// For details, see the script.aculo.us web site: http://script.aculo.us/

Sound = {
  tracks: {},
  _enabled: true,
  template:
    new Template('<embed style="height:0" id="sound_#{track}_#{id}" src="#{url}" loop="false" autostart="true" hidden="true"/>'),
  enable: function(){
    Sound._enabled = true;
  },
  disable: function(){
    Sound._enabled = false;
  },
  play: function(url){
    if(!Sound._enabled) return;
    var options = Object.extend({
      track: 'global', url: url, replace: false
    }, arguments[1] || {});
    
    if(options.replace && this.tracks[options.track]) {
      $R(0, this.tracks[options.track].id).each(function(id){
        var sound = $('sound_'+options.track+'_'+id);
        sound.Stop && sound.Stop();
        sound.remove();
      })
      this.tracks[options.track] = null;
    }
      
    if(!this.tracks[options.track])
      this.tracks[options.track] = { id: 0 }
    else
      this.tracks[options.track].id++;
      
    options.id = this.tracks[options.track].id;
    $$('body')[0].insert( 
      Prototype.Browser.IE ? new Element('bgsound',{
        id: 'sound_'+options.track+'_'+options.id,
        src: options.url, loop: 1, autostart: true
      }) : Sound.template.evaluate(options));
  }
};

if(Prototype.Browser.Gecko && navigator.userAgent.indexOf("Win") > 0){
  if(navigator.plugins && $A(navigator.plugins).detect(function(p){ return p.name.indexOf('QuickTime') != -1 }))
    Sound.template = new Template('<object id="sound_#{track}_#{id}" width="0" height="0" type="audio/mpeg" data="#{url}"/>')
  else
    Sound.play = function(){}
}


/* --- End /home/httpd/app_frame/webroot/js/sound.js --- */
/* --- Start /home/httpd/public/app_frame/webroot/js/MapWidget.js --- */

function MapWidget(elementId, objid)
{
    this.map = null;
    this.mapDiv = null;
    this.elementId = elementId;
    this.centerId = objid;
    this.showTypes = false;
    this.typesMenu = null;
    this.loading = null;
    this.centerLocation = null;
    this.locations = new Array;
    this.details = null;

    this.load = function()
    {
        if(GBrowserIsCompatible())
        {
            var element = document.getElementById(this.elementId);
            if(element)
            {
                // create the large link
                var link = document.createElement('a');
                link.href = '/locations/map/?objid=' + this.centerId;
                link.className = 'largeMap';
                link.innerHTML = 'Large Map';
                element.appendChild(link);
                // Create the map div
                this.mapDiv = document.createElement('div');
                this.mapDiv.className = 'map';
                element.appendChild(this.mapDiv);
                this.map = new GMap2(this.mapDiv);
                this.map.addControl(new GSmallMapControl());
                // Create the loading image
                this.loading = document.createElement('div');
                var img = document.createElement('img');
                img.style.margin = '0px';
                img.src = 'http://assets.westword.com/img/loading.gif';
                img.style.border = 'none';
                this.loading.appendChild(img);
                this.loading.style.backgroundColor = '#FFFFFF';
                this.loading.style.border = '1px solid #CCCCCC';
                this.loading.style.width = '25px';
                this.loading.style.height = '25px';
                this.loading.style.position = 'absolute';
                this.loading.margin = '0px';
                this.loading.padding = '0px';
                this.loading.style.top = '5px';
                this.loading.style.left = this.mapDiv.offsetWidth  - 35 + 'px';
                this.loading.style.zIndex = 1000;
                this.loading.style.display = 'none';
                this.mapDiv.appendChild(this.loading);
                this.setCenter(objid);
                if(this.showTypes)
                {
                    this.loadTypes();
                }
            }
        }
    }

    this.showDetails = function(idx,point)
    {
        var element = document.getElementById(this.elementId);
        if(this.details == null)
        {
            if(element)
            {
                this.details = document.createElement('div');
                this.details.style.position = 'absolute';
                this.details.style.display = 'none';
                this.details.style.zIndex = 1000;
                this.details.className = 'details';
                element.appendChild(this.details);
            }
        }
        if(this.details != null)
        {
            var location = null;
            if(idx == null)
            {
                // Load center location info
                location = this.centerLocation;
                this.details.innerHTML = this.centerLocation.Name;
            }
            else if(idx <= this.locations.length)
            {
                location = this.locations[idx];
            }
            this.details.innerHTML = '';
            if(location.LocationImage)
            {
                this.details.innerHTML = '<img style="float: left; margin-right: 5px;" src="' + location.LocationImage + '">';
            }
            this.details.innerHTML += '<div class="location">' +
                                      '<div class="name">' + location.Name + '</div>' +
                                      '<div class="address">' + location.Address + '<br/>' +
                                      location.City.Name + ' ' + location.City.State + ', ' + location.ZipCode + '</div>'
                                      '</div>';
            this.details.style.display = '';
            var centerPoint = this.map.fromLatLngToDivPixel(this.map.getCenter());
            this.details.style.top = (this.mapDiv.offsetTop + ((this.mapDiv.offsetHeight / 2) + (point.y - centerPoint.y))) + 'px';
            this.details.style.left = (this.mapDiv.offsetLeft + ((this.mapDiv.offsetWidth / 2) + (point.x - centerPoint.x) - this.details.offsetWidth)) + 'px';
        }
    }

    this.hideDetails = function()
    {
        if(this.details != null)
        {
            this.details.style.display = 'none';
        }
    }

    this.setCenter = function(objid)
    {
        var widget = this;
        this.loading.style.display = '';
        url = '/locations/mapWidgetService?action=getLocation&objid=' + objid;
        new Ajax.Request(url,
        {
            method:'get',
            onSuccess: function(transport,json)
            {
                if(json)
                {
                    if(json.Status == 'OK')
                    {
                        widget.centerLocation = json.Location;
                        var point = new GLatLng(widget.centerLocation.Latitude,widget.centerLocation.Longitude);
                        widget.map.setCenter(point,json.Zoom);
                        var marker = new GMarker(point);
                        widget.map.addOverlay(marker);
                        widget.loading.style.display = 'none';
                        GEvent.addListener(marker, "mouseover",
                        function()
                        {
                            var point = widget.map.fromLatLngToDivPixel(this.getLatLng());
                            widget.showDetails(null,point);
                        });
                        GEvent.addListener(marker, "mouseout",
                        function()
                        {
                            widget.hideDetails()
                        });
                    }
                    else
                    {
                        alert(json.Error);
                    }
                }
            }
            ,
            onFailure: function()
            {
                alert('Something went wrong...');
            }
        });
    }

    this.loadNearby = function()
    {
        var widget = this;
        this.map.clearOverlays();
        // Add the center marker back on
        var marker = new GMarker(new GLatLng(this.centerLocation.Latitude,this.centerLocation.Longitude));
        GEvent.addListener(marker, "mouseover",
        function()
        {
            var point = widget.map.fromLatLngToDivPixel(this.getLatLng());
            widget.showDetails(null,point);
        });
        GEvent.addListener(marker, "mouseout",
        function()
        {
            widget.hideDetails()
        });
        this.map.addOverlay(marker);
        this.loading.style.display = '';
        url = '/locations/mapWidgetService?action=getNearby&lat=' + this.centerLocation.Latitude + '&lon=' + this.centerLocation.Longitude + '&type=' + this.typesMenu.value;
        new Ajax.Request(url,
        {
            method:'get',
            onSuccess: function(transport,json)
            {
                if(json)
                {
                    if(json.Status == 'OK')
                    {
                        widget.locations = new Array;
                        for(i = 0; i < json.Locations.length; i++)
                        {
                            var location = json.Locations[i].Location;
                            if(location.objid != widget.centerLocation.objid)
                            {
                                widget.locations.push(location);
                                var point = new GLatLng(location.Latitude,location.Longitude);
                                var icon = new GIcon();
                                icon.image = 'http://assets.westword.com/img/default.png';
                                icon.shadow = 'http://assets.westword.com/img/shadow.png';
                                icon.iconSize = new GSize(31, 49);
                        		icon.shadowSize = new GSize(63, 53);
                        		icon.iconAnchor = new GPoint(31, 49);
                        		icon.infoWindowAnchor = new GPoint(20, 20);
                                var marker = new GMarker(point,icon);
                                marker.objid = location.objid;
                                marker.idx = i;
                                widget.map.addOverlay(marker);
                                widget.loading.style.display = 'none';
                                GEvent.addListener(marker, "mouseover",
                                function()
                                {
                                    var point = widget.map.fromLatLngToDivPixel(this.getLatLng());
                                    widget.showDetails(this.idx,point);
                                });
                                GEvent.addListener(marker, "mouseout",
                                function()
                                {
                                    widget.hideDetails()
                                });
                                GEvent.addListener(marker,"click",
                                    function()
                                    {
                                        document.location.href = '/locations/view/' + this.objid;
                                    }
                                );
                            }
                        }
                    }
                    else
                    {
                        alert(json.Error);
                    }
                }
                widget.loading.style.display = 'none';
            }
            ,
            onFailure: function()
            {
                widget.loading.style.display = 'none';
                alert('Something went wrong...');
            }
        });
    }

    this.loadTypes = function()
    {
        var widget = this;
        this.loading.style.display = '';
        url = '/locations/mapWidgetService?action=getTypes';
        new Ajax.Request(url,
        {
            method:'get',
            onSuccess: function(transport,json)
            {
                if(json)
                {
                    if(json.Status == 'OK')
                    {
                        var element = document.getElementById(widget.elementId);
                        // Add the dropdown if it's not there
                        if(widget.typesMenu == null)
                        {
                            var div = document.createElement('div');
                            div.innerHTML = 'Find nearby:';
                            div.className = 'nearby';
                            element.appendChild(div);
                            widget.typesMenu = document.createElement('select');
                            var option = document.createElement('option');
                            option.innerHTML = 'Select Type';
                            widget.typesMenu.appendChild(option);
                            div.appendChild(widget.typesMenu);
                            widget.typesMenu.onchange = function()
                            {
                                if(widget.typesMenu.value != '')
                                {
                                    widget.loadNearby();
                                }
                            }
                        }
                        for(i = 0; i < json.Types.length; i++)
                        {
                            var option = document.createElement('option');
                            option.setAttribute('value',json.Types[i].LocationType.objid);
                            option.innerHTML = json.Types[i].LocationType.Name;
                            widget.typesMenu.appendChild(option);
                        }
                    }
                    else
                    {
                        alert(json.Error);
                    }
                    widget.loading.style.display = 'none';
                }
            }
            ,
            onFailure: function()
            {
                this.loading.style.display = 'none';
                alert('Something went wrong...');
            }
        });
    }
}

/* --- End /home/httpd/public/app_frame/webroot/js/MapWidget.js --- */
/* --- Start /home/httpd/public/app_frame/webroot/js/milonic_menu_code.js --- */

/*

Milonic DHTML Menu - JavaScript Website Navigation System.
Version 5.790 - Built: Monday February 4 2008 - 12:20
Copyright 2008 (c) Milonic Solutions Limited. All Rights Reserved.
This is a commercial software product, please visit http://www.milonic.com/ for more information.
See http://www.milonic.com/license.php for Commercial License Agreement
All Copyright statements must always remain in place in all files at all times

*******  PLEASE NOTE: THIS IS NOT FREE SOFTWARE, IT MUST BE LICENSED FOR ALL USE  ******* 

License Details:
 Number: 207360
    URL: www.villagevoicemedia.com
   Type: Worldwide
  Dated: Wednesday January 30 2008

*/

lNum=207360;lURL="www.villagevoicemedia.com";lVer="5.790";_$t_="Please visit www.milonic.com for details on how to remove this evaluation message";_mD=2;_d=document;_dB=_d.body;_n=navigator;_L=location;_nv=$tL(_n.appVersion);_nu=$tL(_n.userAgent);_ps=parseInt(_n.productSub);_cls=_toL=X_=Y_=_n=null;_W=window;_wp=_W.createPopup;ie=(_d.all)?1:0;ie4=(!_d.getElementById&&ie)?1:0;ie5=(!ie4&&ie&&!_wp)?1:0;ie55=(!ie4&&ie&&_wp)?1:0;ie7=(_nu.indexOf("msie 7")!=-1)?1:0;ns6=(_nu.indexOf("gecko")!=-1)?1:0;konq=(_nu.indexOf("konqueror")!=-1)?1:0;sfri=(_nu.indexOf("safari")!=-1)?1:0;if(sfri&&_d.evaluate)sfri=0;if(konq||sfri){_ps=0;ns6=0}ns4=(_d.layers)?1:0;ns61=(_ps>=20010726)?1:0;ns7=(_ps>=20020823)?1:0;ns72=(_ps>=20040804)?1:0;ff15=(_ps>=20060000)?1:0;op=(_W.opera)?1:0;if(op||konq){ie=0;ie7=0;}op5=(_nu.indexOf("opera 5")!=-1)?1:0;op6=(_nu.indexOf("opera 6")!=-1||_nu.indexOf("opera/6")!=-1)?1:0;op7=(_nu.indexOf("opera 7")!=-1||_nu.indexOf("opera/7")!=-1)?1:0;_OpV=(op&&_W.opera.version)?_W.opera.version():0;if(_OpV)op7=1;mac=(_nv.indexOf("mac")!=-1)?1:0;if(ns6||ns4||op||sfri)mac=0;ns60=0;if(ns6&&!ns61)ns60=1;if(op7)op=0;IEDtD=0;if(!op&&((_d.all||ns7)&&_d.compatMode=="CSS1Compat")||(mac&&_d.doctype&&_d.doctype.name.indexOf(".dtd")!=-1))IEDtD=1;_jv="javascript:;";inEditMode=_rstC=inDragMode=_d.dne=lcl=$R1=$mD=_mcnt=_sL=_sT=_ofMT=_oldbW=_bW=_oldbH=_bl=_el=_st=_en=_cKA=$BW=0;_mtX="";_startM=_c=1;_trueItemRef=focusedMenu=t_=_itemRef=_mn=-1;_zi=_aN=_bH=999;if(op)ie55=0;B$="absolute";$O="menu";$5="hidden";$_O="scroll";function $c(v){if(_d.getElementById)return _d.getElementById(v);if(_d.all)return _d.all[v]}function _StO(f,m){return setTimeout(f,m)}_m=[];_mi=[];_sm=[];_tsm=[];_cip=[];$S3="2E636F6D2F";$S4="646D2E706870";$S5=4048;_MT=_StO("",0);_oMT=_StO("",0);_cMT=_StO("",0);_mst=_StO("",0);_Mtip=_StO("",0);$u="undefined ";_Lhr=_L.href;$6="visible";if(op5){$5=$tU($5);$6=$tU($6)}function M_hideLayer(){}function _oTree(){}function mmMouseMove(){}function _TtM(){}function _IdM(){}function _ocURL(){}function mmClick(){}function autoOT(){}function _iF0C(){}function showtip(){}function isEditMode(){}function hidetip(){}function mmVisFunction(){}function doMenuResize(){}function _tMR(){}function _maxm(){}function $9(ap){if(ie55){try{if(ap.filters){return 1}}catch(e){}}else return false}function _p8(a,d){var t=[];for(_a=0;_a<a.length;_a++){if(a[_a]!=d){t[t.length]=a[_a]}}return t}function copyOf(w){for(_cO in w){this[_cO]=w[_cO]}}function $tL(v){if(v)return v.toLowerCase()}function $tU(v){if(v)return v.toUpperCase()}function $pU(v){if(v)return parseInt(v)}_lDd=0;function _gLd(){if(_d.readyState&&_d.readyState!="complete"){setTimeout("_gLd()",50);return}_lDd=1;_oldbH=0}if(!_d.readyState)_d.addEventListener('DOMContentLoaded',_gLd,false);else setTimeout("_gLd()",50);function drawMenus(){_startM=1;_oldbH=0;_oldbW=0;_baL=0;if(_W.buildAfterLoad)_baL=1;for(_y=_mcnt;_y<_m.length;_y++)o$(_y,1,_baL);if(_W._pageIsXML){var G=$c(_menuContainer);if(!G){G=_d.createElement("div");G.id=_menuContainer;_dB.appendChild(G)}G.innerHTML=_mtX}}_$S={menu:0,text:1,url:2,showmenu:3,status:4,onbgcolor:5,oncolor:6,offbgcolor:7,offcolor:8,offborder:9,separatorcolor:10,padding:11,fontsize:12,fontstyle:13,fontweight:14,fontfamily:15,high3dcolor:16,low3dcolor:17,pagecolor:18,pagebgcolor:19,headercolor:20,headerbgcolor:21,subimagepadding:22,subimageposition:23,subimage:24,onborder:25,ondecoration:26,separatorsize:27,itemheight:28,image:29,imageposition:30,imagealign:31,overimage:32,decoration:33,type:34,target:35,align:36,imageheight:37,imagewidth:38,openonclick:39,closeonclick:40,keepalive:41,onfunction:42,offfunction:43,onbold:44,onitalic:45,bgimage:46,overbgimage:47,onsubimage:48,separatorheight:49,separatorwidth:50,separatorpadding:51,separatoralign:52,onclass:53,offclass:54,itemwidth:55,pageimage:56,targetfeatures:57,visitedcolor:58,pointer:59,imagepadding:60,valign:61,clickfunction:62,bordercolor:63,borderstyle:64,borderwidth:65,overfilter:66,outfilter:67,margin:68,pagebgimage:69,swap3d:70,separatorimage:71,pageclass:72,menubgimage:73,headerborder:74,pageborder:75,title:76,pagematch:77,rawcss:78,fileimage:79,clickcolor:80,clickbgcolor:81,clickimage:82,clicksubimage:83,imageurl:84,pagesubimage:85,dragable:86,clickclass:87,clickbgimage:88,imageborderwidth:89,overseparatorimage:90,clickseparatorimage:91,pageseparatorimage:92,menubgcolor:93,opendelay:94,tooltip:95,disabled:96,dividespan:97,tipdelay:98,tipfollow:99,tipmenu:100,menustyle:101,pageoncolor:102,id:103,overpageimage:104,nowrap:105,overflow:106,hotkey:107,leftimage:108,rightimage:109,overleftimage:110,overrightimage:111,pageleftimage:112,pagerightimage:113,nobreadcrumb:114,custom:115,subimagecss:116,onsubimagecss:117};function mm_style(){for($i in _$S)this[$i]=_n;this.built=0}_$M={items:0,name:1,top:2,left:3,itemwidth:4,screenposition:5,style:6,alwaysvisible:7,align:8,orientation:9,keepalive:10,openstyle:11,margin:12,overflow:13,position:14,overfilter:15,outfilter:16,menuwidth:17,itemheight:18,followscroll:19,menualign:20,mm_callItem:21,mm_obj_ref:22,mm_built:23,menuheight:24,ignorecollision:25,divides:26,zindex:27,opendelay:28,resizable:29,minwidth:30,maxwidth:31,mm_fixheight:32,C:33,rawcss:34};function menuname(name){for($i in _$M)this[$i]=_n;this.name=$tL(name);_c=1;_mn++}function f_(i){_mi[_bl]=[];_mi[_bl][0]=_mn;i=i.split(";");_sc="";for(var a=0;a<i.length;a++){var p=i[a].indexOf("`");if(p!=-1){_sc=";";_tI=i[a];if(p==i[a].lastIndexOf("`")){for(var b=a;b<i.length;b++){if(i[b+1]){_tI+=";"+i[b+1];a++;if(i[b+1].indexOf("`")!=-1)b=i.length}}}i[a]=_tI.replace(/`/g,"")}p=i[a].indexOf("=");if(p==-1){if(i[a])_si=_si+";"+i[a]+_sc}else{_si=i[a].slice(p+1);_w=i[a].slice(0,p);if(_w=="showmenu")_si=$tL(_si)}if(i[a]&&_$S[_w])_mi[_bl][_$S[_w]]=_si}var S=_x[6];if(_mi[_bl][101])S=eval(_mi[_bl][101]);for($i in S)if(S[$i]){var v=_mi[_bl][_$S[$i]];if(!v&&v!="")_mi[_bl][_$S[$i]]=S[$i]}_m[_mn][0][_c-2]=_bl;_c++;_bl++}_c=0;function ami(t){_t=this;if(_c==1){_c++;_m[_mn]=[];_x=_m[_mn];for($i in _t)_x[_$M[$i]]=_t[$i];_x[21]=-1;_x[0]=[];if(!_x[12])_x[12]=0;var s=_m[_mn][6];var m=_m[_mn];if(m[15]==_n)m[15]=s.overfilter;if(m[16]==_n)m[16]=s.outfilter;if(m[13]==_n)m[13]=s.overflow;s[65]=(s.borderwidth)?$pU(s.borderwidth):0;s[64]=s.borderstyle;s[63]=s.bordercolor;if(_W.ignoreCollisions)m[25]=1;if(!s.built){_WzI=_zi;if(_W.menuZIndex){_WzI=_W.menuZIndex;_zi=_WzI}lcl++;var v=s.visitedcolor;if(v&&!_W._pageIsXML){_oC=s.offcolor;if(!_oC)_oC="#000000";if(!v)v="#ff0000";_d.write("<style>.g_"+lcl+":link{color:"+_oC+"}.g_"+lcl+":visited{color:"+v+"}</style>");s.g_="g_"+lcl}s.built=1}}f_(t)}menuname.prototype.aI=ami;
function _p1(t){if(t._itemRef!=_itemRef)h$(t._itemRef)}function $P($){clearTimeout($);return _n}$7=0;$8=0;function _DC(){if(!_W.contextObject&&_trueItemRef==-1)$bb()}function _5($){return eval($)}function gMY(e){if(ns6){X_=e.pageX;Y_=e.pageY}else{e=event;X_=e.clientX;Y_=e.clientY}if(!op&&_d.all&&_dB){}mmMouseMove();_TtM();_IdM();doMenuResize(focusedMenu)}_dC=_DC;if(_d.onmousedown)_dC=_dC+_d.onmousedown;_d.onmousedown=_dC;_TbS="<table class=milonictable border=0 cellpadding=0 cellspacing=0 style='line-height:normal;padding:0px' ";function $_E(g,t,l,h,w){_px="px";var s=g.style;if(w<0)w=0;if(h<0)h=0;if(w+" "==$u)w=_n;if(h+" "==$u)h=_n;if(op){_px="";if(w!=_n)s.pixelWidth=w;if(h!=_n)s.pixelHeight=h}else{if(w!=_n)s.width=w+_px;if(h!=_n)s.height=h+_px;}if(!isNaN(t)&&t!=_n)s.top=t+_px;if(!isNaN(l)&&l!=_n)s.left=l+_px}function $D(g){if(!g)return;var h,w,o,t,l;h=g.offsetHeight;w=g.offsetWidth;if(op5){h=g.style.pixelHeight;w=g.style.pixelWidth}o=g;t=0;l=0;while(o!=_n){t+=o.offsetTop;l+=o.offsetLeft;o=o.offsetParent}if(sfri){l-=$8;t-=$7}if(mac&&_dB){_mcdb=_dB.currentStyle;_mcf=_mcdb.marginTop;if(_mcf)t=t+$pU(_mcf);_mcf=_mcdb.marginLeft;if(_mcf)l=l+$pU(_mcf)}return(new Array(t,l,h,w))}function $2(g,m){var s,f,i,x;if($9(g)){s=g.style;f=(s.visibility==$6)?_m[m][16]:_m[m][15];if(f){if(g.filters[0])g.filters[0].stop();i="";i="FILTER:";f=f.split(";");for(x=0;x<f.length;x++){i+=" progid:DXImageTransform.Microsoft."+f[x];if($tU(_nv).indexOf("MSIE 5.5")>0)x=_aN;}s.filter=i;g.filters[0].apply();}}}function $3(g,m){if($9(g)){_flt=(g.style.visibility==$6)?_m[m][15]:_m[m][16];if(_flt)g.filters[0].play()}}function $Y(){var o,s,X,v,D,g=arguments,t,g;D=g[0];v=g[1];o=$c($O+D);if(!o)return;s=o.style;_m[D][22]=o;if(v){M_hideLayer(D,v);X=_mLt*_fLm.length+" ";if(_kLm!=Math.ceil(X.substr(0,10)))_mi=[];if(!_startM)_m[D][23]=1;t=g[2]!=_n?g[2]:_n;l=g[3]!=_n?g[3]:_n;if(t||l)$_E(o,t,l);if(_m[D][5])p$(D);if(s.visibility!=$6){$2(o,D);if(!_m[D][27])s.zIndex=_zi;else s.zIndex=_m[D][27];s.visibility=$6;$3(o,D);$V(D,1);mmVisFunction(D,v);if(!_m[D][7])_m[D][21]=_itemRef;$mD++}$1(D)}else{if(_m[D][21]>-1&&_itemRef!=_m[D][21])d$(_m[D][21]);if(ns6||s.visibility==$6){if(!(ie||op7)&&_m[D][13]==$_O)s.overflow=$5;hmL(D);$V(D,0);mmVisFunction(D,v);$2(o,D);s.visibility=$5;if(!ie)s.top="-9999px";$3(o,D);$mD--}_m[D][21]=-1}}function $Z(){var g,a,M;if(inEditMode)return;g=arguments;if(t_>-1)d$(t_,1);t_=-1;_oMT=$P(_oMT);for(a=0;a<_m.length;a++){M=_m[a];if(M&&!M[7]&&!M[10]&&g[0]!=a){$Y(a);M_hideLayer(a,0)}else{hmL(a)}}_zi=_WzI;_itemRef=-1;$j=-1;if(_W.resetAutoOpen)_ocURL()}function $d(v){if(v+" "==$u)return-1;return _mi[v][0]}function $e(v){var t,x;t=$d(v);if(t==-1)return-1;for(x=0;x<_mi.length;x++)if(_mi[x]&&_mi[x][3]==_m[t][1])return _mi[x][0]}_mLt=8294.4;function $f(v){var t,x;t=$d(v);if(t==-1)return-1;for(x=0;x<_mi.length;x++)if(_mi[x][3]==_m[t][1])return x}function $h(v){v=$tL(v);for(var x=0;x<_m.length;x++)if(_m[x]&&v==_m[x][1])return x}_mot=0;function e$(){var g,i,I,b,H;g=arguments;i=g[0];I=_mi[i];if(I[96])return;H=$c("mmlink"+I[0]);hrs=H.style;_lnk=$c("lnk"+i);if(I[42]&&g[1])_5(I[42]);if((I[34]=="header"&&!I[2])||I[34]=="form"){$c($O+I[0]).onselectstart=_n;hrs.visibility=$5;return}_mot=$P(_mot);u_=$c("el"+i);if(u_.e$==1){$_E(H,u_.t,u_.l,u_.h,u_.w);hrs.visibility=$6;return}u_.e$=1;$y=_m[I[0]];if(!$y[9]&&mac){$1A=$D($c("pTR"+i));if(!$1A)$1A=$D(u_)}else $1A=$D(u_);_pm=$c($O+I[0]);k_=$D(_pm);if(H){H._itemRef=i;H.href=_jv;H.target="_self";if(I[34]!="disabled"){if(sfri)H.href=_n;if(I[2])H.href=I[2];H.title="";if(I[76])H.title=I[76];if(I[35])H.target=I[35];hrs.visibility=$6}hrs.zIndex=1;if(I[34]=="html"){hrs.zIndex=-1;hrs=u_.style}if((I[86]||I[34]=="dragable")&&inDragMode==0){if(_lnk)_lnk.href=_jv;drag_drop(I[0],i);hrs.zIndex=-1}if(u_.pt!=k_[0]||u_.pl!=k_[1]||u_.ph!=k_[2]||u_.pw!=k_[3]){_bwC=0;if(!H.border&&H.border!=I[25]){hrs.border=I[25];H.border=I[25];H.C=$pU(hrs.borderTopWidth)*2}if(H.C)_bwC=H.C;b=_m[I[0]][6][65];v_=0;if(mac)if(_m[I[0]][12])v_=_m[I[0]][12];if(konq||sfri||_OpV)v_-=b;u_.t=$1A[0]-k_[0]+v_;u_.l=$1A[1]-k_[1]+v_;if(ff15&&_m[I[0]][13]==$_O){u_.t=u_.t+(b);u_.l=u_.l+(b)}if(!IEDtD&&ie)_bwC=0;u_.h=$1A[2]-_bwC;u_.w=$1A[3]-_bwC;u_.pt=k_[0];u_.pl=k_[1];u_.ph=k_[2];u_.pw=k_[3]}$_E(H,u_.t,u_.l,u_.h,u_.w)}_Cr=(ns6)?_n:"";hrs.cursor=_Cr;if(I[59]){if(I[59]=="hand"&&ns6)I[59]="pointer";hrs.cursor=I[59]}if(I[32]&&I[29])$c("_img"+i).src=I[32];if(I[3]&&I[3]!="M_doc*"&&I[24]&&I[48])$c("simg"+i).src=I[48];if(_lnk&&!l_){_lnk.oC=_lnk.style.color;if(I[6])_lnk.style.color=I[6];if(I[26])_lnk.style.textDecoration=I[26]}if(I[53]){u_.className=I[53];if(_lnk)_lnk.className=I[53]}if(I[117]&&I[24]&&I[3])$c("simg"+i).className=I[117];if(!l_)if(I[5])u_.style.background=I[5];l_=0;if(I[1]&&I[47])u_.style.backgroundImage="url("+I[47]+")";if(I[110]){b=$c("li108"+i);if(I[1]&&b)b.src=I[110]}if(I[111]){b=$c("ri109"+i);if(I[1]&&b)b.src=I[111]}if(I[71]&&I[90])if($c("sep"+i))$c("sep"+i).style.backgroundImage="url('"+I[90]+"')";if(!mac){if(I[44])_lnk.style.fontWeight="bold";if(I[45])_lnk.style.fontStyle="italic"}showtip()}_kLm=_5($qe("6C4E756D"));function d$(){var g,i,I,n,H;g=arguments;i=g[0];if(i==-1)return;u_=$c("el"+i);if(!u_)return;if(!u_.e$)return;u_.e$=0;_trueItemRef=-1;_gs=u_.style;I=_mi[i];_tI=$c("_img"+i);if(_tI&&I[29])_tI.src=I[29];if(I[3]&&I[24]&&I[48])$c("simg"+i).src=I[24];_lnk=$c("lnk"+i);if(_lnk){if(_startM||op||sfri)_lnk.oC=I[8];if(I[34]!="header")_lnk.style.color=_lnk.oC;if(I[26])_lnk.style.textDecoration="none";if(I[33])_lnk.style.textDecoration=I[33]}if(I[116]&&I[24]&&I[3]){$c("simg"+i).className=I[116]}if(I[54]){u_.className=I[54];if(_lnk)_lnk.className=I[54]}if(I[7])_gs.background=I[7];if(I[9])_gs.border=I[9];if(I[46])_gs.backgroundImage="url("+I[46]+")";if(I[108]){b=$c("li108"+i);if(I[1]&&b)b.src=I[108]}if(I[109]){b=$c("ri109"+i);if(I[1]&&b)b.src=I[109]}if(I[71]){s_I=$c("sep"+i);if(s_I)s_I.style.backgroundImage="url("+I[71]+")"}if(!mac){n="normal";if(I[44]&&(I[14]==n||!I[14]))_lnk.style.fontWeight=n;if(I[45]&&(I[13]==n||!I[13]))_lnk.style.fontStyle=n}if(!_startM)hidetip()}function $1C(v){for(var a=0;a<v.length;a++){if(v[a]!=$m){_m3=_m[v[a]];if(_m3&&!(_m3[7]))$Y(v[a])}}}function f$(){_st=-1;_en=_sm.length;_mm=_iP;if(_iP==-1){if(_sm[0]!=$j)return _sm;_mm=$j}for(_b=0;_b<_sm.length;_b++){if(_sm[_b]==_mm)_st=_b+1;if(_sm[_b]==$m)_en=_b}if(_st>-1&&_en>-1){_tsm=_sm.slice(_st,_en)}return _tsm}function _cm3(){_tar=f$();$1C(_tar);for(_b=0;_b<_tar.length;_b++){if(_tar[_b]!=$m)_sm=_p8(_sm,_tar[_b])}}function $r(){_dB=_d.body;if(!_dB)return;$7=_dB.offsetTop;$8=_dB.offsetLeft;if(!op&&_d.all){_mc=_dB;if(IEDtD&&!mac&&!op7)_mc=_d.documentElement;if(!_mc)return;_bH=_mc.clientHeight;_bW=_mc.clientWidth;_sT=_mc.scrollTop;_sL=_mc.scrollLeft;if(konq)_bH=_W.innerHeight}else{_bH=_W.innerHeight;_bW=_W.innerWidth;if(ns6&&_d.documentElement.offsetWidth!=_bW)_bW=_bW-16;_sT=self.scrollY;_sL=self.scrollX;if(op){_sT=_dB.scrollTop;_sL=_dB.scrollleft}}}_fLm=_5($qe("6C55524C"));function $W(i){var I=_mi[i];if(I[3]){_p6=I[39];I[39]=0;_oldMD=_menuOpenDelay;_menuOpenDelay=0;_gm=$c($O+$h(I[3]));_ofMT=1;if(_gm.style.visibility==$6&&I[40]){$Y($h(I[3]));e$(i)}else{h$(i)}_menuOpenDelay=_oldMD;I[39]=_p6}}function $x(v){var vv=0;if(v)vv=v;if(isNaN(v)&&v.indexOf("offset=")==0)vv=$pU(v.substr(7,99));return vv}function popup(){var X,Y,g=arguments;_itemRef=-1;_MT=$P(_MT);_oMT=$P(_oMT);if(g[0]){$m=$h(g[0]);if($m>=0&&!_m[$m].tooltip)$Z($m);_M=_m[$m];if(!_M)return;if(!_M[23])g$($m);_gm=$c($O+$m);if(!_gm)return;j_=$D(_gm);_sm[_sm.length]=$m;$pS=0;if(!_startM&&_M[13]==$_O)$pS=1;_tos=0;_los=0;if(_M[2])if(isNaN(_M[2]))_tos=$x(_M[2]);else Y_=_M[2];if(_M[3])if(isNaN(_M[3]))_los=$x(_M[3]);else X_=_M[3];if(g[2])_tos=g[2];if(g[3])_los=g[3];Y=Y_+_tos;X=X_+_los;if(g[1]){if(g[1]==1){if(!ns6){if(!_M[3]||isNaN(_M[3]))X+=_sL;if(!_M[2]||isNaN(_M[2]))Y+=_sT}}else if(g[1]==2){Y=g[2];X=g[3]}else{_po=$c(g[1]);k_=$D(_po);Y=(k_[0]+k_[2]+_tos)+$7;X=(k_[1]+_los);if(g[4])_M.ttop=_ttop}if(!_M[25]&&!g[4]){if(Y+j_[2]+16>(_bH+_sT))Y=_bH-j_[2]+_sT-16;if(X+j_[3]+16>(_bW+_sL))X=_bW-j_[3]+_sL-16}}if(ns6&&_W.fixMozillaZIndex){X-=_sL;Y-=_sT}_zi=_zi+1;_oMT=$P(_oMT);_moD=(g[5])?g[5]:0;if(!_startM)_oMT=_StO("$Y("+$m+",1,"+Y+","+X+")",_moD);_M[21]=-1}}function popdown(){_ofMT=1;_MT=_StO("$Z()",_menuCloseDelay);_oMT=$P(_oMT)}function g$(m){if(op5||op6)return;if(_W.buildAfterLoad){if(!_lDd)return;createNewMenu(m)}_gm=$c($O+m);if(!_gm)return;if(!_m[m][23])$_E(_gm,-9999);_it=o$(m,0);_mcnt--;_gm.innerHTML=_it;$z(m)}$j=-1;function _colD(){}function h$(i,o){if(i<0)return;var I,_M;if(_itemRef>-1&&_itemRef!=i)hmL(_mi[_itemRef][0]);I=_mi[i];if(!I[65])I[65]=0;I[3]=$tL(I[3]);_mopen=I[3];$m=$h(_mopen);_M=_m[$m];if(_M){if(_M[21]>-1&&_M[21]!=i)d$(_M[21]);_M[21]=i}if(I[34]=="ToolTip")return;if(!I||_startM||inDragMode)return;$y=_m[I[0]];_MT=$P(_MT);if(_m[I[0]][7]&&$j!=I[0]&&!inEditMode){hmL($j);$1C(_sm);_oMT=$P(_oMT);_sm=[];if(!_W.resetAutoOpen)_DC()}if(_M&&!_M[23]&&_mopen){g$($m);if(!_lDd)return}if(t_>-1){_gm=0;if(I[3]){_gm=$c($O+$h(I[3]));if(_gm&&_gm.style.visibility==$6&&i==t_){e$(i,1);return}}if(t_!=i)k$(t_);_oMT=$P(_oMT)}_cMT=$P(_cMT);$m=-1;_itemRef=i;_trueItemRef=i;I=_mi[i];_moD=(_M&&_M[28])?_M[28]:_menuOpenDelay;if(I[94])_moD=I[94];$Q=0;if($y[9]){$Q=1;if(!_W.horizontalMenuDelay)_moD=0}_vq=_M?1:0;e$(i,1);if(_vq&&!_M)return;if(!_sm.length){_sm[0]=I[0];$j=I[0]}_iP=$d(i);if(_iP==-1)$j=I[0];_cMT=_StO("_cm3()",_moD);if(_mopen&&I[39]){_gm=$c($O+$m);if(_gm&&_gm.style.visibility==$6){_cMT=$P(_cMT);_tsm=_sm[_sm.length-1];if(_tsm!=$m)$Y(_tsm)}}if(_W.forgetClickValue)$R1=0;if(_mopen&&(!I[39]||$R1)&&I[34]!="tree"&&I[34]!="disabled"){_pm=$c($O+I[0]);k_=$D(_pm);$m=$h(_mopen);if(_M&&I[41])_M[10]=1;if($y.kAm!=_n&&$y.kAm+" "!=$u){_sm[_sm.length]=$y.kAm}$y.kAm=_n;if(_M&&_M[10]){$y.kAm=$m}if($m>-1){_mnO=$c($O+$m);_mp=$D(_mnO);u_=$c("el"+i);if(!$Q&&mac)u_=$c("pTR"+i);j_=$D(u_);if($Q){$l=j_[1];$k=k_[0]+k_[2]-I[65]}else{$l=k_[1]+k_[3]-I[65];$k=j_[0]}if(!$Q&&$y[13]==$_O&&!op){$k=(ns6&&!ns7)?$k-gevent:$k-_pm.scrollTop}_M=_m[$m];if(_M[2]!=_n)if(isNaN(_M[2])&&_M[2].indexOf("offset=")==0)$k=$k+$x(_M[2]);else $k=_M[2];if(_M[3]!=_n)if(isNaN(_M[3])&&_M[3].indexOf("offset=")==0)$l=$l+$x(_M[3]);else $l=_M[3];var S=0;if(!_M[25]){if(!$Q&&(!_M[2]||isNaN(_M[2]))){_hp=$k+_mp[2];if(_hp>_bH+_sT){$k=(_bH-_mp[2])+_sT-4}if(ns6){S=18;if(!window.scrollMaxX)S=0;if(_hp+S>_bH+_sT)$k=$k-S}}if($l+_mp[3]+3>_bW+_sL){if(!$Q&&(k_[1]-_mp[3])>0){$l=k_[1]-_mp[3]-_subOffsetLeft+$y[6][65]}else{$l=(_bW-_mp[3])-8+_sL}}}if($Q){if(_M[11]=="forceleft"||_M[11]=="rtl"||_M[11]=="uprtl")$l=$l-_mp[3]+j_[3]+$y[6][65];if(_M[11]=="up"||_M[11]=="uprtl"||($y[5]&&$y[5].indexOf("bottom")!=-1)){$k=k_[0]-_mp[2]-1-$x(_M[2])}}else{if(_M[11]=="forceleft"||_M[11]=="rtl"||_M[11]=="uprtl")$l=k_[1]-_mp[3]-(_subOffsetLeft*2);if(_M[11]=="up"||_M[11]=="uprtl"){$k=j_[0]-_mp[2]+j_[2]-$x(_M[2])}$k+=_subOffsetTop;$l+=_subOffsetLeft}if(ns60){$l-=$y[6][65];$k-=$y[6][65]}if(mac){$l-=$y[12]+$y[6][65];$k-=$y[12]+$y[6][65]}if(sfri&&$y[14]=="relative"){$l+=$8;$k+=$7}if(ns6&&_W.fixMozillaZIndex){if($y[14]!="fixed"){$l-=_sL;$k-=_sT}_gmt=$c("tbl"+$m);_gt=$D(_gmt);if($Q){if(_M[13]==$_O&&$k+_gt[2]>_bH)$k+=_sT}else{if($k+_gt[2]>_bH)$k=_bH-_gt[2]-S-2}}if($l<0)$l=0;if($k<0)$k=0;if(o){$Y($m)}else{_oMT=_StO("$Y("+$m+",1,"+$k+","+$l+")",_moD)}_zi++;if(_sm[_sm.length-1]!=$m)_sm[_sm.length]=$m}}isEditMode(i);if(!I[114])i$(_iP);t_=i;if(_ofMT==0)_oMT=$P(_oMT);_ofMT=0;if(_mopen&&_mopen.substr(0,5)=="ajax:")_maxm(_mopen)}_sBarW=0;function $1(m){var hm,hmT;if(op)return;_M=_m[m];if(!_M||_M[13]!="scroll")return;if(_M.ttop){_o4s=_M[2];_M[2]=_M.ttop}hm=$Q;if(_M[21]>-1){hmT=_m[_mi[_M[21]][0]];if(hmT[7]&&hmT[9])hm=1}_gm=$c($O+m);if(!_gm||_M[9])return;_mp=$D(_gm);if(!_M.sW)_M.sW=_mp[3];_gmt=$c("tbl"+m);_gt=$D(_gmt);_MS=_M[6];_Bw=_MS[65]*2;_Mw=_M[12]*2;_smt=_gt[2];if(hm)_smt=_gt[2]+_gt[0]-_sT;if(_smt<_bH-16){_gm.style.overflow="";$k=_n;if(!hm&&(_gt[0]+_gt[2]+16)>(_bH+_sT)){$k=(_bH-_gt[2])+_sT-6-$x(_M[2])}if(!_M[24])$_E(_gm,$k,_n,_gt[2],_gt[3]);if(!_M[24]){if(_M.ttop)_M[2]=_o4s;return}}_gm.style.overflow="auto";i_=_gt[3];if(!$BW){$_E(_gm,_n,_n,50,40);$BW=parseInt(_gm.style.width)-_gm.clientWidth;if(mac)$BW=18}$k=_n;if(hm){_ht=_bH-_gt[0]-8+_sT}else{_ht=_bH-_Mw-14;$k=6+_sT}$l=_n;if(!_M[25]&&_mp[1]+i_>(_bW+_sL))$l=(_bW-i_)-2;if(_M[2]&&!isNaN(_M[2])){$k=_M[2];_ht=(_bH+_sT)-$k-6;if(_ht>_gt[2])_ht=_gt[2]}if(_M[24])_ht=_M[24];i_+=$BW+_Mw;if(ns6&&!ns7)i_=_gt[3]+15;if(ns6){var S=18;if(!window.scrollMaxX)S=0;_hp=$k+_gt[2];if(_hp+S>_bH+_sT)_ht=_ht-S;if(_W.fixMozillaZIndex){if(hm)$k=_mp[0]-_sT;else $k=5}}if(_ht>0){if(_M[24])$k=_n;if(_M[11]=="up")_ht=_bH-$x(_M[2])-10;$_E(_gm,$k,$l,_ht+2-_M[12],i_);if(_M[24]&&!_M[25]){_mp=$D(_gm);if(_mp[0]+_mp[2]-_sT>_bH){$k=_mp[0]-_mp[2]}$_E(_gm,$k)}}if(_M.ttop)_M[2]=_o4s}function i$(p){var c,i;if(p>-1){c=_m[p][21];while(c>-1){i=_mi[c];if(i[34]!="tree")e$(c);if(c==_m[i[0]][21])return;c=_m[i[0]][21]}}}function $I(){if(_W.inResizeMode>-1)return;_mot=_StO('k$(this._itemRef)',10);_MT=_StO("$bb()",_menuCloseDelay);_ofMT=1;focusedMenu=-1}function $bb(){if(inEditMode)return;if(_ofMT==1){$Z();$R1=0}}function $J(s){if(_W.inResizeMode>-1)return;_mot=$P(_mot);_MT=$P(_MT);_ofMT=0;focusedMenu=s;doMenuResize(focusedMenu)}function $Cw(i){if(i[18])i[8]=i[18];if(i[19])i[7]=i[19];if(i[56])i[29]=i[56];if(i[69])i[46]=i[69];if(i[85]&&i[3])i[24]=i[85];if(i[72])i[54]=i[72];if(i[75])i[9]=i[75];if(i[92])i[71]=i[92];if(i[102])i[6]=i[102];if(i[104])i[32]=i[104];if(i[112])i[108]=i[112];if(i[113])i[109]=i[113];i.cpage=1}function $q(i){_hrF=_L.pathname+_L.search+_L.hash;_hx=_Lhr.split("/");_fNm="/"+_hx[_hx.length-1];var I,t,p,u,x;I=_mi[i];t=0;if(I[77]){p=I[77].split(",");for(x=0;x<p.length;x++)if(_hrF.indexOf(p[x])>-1)t=1}if(I[2]){u=I[2];if(_hrF==u||_hrF==u+"/"||u==_Lhr||u+"/"==_Lhr||_fNm=="/"+u)t=1}if(t==1){$Cw(I);_cip[_cip.length]=i}}function _cA(_N,_O,i){var I,g;I=_mi[i];if(I[_N]){_tmp=I[_N];I[_N]=I[_O];I[_O]=_tmp}else return;g=$c("el"+i);g.e$=1;if(_N==81&&I[7]){g.style.background=I[7];l_=1}if(_N==80&&I[8]&&I[1]){$c("lnk"+i).oC=I[8];$c("lnk"+i).style.color=I[8];l_=1}if(_N==87&&I[54]){g.className=I[54]}if(_N==88&&I[46]){g.style.backgroundImage="url("+I[88]+")";d$(i)}if(_N==91&&I[71]){$c("sep"+i).style.backgroundImage="url("+I[91]+")"}_gm=$c("simg"+i);if(_gm&&_N==83&&I[24]&&I[3])_gm.src=I[24];_gm=$c("_img"+i);if(_gm&&_N==82&&I[29])_gm.src=I[29]}function _caA(i){_cA(80,8,i);_cA(81,7,i);_cA(82,29,i);_cA(83,24,i);_cA(87,54,i);_cA(88,46,i);_cA(91,71,i)}function sCM(m,f){var a,M,i,I;for(a=0;a<_m[m][0].length;a++){i=_m[m][0][a];I=_mi[i];if(I[3]){M=$h(I[3]);if(M){_m[M][7]=0;eval(f);sCM(M,f)}}}}l_=0;function $K(i){var I,t,M,a;I=_mi[i];M=_m[I[0]];if(!_W.resetAutoOpen&&!I[34]&&!I[41]&&(I[2]||I[40]))$Z();if(M[11]=="tab"){t=$h(I[3]);sCM(I[0],"$Y(M)");if(t){if(M.Tm&&M.Tm!=t){_m[M.Tm][7]=0;$Y(M.Tm);$c("el"+M.Ti).e$=1;_caA(M.Ti);d$(M.Ti)}if(M.Tm!=t)_caA(i);M.Tm=t;M.Ti=i;if(M.Tm)_m[M.Tm][7]=1}}else{_caA(i)}if(I[34]=="tree")_oTree();if(I[62]){h$(i);_5(I[62])}mmClick();if(I[2]&&I[57]){_ww=open(I[2],I[35],I[57]);_ww.focus();return false}if(I[2]){if(I[34]=="html")_Lhr=I[2];if($c("mmlink"+I[0]).tagName=="DIV")_L.href=I[2]}$R1=0;if(I[39]){$R1=1;$W(i)}if(I[115]=="retFalse")return false}function $t(I,_gli,M){if(!I[1])return "";_Ltxt=I[1];_TiH=((I[34]=="header"||I[34]=="form"||I[34]=="dragable"||I[86]||!I[2])?1:0);_ofc=(I[8]?"color:"+I[8]:"");if(!_TiH&&I[58]&&!I.cpage)_ofc="";_fsize=(I[12]?";font-Size:"+I[12]:"");_fstyle=(I[13]?";font-Style:"+I[13]:";font-Style:normal");_fweight=(I[14]?";font-Weight:"+I[14]:";font-Weight:normal");_ffam=(I[15]?";font-Family:"+I[15]:"");_tdec=(I[33]?";text-Decoration:"+I[33]:";text-Decoration:none;");_disb=(I[34]=="disabled"?"disabled":"");_clss="";if(I[54]){_clss=" class='"+I[54]+"'";if(!I[33])_tdec="";if(!I[13])_fstyle="";if(!I[14])_fweight=""}else if(I[58]){_clss=" class='"+_m[_mi[_gli][0]][6].g_+"'"}m_ee=" ";if(!_TiH)m_ee=" onclick=\"return $K("+_gli+")\" ";_rawC=(I[78]?";"+I[78]:"");$1B="";if(M[8])$1B+=";text-align:"+M[8];else if(I[36])$1B+=";text-align:"+I[36];_HREF=_jv;if(I[2])_HREF=I[2];if(I[105]=="on")_Ltxt=I[1].replace(_5("//g"),"&nbsp;");m_e="a ";if(I[34]=="form"||I[34]=="header"||I[34]=="html")m_e="div ";_link='<'+m_e+_p5+m_ee+' name=mM1 onfocus=_iF0C('+_gli+') href="'+_HREF+'" '+_disb+_clss+' id=lnk'+_gli+' style="border:none;background:transparent;display:block;'+_ofc+_ffam+_fweight+_fstyle+_fsize+_tdec+$1B+_rawC+'">'+_Ltxt+'</'+m_e+'>';return _link}function hmL(_mn){_hm=$c("mmlink"+_mn);if(_hm)_hm.style.visibility=$5}function k$(i){var I=_mi[i];if(!I)return;_oMT=$P(_oMT);if(i>-1)hmL(I[0]);d$(i,1);o_IR=_itemRef;_itemRef=i;if(I&&I[43])_5(I[43]);_itemRef=o_IR}function _p2(M,t){t.style.width="auto";var m=_m[M];if(m[13]!=$_O){$z(M);if(m[5])p$(M)}m.Q=_StO("$1("+M+")",500)}function m$(i,_Tel){var I,_M,A,a,S;_it="";_el=_Tel;I=_mi[_el];$m=I[0];_M=_m[$m];if(_M[11]=="tab")I[39]=1;$q(_el);if(I[34]=="header"){if(I[20])I[8]=I[20];if(I[21])I[7]=I[21];if(I[74])I[9]=I[74]}_ofb=(I[46]?"background-image:url("+I[46]+");":"");if(!_ofb)_ofb=(I[7]?"background:"+I[7]+";":"");$n=" onmouseover=h$("+_Tel+") ";_link=$t(I,_el,_M);$o="";if(_M[18])$o="height:"+$pX(_M[18]);if(I[28])$o="height:"+$pX(I[28]);_clss="";if(I[54])_clss=" class='"+I[54]+"' ";if($Q){if(i==0)_it+="<tr>";if(I[50])I[27]=I[50]}else{if(I[49])I[27]=I[49];if(_M[26]&&!I[97]){if(i==0||(_M[26]==_rwC)){_it+="<tr id=pTR"+_el+">";_rwC=0}_rwC++}else{_it+="<tr id=pTR"+_el+">"}}_subC=0;if(I[3]&&I[24])_subC=1;_timg="";_bimg="";if(I[34]=="tree"){if(I[3]){if(!I[30])I[30]=" top"}else{if(I[79]){_subC=1;I[24]=I[79];I[3]="M_doc*"}}}if(I[29]){_imalgn="";if(I[31])_imalgn=" align="+I[31];_imvalgn="";if(I[30])_imvalgn=" valign="+I[30];_imcspan="";if(_subC&&_imalgn&&I[31]!="left")_imcspan=" colspan=2";_Iwid=(I[38])?"width:"+I[38]+"px;":"width:0;";_Ihgt=(I[37])?"height:"+I[37]+"px;":"";_impad=(I[60])?" style='padding:"+$pX(I[60])+"'":"";_alt=(I[76])?" alt='"+I[76]+"'":"";_timg="<td id=_imgO"+_el+" "+_imcspan+_imvalgn+_imalgn+_impad+">"+(I[84]?"<a href='"+I[84]+"'>":"")+"<img onload=_p2("+$m+",this) border="+(I[89]?I[89]:0)+" style='display:block;"+_Iwid+_Ihgt+"' "+_alt+" id=_img"+_el+" src='"+I[29]+"'>"+(I[84]?'</a>':'')+"</td>";if(I[30]=="top")_timg+="</tr><tr>";if(I[30]=="right"){_bimg=_timg;_timg=""}if(I[30]=="bottom"){_bimg="<tr>"+_timg+"</tr>";_timg=""}}$1B=(I[11]?";padding:"+$pX(I[11]):"");if(!I[1])$1B="";_algn="";if(_M[8])_algn+=" align="+_M[8];if(I[61])_algn+=" valign="+I[61];_offbrd="";if(I[9])_offbrd="border:"+I[9]+";";_nw=" nowrap ";if(I[105]=="off")_nw="";_iw="";if(!$Q&&_M[17])_iw=_M[17];if(_M[4])_iw=_M[4];if(I[55])_iw=I[55];if(I[55]!=_M[6].itemwidth)_iw=I[55];if($Q&&isNaN(_iw)&&_iw.indexOf("%")>-1)_iw=Math.ceil(100/_M[0].length)+"%";if(_M[31])_nw="";if(_iw){_nw="";_iw=" width="+_iw}if(I[97]){_iw+=" colspan="+I[97];_rwC=_M[26]}if(I[108]){_subC=1}if(_subC||I[29]){x_="";w_="";b_="";d_="";if(I[3]&&I[24]){A=0;if(IEDtD&&(_M[11]=="rtl"||_M[11]=="uprtl"))A=1;var C=I[116]?" class="+I[116]:"";_img="<img id=simg"+_el+" onload=_p2("+$m+",this) src='"+I[24]+"'"+C+" style='width:0px;'>";a_P="";if(I[22])a_P=";padding:"+$pX(I[22]);_imps="width=1";if(I[23]){_iA="width=1";_ivA="";_imP=I[23].split(" ");for(a=0;a<_imP.length;a++){if(_imP[a]=="left")A=1;if(_imP[a]=="right")A=0;if(_imP[a]=="top"||_imP[a]=="bottom"||_imP[a]=="middle"){_ivA="valign="+_imP[a];if(_imP[a]=="bottom")A=0}if(_imP[a]=="center"){b_="<tr>";d_="</tr>";_iA="align=center width=100%"}}_imps=_iA+" "+_ivA}_its=b_+"<td "+_imps+" style='font-size:1px"+a_P+";'>";_ite="</td>"+d_;if(A){x_=_its+_img+_ite}else{w_=_its+_img+_ite}}_it+="<td "+_iw+" id=el"+_el+$n+_clss+" style='padding:0px;"+_offbrd+_ofb+$o+";'>";_pw=" width=100% ";if(_W.noSubImageSpacing)_pw="";_it+=_TbS+_pw+" height=100% id=MTbl"+_el+">";_it+="<tr id=td"+_el+">";if(I[108])_it+="<td><img id=li108"+_el+" src="+I[108]+"></td>";_it+=x_;_it+=_timg;if(_link)_it+="<td "+_pw+_nw+_algn+" style='"+$1B+";'>"+_link+"</td>";_it+=_bimg;_it+=w_;if(I[109])_it+="<td><img id=ri109"+_el+" src="+I[109]+"></td>";_it+="</tr>";_it+="</table>";_it+="</td>"}else{if(_link)_it+="<td "+_iw+_clss+_nw+" id=el"+_el+$n+_algn+" style='"+$1B+_offbrd+$o+_ofb+";'>"+_link+"</td>"}S="";if((_M[0][i]!=_M[0][_M[0].length-1])&&I[27]>0){c$="";if(!I[10])I[10]=I[8];_sbg=";background:"+I[10];if(I[71])_sbg=";background-image:url("+I[71]+");";if($Q){if(I[49]){_sepA="middle";if(I[52])_sepA=I[52];S="";if(I[51])S="style=padding:"+$pX(I[51]);_it+="<td id=sep"+_el+" nowrap "+S+" valign="+_sepA+" align=left width=1px><div style='font-size:1px;width:"+$pX(I[27])+";height:"+$pX(I[49])+";"+c$+_sbg+";'></div></td>"}else{if(I[16]&&I[17]){_bwid=I[27]/2;if(_bwid<1)_bwid=1;q_=_bwid+"px solid ";c$+="border-right:"+q_+I[16]+";";c$+="border-left:"+q_+I[17]+";";c$="";_iT=_TbS+"><td></td></table>";if(ns6||ns7)_iT="";_it+="<td style='empty-cells:show;"+c$+";'>"+_iT+"</td>"}else{if(I[51])S="<td nowrap width="+$pX(I[51])+"></td>";_it+=S+"<td id=sep"+_el+" style='padding:0px;width:"+$pX(I[27])+c$+_sbg+";'>"+_TbS+" width="+I[27]+"><td style='padding:0px;'></td></table></td>"+S}}}else{if(I[16]&&I[17]){_bwid=I[27]/2;if(_bwid<1)_bwid=1;q_=_bwid+"px solid ";c$="border-bottom:"+q_+I[16]+";";c$+="border-top:"+q_+I[17]+";";if(mac||ns6||sfri||konq||IEDtD||op)I[27]=0}if(I[51])S="<tr><td height="+I[51]+"></td></tr>";_sepW="100%";if(I[50])_sepW=I[50];_sepA="center";if(I[52])_sepA=I[52];if(!mac)_sbg+=";overflow:hidden";_it+="</tr>"+S+"<tr><td style=padding:0px; id=sep"+_el+" align="+_sepA+"><div style='"+_sbg+";"+c$+"width:"+$pX(_sepW)+";padding:0px;height:"+$pX(I[27])+"font-size:1px;'></div></td></tr>"+S+""}}if(I[34]=="tree"){if(ie&&!mac){_it+="<tr id=OtI"+_el+" style='display:none;'><td></td></tr>"}else{_it+="<tr><td style='height:0px;' valign=top id=OtI"+_el+"></td></tr>"}}return _it}function $z(U){var M=_m[U];_gm=$c($O+U);if(_gm){_gmt=$c("tbl"+U);if(_gmt){$S=_gm.style;$T=_gmt.offsetWidth;if((M[14]=="relative"))if(!M[17])$S.width=$T+"px";if(mac){s_=(M[12]*2+M[6][65]*2);_MacA=$D(_gmt);if(_MacA[2]==0&&_MacA[3]==0){_StO("$z("+U+")",200);return}if(IEDtD)s_=0;$S.overflow=$5;$S.height=$pX(_MacA[2]+s_);$S.width=$pX(_MacA[3]+s_)}if(M[31]>0)if($T>M[31])$_E(_gm,_n,_n,_n,M[31])}}}gevent=0;function _p3(evt,$m){if(evt.target.tagName=="TD"){_egm=$c($O+$m);gevent=evt.layerY-(evt.pageY-$7)+_egm.offsetTop}}function $pX(){var g,x,p;g=arguments;x=g[1]?"":";";p=(!isNaN(g[0]))?g[0]+="px"+x:g[0]+x;return p}function _eMD(d){_it=d.split(":");return _it[1].replace(/;/g,"")}function createNewMenu(y){var M,o,b;_startM=0;M=_m[y];o=_d.createElement("div");o.id="menu"+y;o.onmouseout=new Function("$I()");o.onmouseover=new Function("$J("+y+")");o.onselectstart=new Function("return _f");if(_dB.appendChild){_dB.appendChild(o);o$(y,0);o.className=_cls;n=o.style;if(M[17])n.width=M[17]+"px";if(M[24])n.height=M[24]+"px";if(_ofb)n.background=_eMD(_ofb);if(p_)n.border=_eMD(p_);o.style.zindex=999;o.style.visibility=_visi;if(n_)n.position=_eMD(n_);if($k)n.top=_eMD($k);if($l)n.left=_eMD($l);if(_bgimg)n.backgroundImage=_eMD(_bgimg);if(_mbgc)n.background=_eMD(_mbgc);M[23]=0}}_fSz="'>";function o$(){var g,_M,bw,L,b,B,A;g=arguments;$m=g[0];B=g[1];_mcnt++;_M=_m[$m];_mt="";if(!_M)return;L=_M[0].length;A=g[2];if(A&&_M[7]==_n){for(b=0;b<L;b++)$q(_M[0][b]);return}if(_W.noTabIndex)_p5=" tabindex=-1 ";else _p5="";_MS=_M[6];y_="";$k="";$l="";if(_M[7]==0)_M[7]=_n;if((!_M[14])&&(!_M[7]))$k="top:-"+$pX(_aN);if(_M[2]!=_n)if(!isNaN(_M[2]))$k="top:"+$pX(_M[2]);if(_M[3]!=_n)if(!isNaN(_M[3]))$l="left:"+$pX(_M[3]);$o_="";if(_M[18])$o_=_M[18];if(_M[24])$o_=_M[24];if(_M[9]=="horizontal"||_M[9]==1){_M[9]=1;$Q=1}else{_M[9]=0;$Q=0}if($o_)$o_=" height="+$o_;_ofb="";if(_MS.offbgcolor)_ofb="background:"+_MS.offbgcolor;p_="";q_="";bw="";if(_MS[65]){_brdsty=_MS[64]?_MS[64]:"solid";_brdcol=_MS.offcolor?_MS.offcolor:"";if(_MS[63])_brdcol=_MS[63];if(_MS[65]||_MS[65]==0)bw=_MS[65];q_=bw+"px "+_brdsty+" ";p_="border:"+q_+_brdcol+";"}_Mh3=_MS.high3dcolor;_Ml3=_MS.low3dcolor;if(_Mh3&&_Ml3){_h3d=_Mh3;_l3d=_Ml3;if(_MS.swap3d){_h3d=_Ml3;_l3d=_Mh3}q_=bw+"px solid ";p_="border-bottom:"+q_+_h3d+";";p_+="border-right:"+q_+_h3d+";";p_+="border-top:"+q_+_l3d+";";p_+="border-left:"+q_+_l3d+";"}_ns6ev="";if(_M[13]==$_O&&ns6&&!ns7)_ns6ev="onmousemove='_p3(event,"+$m+")'";_bgimg=_MS.menubgimage?";background-image:url("+_MS.menubgimage+");":"";if(!_M[14]&&!_M[7]&&_W.fixMozillaZIndex&&ns6)_M[14]="fixed";n_=B$;if(_M[14]){n_=_M[14];if(_M[14]=="relative"){$k="";$l=""}if(_M[14]=="fixed"&&!ns6)n_=B$}$1B="padding:0px;";if(_M[12])$1B=";padding:"+$pX(_M[12]);_cls="mmenu";if(_MS.offclass)_cls=_MS.offclass;if(n_)n_="position:"+n_;_visi=$5;_mbgc="";if(B==1){_hght="";if(_M[17])_hght=";width:"+$pX(_M[17]);if(_M[24])_hght+=";height:"+$pX(_M[24]);if(_MS.menubgcolor)_mbgc=";background-color:"+_MS.menubgcolor;if(_M[11]=="rtl")$1B+="align:right;";_mali=_M[20]?";text-align:"+_M[20]:"";_rcss=_M[34]?_M[34]:"";_mt+="<div class=mmenucontainer onmouseout=$I() onmouseover=$J("+$m+") onselectstart='return 0' "+_ns6ev+" id=menu"+$m+" style='"+_rcss+$1B+_ofb+";"+p_+_hght+"z-index:999;visibility:"+_visi+";"+n_+";"+$k+";"+$l+_bgimg+_mbgc+_mali+"'>"}if(_M[7]||!_startM||(op5||op6)||_W.buildAllMenus){_M[23]=1;if(!(mac)&&ie)_fSz="font-size:999px;'>&nbsp;";_rwC=0;if($Q){if(_M[26]>1)_rwC=Math.ceil(_M[0].length/_M[26]);_rwT=_rwC}else{if(_M[4])y_=_M[4];if(_M[6].itemwidth)y_=_M[6].itemwidth}_mali="";if(_M[20])_mali=" align="+_M[20];if(y_)y_=" width="+y_;if(!_M[32])y_+=" "+$o_;_mt+=_TbS+y_+" id=tbl"+$m+_mali+">";for(b=0;b<_M[0].length;b++){_mt+=m$(b,_M[0][b]);_el++;if($Q&&_rwC>1){if(b+1==_rwT){_mt+="</tr><tr>";_rwT=_rwT+_rwC}}}if(mac&&!$Q)_mt+="<tr><td id=btm"+$m+"></td></tr>";_mt+="</table>"+" ";m_e=(_M[6].type=="div"||(ns61&&_M[6].type=="tree")?"div":"a");m_e+=_p5;_mt+="<"+m_e+" name=mM1 id=mmlink"+$m+" href=# onclick='return $K(this._itemRef)' onmouseover='_p1(this);_mot=$P(_mot)' style='outline:none;line-height:normal;background:transparent;text-decoration:none;height:1px;width:1px;overflow:hidden;position:"+B$+";"+_fSz+"</"+m_e+">"}else{if(B==1)for(b=0;b<L;b++){$q(_el);_el++}}if(B==1)_mt+="</div>";if(B==1){if(_W._pageIsXML)_mtX+=_mt;else _d.write(_mt)}else return _mt;if(_M[7]){_M[22]=$c($O+$m)}if(_M[19]){_M[19]=_M[19].toString();_fs=_M[19].split(",");if(!_fs[1])_fs[1]=50;if(!_fs[2])_fs[2]=2;_M[19]=_fs[0];$X($m,_fs[1],_fs[2])}if($m==_m.length-1||(A&&_M[7])){_mst=_StO("$N()",50);$p()}}$S2="6D696C6F6E6963";function $p(){if(!_W.disablePagePath){if(_cip.length>0){for(_c=0;_c<_cip.length;_c++){_ci=_cip[_c];_mni=$f(_ci);if(_mni==-1)_mni=_ci;if(_mni+" "!=$u){while(_mni!=-1){var I=_mi[_mni];$Cw(I);_gi=$c("el"+_mni);if(_gi)_gi.e$=1;d$(_mni);_omni=_mni;_mni=$f(_mni);if(_mni==_omni||_mni+" "==$u)_mni=-1}}}}}}function _p4(V,n){var S,m;S=[];if(isNaN(V[n])&&V[n].indexOf("offset=")==0){S[0]=V[n].substr(7,99);m=S[0].indexOf(";minimum=");if(m>-1){S[1]=S[0].substr(m+9,99);S[0]=S[0].substr(0,m)}V[n]=_n}return S}function p$(m){var M=_m[m];if(M[5]){_gm=$c($O+m);if(!_gm)return;j_=$D(_gm);_LoM=0;if(!_gm.leftOffset){_oSA=_p4(M,3);_gm.leftOffset=_oSA[0];_gm._LoM=_oSA[1]}_lft=_n;if(!M[3]){if(M[5].indexOf("left")!=-1)_lft=0;if(M[5].indexOf("center")!=-1)_lft=(_bW/2)-(j_[3]/2);if(M[5].indexOf("right")!=-1)_lft=(_bW-j_[3]);if(_gm.leftOffset)_lft=_lft+$pU(_gm.leftOffset)}_ToM=0;if(!_gm.topOffset){_oSA=_p4(M,2);_gm.topOffset=_oSA[0];_gm._ToM=_oSA[1]}m_=_n;if(!M[2]>=0){m_=_n;if(M[5].indexOf("top")!=-1)m_=0;if(M[5].indexOf("middle")!=-1)m_=(_bH/2)-(j_[2]/2);if(M[5].indexOf("bottom")!=-1)m_=_bH-j_[2];if(_gm.topOffset)m_=m_+$pU(_gm.topOffset)}if(_lft<0)_lft=0;if(_lft<_gm._LoM)_lft=_gm._LoM;if(m_)m_=$pU(m_);if(_lft)_lft=$pU(_lft);$_E(_gm,m_,_lft);if(M[19])M[19]=m_;if(M[7])$V(m,1);_gm.m_=m_}}function $X(m,c,r){if(!_startM&&!inDragMode){var M=_m[m];_fogm=M[22];h_=$D(_fogm);_tt=(_sT>M[2]-M[19])?_sT-(_sT-M[19]):M[2]-_sT;if(h_&&h_[0]-_sT!=_tt){diff=_sT+_tt;_rcor=(diff-h_[0]<1)?r:-r;_fv=$pU((diff-_rcor-h_[0])/r);if(r==1)_fv=$pU((diff-h_[0]));if(_fv!=0)diff=h_[0]+_fv;$_E(_fogm,diff);if(h_.m_)M[19]=h_.m_;if(ie55){_fogm=$c("ifM"+m);if(_fogm)$_E(_fogm,diff)}}}_fS=_StO("$X('"+m+"',"+c+","+r+")",c)}function $qe(s){var x,q,a;x=s.split("");q="";for(a=0;a<s.length;a++){q+="%"+x[a]+x[a+1];a++}return unescape(q)}$S1="687474703A2F2F7777772E";function $N(){var a;$r();if(_bH!=_oldbH||_bW!=_oldbW){_tMR();for(a=0;a<_m.length;a++){if(_m[a]&&_m[a][7]){$Y(a,1);$z(a)}}}if(_oldbH==0){_oldbH=_bH;if(!_W.disableMouseMove)_d.onmousemove=gMY}if(_startM){$mD=0;$J(-1);_ofMT=1}_startM=0;_oldbH=_bH;_oldbW=_bW;_mst=_StO("$N()",70)}getMenuByItem=$d;getParentMenuByItem=$e;getParentItemByItem=$f;_drawMenu=o$;BDMenu=g$;gmobj=$c;menuDisplay=$Y;gpos=$D;spos=$_E;_fixMenu=$z;getMenuByName=$h;itemOn=e$;itemOff=d$;_popi=h$;clickAction=$K;_setPosition=p$;closeAllMenus=$Z;function $V($m,_on){var _M,F,f,p,g,S;_M=_m[$m];if(ns6||_M.treemenu||_M[14]=="relative"||_W._CFix||!_M[22])return;if(ie55){if(_on){if(_M[7])F="iFM"+$m;else F="iF"+$mD;if(_M.ifr)f=_M.ifr;else f=$c(F);if(!f){if(!_lDd)return;f=_d.createElement("iframe");S=f.style;f.src="javascript:false";f.id=F;S.filter="Alpha(Opacity=0)";S.position=B$;S.className="mmenu";if(_dB.appendChild)_dB.appendChild(f)}p=$D(_M[22]);S=f.style;$_E(f,p[0],p[1],p[2],p[3]);S.visibility=$6;S.zIndex=_M[22].style.zIndex-2;_M.ifr=f}else{g=$c("iF"+($mD-1));if(g){$_E(g,-9999);g.style.visibility=$5;_M.ifr=_n}}}}


/* --- End /home/httpd/public/app_frame/webroot/js/milonic_menu_code.js --- */
/* --- Start /home/httpd/public/app_frame/webroot/js/TrackView.js --- */

function TrackView(pageUrl, category, subcategory)
{
    // Tracker webservice url
    pageUrl = pageUrl.replace(/\//g,'::');
    var url = '/services/TrackView/?track=' + pageUrl + '&category=' + category + '&subcategory=' + subcategory;

    new Ajax.Request(url,
    {
        method:'get',
        onSuccess: function(transport,json)
        {
            if(json)
            {
                // Leave empty for now, it's just transparent tracking
                if(json.status == 'OK')
                {

                }
                else if(json.status == 'ERROR')
                {

                }
            }
        },
        onFailure: function()
        {
            // Leave empty for now, it's just transparent tracking
        }
    }
    );
}

/* --- End /home/httpd/public/app_frame/webroot/js/TrackView.js --- */
/* --- Start /home/httpd/public/app_frame/webroot/js/RotateFourMin.js --- */

/*
 *  RotateFour.js - Class to handle the Featured Stories RotateFour widget
 */

function RotateFourMin( tag ) {

	// time to rotate in seconds
	var ROTATION_TIME = 10;

	// find the content divs in the widget
	var divList = $($$('.Featured')[0]).select( 'div' );

	var currentFeature = 0;
	var currentTicks = 0;

	var featureTimer = setInterval( clockTick, 1000	);

	function showFeature( n ) {
		$(divList[currentFeature]).hide();
		currentFeature = n;
		if( currentFeature >= divList.length ) {
			currentFeature = 0;
		}
		if( currentFeature < 0 ) {
			currentFeature = divList.length - 1;
		}
		$(divList[currentFeature]).show();
	}

	function clockTick() {
		if( ++currentTicks >= ROTATION_TIME ) {
			currentTicks = 0;
			// next!
			showFeature( currentFeature + 1 );
		}
	}

	this.selectFeature = function( n ) {
		currentTicks = 0;
		// if they click the same feature again, just return
		if( n == currentFeature ) {
			return;
		}
		// show the one they want
		showFeature( n );
	};

	this.nextFeature = function() {
		currentTicks = 0;
		showFeature( currentFeature + 1 );
	};

	this.previousFeature = function() {
		currentTicks = 0;
		showFeature( currentFeature - 1 );
	};

}


/* --- End /home/httpd/public/app_frame/webroot/js/RotateFourMin.js --- */
/* --- Start /home/httpd/public/app_frame/webroot/js/RolloverFour.js --- */

/*
 *  RolloverFour.js - Class to handle the Featured Stories RotateFour widget
 */

function RolloverFour( tag ) {

	// find the li tags in the widget
	var liList = $($$('.RolloverFour')[0]).select( 'li' );
	liList.each( function ( li, n ) {
		// give each li an onclick
		// (because of yet another IE6 fuck-up, we need to do the onclick in an href
		//$(li).select( 'a' )[0].setAttribute( 'href', 'javascript:oRotateFour' + tag + '.selectFeature( ' + n + ' )' );
		//$(li).setAttribute( 'onmouseover', 'oRolloverFour' + tag + '.selectFeature( ' + n + ' )' );
		$(li).onmouseover = function () { eval( 'oRolloverFour' + tag + '.selectFeature( ' + n + ' )' ); };
	} );

	// find the content divs in the widget
	var divList = $($$('.Featured')[0]).select( 'div' );

	var currentFeature = 0;

	function showFeature( n ) {
		$(divList[currentFeature]).hide();
		$(liList[currentFeature].select( 'div' )[0]).setAttribute( 'class', '' );
		currentFeature = n >= liList.length ? 0 : n;
		$(liList[currentFeature].select( 'div' )[0]).setAttribute( 'class', 'Selected' );
		$(divList[currentFeature]).show();
	}

	this.selectFeature = function( n ) {
		currentTicks = 0;
		// if they click the same feature again, just return
		if( n == currentFeature ) {
			return;
		}
		// show the one they want
		showFeature( n );
	};

}


/* --- End /home/httpd/public/app_frame/webroot/js/RolloverFour.js --- */
/* --- Start /home/httpd/public/app_frame/webroot/js/RotateFour.js --- */

/*
 *  RotateFour.js - Class to handle the Featured Stories RotateFour widget
 */

function RotateFour( tag ) {

	// time to rotate in seconds
	var ROTATION_TIME = 10;

	// find the li tags in the widget
	var liList = $($$('.RotateFour')[0]).select( 'li' );
	liList.each( function ( li, n ) {
		// give each li an onclick
		// (because of yet another IE6 fuck-up, we need to do the onclick in an href
		$(li).select( 'a' )[0].setAttribute( 'href', 'javascript:oRotateFour' + tag + '.selectFeature( ' + n + ' )' );
	} );

	// find the content divs in the widget
	var divList = $($$('.Featured')[0]).select( 'div' );

	var currentFeature = 0;
	var currentTicks = 0;

	var featureTimer = setInterval( clockTick, 1000	);

	function showFeature( n ) {
		$(divList[currentFeature]).hide();
		// now switch the previous one back (saves execution time in this order)
		$(liList[currentFeature].select( '.Thumb' )[0]).show();
		$(liList[currentFeature].select( '.Arrow' )[0]).hide();
		$(liList[currentFeature].select( 'div' )[0]).setAttribute( 'class', '' );
		currentFeature = n >= liList.length ? 0 : n;
		// switch out the thumb with the arrow on the upcoming li
		$(liList[currentFeature].select( '.Thumb' )[0]).hide();
		$(liList[currentFeature].select( '.Arrow' )[0]).show();
		$(liList[currentFeature].select( 'div' )[0]).setAttribute( 'class', 'Selected' );
		$(divList[currentFeature]).show();
	}

	function clockTick() {
		if( ++currentTicks >= ROTATION_TIME ) {
			currentTicks = 0;
			// next!
			showFeature( currentFeature + 1 );
		}
	}

	this.selectFeature = function( n ) {
		currentTicks = 0;
		// if they click the same feature again, just return
		if( n == currentFeature ) {
			return;
		}
		// show the one they want
		showFeature( n );
	};

}


/* --- End /home/httpd/public/app_frame/webroot/js/RotateFour.js --- */
/* --- Start /home/httpd/public/app_frame/webroot/js/Slideshow.js --- */

/* Slideshow.js */
function Slideshow(url, current, next, prev){
    /* Input */
    this.url = url;
    this.current = current;
    this.next = next;
    this.prev = prev;

    /* Constants */
    this.timeout = null;
    this.rotateTime = 4000;
    this.windowLocation = window.location.href;

    this.play = function(){
        this.timeout = setTimeout('window.location.href="' + this.url + this.next + '?play=true"', this.rotateTime);
    }
    this.pause = function(){
        clearTimeout(this.timeout);
    }

    if(this.windowLocation.indexOf('play=true') !== -1){
        this.play();
    }
}

/* --- End /home/httpd/public/app_frame/webroot/js/Slideshow.js --- */

/* --- Start /home/httpd/public/app_frame/webroot/js/VVVisual.js --- */

/*
 *  VVVisual.js - Effects that are visible to the user
 *
 *  ************************************************************
 *  Note: Before adding any new functions into this class
 *        PLEASE check the prototype and scriptaculous libraries
 *        for duplicate functionality.
 *  ************************************************************
 */

function VVVisual() {

}
//-----------------------------------------------------------------------------
/*
 * PhotoRotator class
 */
//-----------------------------------------------------------------------------
function PhotoRotator(parentId)
{
    //-------------------------------------------------------------------------
    /*
    * Class methods
    */
    //-------------------------------------------------------------------------
    /*
    ** Add a photo to the list of photos to rotate
    **
    ** @param photo - url of photo
    ** @return void
    */
    this.addPhoto = function(photo)
    {
        var div = document.createElement('div');
        var img = document.createElement('img');
        img.className = 'PhotoRotatorImage';
        img.src = photo;
        if(this.index != this.photos.length)
        {
            div.style.display = 'none';
        }
        div.appendChild(img);
        this.parentElement.appendChild(div);
        this.photos.push(div);
    }
    //-------------------------------------------------------------------------
    /*
    ** Set the interval between photos
    **
    ** @param interval - interval between photos in seconds
    ** @return void
    */
    this.setInterval = function(interval)
    {
        if(interval)
        {
            this.intervalTime = interval;
        }
        if(this.interval)
        {
            clearInterval(this.interval);
            this.interval = setInterval(this.next,this.intervalTime * 1000);
        }
    }
    //-------------------------------------------------------------------------
    /*
    ** Toggle play/pause mode
    **
    ** @return void
    */
    this.playPause = function()
    {
        if(this.interval)
        {
            this.pause();
        }
        else
        {
            this.play();
        }
    }
    //-------------------------------------------------------------------------
    /*
    ** Start rotating
    **
    ** @return void
    */
    this.play = function()
    {
        if(this.interval == null)
        {
            var rotatorRefPlay = this;
            this.interval = setInterval(function()
                                        {
                                            rotatorRefPlay.next();
                                        }
                                        ,this.intervalTime * 1000);
            this.controls.src = 'http://assets.westword.com/img/play_controls.gif';
            this.showControls();
        }
    }
    //-------------------------------------------------------------------------
    /*
    ** Stop rotating
    **
    ** @return void
    */
    this.pause = function()
    {
        if(this.interval)
        {
            clearInterval(this.interval);
            this.interval = null;
            this.controls.src = 'http://assets.westword.com/img/play_controls_paused.gif';
        }
    }
    //-------------------------------------------------------------------------
    /*
    ** Show the next photo
    **
    ** @return void
    */
    this.next = function()
    {
        this.index++;
        if(this.index >= this.photos.length)
        {
            this.index = 0;
        }
        if(this.photos.length > 0)
        {
            var i = null;
            for(i = 0; i < this.photos.length; i++)
            {
                //this.photos[i].hide();
                this.photos[i].style.display = 'none';
            }
            if(this.transitionType != '')
            {
                this.hideControls();
                new Effect.toggle(this.photos[this.index],this.transitionType,this.transitionOptions);
                var rotatorRefNext = this;
                setTimeout(function()
                           {
                                rotatorRefNext.showControls();
                           }
                           , this.transitionOptions.duration * 1000);
            }
            else
            {
                //this.photos[this.index].show();
                this.photos[this.index].style.display = '';
            }
        }
    }
    //-------------------------------------------------------------------------
    /*
    ** Show the previous photo
    **
    ** @return void
    */
    this.previous = function()
    {
        this.index--;
        if(this.index < 0)
        {
            this.index = this.photos.length - 1;
        }
        if(this.photos.length > 0)
        {
            var i = null;
            for(i = 0; i < this.photos.length; i++)
            {
                //this.photos[i].hide();
                this.photos[i].style.display = 'none';
            }
            if(this.transitionType != '')
            {
                this.hideControls();
                new Effect.toggle(this.photos[this.index],this.transitionType,this.transitionOptions);
                var rotatorRefPrev = this;
                setTimeout(function()
                           {
                                rotatorRefPrev.showControls();
                           }
                           , this.transitionOptions.duration * 1000);
            }
            else
            {
                //this.photos[this.index].show();
                this.photos[this.index].style.display = '';
            }
        }
    }
    //-------------------------------------------------------------------------
    /*
    ** Set the type of transition to use
    **
    ** @param type - type of transition, possible values: '','appear','slide','blind'
    ** @return void
    */
    this.setTransitionType = function(type)
    {
        switch(type.toLowerCase())
        {
            case 'appear':
                this.transitionType = 'appear';
                break;
            case 'slide':
                this.transitionType = 'slide';
                break;
            case 'blind':
                this.transitionType = 'blind';
                break;
        };
    }
    //-------------------------------------------------------------------------
    /*
    ** Set the duration of the transition
    **
    ** @param duration - duration of transition in seconds
    ** @return void
    */
    this.setTransitionDuration = function(duration)
    {
        this.transitionOptions.duration = duration;
    }
    //-------------------------------------------------------------------------
    /*
    ** Show the controls
    **
    ** @return void
    */
    this.showControls = function()
    {
        this.controls.style.left = (this.parentElement.offsetWidth - 40) + 'px';
        this.controls.style.top = (this.parentElement.offsetHeight - 5) + 'px';
        this.controls.style.visibility = 'visible';
    }
    //-------------------------------------------------------------------------
    /*
    ** Hide the controls
    **
    ** @return void
    */
    this.hideControls = function()
    {
        this.controls.style.visibility = 'hidden';
    }
    //-------------------------------------------------------------------------
    /*
    * Class constructor code
    */
    //-------------------------------------------------------------------------
    // Get the element to attach to
    this.parentElement = document.getElementById(parentId);
    var rotatorRef = this;
    // Create the controls
    this.controls = document.createElement('img');
    this.controls.className = 'PhotoRotatorControls';
    this.controls.src = 'http://assets.westword.com/img/play_controls.gif';
    this.controls.border = 0;
    //z-index: 1; position: relative; margin-left: -40px; margin-bottom: 5px;
    this.controls.style.zIndex = 100;
    this.controls.style.position = 'relative';
    this.controls.style.left = (this.parentElement.offsetWidth - 40) + 'px';
    //alert(this.controls.style.left);
    this.controls.style.top = (this.parentElement.offsetHeight - 5) + 'px';
    //alert(this.controls.style.top);
    this.controls.useMap = '#playControlsMap';
    this.parentElement.appendChild(this.controls);
    // Create the image map for the controls
    if(navigator.appName == 'Microsoft Internet Explorer')
    {
        // This is STUPID but only thing that works in IE, otherwise IE wasn't 'linking' the map properly
        this.controlMap = document.createElement("<map name=\"playControlsMap\">");
    }
    else
    {
        this.controlMap = document.createElement('map');
        this.controlMap.name = 'playControlsMap';
    }
    this.controlMapAreas = new Array();
    this.controlMapAreas[0] = document.createElement('area');
    this.controlMapAreas[0].onclick = function(){rotatorRef.pause(); rotatorRef.previous();}
    this.controlMapAreas[0].coords = '0,0,8,13';
    this.controlMapAreas[0].shape = 'rect';
    this.controlMap.appendChild(this.controlMapAreas[0]);
    this.controlMapAreas[1] = document.createElement('area');
    this.controlMapAreas[1].onclick = function(){rotatorRef.playPause();}
    this.controlMapAreas[1].coords = '11,0,23,13';
    this.controlMapAreas[1].shape = 'rect';
    this.controlMap.appendChild(this.controlMapAreas[1]);
    this.controlMapAreas[2] = document.createElement('area');
    this.controlMapAreas[2].onclick = function(){rotatorRef.pause(); rotatorRef.next();}
    this.controlMapAreas[2].coords = '26,0,34,13';
    this.controlMapAreas[2].shape = 'rect';
    this.controlMap.appendChild(this.controlMapAreas[2]);
    this.parentElement.appendChild(this.controlMap);
    // Array of photos to rotate
    this.photos = new Array();
    // Default time for interval
    this.intervalTime = 3;
    this.interval = null;
    this.index = 0;
    this.transitionType = 'appear';
    this.transitionOptions = new Object;
    this.transitionOptions.duration = 2;
}
//-----------------------------------------------------------------------------
/*
 * Tab control class
 */
//-----------------------------------------------------------------------------
function TabSet(parentId)
{
    //-------------------------------------------------------------------------
    /*
    ** Constructor code
    */
    this.tabs = new Array();
    this.parentElement = document.getElementById(parentId);
    this.tabSet = document.createElement('ul');
    this.tabSet.className = 'tabs';
    this.parentElement.appendChild(this.tabSet);
    this.activeIndex = null;
    //-------------------------------------------------------------------------
    /*
    ** Add a tab to the tabset
    **
    ** @param tabName - Name of tab
    ** @param contentId - Id of element to show/hide on click of tab
    ** @param active - Make this tab active immediately
    */
    this.addTab = function(tabName, contentId, active)
    {
        var tab = document.createElement('li');
        tab.innerHTML = tabName;
        tab.contentBodyElementId = contentId;
        tab.tabSet = this;
        tab.index = this.tabs.length;
        tab.classExtra = contentId;
        this.tabSet.appendChild(tab);
        this.tabs.push(tab);
        if(active)
        {
            tab.className = 'tab active ' + tab.classExtra;
        }
        else
        {
            tab.className = 'tab inactive ' + tab.classExtra;
        }
        tab.onclick = function()
        {
            var tabSet = tab.tabSet;
            for(i = 0; i < tabSet.tabs.length; i++)
            {

                var contentBody = document.getElementById(tabSet.tabs[i].contentBodyElementId);
                if(tab != tabSet.tabs[i])
                {
                    tabSet.tabs[i].className = 'tab inactive ' + tabSet.tabs[i].classExtra;
                    //contentBody.hide();
                    contentBody.style.display = 'none';
                }
                else
                {
                    tabSet.tabs[i].className = 'tab active ' + tabSet.tabs[i].classExtra;
                    //contentBody.show();
                    contentBody.style.display = '';
                }
            }
            if(tabSet.activeIndex != null)
            {
                tabSet.orderTabs(tab.index);
            }
        }
    }

    this.activateTab = function(tabName)
    {
        var index = 0;
        for(i = 0; i < this.tabs.length; i++)
        {
            var contentBody = document.getElementById(this.tabs[i].contentBodyElementId);
            if(this.tabs[i].innerHTML == tabName)
            {
                this.tabs[i].className = 'tab active ' + this.tabs[i].classExtra;
                contentBody.style.display = '';
                index = i;
            }
            else
            {
                this.tabs[i].className = 'tab inactive '  + this.tabs[i].classExtra;
                contentBody.style.display = 'none';
            }

        }
        if(this.activeIndex != null)
        {
            this.orderTabs(index);
        }
    }

    this.setActiveIndex = function(activeIndex)
    {
        this.activeIndex = activeIndex;
        var index = 0;
        for(i = 0; i < this.tabs.length; i++)
        {
            if(this.tabs[i].className == 'tab active ' + this.tabs[i].classExtra)
            {
                index = i;
                break;
            }
        }
        this.orderTabs(index);
    }

    this.orderTabs = function(startIndex)
    {
        if(this.activeIndex != null)
        {
            for(i = 0; i < this.tabs.length; i++)
            {
                this.tabSet.removeChild(this.tabs[i]);
            }
            var index = this.activeIndex + startIndex >= this.tabs.length ? this.activeIndex + startIndex - this.tabs.length : this.activeIndex + startIndex;
            for(i = 0; i < this.tabs.length; i++)
            {
                this.tabSet.appendChild(this.tabs[index]);
                index = index + 1 >= this.tabs.length ? 0 : index + 1;
            }
        }
    }
}
//-----------------------------------------------------------------------------
/*
*   Calendar widget class
*/
//-----------------------------------------------------------------------------
function Calendar(parentId)
{
    //-------------------------------------------------------------------------
    /*
    ** Constructor code
    */
    this.parentElement = document.getElementById(parentId);
    this.allowPastClick = true;
    this.showClose = false;
    var today = new Date();
    this.month = today.getMonth();
    this.year = today.getFullYear();
    this.monthNamesLong = new Array('January','February','March','April','May','June','July','August','September','October','November','December');
    this.monthNamesShort = new Array('Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Oct','Sep','Nov','Dec');
    this.weekDayNamesLong = new Array('Sun','Mon','Tue','Wed','Thu','Fri','Sat');
    this.weekDayNamesShort = new Array('S','M','T','W','T','F','S');

    // create the table used to represent the calander (9 rows x 7 columns : 1 column in first row 3 columns in second row)
    this.table = document.createElement('table');
    this.table.className = 'popupCalendar';
    this.table.border = 0;
    this.table.cellSpacing = 0;
    this.table.cellPadding = 0;
    for(i = 0; i < 9; i++)
    {
        var row = this.table.insertRow(-1);
        if(i == 0)
        {
            var cell = row.insertCell(-1);
            cell.colSpan = '7';
            cell.style.textAlign = 'center';
            cell.className = 'year';
        }
        else if(i == 1)
        {
            var cell = row.insertCell(-1);
            var self = this;
            cell.innerHTML = "&lt;&lt;";
            cell.className = "prevnext";
            cell.onclick = function()
            {
                self.prevMonth();
            }
            cell.style.cursor = 'pointer';
            cell.style.textAlign = 'center';
            cell = row.insertCell(-1);
            cell.colSpan = '5';
            cell.innerHTML = "";
            cell.style.textAlign = 'center';
            cell = row.insertCell(-1);
            cell.innerHTML = "&gt;&gt;";
            cell.className = "prevnext";
            cell.onclick = function()
            {
                self.nextMonth();
            }
            cell.style.cursor = 'pointer';
            cell.style.textAlign = 'center';

        }
        else
        {
            for(j = 0; j < 7; j++)
            {
                var cell = row.insertCell(-1);
                cell.style.textAlign = 'center';
                if(i == 2)
                {
                    cell.innerHTML = this.weekDayNamesShort[j];
                    cell.className = 'weekday';
                    cell.dayOfWeek = j;
                    cell.onclick = function()
                    {
                        self.clickDay(this.dayOfWeek);
                    }
                }
            }
        }
    }
    this.parentElement.insertBefore(this.table,this.parentElement.firstChild);

    //-------------------------------------------------------------------------
    /*
    ** allow/disallow clicking on 'past' dates
    **
    ** @param boolean value
    */
    this.allowPastDates = function(value)
    {
        this.allowPastClick = value;
    }
    //-------------------------------------------------------------------------
    /*
    ** set the current month
    **
    ** @param integer month
    */
    this.setMonth = function(month)
    {
        if(month >= 1 && month <= 12)
        {
            this.month = month - 1;
        }
    }
    //-------------------------------------------------------------------------
    /*
    ** show the close button
    */
    this.allowClose = function(value)
    {
        this.showClose = value;
    }
    //-------------------------------------------------------------------------
    /*
    ** set the current year
    **
    ** @param integer year
    */
    this.setYear = function(year)
    {
        if(year.length == 4 && !isNaN(year))
        {
            this.year = year;
        }
        else if(year.length == 2 && !isNaN(year))
        {
            this.year = '20' + year;
        }
    }
    //-------------------------------------------------------------------------
    /*
    ** increment the month
    **
    */
    this.nextMonth = function()
    {
        if(this.month == 11)
        {
            this.month = 0;
            this.year++;
        }
        else
        {
            this.month++;
        }
        this.load();
    }
    //-------------------------------------------------------------------------
    /*
    ** decrement the month
    **
    */
    this.prevMonth = function()
    {
        if(this.month == 0)
        {
            this.month = 11;
            this.year--;
        }
        else
        {
            this.month--;
        }
        this.load();
    }
    //-------------------------------------------------------------------------
    /*
    ** called when a date is clicked, if onDateClick is set that will be called
    **
    */
    this.clickDate = function(day)
    {
        var date = new Date;
        date.setDate(day);
        date.setMonth(this.month);
        date.setFullYear(this.year);
        if(this.onDateClick)
        {
            this.onDateClick(date);
        }
    }
    //-------------------------------------------------------------------------
    /*
    ** called when a week day is clicked, if onDayClick is set that will be called
    **
    */
    this.clickDay = function(day)
    {
        if(this.onDayClick)
        {
            this.onDayClick(day);
        }
    }
    //-------------------------------------------------------------------------
    /*
    ** hide the calendar
    **
    */
    this.hide = function()
    {
        this.parentElement.style.display = 'none';
    }
    //-------------------------------------------------------------------------
    /*
    ** show the calendar
    **
    */
    this.show = function()
    {
        this.parentElement.style.display = '';
        this.load();
    }
    //-------------------------------------------------------------------------
    /*
    ** toggle visible state of calendar
    **
    */
    this.toggle = function()
    {
        if(this.isVisible())
        {
            this.hide();
        }
        else
        {
            this.show();
        }
    }
    //-------------------------------------------------------------------------
    /*
    ** check if calendar is visibile
    **
    */
    this.isVisible = function()
    {
        return this.parentElement.style.display != 'none';
    }
    //-------------------------------------------------------------------------
    /*
    ** load/initialize the calendar (code that generates the table for the month)
    **
    */
    this.load = function()
    {
        var today = new Date();
        today.setHours(0);
        today.setMinutes(0);
        today.setSeconds(0);
        today.setMilliseconds(0);
        var date = new Date(this.monthNamesLong[this.month] + ' 1 ' + this.year);
        var dayOfWeek = date.getDay();
        var self = this;
        var k = 1;
        this.table.rows[0].cells[0].innerHTML = date.getFullYear();
        this.table.rows[0].cells[0].onclick = function()
        {
            this.innerHTML = '';
            var text = document.createElement('input');
            this.onclick = null;
            text.type = 'text';
            text.value = self.year;
            text.size = 4;
            text.maxLength = 4;
            this.appendChild(text);
            text.focus();
            text.onkeypress = function(key)
            {
                if(!key)
                {
                    key = window.event;
                }
                if(key.keyCode == 13 && this.value.length == 4)
                {
                    if(!isNaN(this.value))
                    {
                        self.year = this.value;
                    }
                    this.parentNode.removeChild(this);
                    self.load();
                }
            }
            text.onblur = function()
            {
                this.parentNode.removeChild(this);
                self.load();
            }
        }
        if(this.showClose)
        {
            var close = document.createElement('img');
            close.src = 'http://assets.westword.com/img/close-grey.gif';
            close.alt = 'close';
            close.title = 'close';
            close.style.position = 'absolute';
            close.style.top = '2px';
            close.style.left = this.table.offsetWidth - 17 + 'px';
            close.style.width = 15 + 'px';
            close.style.height = 15 + 'px';
            close.onclick = function()
            {
                self.hide();
            }
            this.table.rows[0].cells[0].appendChild(close);
        }
        this.table.rows[1].cells[1].innerHTML = this.monthNamesLong[date.getMonth()];
        this.table.rows[1].cells[1].onclick = function()
        {
            this.onclick = null;
            this.innerHTML = "";
            var dropdown = document.createElement('select');
            for(i = 0; i < 12; i++)
            {
                var option = document.createElement('option');
                option.value = i;
                option.innerHTML = self.monthNamesLong[i];
                if(navigator.appName == "Microsoft Internet Explorer")
                {
                    dropdown.appendChild(option); // IE only
                }
                else
                {
                    dropdown.add(option,null); // standards compliant
                }
                if(i == self.month)
                {
                    dropdown.selectedIndex = i;
                }
            }
            dropdown.onchange = function()
            {
                this.parentNode.removeChild(this);
                self.month = this.value;
                self.load();
            }
            dropdown.onblur = function()
            {
                this.parentNode.removeChild(this);
                self.load();
            }
            this.appendChild(dropdown);
            dropdown.focus();
        }
        for(i = 3; i < 9; i++)
        {
            for(j = 0; j < 7; j++)
            {
                date.setDate(k);
                if((i == 3 && j >= dayOfWeek) || (i != 3 && date.getDate() == k && date.getMonth() == this.month))
                {
                    this.table.rows[i].cells[j].innerHTML = k;
                    this.table.rows[i].cells[j].className = 'past';
                    this.table.rows[i].cells[j].dayOfMonth = k;
                    if(this.allowPastClick || date >= today)
                    {
                        if(date.getTime() == today.getTime())
                        {
                            this.table.rows[i].cells[j].className = 'today';
                        }
                        else
                        {
                            this.table.rows[i].cells[j].className = '';
                        }
                        this.table.rows[i].cells[j].onclick = function()
                        {
                            self.clickDate(this.dayOfMonth);
                        }
                    }
                    else
                    {
                        this.table.rows[i].cells[j].onclick = null;
                    }
                    k++;
                }
                else
                {
                    this.table.rows[i].cells[j].innerHTML = "";
                    this.table.rows[i].cells[j].className = 'empty';
                    this.table.rows[i].cells[j].onclick = null;
                    this.table.rows[i].cells[j].dayOfMonth = null;
                }
            }
        }
    }
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
function KeywordHighlighter(contentBodyId, className)
{
    this.highlightClass = className;
    this.contentBodyId = contentBodyId;

    this.highlight = function(keywordsArray)
    {
        var bodyDiv = null;
        if(this.contentBodyId)
        {
            bodyDiv = document.getElementById(this.contentBodyId);
        }
        else
        {
            bodyDiv = document.body;
        }
        var i = 0;
        for(i = 0; i < keywordsArray.length; i++)
        {
            if(keywordsArray[i].length > 1)
            {
                this.walkReplace(bodyDiv.firstChild,keywordsArray[i]);
            }
        }
    }

    this.highlightReferer = function()
    {
        var referrer = unescape(document.referrer);
        var idx = referrer.indexOf('keywords=');
        if(idx >= 0)
        {
            var keywords = null;
            var endIdx = referrer.indexOf('&',idx);
            if(endIdx >= 0)
            {
                keywords = referrer.substr(idx + 9,endIdx - idx - 9);
            }
            else
            {
                keywords = referrer.substr(idx + 9);
            }
            // Strip off surrounding quotes
            if(keywords.indexOf('"') == 0 && keywords.lastIndexOf('"') == keywords.length - 1)
            {
                keywords = keywords.substr(1,keywords.length - 2);
            }
            var keywordsArray = keywords.split("+");
            this.highlight(keywordsArray);
        }
    }

    this.walkReplace = function(node,search)
    {
        var k = 0;
        while(node && k < 1000)
        {
            if(node.childNodes.length > 0)
            {
                this.walkReplace(node.firstChild,search);
            }
            else
            {
                var regex =  new RegExp('\\b' + search + '\\b', 'gi');
                if(node.nodeType == 3)
                {
                    var match = regex.exec(node.data);
                    if(match)
                    {
                        var val = match[0];
                        var k = '';
                        var node2 = node.splitText(match.index);
                        var node3 = node2.splitText(val.length);
                        var span = node.ownerDocument.createElement('SPAN');
                        node.parentNode.replaceChild(span, node2);
                        span.className = this.highlightClass;
                        span.appendChild(node2);
                        node = span;
                    }
                }
            }
            node = node.nextSibling;
            k++;
        }
    }
}
//-----------------------------------------------------------------------------
function locationMap(elementId,centerLatitude,centerLongitude,zoom)
{
    this.mapElementId = elementId;
    this.resultsElementId = null;
    this.map = null;
    this.showPages = 5;
    if(GBrowserIsCompatible())
    {
        this.map = new GMap2(document.getElementById(this.mapElementId));
        this.map.addControl(new GSmallMapControl());
        this.map.addControl(new GOverviewMapControl());
        if(centerLatitude && centerLongitude)
        {
            this.map.setCenter(new GLatLng(centerLatitude,centerLongitude),zoom);
        }
    }

    this.createPages = function(total,pageSize,currentPage,params)
    {
        if(this.resultsElementId)
        {
            var resultsDiv = document.getElementById(this.resultsElementId);
            if(resultsDiv)
            {
                var pagesDiv = document.createElement('div');
                var totalDiv = document.createElement('div');
                totalDiv.className = '';
                pagesDiv.className = 'pagination';
                resultsDiv.appendChild(totalDiv);
                resultsDiv.appendChild(pagesDiv);
                var start = ((currentPage - 1) * pageSize) + 1;
                var end = start + pageSize > total ? total : currentPage * pageSize;
                totalDiv.innerHTML = start + '-' + end + ' of ' + total + ' results';
                var paramString = "";
                for(property in params)
                {
                    if(property != 'page')
                    {
                        if(paramString != "")
                        {
                            paramString += "&";
                        }
                        paramString += property + "=" + params[property];
                    }
                }
                var pages = Math.round(total / pageSize);
                var page = 1;
                if(currentPage != 1)
                {
                    if(currentPage - 2 >= 1)
                    {
                        page = currentPage - 2;
                    }
                    else
                    {
                        page = 1;
                    }
                    if(page + this.showPages > pages)
                    {
                        page = pages - this.showPages;
                    }
                }
                if(currentPage > 1)
                {
                    var pageSpan = document.createElement('span');
                    pageSpan.className = 'page';
                    pageSpan.innerHTML = "<a href='?" + paramString + "&page=1'>&lt;&lt;</a>";
                    pagesDiv.appendChild(pageSpan);
                    var pageSpan = document.createElement('span');
                    pageSpan.className = 'page';
                    pageSpan.innerHTML = "<a href='?" + paramString + "&page=" + (currentPage - 1) + "'>&lt;</a>";
                    pagesDiv.appendChild(pageSpan);
                }
                for(i = 0; i < this.showPages; i++)
                {
                    if(page >= pages)
                    {
                        break;
                    }
                    var pageSpan = document.createElement('span');
                    pageSpan.className = 'page';
                    if(page == currentPage)
                    {
                        pageSpan.innerHTML = '[' + page + ']';
                    }
                    else
                    {
                        pageSpan.innerHTML = "<a href='?" + paramString + "&page=" + page + "'>" + page + "</a>";
                    }
                    pagesDiv.appendChild(pageSpan);
                    page++;
                }
                if(currentPage < pages)
                {
                    var pageSpan = document.createElement('span');
                    pageSpan.className = 'page';
                    pageSpan.innerHTML = "<a href='?" + paramString + "&page=" + (currentPage + 1) + "'>&gt;</a>";
                    pagesDiv.appendChild(pageSpan);
                    var pageSpan = document.createElement('span');
                    pageSpan.className = 'page';
                    pageSpan.innerHTML = "<a href='?" + paramString + "&page=" + pages + "'>&gt;&gt;</a>";
                    pagesDiv.appendChild(pageSpan);
                }
            }
        }
    }

    /*
    ** Send an ajax request for locations
    */
    this.sendRequest = function(url)
    {
        var mapObject = this;
        new Ajax.Request(url,
        {
            method:'get',
            onSuccess: function(transport,json)
            {
                if(json)
                {
                    if(json.status == 'OK')
                    {
                        mapObject.createPages(json.result.total,json.result.pageSize,json.params.page,json.params);
                        for(i = 0; i < json.result.locations.length; i++)
                        {
                            var location = json.result.locations[i];
                            mapObject.addLocation(location.Location.Latitude,
                                            location.Location.Longitude,
                                            location.Location.Name,
                                            '/locations/view/' + location.Location.objid,
                                            location.Location.LocationImage,
                                            location.Location.Address,
                                            location.Location.City.Name,
                                            location.Location.City.State,
                                            location.Location.ZipCode,
                                            location.Location.Phone,
                                            location.Location.Awards,
                                            location.Location.Description);
                        }
                    }
                    else
                    {
                        alert(json.message);
                    }
                }
            }
            ,
            onFailure: function()
            {
                alert('Something went wrong...');
            }
        }
    );
    }

    /*
    ** Set the element for a result list to be written into
    **
    ** @param string elementId - id of the element
    */
    this.setResultsElement = function(elementId)
    {
        this.resultsElementId = elementId;
    }

    /*
    ** Add a location marker to the map
    **
    ** @param float latitude - Latitude of marker
    ** @param float longitude - Longitude of marker
    ** @param string name - Name of location
    ** @param string link - Href source of link for name
    ** @param string image - src of image for location
    ** @param string address - address of the location
    ** @param string city - city of the location
    ** @param string state - state of the location
    ** @param string zip - zipcode of the location
    ** @return void
    */
    this.addLocation = function(latitude, longitude, name, link, image, address, city, state, zip, phone, awards, description)
    {
        var point = new GLatLng(latitude, longitude);
        var marker = new GMarker(point);
        marker.html = "";
        if(image)
        {
            marker.html += "<img style='float: left; margin-bottom: 5px;' src='" + image + "' class='locationImage'>";
            marker.html += "<div class='locationDetails' style='margin-bottom: 5px; margin-left: 80px;'>";
        }
        else
        {
            marker.html += "<div class='locationDetails' style='margin-bottom: 5px;'>";
        }
        if(awards)
        {
            marker.html += "<div class='awards'>";
            for(j = 0; j < awards.length; j++)
            {
                var award = awards[j].BestOfAward;
                marker.html += "<a href='/bestOf/award/" + award.Year.Year + "/" + award.objid + "'>" + award.Award + "</a> (" + award.Year.Year + ")<br/>";
            }
            marker.html += "</div>";
        }
        marker.html += "<div class='locationName'><a href='" + link + "'>" + name + "</a></div>" +
                       "<div class='locationAddress'>" + address + "</div>" +
                       "<div class='locationCityStateZip'>" + city + ", " + state + " " + zip + "</div>";

        if(phone)
        {
            marker.html += "<div class='locationPhone'>" + phone + "</div>";
        }
        if(description)
        {
            marker.html += "<div class='locationDesc'>" + description + "</div>";
        }
        marker.html += "</div><div style='clear: both;'></div>";
        GEvent.addListener(marker,"click",function()
        {
            this.openInfoWindowHtml(this.html);
        });
        this.map.addOverlay(marker);
        if(this.resultsElementId)
        {
            var results = document.getElementById(this.resultsElementId);
            var result = document.createElement('div');
            result.className = 'result';
            result.innerHTML = "<div class='locationName'><a href='" + link + "'>" + name + "</a></div>" +
                               "<div class='locationAddress'>" + address + "</div>";
            result.marker = marker;
            var map = this.map;
            result.onmouseover = function()
            {
                this.className = 'result hover';
                var infoWindow = map.getInfoWindow();
                if(infoWindow.getPoint() != this.marker.getPoint())
                {
                    this.marker.openInfoWindow(this.marker.html);
                }
            }
            result.onmouseout = function()
            {
                this.className = 'result';
            }
            results.appendChild(result);
        }
    }
}
//-----------------------------------------------------------------------------
function List(elementId, name, collapseSize)
{
    this.expand = function()
    {
        for(i = 0; i < this.listElement.childNodes.length; i++)
        {
            var item = this.listElement.childNodes[i];
            if(item.nodeName == 'LI')
            {
                item.style.display = '';
            }
        }
        if(this.listLink)
        {
            this.listLink.innerHTML = 'Less ' + this.listName;
            var listRef = this;
            this.listLink.onclick = function()
            {
                listRef.collapse(listRef.collapseSize);
            }
        }
    }

    this.collapse = function(count)
    {
        var j = 0;
        for(i = 0; i < this.listElement.childNodes.length; i++)
        {
            var item = this.listElement.childNodes[i];
            if(item.nodeName == 'LI')
            {
                if(j++ >= count)
                {
                    item.style.display = 'none';
                }
            }
        }
        if(this.listLink)
        {
            this.listLink.innerHTML = 'More ' + this.listName;
            var listRef = this;
            this.listLink.onclick = function()
            {
                listRef.expand();
            }
        }
    }
    /**
     *
     */
    this.listElement = document.getElementById(elementId);
    if(this.listElement)
    {
        if(name)
        {
            this.listName = name;
            this.listLink = document.createElement('a');
            this.listLink.className = 'more';
            this.listElement.appendChild(this.listLink);
        }
        else
        {
            this.listName = null;
            this.listLink = null;
        }
        this.collapseSize = collapseSize;
        this.collapse(collapseSize);
    }
}
//-----------------------------------------------------------------------------

/* --- End /home/httpd/public/app_frame/webroot/js/VVVisual.js --- */
/* --- Start /home/httpd/public/app_frame/webroot/js/VVCookie.js --- */

/*
 *  VVCookie.js - Cookie related functions
 *
 *  ************************************************************
 *  Note: Before adding any new functions into this class
 *        PLEASE check the prototype and scriptaculous libraries
 *        for duplicate functionality.
 *  ************************************************************
 */

function VVCookie() {

}


/* --- End /home/httpd/public/app_frame/webroot/js/VVCookie.js --- */
/* --- Start /home/httpd/public/app_frame/webroot/js/Paperfinder.js --- */

function validate_paper_finder( f )
{
	var e = f.zip;
	var v = e.value;
	if ( !v || v.replace( /\s/g, '' ) == '' )
	{
		alert( 'Please enter a ZIP code.' );
		e.focus();
		return false;
	}
}

/* --- End /home/httpd/public/app_frame/webroot/js/Paperfinder.js --- */
/* --- Start /home/httpd/public/app_frame/webroot/js/VVDate.js --- */

/*
 *  VVDate.js - Date and Time manipulation functions
 *
 *  ************************************************************
 *  Note: Before adding any new functions into this class
 *        PLEASE check the prototype and scriptaculous libraries
 *        for duplicate functionality.
 *  ************************************************************
 */

function VVDate() {

}


/* --- End /home/httpd/public/app_frame/webroot/js/VVDate.js --- */
/* --- Start /home/httpd/public/app_frame/webroot/js/VVOAS.js --- */

/*
 *  VVOAS.js - OAS Ad insertion script
 *
 *  Wrapper for OAS ad emission logic
 *
 *  ************************************************************
 *  Note: Before adding any new functions into this class
 *        PLEASE check the prototype and scriptaculous libraries
 *        for duplicate functionality.
 *  ************************************************************
 *
 */

function VVOAS() {

}


/* --- End /home/httpd/public/app_frame/webroot/js/VVOAS.js --- */
/* --- Start /home/httpd/public/app_frame/webroot/js/VVFlash.js --- */

/*
 *  VVFlash.js - Flash specific functions
 *
 *  ************************************************************
 *  Note: Before adding any new functions into this class
 *        PLEASE check the prototype and scriptaculous libraries
 *        for duplicate functionality.
 *  ************************************************************
 */

function VVFlash() {

}


/* --- End /home/httpd/public/app_frame/webroot/js/VVFlash.js --- */
/* --- Start /home/httpd/public/app_frame/webroot/js/swfobject.js --- */

/**
 * SWFObject v1.4.3: Flash Player detection and embed - http://blog.deconcept.com/swfobject/
 *
 * SWFObject is (c) 2006 Geoff Stearns and is released under the MIT License:
 * http://www.opensource.org/licenses/mit-license.php
 *
 * **SWFObject is the SWF embed script formerly known as FlashObject. The name was changed for
 *   legal reasons.
 */
if(typeof deconcept == "undefined") var deconcept = new Object();
if(typeof deconcept.util == "undefined") deconcept.util = new Object();
if(typeof deconcept.SWFObjectUtil == "undefined") deconcept.SWFObjectUtil = new Object();
deconcept.SWFObject = function(swf, id, w, h, ver, c, useExpressInstall, quality, xiRedirectUrl, redirectUrl, detectKey){
	if (!document.getElementById) { return; }
	this.DETECT_KEY = detectKey ? detectKey : 'detectflash';
	this.skipDetect = deconcept.util.getRequestParameter(this.DETECT_KEY);
	this.params = new Object();
	this.variables = new Object();
	this.attributes = new Array();
	if(swf) { this.setAttribute('swf', swf); }
	if(id) { this.setAttribute('id', id); }
	if(w) { this.setAttribute('width', w); }
	if(h) { this.setAttribute('height', h); }
	if(ver) { this.setAttribute('version', new deconcept.PlayerVersion(ver.toString().split("."))); }
	this.installedVer = deconcept.SWFObjectUtil.getPlayerVersion();
	if(c) { this.addParam('bgcolor', c); }
	var q = quality ? quality : 'high';
	this.addParam('quality', q);
	this.setAttribute('useExpressInstall', useExpressInstall);
	this.setAttribute('doExpressInstall', false);
	var xir = (xiRedirectUrl) ? xiRedirectUrl : window.location;
	this.setAttribute('xiRedirectUrl', xir);
	this.setAttribute('redirectUrl', '');
	if(redirectUrl) { this.setAttribute('redirectUrl', redirectUrl); }
}
deconcept.SWFObject.prototype = {
	setAttribute: function(name, value){
		this.attributes[name] = value;
	},
	getAttribute: function(name){
		return this.attributes[name];
	},
	addParam: function(name, value){
		this.params[name] = value;
	},
	getParams: function(){
		return this.params;
	},
	addVariable: function(name, value){
		this.variables[name] = value;
	},
	getVariable: function(name){
		return this.variables[name];
	},
	getVariables: function(){
		return this.variables;
	},
	getVariablePairs: function(){
		var variablePairs = new Array();
		var key;
		var variables = this.getVariables();
		for(key in variables){
			variablePairs.push(key +"="+ variables[key]);
		}
		return variablePairs;
	},
	getSWFHTML: function() {
		var swfNode = "";
		if (navigator.plugins && navigator.mimeTypes && navigator.mimeTypes.length) { // netscape plugin architecture
			if (this.getAttribute("doExpressInstall")) { this.addVariable("MMplayerType", "PlugIn"); }
			swfNode = '<embed type="application/x-shockwave-flash" src="'+ this.getAttribute('swf') +'" width="'+ this.getAttribute('width') +'" height="'+ this.getAttribute('height') +'"';
			swfNode += ' id="'+ this.getAttribute('id') +'" name="'+ this.getAttribute('id') +'" ';
			var params = this.getParams();
			 for(var key in params){ swfNode += [key] +'="'+ params[key] +'" '; }
			var pairs = this.getVariablePairs().join("&");
			 if (pairs.length > 0){ swfNode += 'flashvars="'+ pairs +'"'; }
			swfNode += '/>';
		} else { // PC IE
			if (this.getAttribute("doExpressInstall")) { this.addVariable("MMplayerType", "ActiveX"); }
			swfNode = '<object id="'+ this.getAttribute('id') +'" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" width="'+ this.getAttribute('width') +'" height="'+ this.getAttribute('height') +'">';
			swfNode += '<param name="movie" value="'+ this.getAttribute('swf') +'" />';
			var params = this.getParams();
			for(var key in params) {
			 swfNode += '<param name="'+ key +'" value="'+ params[key] +'" />';
			}
			var pairs = this.getVariablePairs().join("&");
			if(pairs.length > 0) {swfNode += '<param name="flashvars" value="'+ pairs +'" />';}
			swfNode += "</object>";
		}
		return swfNode;
	},
	write: function(elementId){
		if(this.getAttribute('useExpressInstall')) {
			// check to see if we need to do an express install
			var expressInstallReqVer = new deconcept.PlayerVersion([6,0,65]);
			if (this.installedVer.versionIsValid(expressInstallReqVer) && !this.installedVer.versionIsValid(this.getAttribute('version'))) {
				this.setAttribute('doExpressInstall', true);
				this.addVariable("MMredirectURL", escape(this.getAttribute('xiRedirectUrl')));
				document.title = document.title.slice(0, 47) + " - Flash Player Installation";
				this.addVariable("MMdoctitle", document.title);
			}
		}
		if(this.skipDetect || this.getAttribute('doExpressInstall') || this.installedVer.versionIsValid(this.getAttribute('version'))){
			var n = (typeof elementId == 'string') ? document.getElementById(elementId) : elementId;
			n.innerHTML = this.getSWFHTML();
			return true;
		}else{
			if(this.getAttribute('redirectUrl') != "") {
				document.location.replace(this.getAttribute('redirectUrl'));
			}
		}
		return false;
	}
}

/* ---- detection functions ---- */
deconcept.SWFObjectUtil.getPlayerVersion = function(){
	var PlayerVersion = new deconcept.PlayerVersion([0,0,0]);
	if(navigator.plugins && navigator.mimeTypes.length){
		var x = navigator.plugins["Shockwave Flash"];
		if(x && x.description) {
			PlayerVersion = new deconcept.PlayerVersion(x.description.replace(/([a-zA-Z]|\s)+/, "").replace(/(\s+r|\s+b[0-9]+)/, ".").split("."));
		}
	}else{
		// do minor version lookup in IE, but avoid fp6 crashing issues
		// see http://blog.deconcept.com/2006/01/11/getvariable-setvariable-crash-internet-explorer-flash-6/
		try{
			var axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.7");
		}catch(e){
			try {
				var axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.6");
				PlayerVersion = new deconcept.PlayerVersion([6,0,21]);
				axo.AllowScriptAccess = "always"; // throws if player version < 6.0.47 (thanks to Michael Williams @ Adobe for this code)
			} catch(e) {
				if (PlayerVersion.major == 6) {
					return PlayerVersion;
				}
			}
			try {
				axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash");
			} catch(e) {}
		}
		if (axo != null) {
			PlayerVersion = new deconcept.PlayerVersion(axo.GetVariable("$version").split(" ")[1].split(","));
		}
	}
	return PlayerVersion;
}
deconcept.PlayerVersion = function(arrVersion){
	this.major = arrVersion[0] != null ? parseInt(arrVersion[0]) : 0;
	this.minor = arrVersion[1] != null ? parseInt(arrVersion[1]) : 0;
	this.rev = arrVersion[2] != null ? parseInt(arrVersion[2]) : 0;
}
deconcept.PlayerVersion.prototype.versionIsValid = function(fv){
	if(this.major < fv.major) return false;
	if(this.major > fv.major) return true;
	if(this.minor < fv.minor) return false;
	if(this.minor > fv.minor) return true;
	if(this.rev < fv.rev) return false;
	return true;
}
/* ---- get value of query string param ---- */
deconcept.util = {
	getRequestParameter: function(param) {
		var q = document.location.search || document.location.hash;
		if(q) {
			var pairs = q.substring(1).split("&");
			for (var i=0; i < pairs.length; i++) {
				if (pairs[i].substring(0, pairs[i].indexOf("=")) == param) {
					return pairs[i].substring((pairs[i].indexOf("=")+1));
				}
			}
		}
		return "";
	}
}
/* fix for video streaming bug */
deconcept.SWFObjectUtil.cleanupSWFs = function() {
	var objects = document.getElementsByTagName("OBJECT");
	if (objects.length > 0) {
		__flash_unloadHandler = function(){}; // fixes but in fp9
		__flash_savedUnloadHandler = function(){};// fixes but in fp9 see http://blog.deconcept.com/
	}
	for (var i=0; i < objects.length; i++) {
		objects[i].style.display = 'none';
		for (var x in objects[i]) {
			if (typeof objects[i][x] == 'function') {
				objects[i][x] = function(){};
			}
		}
	}
}
if (typeof window.onbeforeunload == 'function') {
	var oldBeforeUnload = window.onbeforeunload;
	window.onbeforeunload = function() {
		deconcept.SWFObjectUtil.cleanupSWFs();
		oldBeforeUnload();
	}
} else {
	window.onbeforeunload = deconcept.SWFObjectUtil.cleanupSWFs;

}
/* add Array.push if needed (ie5) */
if (Array.prototype.push == null) { Array.prototype.push = function(item) { this[this.length] = item; return this.length; }}

/* add some aliases for ease of use/backwards compatibility */

var getQueryParamValue = deconcept.util.getRequestParameter;
var FlashObject = deconcept.SWFObject; // for legacy support
var SWFObject = deconcept.SWFObject;

/* --- End /home/httpd/public/app_frame/webroot/js/swfobject.js --- */
/* --- Start /home/httpd/public/app_frame/webroot/js/VVJava.js --- */

/*
 *  VVJava.js - Java-specific functions (NOT JavaScript)
 *
 *  ************************************************************
 *  Note: Before adding any new functions into this class
 *        PLEASE check the prototype and scriptaculous libraries
 *        for duplicate functionality.
 *  ************************************************************
 */

function VVJava() {

}


/* --- End /home/httpd/public/app_frame/webroot/js/VVJava.js --- */
/* --- Start /home/httpd/public/app_frame/webroot/js/AdIndex.js --- */

/* AdIndex.js */
function AdIndex(){
    this.tower = function(section, limit){
        new Ajax.Updater('AdIndexTower', '/adIndex/ajaxTower/adIndexSection:' + section + ';adIndexLimit:' + limit, { method: 'get' });
    }

    this.track = function(adId){
        if(window.location.href.indexOf("tower") != -1){
            var url = '/adIndex/track/' + adId + '/tower_impressions';
        }
        else{
            var url = '/adIndex/track/' + adId + '/impressions';
        }
        new Ajax.Request(url, { method: 'get'});
    }
}

/* --- End /home/httpd/public/app_frame/webroot/js/AdIndex.js --- */
/* --- Start /home/httpd/public/app_frame/webroot/js/BlurFocusFix.js --- */

/*
 *  BlurFocusFix.js - Class to make designated text fields do that value switcheroo onfocus and onblur
 *   @author andy
 */

function BlurFocusFix( classToFind ) {

	var fieldList = $$( 'input.' + classToFind );
	fieldList.each( function ( field, n ) {
		$(field).setAttribute( 'defaultValue', $(field).value );	
		$(field).onfocus = function () {
			if( this.value != this.getAttribute( 'defaultValue' ) && this.value.length ) {
				return;
			}
			this.value = "";
		};
		$(field).onblur = function () {
			if( this.value.length == 0 ) {
				// Don't put the value back in anymore... sweet.
				// this.value = this.getAttribute( 'defaultValue' );
			}
		};
	} );

}

loadMgr.addLoadEvent( "var blurFocusFix = new BlurFocusFix( 'BlurFocusFix' )" );


/* --- End /home/httpd/public/app_frame/webroot/js/BlurFocusFix.js --- */
/* --- Start /home/httpd/public/app_frame/webroot/js/DropDown.js --- */

function DropDown(className)
{
    this.div = document.createElement('div');
    this.span = document.createElement('span');
    this.div.className = className;
    this.ul = document.createElement('ul');
    this.ul.style.display = 'none';
    this.ul.style.position = 'absolute';
    this.ul.onmouseover = function()
    {
        this.underMouse = true;
    }
    this.ul.onmouseout = function()
    {
        this.underMouse = false;
        var ul = this;
        closeUL = function()
        {
            if(!ul.underMouse)
            {
                ul.style.display = 'none';
            }
        }
        setTimeout('closeUL()',500);
    }
    this.div.appendChild(this.span);
    this.div.appendChild(this.ul);
    this.onChange = null;

    this.div.onclick = function()
    {
        var ul = this.getElementsByTagName('ul');
        ul = ul[0];
        if(ul.style.display == 'none')
        {
            var left = this.offsetLeft;
            var top = this.offsetTop;
            var temp = this;
            while(temp = temp.offsetParent)
            {
                left += temp.offsetLeft;
                top += temp.offsetTop;
            }
            ul.style.top = top + this.offsetHeight + 'px';
            ul.style.left = left + 'px';
            ul.style.display = '';
        }
        else
        {
            ul.style.display = 'none';
        }
    }

    this.addItem = function(key, value, selected)
    {
        var li = document.createElement('li');
        li.innerHTML = key;
        li.itemValue = value;
        var parent = this;
        li.onclick = function()
        {
            parent.span.innerHTML = this.innerHTML;
            if(parent.onChange)
            {
                parent.onChange(this.innerHTML,this.itemValue);
            }
        }
        li.onmouseover = function()
        {
            this.className = 'hover';
            parent.underMouse = true;
        }
        li.onmouseout = function()
        {
            this.className = '';
            parent.underMouse = false;
        }
        this.ul.appendChild(li);
        if(selected)
        {
            this.selected = li;
            this.span.innerHTML = key;
        }
    }

    this.render = function(parentId)
    {
        var parent = document.getElementById(parentId);
        if(parent)
        {
            parent.appendChild(this.div);
            for(i = 0; i < this.ul.childNodes.length; i++)
            {
                var li = this.ul.childNodes[i];
                if(li.tagName == 'LI')
                {
                    //li.style.minWidth = this.div.offsetWidth + 'px';
                }
            }
        }
    }
}

/* --- End /home/httpd/public/app_frame/webroot/js/DropDown.js --- */
/* --- Start /home/httpd/public/app_frame/webroot/js/VVPopup.js --- */

/*
 *  VVPopup.js - Popup window functions
 *
 *  ************************************************************
 *  Note: Before adding any new functions into this class
 *        PLEASE check the prototype and scriptaculous libraries
 *        for duplicate functionality.
 *  ************************************************************
 */

function VVPopup() {

}


/* --- End /home/httpd/public/app_frame/webroot/js/VVPopup.js --- */
/* --- Start /home/httpd/public/app_frame/webroot/js/SMS.js --- */

function SMSForm(id,message)
{
    this.message = message;
    this.element = null;
    this.visible = 0;
    this.parentId = id;
    this.carriers = null;
    this.number = null;

    this.create = function()
    {
        if(this.parentId)
        {
            var parent = document.getElementById(this.parentId);
            var widget = this;
            this.element = document.createElement('div');
            this.element.style.display = 'none';
            this.element.style.position = 'absolute';
            this.element.className = 'SMSForm';
            parent.appendChild(this.element);
            var div = document.createElement('div');
            div.innerHTML = 'Carrier:';
            this.element.appendChild(div);
            this.carriers = document.createElement('select');
            this.element.appendChild(this.carriers);
            var option = document.createElement('option');
            option.value = 0;
            option.innerHTML = 'Select Carrier';
            this.carriers.appendChild(option);
            div = document.createElement('div');
            div.innerHTML = 'Number:';
            this.element.appendChild(div);
            this.number = document.createElement('input');
            this.number.type = 'text';
            this.element.appendChild(this.number);
            var button = document.createElement('button');
            button.innerHTML = 'Send';
            button.onclick = function()
            {
                widget.send();
            }
            this.element.appendChild(button);
            var close = document.createElement('img');
            close.src = 'http://assets.westword.com/img/close-grey.gif';
            close.style.marginLeft = '5px';
            close.style.cursor = 'pointer';
            close.style.position = 'absolute';
            close.style.top = '5px';
            close.style.right = '5px';
            close.onclick = function()
            {
                widget.hide();
            }
            this.element.appendChild(close);
            this.loadCarriers();
        }
    }

    this.show = function()
    {
        this.visible = true;
        if(this.element == null)
        {
            this.create();
        }
        if(this.element)
        {
            this.element.style.display = '';
        }
    }

    this.hide = function()
    {
        this.visible = false;
        if(this.element)
        {
            this.element.style.display = 'none';
        }
    }

    this.toggle = function()
    {
        if(this.visible)
        {
            this.hide();
        }
        else
        {
            this.show();
        }
    }

    this.send = function()
    {
        if(this.carriers.value == 0)
        {
            alert('Please select a carrier.');
        }
        else if(!this.number.value)
        {
            alert('Please enter the phone number.');
        }
        else
        {
            var url = '/services/smsSend/?debug:0&carrier=' + this.carriers.value + '&number=' + this.number.value + '&message=' + this.message;
            var widget = this;
            new Ajax.Request(url,
            {
                method:'get',
                onSuccess: function(transport,json)
                {
                    if(json)
                    {
                        if(json.Status == 'OK')
                        {
                            alert('Message sent');
                        }
                        else
                        {
                            alert(json.Error);
                        }
                    }
                    widget.hide();
                }
                ,
                onFailure: function()
                {
                    alert('Something went wrong...');
                    widget.hide();
                }
            });
        }
    }

    this.loadCarriers = function()
    {
        var widget = this;
        var url = '/services/smsGetCarriers?debug:0';
        new Ajax.Request(url,
        {
            method:'get',
            onSuccess: function(transport,json)
            {
                if(json)
                {
                    if(json.Status == 'OK')
                    {
                        if(widget.carriers)
                        {
                            for(i = 0; i < json.Carriers.length; i++)
                            {
                                var carrier = json.Carriers[i].Carrier;
                                var option = document.createElement('option');
                                option.value = carrier.carrier_id;
                                option.innerHTML = carrier.name;
                                widget.carriers.appendChild(option);
                            }
                        }
                    }
                    else
                    {
                        alert(json.Error);
                    }
                }
            }
            ,
            onFailure: function()
            {
                alert('Something went wrong...');
            }
        });
    }
}

/* --- End /home/httpd/public/app_frame/webroot/js/SMS.js --- */
/* --- Start /home/httpd/public/app_frame/webroot/js/RRCheckboxToggle.js --- */

function RRCheckboxToggle()
{
    var checkboxes = $$('input[type="checkbox"][id^="checkbox"]');
    var toggle     = $('toggle');
    if (checkboxes != null && toggle != null) {
        toggle.observe(
            'click',
            function(element) {
                if (toggle.checked == true) {
                    checkboxes.each(
                        function(element) {
                            element.checked = false;
                        }
                    );
                }
            }
        );

        checkboxes.each(
            function(element) {
                element.observe(
                    'click',
                    function(element) {
                        toggle.checked = false;
                    }
                );
            }
        );
    }
}

loadMgr.addLoadEvent('var rrCheckboxToggle = new RRCheckboxToggle();');


/* --- End /home/httpd/public/app_frame/webroot/js/RRCheckboxToggle.js --- */
/* --- Start /home/httpd/public/app_frame/webroot/js/RankIt.js --- */

var RankIt = {
	attr : 'RankIt_refID',
	globalRef : '',
	displayTouched : false,
	overClicker : false, 
	getElementsByClassName : function (className, tag, elm){ /*From Roberts talk*/
		if (document.getElementsByClassName) {
			this.getElementsByClassName = function (className, tag, elm) {
				elm = elm || document;
				var elements = elm.getElementsByClassName(className),
					nodeName = (tag)? new RegExp("\\b" + tag + "\\b", "i") : null,
					returnElements = [],
					current;
				for(var i=0, il=elements.length; i<il; i+=1){
					current = elements[i];
					if(!nodeName || nodeName.test(current.nodeName)) {
						returnElements.push(current);
					}
				}
				return returnElements;
			};
		}
		else if (document.evaluate) {
			this.getElementsByClassName = function (className, tag, elm) {
				tag = tag || "*";
				elm = elm || document;
				var classes = className.split(" "),
					classesToCheck = "",
					xhtmlNamespace = "http://www.w3.org/1999/xhtml",
					namespaceResolver = (document.documentElement.namespaceURI === xhtmlNamespace)? xhtmlNamespace : null,
					returnElements = [],
					elements,
					node;
				for(var j=0, jl=classes.length; j<jl; j+=1){
					classesToCheck += "[contains(concat(' ', @class, ' '), ' " + classes[j] + " ')]";
				}
				try	{
					elements = document.evaluate(".//" + tag + classesToCheck, elm, namespaceResolver, 0, null);
				}
				catch (e) {
					elements = document.evaluate(".//" + tag + classesToCheck, elm, null, 0, null);
				}
				while ((node = elements.iterateNext())) {
					returnElements.push(node);
				}
				return returnElements;
			};
		}
		else {
			this.getElementsByClassName = function (className, tag, elm) {
				tag = tag || "*";
				elm = elm || document;
				var classes = className.split(" "),
					classesToCheck = [],
					elements = (tag === "*" && elm.all)? elm.all : elm.getElementsByTagName(tag),
					current,
					returnElements = [],
					match;
				for(var k=0, kl=classes.length; k<kl; k+=1){
					classesToCheck.push(new RegExp("(^|\\s)" + classes[k] + "(\\s|$)"));
				}
				for(var l=0, ll=elements.length; l<ll; l+=1){
					current = elements[l];
					match = false;
					for(var m=0, ml=classesToCheck.length; m<ml; m+=1){
						match = classesToCheck[m].test(current.className);
						if (!match) {
							break;
						}
					}
					if (match) {
						returnElements.push(current);
					}
				}
				return returnElements;
			};
		}
		return this.getElementsByClassName(className, tag, elm);
	},
	getRandom : function() {
		var chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz";
		var string_length = 15;
		var randomstring = '';
		for (var i=0; i<string_length; i++) {
			var rnum = Math.floor(Math.random() * chars.length);
			randomstring += chars.substring(rnum,rnum+1);
		}
		return randomstring;
	},
	getHtml : function(o){
		var ret = document.createElement(o.tagName); 
		for(var i in o) if(i!='tagName') ret[i] = o[i]; 
		return ret;
	},
	getObj : function(o){
		return o || document.getElementById(this.globalRef);
	},
	getImgIdentifier : function(imgObj){
		return imgObj.src;
	},
	init : function(){
		var el = this.getElementsByClassName('rankit');
		for(var i in el){ 
		    if(typeof(el[i])=='object'){
			var img = el[i].cloneNode(true);
			var wrap = this.getHtml({tagName : 'span', className : 'rankitWrap'});
			var clicker = this.getHtml({tagName : 'a', className : 'rankitClick', href : 'javascript:void(0)',innerHTML : '&nbsp;'});
			var newID = this.getRandom();
			var imgRef = this.getImgIdentifier(img);
			clicker.setAttribute(this.attr,newID);
			img.setAttribute(this.attr,newID);
			clicker.onmouseover = function(){
				RankIt.globalRef = this.getAttribute(RankIt.attr);
				RankIt.showDisplay(this);
				RankIt.displayTouched = false;
				RankIt.overClicker = true;
			};
			clicker.onmouseout = function(){
				RankIt.overClicker = false;
				setTimeout('RankIt.timedHide()',1000);
			};
			var disp = this.getHtml({tagName : 'span', className : 'rankitDisplay', id : newID});
			disp.setAttribute(this.attr,newID);
			disp.onmouseout = function(){ 
				RankIt.displayTouched = false;
				setTimeout('RankIt.timedHide()',1000);
			};
			disp.onmouseover = function(){ RankIt.displayTouched = true;};
			var dispInner = this.getHtml({tagName : 'span', className : 'rankitDisplayInner', innerHTML : 'Rank &raquo;'});
			disp.appendChild(dispInner);
			
			//Attach Thumbs
			var thumbs = ['rankit_thumbup','rankit_thumbdown'];
			for(var j in thumbs){
				var lnk = this.getHtml({tagName : 'a', className : thumbs[j], innerHTML : '&nbsp;', href : 'javascript:void(0)'});
				dispInner.appendChild(lnk);
				lnk.onclick = function(){ RankIt.submitVote(this); };
				lnk.setAttribute('imgRef',imgRef);
			}
			
			wrap.appendChild(img);
			wrap.appendChild(disp);
			wrap.appendChild(clicker);
			el[i].style.display = 'none';
			el[i].id = 'bx7sndu3878hf74'; 
			el[i].parentNode.insertBefore(wrap,el[i]);
			el[i].parentNode.removeChild(el[i]); 
		    }
		}
	},
	toggleDisplay : function(obj){
		obj = this.getObj(obj);
		var f = document.getElementById(obj.getAttribute(this.attr));
		f.style.display = (f.style.display=='block') ? 'none' : 'block';
	},
	showDisplay : function(obj){
		obj = this.getObj(obj);
		var f = document.getElementById(obj.getAttribute(this.attr));
		f.style.display = 'block';
	},
	hideDisplay : function(obj){
		obj = this.getObj(obj);
		var f = document.getElementById(obj.getAttribute(this.attr));
		f.style.display = 'none';
	},
	timedHide : function(){
		if(this.displayTouched==false && this.overClicker==false){
			var els = this.getElementsByClassName('rankitDisplay');
			for(var i in els){
			    if(typeof(els[i])=='object'){
				els[i].style.display = 'none';
			    }
			}
		}
	},
	submitVote : function(obj){
		var imgRef = obj.getAttribute('imgRef');
		var vote = (obj.className=='rankit_thumbup') ? 'yay' : 'nay';
		alert(imgRef+' : '+vote);
		this.voteComplete();
	},
	voteComplete : function(){
		var obj = document.getElementById(this.globalRef);
		var inner = this.getHtml({tagName : 'span',className : 'rankitDisplayInner'});
		var strong = this.getHtml({tagName : 'strong', innerHTML : 'Thank you. | '});
		var lnk = this.getHtml({tagName : 'a',href : 'javascript:void(0)',innerHTML : 'Vote Again.'});
		lnk.onclick = function(){location.reload(true);};
		obj.innerHTML = '';
		obj.appendChild(inner);
		inner.appendChild(strong);
		strong.appendChild(lnk);
		
	}
};

loadMgr.addLoadEvent("RankIt.init()");

/* --- End /home/httpd/public/app_frame/webroot/js/RankIt.js --- */
/* --- Start /home/httpd/public/app_frame/webroot/js/Trailer.js --- */


var TrailerPopupSingleton = (
	function () {
		var instance = {
			init: function () {
				// use prototype to get elements by class name and add the appropriate
				// attributes to it
				var popUpLinks = $$('a.TrailerPopup');
				for( var l = 0; l < popUpLinks.length; l++ ){
					// because there can be multiple widgets which will attemp to instantiate this beast
					// more than once, this thing won't know which a tags it's touched, so just ignore the 
					// ones that already have the "trailerLink" attribute set
					if( popUpLinks[l].readAttribute( "trailerLink" ) == null ) {
						var link = popUpLinks[l].readAttribute( "href" );
						popUpLinks[l].setAttribute( "trailerLink", link );
						popUpLinks[l].setAttribute( "href", "javascript:trailerPopup.showTrailerPopUp( '" + link + "' )" );
					}
				}
			},
			wTrailerWindow: -1,
			showTrailerPopUp: function ( link ) {
				this.wTrailerWindow = window.open(
					link,
					"wTrailerViewer",
					"height=440,width=728,status=no,toolbar=no,menubar=no,resizable=yes,status=no"
				);
				this.wTrailerWindow.focus();
			}
		};
		return { getInstance: function () { return instance; } }
	}
)();














/*
   This file contains functions to generate OBJECT and EMBED tags for QuickTime content.
   These functions assemble the tags from parameters passed to them as parameters.

    QT_WriteOBJECT()              - generate HTML tags and insert them into the calling document
    QT_WriteOBJECT_XHTML()        - generate XHTML tags and insert them into the calling document

    QT_GenerateOBJECTText()       - generate HTML tags and return them as a string
    QT_GenerateOBJECTText_XHTML() - generate XHTML tags and return them as a string

    AC_QuickTimeVersion()         - return the version of this file as a floating point number.

   To call one of these functions, pass the url, width, height, and required ActiveX
   control version as parameters 1 through 4, and pass all other attributes and
   parameters that you would otherwise specify for the OBJECT, PARAM, and EMBED
   tags as pairs of parameters:

   <script language="JavaScript" type="text/javascript">
      QT_WriteOBJECT(srcURL, width, height, activeXVersion,
         "attributeName1", "attributeValue1",
         "attributeName1", "attributeValue2",
         "attributeName1", "attributeValue3",
         "attributeName1", "attributeValue4",
         ...
         "attributeNameN", "attributeValueN"
      );
    </script>

   These functions automatically add the "classid", "codebase", and "pluginspage" tags to
   the OBJECT and/or EMBED tags with standard values if they are not specified in the
   parameter list, so you need not supply these tags unless you require non-standard values.

   Although the OBJECT and EMBED tags typically have the same attributes and parameters, it
   is sometimes useful to have different values for each.
   Any attribute name prefixed with "obj#" is added to the OBJECT tag only, any attribute
   name prefixed with "emb#" is added to the EMBED tag only.

   <script language="JavaScript" type="text/javascript">
      QT_WriteOBJECT('http://www.domain.com/sample.mov', '480', '288', ''
        , 'emb#bgcolor', '#FFFFFF');
   </script>

 */

/************** LOCALIZABLE GLOBAL VARIABLES ****************/

var gArgCountErr =	'The "%%" function requires an even number of arguments.'
				+	'\nArguments should be in the form "atttributeName", "attributeValue", ...';

/******************** END LOCALIZABLE **********************/

var gTagAttrs				= null;
var gQTGeneratorVersion		= 0.8;

function AC_QuickTimeVersion()	{ return gQTGeneratorVersion; }

function _QTComplain(callingFcnName, errMsg)
{
    errMsg = errMsg.replace("%%", callingFcnName);
	alert(errMsg);
}

function _QTAddAttribute(prefix, slotName, tagName)
{
	var		value;

	value = gTagAttrs[prefix + slotName];
	if ( null == value )
		value = gTagAttrs[slotName];

	if ( null != value )
	{
		if ( 0 == slotName.indexOf(prefix) && (null == tagName) )
			tagName = slotName.substring(prefix.length);
		if ( null == tagName )
			tagName = slotName;
		return tagName + '="' + value + '" ';
	}
	else
		return "";
}

function _QTAddObjectAttr(slotName, tagName)
{
	// don't bother if it is only for the embed tag
	if ( 0 == slotName.indexOf("emb#") )
		return "";

	if ( 0 == slotName.indexOf("obj#") && (null == tagName) )
		tagName = slotName.substring(4);

	return _QTAddAttribute("obj#", slotName, tagName);
}

function _QTAddEmbedAttr(slotName, tagName)
{
	// don't bother if it is only for the object tag
	if ( 0 == slotName.indexOf("obj#") )
		return "";

	if ( 0 == slotName.indexOf("emb#") && (null == tagName) )
		tagName = slotName.substring(4);

	return _QTAddAttribute("emb#", slotName, tagName);
}


function _QTAddObjectParam(slotName, generateXHTML)
{
	var		paramValue;
	var		paramStr = "";
	var		endTagChar = (generateXHTML) ? ' />' : '>';

	if ( -1 == slotName.indexOf("emb#") )
	{
		// look for the OBJECT-only param first. if there is none, look for a generic one
		paramValue = gTagAttrs["obj#" + slotName];
		if ( null == paramValue )
			paramValue = gTagAttrs[slotName];

		if ( 0 == slotName.indexOf("obj#") )
			slotName = slotName.substring(4);

		if ( null != paramValue )
			paramStr = '  <param name="' + slotName + '" value="' + paramValue + '"' + endTagChar + '\n';
	}

	return paramStr;
}

function _QTDeleteTagAttrs()
{
	for ( var ndx = 0; ndx < arguments.length; ndx++ )
	{
		var attrName = arguments[ndx];
		delete gTagAttrs[attrName];
		delete gTagAttrs["emb#" + attrName];
		delete gTagAttrs["obj#" + attrName];
	}
}



// generate an embed and object tag, return as a string
function _QTGenerate(callingFcnName, generateXHTML, args)
{
	// is the number of optional arguments even?
	if ( args.length < 4 || (0 != (args.length % 2)) )
	{
		_QTComplain(callingFcnName, gArgCountErr);
		return "";
	}

	// allocate an array, fill in the required attributes with fixed place params and defaults
	gTagAttrs = new Array();
	gTagAttrs["src"] = args[0];
	gTagAttrs["width"] = args[1];
	gTagAttrs["height"] = args[2];
	gTagAttrs["classid"] = "clsid:02BF25D5-8C17-4B23-BC80-D3488ABDDC6B";
	gTagAttrs["pluginspage"] = "http://www.apple.com/quicktime/download/";

	// set up codebase attribute with specified or default version before parsing args so
	//  anything passed in will override
	var activexVers = args[3]
	if ( (null == activexVers) || ("" == activexVers) )
		activexVers = "6,0,2,0";
	gTagAttrs["codebase"] = "http://www.apple.com/qtactivex/qtplugin.cab#version=" + activexVers;

	var	attrName,
		attrValue;

	// add all of the optional attributes to the array
	for ( var ndx = 4; ndx < args.length; ndx += 2)
	{
		attrName = args[ndx].toLowerCase();
		attrValue = args[ndx + 1];

		// "name" and "id" should have the same value, the former goes in the embed and the later goes in
		//  the object. use one array slot
		if ( "name" == attrName || "id" == attrName )
			gTagAttrs["name"] = attrValue;

		else
			gTagAttrs[attrName] = attrValue;
	}

	// init both tags with the required and "special" attributes
	var objTag =  '<object '
					+ _QTAddObjectAttr("classid")
					+ _QTAddObjectAttr("width")
					+ _QTAddObjectAttr("height")
					+ _QTAddObjectAttr("codebase")
					+ _QTAddObjectAttr("name", "id")
					+ _QTAddObjectAttr("tabindex")
					+ _QTAddObjectAttr("hspace")
					+ _QTAddObjectAttr("vspace")
					+ _QTAddObjectAttr("border")
					+ _QTAddObjectAttr("align")
					+ _QTAddObjectAttr("class")
					+ _QTAddObjectAttr("title")
					+ _QTAddObjectAttr("accesskey")
					+ _QTAddObjectAttr("noexternaldata")
					+ '>\n'
					+ _QTAddObjectParam("src", generateXHTML);
	var embedTag = '  <embed '
					+ _QTAddEmbedAttr("src")
					+ _QTAddEmbedAttr("width")
					+ _QTAddEmbedAttr("height")
					+ _QTAddEmbedAttr("pluginspage")
					+ _QTAddEmbedAttr("name")
					+ _QTAddEmbedAttr("align")
					+ _QTAddEmbedAttr("tabindex");

	// delete the attributes/params we have already added
	_QTDeleteTagAttrs("src","width","height","pluginspage","classid","codebase","name","tabindex",
					"hspace","vspace","border","align","noexternaldata","class","title","accesskey");

	// and finally, add all of the remaining attributes to the embed and object
	for ( var attrName in gTagAttrs )
	{
		attrValue = gTagAttrs[attrName];
		if ( null != attrValue )
		{
			embedTag += _QTAddEmbedAttr(attrName);
			objTag += _QTAddObjectParam(attrName, generateXHTML);
		}
	}

	// end both tags, we're done
	return objTag + embedTag + '> </em' + 'bed>\n</ob' + 'ject' + '>';
}

// return the object/embed as a string
function QT_GenerateOBJECTText()
{
	return _QTGenerate("QT_GenerateOBJECTText", false, arguments);
}

function QT_GenerateOBJECTText_XHTML()
{
	return _QTGenerate("QT_GenerateOBJECTText_XHTML", true, arguments);
}

function QT_WriteOBJECT()
{
	document.writeln(_QTGenerate("QT_WriteOBJECT", false, arguments));
}

function QT_WriteOBJECT_XHTML()
{
	document.writeln(_QTGenerate("QT_WriteOBJECT_XHTML", true, arguments));
}

/* --- End /home/httpd/public/app_frame/webroot/js/Trailer.js --- */
/* --- Start /home/httpd/public/app_frame/webroot/js/Rating.js --- */

function Rating()
{
    this.maxRating = 5;
    this.parentElement = null;
    this.list = null;
    this.rating = 0;
    this.empty = 'http://assets.westword.com/img/star-empty.jpg';
    this.full = 'http://assets.westword.com/img/star-full.jpg';
    this.ratings = new Array;
    this.onChange = null;
    this.displayOnly = false;

    this.render = function(parentId)
    {
        this.parentElement = document.getElementById(parentId);
        if(this.parentElement)
        {
            this.list = document.createElement('ul');
            this.list.className = 'Rating';
            var i;
            for(i = 0; i < this.maxRating; i++)
            {
                var item = document.createElement('li');
                item.control = this;
                item.rating = i + 1;
                item.image = document.createElement('img');
                item.image.src = this.empty;
                item.image.rating = i + 1;
                item.image.control = this;
                item.image.title = (i + 1) + ' star';
                if(i > 0)
                {
                    item.image.title += 's';
                }
                item.onmouseover = function()
                {
                    this.control.hoverRating(this.rating - 1);
                }
                item.onmouseout = function()
                {
                    this.control.hoverRating(this.control.rating - 1);
                }
                item.image.onclick = function()
                {
                    if(!this.control.displayOnly)
                    {
                        this.control.rating = this.rating;
                        if(this.control.onChange)
                        {
                            this.control.onChange(this.rating);
                        }
                    }
                }
                item.appendChild(item.image);
                this.ratings[i] = item;
                this.list.appendChild(item);
            }
            this.parentElement.appendChild(this.list);
        }
    }

    this.setRating = function(rating)
    {
        this.rating = rating;
        var i;
        for(i = 0; i < this.maxRating; i++)
        {
            if(i <= rating - 1)
            {
                this.ratings[i].image.src = this.full;
            }
            else
            {
                this.ratings[i].image.src = this.empty;
            }
        }
    }

    this.hoverRating = function(idx)
    {
        if(!this.displayOnly)
        {
            var i;
            for(i = 0; i < this.maxRating; i++)
            {
                if(i <= idx)
                {
                    this.ratings[i].image.src = this.full;
                }
                else
                {
                    this.ratings[i].image.src = this.empty;
                }
            }
        }
    }
}

/* --- End /home/httpd/public/app_frame/webroot/js/Rating.js --- */
/* --- Start /home/httpd/public/app_frame/webroot/js/LSBBCoupon.js --- */

function LSBBCoupon_window(url,window_name,window_width,window_height)
{
    var w = window.open(url,window_name,'width=' + window_width + ',height=' + window_height + ',resizable');
}

/* --- End /home/httpd/public/app_frame/webroot/js/LSBBCoupon.js --- */
/* --- Start /home/httpd/public/app_frame/webroot/js/VVForm.js --- */

/*
 *  VVForm.js - Form Manipulation and validation script
 *
 *  ************************************************************
 *  Note: Before adding any new functions into this class
 *        PLEASE check the prototype and scriptaculous libraries
 *        for duplicate functionality.
 *  ************************************************************
 */

function VVForm() {

}

function clearInput( id, value )
{
	if( document.getElementById( id ).value == value )
	{
		document.getElementById( id ).value='';
	}
}

function resetInput( id, value )
{
	if( document.getElementById( id ).value == "" )
	{
        document.getElementById( id ).value=value;
	}
}

/* --- End /home/httpd/public/app_frame/webroot/js/VVForm.js --- */


/* Generated at 2008-10-28 12:38:07 */

/* NA () - 192.168.62.208 - [0.525] */
