/*  Prototype JavaScript framework, version 1.6.1
 *  (c) 2005-2009 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.1',

  Browser: (function(){
    var ua = navigator.userAgent;
    var isOpera = Object.prototype.toString.call(window.opera) == '[object Opera]';
    return {
      IE:             !!window.attachEvent && !isOpera,
      Opera:          isOpera,
      WebKit:         ua.indexOf('AppleWebKit/') > -1,
      Gecko:          ua.indexOf('Gecko') > -1 && ua.indexOf('KHTML') === -1,
      MobileSafari:   /Apple.*Mobile.*Safari/.test(ua)
    }
  })(),

  BrowserFeatures: {
    XPath: !!document.evaluate,
    SelectorsAPI: !!document.querySelector,
    ElementExtensions: (function() {
      var constructor = window.Element || window.HTMLElement;
      return !!(constructor && constructor.prototype);
    })(),
    SpecificElementExtensions: (function() {
      if (typeof window.HTMLDivElement !== 'undefined')
        return true;

      var div = document.createElement('div');
      var form = document.createElement('form');
      var isSupported = false;

      if (div['__proto__'] && (div['__proto__'] !== form['__proto__'])) {
        isSupported = true;
      }

      div = form = null;

      return isSupported;
    })()
  },

  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;


var Abstract = { };


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

/* Based on Alex Arnell's inheritance implementation. */

var Class = (function() {
  function subclass() {};
  function create() {
    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) {
      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;
  }

  function addMethods(source) {
    var ancestor   = this.superclass && this.superclass.prototype;
    var properties = Object.keys(source);

    if (!Object.keys({ toString: true }).length) {
      if (source.toString != Object.prototype.toString)
        properties.push("toString");
      if (source.valueOf != Object.prototype.valueOf)
        properties.push("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 = (function(m) {
          return function() { return ancestor[m].apply(this, arguments); };
        })(property).wrap(method);

        value.valueOf = method.valueOf.bind(method);
        value.toString = method.toString.bind(method);
      }
      this.prototype[property] = value;
    }

    return this;
  }

  return {
    create: create,
    Methods: {
      addMethods: addMethods
    }
  };
})();
(function() {

  var _toString = Object.prototype.toString;

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

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

  function toJSON(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 (isElement(object)) return;

    var results = [];
    for (var property in object) {
      var value = toJSON(object[property]);
      if (!isUndefined(value))
        results.push(property.toJSON() + ': ' + value);
    }

    return '{' + results.join(', ') + '}';
  }

  function toQueryString(object) {
    return $H(object).toQueryString();
  }

  function toHTML(object) {
    return object && object.toHTML ? object.toHTML() : String.interpret(object);
  }

  function keys(object) {
    var results = [];
    for (var property in object)
      results.push(property);
    return results;
  }

  function values(object) {
    var results = [];
    for (var property in object)
      results.push(object[property]);
    return results;
  }

  function clone(object) {
    return extend({ }, object);
  }

  function isElement(object) {
    return !!(object && object.nodeType == 1);
  }

  function isArray(object) {
    return _toString.call(object) == "[object Array]";
  }


  function isHash(object) {
    return object instanceof Hash;
  }

  function isFunction(object) {
    return typeof object === "function";
  }

  function isString(object) {
    return _toString.call(object) == "[object String]";
  }

  function isNumber(object) {
    return _toString.call(object) == "[object Number]";
  }

  function isUndefined(object) {
    return typeof object === "undefined";
  }

  extend(Object, {
    extend:        extend,
    inspect:       inspect,
    toJSON:        toJSON,
    toQueryString: toQueryString,
    toHTML:        toHTML,
    keys:          keys,
    values:        values,
    clone:         clone,
    isElement:     isElement,
    isArray:       isArray,
    isHash:        isHash,
    isFunction:    isFunction,
    isString:      isString,
    isNumber:      isNumber,
    isUndefined:   isUndefined
  });
})();
Object.extend(Function.prototype, (function() {
  var slice = Array.prototype.slice;

  function update(array, args) {
    var arrayLength = array.length, length = args.length;
    while (length--) array[arrayLength + length] = args[length];
    return array;
  }

  function merge(array, args) {
    array = slice.call(array, 0);
    return update(array, args);
  }

  function argumentNames() {
    var names = this.toString().match(/^[\s\(]*function[^(]*\(([^)]*)\)/)[1]
      .replace(/\/\/.*?[\r\n]|\/\*(?:.|[\r\n])*?\*\//g, '')
      .replace(/\s+/g, '').split(',');
    return names.length == 1 && !names[0] ? [] : names;
  }

  function bind(context) {
    if (arguments.length < 2 && Object.isUndefined(arguments[0])) return this;
    var __method = this, args = slice.call(arguments, 1);
    return function() {
      var a = merge(args, arguments);
      return __method.apply(context, a);
    }
  }

  function bindAsEventListener(context) {
    var __method = this, args = slice.call(arguments, 1);
    return function(event) {
      var a = update([event || window.event], args);
      return __method.apply(context, a);
    }
  }

  function curry() {
    if (!arguments.length) return this;
    var __method = this, args = slice.call(arguments, 0);
    return function() {
      var a = merge(args, arguments);
      return __method.apply(this, a);
    }
  }

  function delay(timeout) {
    var __method = this, args = slice.call(arguments, 1);
    timeout = timeout * 1000
    return window.setTimeout(function() {
      return __method.apply(__method, args);
    }, timeout);
  }

  function defer() {
    var args = update([0.01], arguments);
    return this.delay.apply(this, args);
  }

  function wrap(wrapper) {
    var __method = this;
    return function() {
      var a = update([__method.bind(this)], arguments);
      return wrapper.apply(this, a);
    }
  }

  function methodize() {
    if (this._methodized) return this._methodized;
    var __method = this;
    return this._methodized = function() {
      var a = update([this], arguments);
      return __method.apply(null, a);
    };
  }

  return {
    argumentNames:       argumentNames,
    bind:                bind,
    bindAsEventListener: bindAsEventListener,
    curry:               curry,
    delay:               delay,
    defer:               defer,
    wrap:                wrap,
    methodize:           methodize
  }
})());


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


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();
        this.currentlyExecuting = false;
      } catch(e) {
        this.currentlyExecuting = false;
        throw e;
      }
    }
  }
});
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, (function() {

  function prepareReplacement(replacement) {
    if (Object.isFunction(replacement)) return replacement;
    var template = new Template(replacement);
    return function(match) { return template.evaluate(match) };
  }

  function gsub(pattern, replacement) {
    var result = '', source = this, match;
    replacement = prepareReplacement(replacement);

    if (Object.isString(pattern))
      pattern = RegExp.escape(pattern);

    if (!(pattern.length || pattern.source)) {
      replacement = replacement('');
      return replacement + source.split('').join(replacement) + 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;
  }

  function sub(pattern, replacement, count) {
    replacement = prepareReplacement(replacement);
    count = Object.isUndefined(count) ? 1 : count;

    return this.gsub(pattern, function(match) {
      if (--count < 0) return match[0];
      return replacement(match);
    });
  }

  function scan(pattern, iterator) {
    this.gsub(pattern, iterator);
    return String(this);
  }

  function truncate(length, truncation) {
    length = length || 30;
    truncation = Object.isUndefined(truncation) ? '...' : truncation;
    return this.length > length ?
      this.slice(0, length - truncation.length) + truncation : String(this);
  }

  function strip() {
    return this.replace(/^\s+/, '').replace(/\s+$/, '');
  }

  function stripTags() {
    return this.replace(/<\w+(\s+("[^"]*"|'[^']*'|[^>])+)?>|<\/\w+>/gi, '');
  }

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

  function extractScripts() {
    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];
    });
  }

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

  function escapeHTML() {
    return this.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');
  }

  function unescapeHTML() {
    return this.stripTags().replace(/&lt;/g,'<').replace(/&gt;/g,'>').replace(/&amp;/g,'&');
  }


  function toQueryParams(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;
    });
  }

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

  function succ() {
    return this.slice(0, this.length - 1) +
      String.fromCharCode(this.charCodeAt(this.length - 1) + 1);
  }

  function times(count) {
    return count < 1 ? '' : new Array(count + 1).join(this);
  }

  function camelize() {
    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;
  }

  function capitalize() {
    return this.charAt(0).toUpperCase() + this.substring(1).toLowerCase();
  }

  function underscore() {
    return this.replace(/::/g, '/')
               .replace(/([A-Z]+)([A-Z][a-z])/g, '$1_$2')
               .replace(/([a-z\d])([A-Z])/g, '$1_$2')
               .replace(/-/g, '_')
               .toLowerCase();
  }

  function dasherize() {
    return this.replace(/_/g, '-');
  }

  function inspect(useDoubleQuotes) {
    var escapedString = this.replace(/[\x00-\x1f\\]/g, function(character) {
      if (character in String.specialChar) {
        return String.specialChar[character];
      }
      return '\\u00' + character.charCodeAt().toPaddedString(2, 16);
    });
    if (useDoubleQuotes) return '"' + escapedString.replace(/"/g, '\\"') + '"';
    return "'" + escapedString.replace(/'/g, '\\\'') + "'";
  }

  function toJSON() {
    return this.inspect(true);
  }

  function unfilterJSON(filter) {
    return this.replace(filter || Prototype.JSONFilter, '$1');
  }

  function isJSON() {
    var str = this;
    if (str.blank()) return false;
    str = this.replace(/\\./g, '@').replace(/"[^"\\\n\r]*"/g, '');
    return (/^[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]*$/).test(str);
  }

  function evalJSON(sanitize) {
    var json = this.unfilterJSON();
    try {
      if (!sanitize || json.isJSON()) return eval('(' + json + ')');
    } catch (e) { }
    throw new SyntaxError('Badly formed JSON string: ' + this.inspect());
  }

  function include(pattern) {
    return this.indexOf(pattern) > -1;
  }

  function startsWith(pattern) {
    return this.indexOf(pattern) === 0;
  }

  function endsWith(pattern) {
    var d = this.length - pattern.length;
    return d >= 0 && this.lastIndexOf(pattern) === d;
  }

  function empty() {
    return this == '';
  }

  function blank() {
    return /^\s*$/.test(this);
  }

  function interpolate(object, pattern) {
    return new Template(this, pattern).evaluate(object);
  }

  return {
    gsub:           gsub,
    sub:            sub,
    scan:           scan,
    truncate:       truncate,
    strip:          String.prototype.trim ? String.prototype.trim : strip,
    stripTags:      stripTags,
    stripScripts:   stripScripts,
    extractScripts: extractScripts,
    evalScripts:    evalScripts,
    escapeHTML:     escapeHTML,
    unescapeHTML:   unescapeHTML,
    toQueryParams:  toQueryParams,
    parseQuery:     toQueryParams,
    toArray:        toArray,
    succ:           succ,
    times:          times,
    camelize:       camelize,
    capitalize:     capitalize,
    underscore:     underscore,
    dasherize:      dasherize,
    inspect:        inspect,
    toJSON:         toJSON,
    unfilterJSON:   unfilterJSON,
    isJSON:         isJSON,
    evalJSON:       evalJSON,
    include:        include,
    startsWith:     startsWith,
    endsWith:       endsWith,
    empty:          empty,
    blank:          blank,
    interpolate:    interpolate
  };
})());

var Template = Class.create({
  initialize: function(template, pattern) {
    this.template = template.toString();
    this.pattern = pattern || Template.Pattern;
  },

  evaluate: function(object) {
    if (object && Object.isFunction(object.toTemplateReplacements))
      object = object.toTemplateReplacements();

    return this.template.gsub(this.pattern, function(match) {
      if (object == null) return (match[1] + '');

      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].replace(/\\\\]/g, ']') : 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);
    });
  }
});
Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/;

var $break = { };

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

  function eachSlice(number, iterator, context) {
    var index = -number, slices = [], array = this.toArray();
    if (number < 1) return array;
    while ((index += number) < array.length)
      slices.push(array.slice(index, index+number));
    return slices.collect(iterator, context);
  }

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

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

  function collect(iterator, context) {
    iterator = iterator || Prototype.K;
    var results = [];
    this.each(function(value, index) {
      results.push(iterator.call(context, value, index));
    });
    return results;
  }

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

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

  function grep(filter, iterator, context) {
    iterator = iterator || Prototype.K;
    var results = [];

    if (Object.isString(filter))
      filter = new RegExp(RegExp.escape(filter));

    this.each(function(value, index) {
      if (filter.match(value))
        results.push(iterator.call(context, value, index));
    });
    return results;
  }

  function include(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;
  }

  function inGroupsOf(number, fillWith) {
    fillWith = Object.isUndefined(fillWith) ? null : fillWith;
    return this.eachSlice(number, function(slice) {
      while(slice.length < number) slice.push(fillWith);
      return slice;
    });
  }

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

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

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

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

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

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

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

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

  function toArray() {
    return this.map();
  }

  function zip() {
    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));
    });
  }

  function size() {
    return this.toArray().length;
  }

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









  return {
    each:       each,
    eachSlice:  eachSlice,
    all:        all,
    every:      all,
    any:        any,
    some:       any,
    collect:    collect,
    map:        collect,
    detect:     detect,
    findAll:    findAll,
    select:     findAll,
    filter:     findAll,
    grep:       grep,
    include:    include,
    member:     include,
    inGroupsOf: inGroupsOf,
    inject:     inject,
    invoke:     invoke,
    max:        max,
    min:        min,
    partition:  partition,
    pluck:      pluck,
    reject:     reject,
    sortBy:     sortBy,
    toArray:    toArray,
    entries:    toArray,
    zip:        zip,
    size:       size,
    inspect:    inspect,
    find:       detect
  };
})();
function $A(iterable) {
  if (!iterable) return [];
  if ('toArray' in Object(iterable)) return iterable.toArray();
  var length = iterable.length || 0, results = new Array(length);
  while (length--) results[length] = iterable[length];
  return results;
}

function $w(string) {
  if (!Object.isString(string)) return [];
  string = string.strip();
  return string ? string.split(/\s+/) : [];
}

Array.from = $A;


(function() {
  var arrayProto = Array.prototype,
      slice = arrayProto.slice,
      _each = arrayProto.forEach; // use native browser JS 1.6 implementation if available

  function each(iterator) {
    for (var i = 0, length = this.length; i < length; i++)
      iterator(this[i]);
  }
  if (!_each) _each = each;

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

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

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

  function compact() {
    return this.select(function(value) {
      return value != null;
    });
  }

  function flatten() {
    return this.inject([], function(array, value) {
      if (Object.isArray(value))
        return array.concat(value.flatten());
      array.push(value);
      return array;
    });
  }

  function without() {
    var values = slice.call(arguments, 0);
    return this.select(function(value) {
      return !values.include(value);
    });
  }

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

  function uniq(sorted) {
    return this.inject([], function(array, value, index) {
      if (0 == index || (sorted ? array.last() != value : !array.include(value)))
        array.push(value);
      return array;
    });
  }

  function intersect(array) {
    return this.uniq().findAll(function(item) {
      return array.detect(function(value) { return item === value });
    });
  }


  function clone() {
    return slice.call(this, 0);
  }

  function size() {
    return this.length;
  }

  function inspect() {
    return '[' + this.map(Object.inspect).join(', ') + ']';
  }

  function toJSON() {
    var results = [];
    this.each(function(object) {
      var value = Object.toJSON(object);
      if (!Object.isUndefined(value)) results.push(value);
    });
    return '[' + results.join(', ') + ']';
  }

  function indexOf(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;
  }

  function lastIndexOf(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;
  }

  function concat() {
    var array = slice.call(this, 0), item;
    for (var i = 0, length = arguments.length; i < length; i++) {
      item = arguments[i];
      if (Object.isArray(item) && !('callee' in item)) {
        for (var j = 0, arrayLength = item.length; j < arrayLength; j++)
          array.push(item[j]);
      } else {
        array.push(item);
      }
    }
    return array;
  }

  Object.extend(arrayProto, Enumerable);

  if (!arrayProto._reverse)
    arrayProto._reverse = arrayProto.reverse;

  Object.extend(arrayProto, {
    _each:     _each,
    clear:     clear,
    first:     first,
    last:      last,
    compact:   compact,
    flatten:   flatten,
    without:   without,
    reverse:   reverse,
    uniq:      uniq,
    intersect: intersect,
    clone:     clone,
    toArray:   clone,
    size:      size,
    inspect:   inspect,
    toJSON:    toJSON
  });

  var CONCAT_ARGUMENTS_BUGGY = (function() {
    return [].concat(arguments)[0][0] !== 1;
  })(1,2)

  if (CONCAT_ARGUMENTS_BUGGY) arrayProto.concat = concat;

  if (!arrayProto.indexOf) arrayProto.indexOf = indexOf;
  if (!arrayProto.lastIndexOf) arrayProto.lastIndexOf = lastIndexOf;
})();
function $H(object) {
  return new Hash(object);
};

var Hash = Class.create(Enumerable, (function() {
  function initialize(object) {
    this._object = Object.isHash(object) ? object.toObject() : Object.clone(object);
  }

  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 set(key, value) {
    return this._object[key] = value;
  }

  function get(key) {
    if (this._object[key] !== Object.prototype[key])
      return this._object[key];
  }

  function unset(key) {
    var value = this._object[key];
    delete this._object[key];
    return value;
  }

  function toObject() {
    return Object.clone(this._object);
  }

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

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

  function index(value) {
    var match = this.detect(function(pair) {
      return pair.value === value;
    });
    return match && match.key;
  }

  function merge(object) {
    return this.clone().update(object);
  }

  function update(object) {
    return new Hash(object).inject(this, function(result, pair) {
      result.set(pair.key, pair.value);
      return result;
    });
  }

  function toQueryPair(key, value) {
    if (Object.isUndefined(value)) return key;
    return key + '=' + encodeURIComponent(String.interpret(value));
  }

  function toQueryString() {
    return this.inject([], function(results, pair) {
      var key = encodeURIComponent(pair.key), values = pair.value;

      if (values && typeof values == 'object') {
        if (Object.isArray(values))
          return results.concat(values.map(toQueryPair.curry(key)));
      } else results.push(toQueryPair(key, values));
      return results;
    }).join('&');
  }

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

  function toJSON() {
    return Object.toJSON(this.toObject());
  }

  function clone() {
    return new Hash(this);
  }

  return {
    initialize:             initialize,
    _each:                  _each,
    set:                    set,
    get:                    get,
    unset:                  unset,
    toObject:               toObject,
    toTemplateReplacements: toObject,
    keys:                   keys,
    values:                 values,
    index:                  index,
    merge:                  merge,
    update:                 update,
    toQueryString:          toQueryString,
    inspect:                inspect,
    toJSON:                 toJSON,
    clone:                  clone
  };
})());

Hash.from = $H;
Object.extend(Number.prototype, (function() {
  function toColorPart() {
    return this.toPaddedString(2, 16);
  }

  function succ() {
    return this + 1;
  }

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

  function toPaddedString(length, radix) {
    var string = this.toString(radix || 10);
    return '0'.times(length - string.length) + string;
  }

  function toJSON() {
    return isFinite(this) ? this.toString() : 'null';
  }

  function abs() {
    return Math.abs(this);
  }

  function round() {
    return Math.round(this);
  }

  function ceil() {
    return Math.ceil(this);
  }

  function floor() {
    return Math.floor(this);
  }

  return {
    toColorPart:    toColorPart,
    succ:           succ,
    times:          times,
    toPaddedString: toPaddedString,
    toJSON:         toJSON,
    abs:            abs,
    round:          round,
    ceil:           ceil,
    floor:          floor
  };
})());

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

var ObjectRange = Class.create(Enumerable, (function() {
  function initialize(start, end, exclusive) {
    this.start = start;
    this.end = end;
    this.exclusive = exclusive;
  }

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

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

  return {
    initialize: initialize,
    _each:      _each,
    include:    include
  };
})());



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();
    else if (Object.isHash(this.options.parameters))
      this.options.parameters = this.options.parameters.toObject();
  }
});
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)) {
      params['_method'] = this.method;
      this.method = 'post';
    }

    this.parameters = params;

    if (params = Object.toQueryString(params)) {
      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';
    }

    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 && this.isSameOrigin() && 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') {
      this.transport.onreadystatechange = Prototype.emptyFunction;
    }
  },

  isSameOrigin: function() {
    var m = this.url.match(/^\s*https?:\/\/[^\/]*/);
    return !m || (m[0] == '#{protocol}//#{domain}#{port}'.interpolate({
      protocol: location.protocol,
      domain: document.domain,
      port: location.port ? ':' + location.port : ''
    }));
  },

  getHeader: function(name) {
    try {
      return this.transport.getResponseHeader(name) || null;
    } 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  = Object.isUndefined(xml) ? 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 ||
        !this.request.isSameOrigin());
    } 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')) ||
        this.responseText.blank())
          return null;
    try {
      return this.responseText.evalJSON(options.sanitizeJSON ||
        !this.request.isSameOrigin());
    } 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 = Object.clone(options);
    var onComplete = options.onComplete;
    options.onComplete = (function(response, json) {
      this.updateContent(response.responseText);
      if (Object.isFunction(onComplete)) onComplete(response, json);
    }).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);
    }
  }
});

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) {
  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(global) {

  var SETATTRIBUTE_IGNORES_NAME = (function(){
    var elForm = document.createElement("form");
    var elInput = document.createElement("input");
    var root = document.documentElement;
    elInput.setAttribute("name", "test");
    elForm.appendChild(elInput);
    root.appendChild(elForm);
    var isBuggy = elForm.elements
      ? (typeof elForm.elements.test == "undefined")
      : null;
    root.removeChild(elForm);
    elForm = elInput = null;
    return isBuggy;
  })();

  var element = global.Element;
  global.Element = function(tagName, attributes) {
    attributes = attributes || { };
    tagName = tagName.toLowerCase();
    var cache = Element.cache;
    if (SETATTRIBUTE_IGNORES_NAME && 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(global.Element, element || { });
  if (element) global.Element.prototype = element.prototype;
})(this);

Element.cache = { };
Element.idCounter = 1;

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 = $(element);
    element.style.display = 'none';
    return element;
  },

  show: function(element) {
    element = $(element);
    element.style.display = '';
    return element;
  },

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

  update: (function(){

    var SELECT_ELEMENT_INNERHTML_BUGGY = (function(){
      var el = document.createElement("select"),
          isBuggy = true;
      el.innerHTML = "<option value=\"test\">test</option>";
      if (el.options && el.options[0]) {
        isBuggy = el.options[0].nodeName.toUpperCase() !== "OPTION";
      }
      el = null;
      return isBuggy;
    })();

    var TABLE_ELEMENT_INNERHTML_BUGGY = (function(){
      try {
        var el = document.createElement("table");
        if (el && el.tBodies) {
          el.innerHTML = "<tbody><tr><td>test</td></tr></tbody>";
          var isBuggy = typeof el.tBodies[0] == "undefined";
          el = null;
          return isBuggy;
        }
      } catch (e) {
        return true;
      }
    })();

    var SCRIPT_ELEMENT_REJECTS_TEXTNODE_APPENDING = (function () {
      var s = document.createElement("script"),
          isBuggy = false;
      try {
        s.appendChild(document.createTextNode(""));
        isBuggy = !s.firstChild ||
          s.firstChild && s.firstChild.nodeType !== 3;
      } catch (e) {
        isBuggy = true;
      }
      s = null;
      return isBuggy;
    })();

    function update(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 === 'SCRIPT' && SCRIPT_ELEMENT_REJECTS_TEXTNODE_APPENDING) {
        element.text = content;
        return element;
      }

      if (SELECT_ELEMENT_INNERHTML_BUGGY || TABLE_ELEMENT_INNERHTML_BUGGY) {
        if (tagName in Element._insertionTranslations.tags) {
          while (element.firstChild) {
            element.removeChild(element.firstChild);
          }
          Element._getContentFromAnonymousElement(tagName, content.stripScripts())
            .each(function(node) {
              element.appendChild(node)
            });
        }
        else {
          element.innerHTML = content.stripScripts();
        }
      }
      else {
        element.innerHTML = content.stripScripts();
      }

      content.evalScripts.bind(content).defer();
      return element;
    }

    return update;
  })(),

  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, insert, tagName, childNodes;

    for (var position in insertions) {
      content  = insertions[position];
      position = position.toLowerCase();
      insert = Element._insertionTranslations[position];

      if (content && content.toElement) content = content.toElement();
      if (Object.isElement(content)) {
        insert(element, content);
        continue;
      }

      content = Object.toHTML(content);

      tagName = ((position == 'before' || position == 'after')
        ? element.parentNode : element).tagName.toUpperCase();

      childNodes = Element._getContentFromAnonymousElement(tagName, content.stripScripts());

      if (position == 'top' || position == 'after') childNodes.reverse();
      childNodes.each(insert.curry(element));

      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(element, 'parentNode');
  },

  descendants: function(element) {
    return Element.select(element, "*");
  },

  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(element, 'previousSibling');
  },

  nextSiblings: function(element) {
    return Element.recursivelyCollect(element, 'nextSibling');
  },

  siblings: function(element) {
    element = $(element);
    return Element.previousSiblings(element).reverse()
      .concat(Element.nextSiblings(element));
  },

  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(element);
    return Object.isNumber(expression) ? ancestors[expression] :
      Selector.findElement(ancestors, expression, index);
  },

  down: function(element, expression, index) {
    element = $(element);
    if (arguments.length == 1) return Element.firstDescendant(element);
    return Object.isNumber(expression) ? Element.descendants(element)[expression] :
      Element.select(element, expression)[index || 0];
  },

  previous: function(element, expression, index) {
    element = $(element);
    if (arguments.length == 1) return $(Selector.handlers.previousElementSibling(element));
    var previousSiblings = Element.previousSiblings(element);
    return Object.isNumber(expression) ? previousSiblings[expression] :
      Selector.findElement(previousSiblings, expression, index);
  },

  next: function(element, expression, index) {
    element = $(element);
    if (arguments.length == 1) return $(Selector.handlers.nextElementSibling(element));
    var nextSiblings = Element.nextSiblings(element);
    return Object.isNumber(expression) ? nextSiblings[expression] :
      Selector.findElement(nextSiblings, expression, index);
  },


  select: function(element) {
    var args = Array.prototype.slice.call(arguments, 1);
    return Selector.findChildElements(element, args);
  },

  adjacent: function(element) {
    var args = Array.prototype.slice.call(arguments, 1);
    return Selector.findChildElements(element.parentNode, args).without(element);
  },

  identify: function(element) {
    element = $(element);
    var id = Element.readAttribute(element, 'id');
    if (id) return id;
    do { id = 'anonymous_element_' + Element.idCounter++ } while ($(id));
    Element.writeAttribute(element, '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] = Object.isUndefined(value) ? true : value;

    for (var attr in attributes) {
      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(element).height;
  },

  getWidth: function(element) {
    return Element.getDimensions(element).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(element, 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(element, className) ?
      'removeClassName' : 'addClassName'](element, className);
  },

  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 (ancestor.contains)
      return ancestor.contains(element) && ancestor !== element;

    while (element = element.parentNode)
      if (element == ancestor) return true;

    return false;
  },

  scrollTo: function(element) {
    element = $(element);
    var pos = Element.cumulativeOffset(element);
    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 || value == 'auto') {
      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') ?
          (Object.isUndefined(elementStyle.styleFloat) ? '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(element, 'display');
    if (display != 'none' && display != null) // Safari bug
      return {width: element.offsetWidth, height: element.offsetHeight};

    var els = element.style;
    var originalVisibility = els.visibility;
    var originalPosition = els.position;
    var originalDisplay = els.display;
    els.visibility = 'hidden';
    if (originalPosition != 'fixed') // Switching fixed to absolute causes issues in Safari
      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';
      if (Prototype.Browser.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.toUpperCase() == 'BODY') break;
        var p = Element.getStyle(element, 'position');
        if (p !== 'static') break;
      }
    } while (element);
    return Element._returnOffset(valueL, valueT);
  },

  absolutize: function(element) {
    element = $(element);
    if (Element.getStyle(element, 'position') == 'absolute') return element;

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

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

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

  relativize: function(element) {
    element = $(element);
    if (Element.getStyle(element, 'position') == 'relative') return element;

    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;

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

    } while (element = element.offsetParent);

    element = forElement;
    do {
      if (!Prototype.Browser.Opera || (element.tagName && (element.tagName.toUpperCase() == '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] || { });

    source = $(source);
    var p = Element.viewportOffset(source);

    element = $(element);
    var delta = [0, 0];
    var parent = null;
    if (Element.getStyle(element, 'position') == 'absolute') {
      parent = Element.getOffsetParent(element);
      delta = Element.viewportOffset(parent);
    }

    if (parent == document.body) {
      delta[0] -= document.body.offsetLeft;
      delta[1] -= document.body.offsetTop;
    }

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

Object.extend(Element.Methods, {
  getElementsBySelector: Element.Methods.select,

  childElements: Element.Methods.immediateDescendants
});

Element._attributeTranslations = {
  write: {
    names: {
      className: 'class',
      htmlFor:   'for'
    },
    values: { }
  }
};

if (Prototype.Browser.Opera) {
  Element.Methods.getStyle = Element.Methods.getStyle.wrap(
    function(proceed, element, style) {
      switch (style) {
        case 'left': case 'top': case 'right': case 'bottom':
          if (proceed(element, 'position') === 'static') return null;
        case 'height': case 'width':
          if (!Element.visible(element)) return null;

          var dim = parseInt(proceed(element, style), 10);

          if (dim !== element['offset' + style.capitalize()])
            return dim + 'px';

          var properties;
          if (style === 'height') {
            properties = ['border-top-width', 'padding-top',
             'padding-bottom', 'border-bottom-width'];
          }
          else {
            properties = ['border-left-width', 'padding-left',
             'padding-right', 'border-right-width'];
          }
          return properties.inject(dim, function(memo, property) {
            var val = proceed(element, property);
            return val === null ? memo : memo - parseInt(val, 10);
          }) + 'px';
        default: return proceed(element, style);
      }
    }
  );

  Element.Methods.readAttribute = Element.Methods.readAttribute.wrap(
    function(proceed, element, attribute) {
      if (attribute === 'title') return element.title;
      return proceed(element, attribute);
    }
  );
}

else if (Prototype.Browser.IE) {
  Element.Methods.getOffsetParent = Element.Methods.getOffsetParent.wrap(
    function(proceed, element) {
      element = $(element);
      try { element.offsetParent }
      catch(e) { return $(document.body) }
      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;
    }
  );

  $w('positionedOffset viewportOffset').each(function(method) {
    Element.Methods[method] = Element.Methods[method].wrap(
      function(proceed, element) {
        element = $(element);
        try { element.offsetParent }
        catch(e) { return Element._returnOffset(0,0) }
        var position = element.getStyle('position');
        if (position !== 'static') return proceed(element);
        var offsetParent = element.getOffsetParent();
        if (offsetParent && offsetParent.getStyle('position') === 'fixed')
          offsetParent.setStyle({ zoom: 1 });
        element.setStyle({ position: 'relative' });
        var value = proceed(element);
        element.setStyle({ position: position });
        return value;
      }
    );
  });

  Element.Methods.cumulativeOffset = Element.Methods.cumulativeOffset.wrap(
    function(proceed, element) {
      try { element.offsetParent }
      catch(e) { return Element._returnOffset(0,0) }
      return proceed(element);
    }
  );

  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 = (function(){

    var classProp = 'className';
    var forProp = 'for';

    var el = document.createElement('div');

    el.setAttribute(classProp, 'x');

    if (el.className !== 'x') {
      el.setAttribute('class', 'x');
      if (el.className === 'x') {
        classProp = 'class';
      }
    }
    el = null;

    el = document.createElement('label');
    el.setAttribute(forProp, 'x');
    if (el.htmlFor !== 'x') {
      el.setAttribute('htmlFor', 'x');
      if (el.htmlFor === 'x') {
        forProp = 'htmlFor';
      }
    }
    el = null;

    return {
      read: {
        names: {
          'class':      classProp,
          'className':  classProp,
          'for':        forProp,
          'htmlFor':    forProp
        },
        values: {
          _getAttr: function(element, attribute) {
            return element.getAttribute(attribute);
          },
          _getAttr2: function(element, attribute) {
            return element.getAttribute(attribute, 2);
          },
          _getAttrNode: function(element, attribute) {
            var node = element.getAttributeNode(attribute);
            return node ? node.value : "";
          },
          _getEv: (function(){

            var el = document.createElement('div');
            el.onclick = Prototype.emptyFunction;
            var value = el.getAttribute('onclick');
            var f;

            if (String(value).indexOf('{') > -1) {
              f = function(element, attribute) {
                attribute = element.getAttribute(attribute);
                if (!attribute) return null;
                attribute = attribute.toString();
                attribute = attribute.split('{')[1];
                attribute = attribute.split('}')[0];
                return attribute.strip();
              };
            }
            else if (value === '') {
              f = function(element, attribute) {
                attribute = element.getAttribute(attribute);
                if (!attribute) return null;
                return attribute.strip();
              };
            }
            el = null;
            return f;
          })(),
          _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.extend({
      cellpadding: 'cellPadding',
      cellspacing: 'cellSpacing'
    }, 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 frameBorder').each(function(attr) {
    Element._attributeTranslations.write.names[attr.toLowerCase()] = attr;
    Element._attributeTranslations.has[attr.toLowerCase()] = attr;
  });

  (function(v) {
    Object.extend(v, {
      href:        v._getAttr2,
      src:         v._getAttr2,
      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);

  if (Prototype.BrowserFeatures.ElementExtensions) {
    (function() {
      function _descendants(element) {
        var nodes = element.getElementsByTagName('*'), results = [];
        for (var i = 0, node; node = nodes[i]; i++)
          if (node.tagName !== "!") // Filter out comment nodes.
            results.push(node);
        return results;
      }

      Element.Methods.down = function(element, expression, index) {
        element = $(element);
        if (arguments.length == 1) return element.firstDescendant();
        return Object.isNumber(expression) ? _descendants(element)[expression] :
          Element.select(element, expression)[index || 0];
      }
    })();
  }

}

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.toUpperCase() == 'IMG' && element.width) {
        element.width++; element.width--;
      } else try {
        var n = document.createTextNode(' ');
        element.appendChild(n);
        element.removeChild(n);
      } catch (e) { }

    return element;
  };

  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 ('outerHTML' in document.documentElement) {
  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];
  if (t) {
    div.innerHTML = t[0] + html + t[1];
    t[2].times(function() { div = div.firstChild });
  } else div.innerHTML = html;
  return $A(div.childNodes);
};

Element._insertionTranslations = {
  before: function(element, node) {
    element.parentNode.insertBefore(node, element);
  },
  top: function(element, node) {
    element.insertBefore(node, element.firstChild);
  },
  bottom: function(element, node) {
    element.appendChild(node);
  },
  after: function(element, node) {
    element.parentNode.insertBefore(node, element.nextSibling);
  },
  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() {
  var tags = Element._insertionTranslations.tags;
  Object.extend(tags, {
    THEAD: tags.TBODY,
    TFOOT: tags.TBODY,
    TH:    tags.TD
  });
})();

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);

(function(div) {

  if (!Prototype.BrowserFeatures.ElementExtensions && div['__proto__']) {
    window.HTMLElement = { };
    window.HTMLElement.prototype = div['__proto__'];
    Prototype.BrowserFeatures.ElementExtensions = true;
  }

  div = null;

})(document.createElement('div'))

Element.extend = (function() {

  function checkDeficiency(tagName) {
    if (typeof window.Element != 'undefined') {
      var proto = window.Element.prototype;
      if (proto) {
        var id = '_' + (Math.random()+'').slice(2);
        var el = document.createElement(tagName);
        proto[id] = 'x';
        var isBuggy = (el[id] !== 'x');
        delete proto[id];
        el = null;
        return isBuggy;
      }
    }
    return false;
  }

  function extendElementWith(element, methods) {
    for (var property in methods) {
      var value = methods[property];
      if (Object.isFunction(value) && !(property in element))
        element[property] = value.methodize();
    }
  }

  var HTMLOBJECTELEMENT_PROTOTYPE_BUGGY = checkDeficiency('object');

  if (Prototype.BrowserFeatures.SpecificElementExtensions) {
    if (HTMLOBJECTELEMENT_PROTOTYPE_BUGGY) {
      return function(element) {
        if (element && typeof element._extendedByPrototype == 'undefined') {
          var t = element.tagName;
          if (t && (/^(?:object|applet|embed)$/i.test(t))) {
            extendElementWith(element, Element.Methods);
            extendElementWith(element, Element.Methods.Simulated);
            extendElementWith(element, Element.Methods.ByTag[t.toUpperCase()]);
          }
        }
        return element;
      }
    }
    return Prototype.K;
  }

  var Methods = { }, ByTag = Element.Methods.ByTag;

  var extend = Object.extend(function(element) {
    if (!element || typeof element._extendedByPrototype != 'undefined' ||
        element.nodeType != 1 || element == window) return element;

    var methods = Object.clone(Methods),
        tagName = element.tagName.toUpperCase();

    if (ByTag[tagName]) Object.extend(methods, ByTag[tagName]);

    extendElementWith(element, methods);

    element._extendedByPrototype = Prototype.emptyFunction;
    return element;

  }, {
    refresh: function() {
      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];

    var element = document.createElement(tagName);
    var proto = element['__proto__'] || element.constructor.prototype;
    element = null;
    return proto;
  }

  var elementPrototype = window.HTMLElement ? HTMLElement.prototype :
   Element.prototype;

  if (F.ElementExtensions) {
    copy(Element.Methods, elementPrototype);
    copy(Element.Methods.Simulated, elementPrototype, 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() {
    return { width: this.getWidth(), height: this.getHeight() };
  },

  getScrollOffsets: function() {
    return Element._returnOffset(
      window.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft,
      window.pageYOffset || document.documentElement.scrollTop  || document.body.scrollTop);
  }
};

(function(viewport) {
  var B = Prototype.Browser, doc = document, element, property = {};

  function getRootElement() {
    if (B.WebKit && !doc.evaluate)
      return document;

    if (B.Opera && window.parseFloat(window.opera.version()) < 9.5)
      return document.body;

    return document.documentElement;
  }

  function define(D) {
    if (!element) element = getRootElement();

    property[D] = 'client' + D;

    viewport['get' + D] = function() { return element[property[D]] };
    return viewport['get' + D]();
  }

  viewport.getWidth  = define.curry('Width');

  viewport.getHeight = define.curry('Height');
})(document.viewport);


Element.Storage = {
  UID: 1
};

Element.addMethods({
  getStorage: function(element) {
    if (!(element = $(element))) return;

    var uid;
    if (element === window) {
      uid = 0;
    } else {
      if (typeof element._prototypeUID === "undefined")
        element._prototypeUID = [Element.Storage.UID++];
      uid = element._prototypeUID[0];
    }

    if (!Element.Storage[uid])
      Element.Storage[uid] = $H();

    return Element.Storage[uid];
  },

  store: function(element, key, value) {
    if (!(element = $(element))) return;

    if (arguments.length === 2) {
      Element.getStorage(element).update(key);
    } else {
      Element.getStorage(element).set(key, value);
    }

    return element;
  },

  retrieve: function(element, key, defaultValue) {
    if (!(element = $(element))) return;
    var hash = Element.getStorage(element), value = hash.get(key);

    if (Object.isUndefined(value)) {
      hash.set(key, defaultValue);
      value = defaultValue;
    }

    return value;
  },

  clone: function(element, deep) {
    if (!(element = $(element))) return;
    var clone = element.cloneNode(deep);
    clone._prototypeUID = void 0;
    if (deep) {
      var descendants = Element.select(clone, '*'),
          i = descendants.length;
      while (i--) {
        descendants[i]._prototypeUID = void 0;
      }
    }
    return Element.extend(clone);
  }
});
/* 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();

    if (this.shouldUseSelectorsAPI()) {
      this.mode = 'selectorsAPI';
    } else if (this.shouldUseXPath()) {
      this.mode = 'xpath';
      this.compileXPathMatcher();
    } else {
      this.mode = "normal";
      this.compileMatcher();
    }

  },

  shouldUseXPath: (function() {

    var IS_DESCENDANT_SELECTOR_BUGGY = (function(){
      var isBuggy = false;
      if (document.evaluate && window.XPathResult) {
        var el = document.createElement('div');
        el.innerHTML = '<ul><li></li></ul><div><ul><li></li></ul></div>';

        var xpath = ".//*[local-name()='ul' or local-name()='UL']" +
          "//*[local-name()='li' or local-name()='LI']";

        var result = document.evaluate(xpath, el, null,
          XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);

        isBuggy = (result.snapshotLength !== 2);
        el = null;
      }
      return isBuggy;
    })();

    return function() {
      if (!Prototype.BrowserFeatures.XPath) return false;

      var e = this.expression;

      if (Prototype.Browser.WebKit &&
       (e.include("-of-type") || e.include(":empty")))
        return false;

      if ((/(\[[\w-]*?:|:checked)/).test(e))
        return false;

      if (IS_DESCENDANT_SELECTOR_BUGGY) return false;

      return true;
    }

  })(),

  shouldUseSelectorsAPI: function() {
    if (!Prototype.BrowserFeatures.SelectorsAPI) return false;

    if (Selector.CASE_INSENSITIVE_CLASS_NAMES) return false;

    if (!Selector._div) Selector._div = new Element('div');

    try {
      Selector._div.querySelector(this.expression);
    } catch(e) {
      return false;
    }

    return true;
  },

  compileMatcher: function() {
    var e = this.expression, ps = Selector.patterns, h = Selector.handlers,
        c = Selector.criteria, le, p, m, len = ps.length, name;

    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 = 0; i<len; i++) {
        p = ps[i].re;
        name = ps[i].name;
        if (m = e.match(p)) {
          this.matcher.push(Object.isFunction(c[name]) ? c[name](m) :
            new Template(c[name]).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, len = ps.length, name;

    if (Selector._cache[e]) {
      this.xpath = Selector._cache[e]; return;
    }

    this.matcher = ['.//*'];
    while (e && le != e && (/\S/).test(e)) {
      le = e;
      for (var i = 0; i<len; i++) {
        name = ps[i].name;
        if (m = e.match(ps[i].re)) {
          this.matcher.push(Object.isFunction(x[name]) ? x[name](m) :
            new Template(x[name]).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;
    var e = this.expression, results;

    switch (this.mode) {
      case 'selectorsAPI':
        if (root !== document) {
          var oldId = root.id, id = $(root).identify();
          id = id.replace(/([\.:])/g, "\\$1");
          e = "#" + id + " " + e;
        }

        results = $A(root.querySelectorAll(e)).map(Element.extend);
        root.id = oldId;

        return results;
      case 'xpath':
        return document._getElementsByXPath(this.xpath, root);
      default:
       return this.matcher(root);
    }
  },

  match: function(element) {
    this.tokens = [];

    var e = this.expression, ps = Selector.patterns, as = Selector.assertions;
    var le, p, m, len = ps.length, name;

    while (e && le !== e && (/\S/).test(e)) {
      le = e;
      for (var i = 0; i<len; i++) {
        p = ps[i].re;
        name = ps[i].name;
        if (m = e.match(p)) {
          if (as[name]) {
            this.tokens.push([name, Object.clone(m)]);
            e = e.replace(m[0], '');
          } else {
            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() + ">";
  }
});

if (Prototype.BrowserFeatures.SelectorsAPI &&
 document.compatMode === 'BackCompat') {
  Selector.CASE_INSENSITIVE_CLASS_NAMES = (function(){
    var div = document.createElement('div'),
     span = document.createElement('span');

    div.id = "prototype_test_id";
    span.className = 'Test';
    div.appendChild(span);
    var isIgnored = (div.querySelector('#prototype_test_id .test') !== null);
    div = span = null;
    return isIgnored;
  })();
}

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: function(m) {
      m[1] = m[1].toLowerCase();
      return new Template("[@#{1}]").evaluate(m);
    },
    attr: function(m) {
      m[1] = m[1].toLowerCase();
      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)]",
      'checked':     "[@checked]",
      'disabled':    "[(@disabled) and (@type!='hidden')]",
      'enabled':     "[not(@disabled) and (@type!='hidden')]",
      'not': function(m) {
        var e = m[6], p = Selector.patterns,
            x = Selector.xpath, le, v, len = p.length, name;

        var exclusion = [];
        while (e && le != e && (/\S/).test(e)) {
          le = e;
          for (var i = 0; i<len; i++) {
            name = p[i].name
            if (m = e.match(p[i].re)) {
              v = Object.isFunction(x[name]) ? x[name](m) : new Template(x[name]).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); c = false;',
    attr: function(m) {
      m[3] = (m[5] || m[6]);
      return new Template('n = h.attr(n, r, "#{1}", "#{3}", "#{2}", c); 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: [
    { name: 'laterSibling', re: /^\s*~\s*/ },
    { name: 'child',        re: /^\s*>\s*/ },
    { name: 'adjacent',     re: /^\s*\+\s*/ },
    { name: 'descendant',   re: /^\s/ },

    { name: 'tagName',      re: /^\s*(\*|[\w\-]+)(\b|$)?/ },
    { name: 'id',           re: /^#([\w\-\*]+)(\b|$)/ },
    { name: 'className',    re: /^\.([\w\-\*]+)(\b|$)/ },
    { name: 'pseudo',       re: /^:((first|last|nth|nth-last|only)(-child|-of-type)|empty|checked|(en|dis)abled|not)(\((.*?)\))?(\b|$|(?=\s|[:+~>]))/ },
    { name: 'attrPresence', re: /^\[((?:[\w-]+:)?[\w-]+)\]/ },
    { name: 'attr',         re: /\[((?:[\w-]*:)?[\w-]+)\s*(?:([!^$*~|]?=)\s*((['"])([^\4]*?)\4|([^'"][^\]]*?)))?\]/ }
  ],

  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 nodeValue && Selector.operators[matches[2]](nodeValue, matches[5] || matches[6]);
    }
  },

  handlers: {
    concat: function(a, b) {
      for (var i = 0, node; node = b[i]; i++)
        a.push(node);
      return a;
    },

    mark: function(nodes) {
      var _true = Prototype.emptyFunction;
      for (var i = 0, node; node = nodes[i]; i++)
        node._countedByPrototype = _true;
      return nodes;
    },

    unmark: (function(){

      var PROPERTIES_ATTRIBUTES_MAP = (function(){
        var el = document.createElement('div'),
            isBuggy = false,
            propName = '_countedByPrototype',
            value = 'x'
        el[propName] = value;
        isBuggy = (el.getAttribute(propName) === value);
        el = null;
        return isBuggy;
      })();

      return PROPERTIES_ATTRIBUTES_MAP ?
        function(nodes) {
          for (var i = 0, node; node = nodes[i]; i++)
            node.removeAttribute('_countedByPrototype');
          return nodes;
        } :
        function(nodes) {
          for (var i = 0, node; node = nodes[i]; i++)
            node._countedByPrototype = void 0;
          return nodes;
        }
    })(),

    index: function(parentNode, reverse, ofType) {
      parentNode._countedByPrototype = Prototype.emptyFunction;
      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._countedByPrototype)) node.nodeIndex = j++;
        }
      } else {
        for (var i = 0, j = 1, nodes = parentNode.childNodes; node = nodes[i]; i++)
          if (node.nodeType == 1 && (!ofType || node._countedByPrototype)) node.nodeIndex = j++;
      }
    },

    unique: function(nodes) {
      if (nodes.length == 0) return nodes;
      var results = [], n;
      for (var i = 0, l = nodes.length; i < l; i++)
        if (typeof (n = nodes[i])._countedByPrototype == 'undefined') {
          n._countedByPrototype = Prototype.emptyFunction;
          results.push(Element.extend(n));
        }
      return Selector.handlers.unmark(results);
    },

    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, 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;
    },

    tagName: function(nodes, root, tagName, combinator) {
      var uTagName = tagName.toUpperCase();
      var results = [], h = Selector.handlers;
      if (nodes) {
        if (combinator) {
          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() === uTagName) results.push(node);
        return results;
      } else return root.getElementsByTagName(tagName);
    },

    id: function(nodes, root, id, combinator) {
      var targetNode = $(id), h = Selector.handlers;

      if (root == document) {
        if (!targetNode) return [];
        if (!nodes) return [targetNode];
      } else {
        if (!root.sourceIndex || root.sourceIndex < 1) {
          var nodes = root.getElementsByTagName('*');
          for (var j = 0, node; node = nodes[j]; j++) {
            if (node.id === id) return [node];
          }
        }
      }

      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, combinator) {
      if (!nodes) nodes = root.getElementsByTagName("*");
      if (nodes && combinator) nodes = this[combinator](nodes);
      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, combinator) {
      if (!nodes) nodes = root.getElementsByTagName("*");
      if (nodes && combinator) nodes = this[combinator](nodes);
      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);
    },

    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;
      });
    },

    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._countedByPrototype) {
          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++) {
        if (node.tagName == '!' || node.firstChild) 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._countedByPrototype) 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 && (!node.type || node.type !== 'hidden'))
          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 == v || nv && nv.startsWith(v); },
    '$=': function(nv, v) { return nv == v || nv && nv.endsWith(v); },
    '*=': function(nv, v) { return nv == v || nv && nv.include(v); },
    '~=': function(nv, v) { return (' ' + nv + ' ').include(' ' + v + ' '); },
    '|=': function(nv, v) { return ('-' + (nv || "").toUpperCase() +
     '-').include('-' + (v || "").toUpperCase() + '-'); }
  },

  split: function(expression) {
    var expressions = [];
    expression.scan(/(([\w#:.~>+()\s-]+|\*|\[.*?\])+)\s*(,|$)/, function(m) {
      expressions.push(m[1].strip());
    });
    return expressions;
  },

  matchElements: function(elements, expression) {
    var matches = $$(expression), h = Selector.handlers;
    h.mark(matches);
    for (var i = 0, results = [], element; element = elements[i]; i++)
      if (element._countedByPrototype) 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) {
    expressions = Selector.split(expressions.join(','));
    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;
  }
});

if (Prototype.Browser.IE) {
  Object.extend(Selector.handlers, {
    concat: function(a, b) {
      for (var i = 0, node; node = b[i]; i++)
        if (node.tagName !== "!") a.push(node);
      return a;
    }
  });
}

function $$() {
  return Selector.findChildElements(document, $A(arguments));
}

var Form = {
  reset: function(form) {
    form = $(form);
    form.reset();
    return form;
  },

  serializeElements: function(elements, options) {
    if (typeof options != 'object') options = { hash: !!options };
    else if (Object.isUndefined(options.hash)) 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 != 'file' && (element.type != 'submit' || (!submitted &&
            submit !== false && (!submit || key == submit) && (submitted = true)))) {
          if (key in result) {
            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) {
    var elements = $(form).getElementsByTagName('*'),
        element,
        arr = [ ],
        serializers = Form.Element.Serializers;
    for (var i = 0; element = elements[i]; i++) {
      arr.push(element);
    }
    return arr.inject([], function(elements, child) {
      if (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)$/i.test(element.tagName);
    });
  },

  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)$/i.test(element.type))))
        element.select();
    } catch (e) { }
    return element;
  },

  disable: function(element) {
    element = $(element);
    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 (Object.isUndefined(value)) return element.checked ? element.value : null;
    else element.checked = !!value;
  },

  textarea: function(element, value) {
    if (Object.isUndefined(value)) return element.value;
    else element.value = value;
  },

  select: function(element, value) {
    if (Object.isUndefined(value))
      return this[element.type == 'select-one' ?
        'selectOne' : 'selectMany'](element);
    else {
      var opt, currentValue, single = !Object.isArray(value);
      for (var i = 0, length = element.length; i < length; i++) {
        opt = element.options[i];
        currentValue = this.optionValue(opt);
        if (single) {
          if (currentValue == value) {
            opt.selected = true;
            return;
          }
        }
        else opt.selected = value.include(currentValue);
      }
    }
  },

  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) {
    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);
  }
});
(function() {

  var 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: {}
  };

  var docEl = document.documentElement;
  var MOUSEENTER_MOUSELEAVE_EVENTS_SUPPORTED = 'onmouseenter' in docEl
    && 'onmouseleave' in docEl;

  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);
    };
  }

  function isLeftClick(event)   { return _isButton(event, 0) }

  function isMiddleClick(event) { return _isButton(event, 1) }

  function isRightClick(event)  { return _isButton(event, 2) }

  function element(event) {
    event = Event.extend(event);

    var node = event.target, type = event.type,
     currentTarget = event.currentTarget;

    if (currentTarget && currentTarget.tagName) {
      if (type === 'load' || type === 'error' ||
        (type === 'click' && currentTarget.tagName.toLowerCase() === 'input'
          && currentTarget.type === 'radio'))
            node = currentTarget;
    }

    if (node.nodeType == Node.TEXT_NODE)
      node = node.parentNode;

    return Element.extend(node);
  }

  function findElement(event, expression) {
    var element = Event.element(event);
    if (!expression) return element;
    var elements = [element].concat(element.ancestors());
    return Selector.findElement(elements, expression, 0);
  }

  function pointer(event) {
    return { x: pointerX(event), y: pointerY(event) };
  }

  function pointerX(event) {
    var docElement = document.documentElement,
     body = document.body || { scrollLeft: 0 };

    return event.pageX || (event.clientX +
      (docElement.scrollLeft || body.scrollLeft) -
      (docElement.clientLeft || 0));
  }

  function pointerY(event) {
    var docElement = document.documentElement,
     body = document.body || { scrollTop: 0 };

    return  event.pageY || (event.clientY +
       (docElement.scrollTop || body.scrollTop) -
       (docElement.clientTop || 0));
  }


  function stop(event) {
    Event.extend(event);
    event.preventDefault();
    event.stopPropagation();

    event.stopped = true;
  }

  Event.Methods = {
    isLeftClick: isLeftClick,
    isMiddleClick: isMiddleClick,
    isRightClick: isRightClick,

    element: element,
    findElement: findElement,

    pointer: pointer,
    pointerX: pointerX,
    pointerY: pointerY,

    stop: stop
  };


  var methods = Object.keys(Event.Methods).inject({ }, function(m, name) {
    m[name] = Event.Methods[name].methodize();
    return m;
  });

  if (Prototype.Browser.IE) {
    function _relatedTarget(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);
    }

    Object.extend(methods, {
      stopPropagation: function() { this.cancelBubble = true },
      preventDefault:  function() { this.returnValue = false },
      inspect: function() { return '[object Event]' }
    });

    Event.extend = function(event, element) {
      if (!event) return false;
      if (event._extendedByPrototype) return event;

      event._extendedByPrototype = Prototype.emptyFunction;
      var pointer = Event.pointer(event);

      Object.extend(event, {
        target: event.srcElement || element,
        relatedTarget: _relatedTarget(event),
        pageX:  pointer.x,
        pageY:  pointer.y
      });

      return Object.extend(event, methods);
    };
  } else {
    Event.prototype = window.Event.prototype || document.createEvent('HTMLEvents').__proto__;
    Object.extend(Event.prototype, methods);
    Event.extend = Prototype.K;
  }

  function _createResponder(element, eventName, handler) {
    var registry = Element.retrieve(element, 'prototype_event_registry');

    if (Object.isUndefined(registry)) {
      CACHE.push(element);
      registry = Element.retrieve(element, 'prototype_event_registry', $H());
    }

    var respondersForEvent = registry.get(eventName);
    if (Object.isUndefined(respondersForEvent)) {
      respondersForEvent = [];
      registry.set(eventName, respondersForEvent);
    }

    if (respondersForEvent.pluck('handler').include(handler)) return false;

    var responder;
    if (eventName.include(":")) {
      responder = function(event) {
        if (Object.isUndefined(event.eventName))
          return false;

        if (event.eventName !== eventName)
          return false;

        Event.extend(event, element);
        handler.call(element, event);
      };
    } else {
      if (!MOUSEENTER_MOUSELEAVE_EVENTS_SUPPORTED &&
       (eventName === "mouseenter" || eventName === "mouseleave")) {
        if (eventName === "mouseenter" || eventName === "mouseleave") {
          responder = function(event) {
            Event.extend(event, element);

            var parent = event.relatedTarget;
            while (parent && parent !== element) {
              try { parent = parent.parentNode; }
              catch(e) { parent = element; }
            }

            if (parent === element) return;

            handler.call(element, event);
          };
        }
      } else {
        responder = function(event) {
          Event.extend(event, element);
          handler.call(element, event);
        };
      }
    }

    responder.handler = handler;
    respondersForEvent.push(responder);
    return responder;
  }

  function _destroyCache() {
    for (var i = 0, length = CACHE.length; i < length; i++) {
      Event.stopObserving(CACHE[i]);
      CACHE[i] = null;
    }
  }

  var CACHE = [];

  if (Prototype.Browser.IE)
    window.attachEvent('onunload', _destroyCache);

  if (Prototype.Browser.WebKit)
    window.addEventListener('unload', Prototype.emptyFunction, false);


  var _getDOMEventName = Prototype.K;

  if (!MOUSEENTER_MOUSELEAVE_EVENTS_SUPPORTED) {
    _getDOMEventName = function(eventName) {
      var translations = { mouseenter: "mouseover", mouseleave: "mouseout" };
      return eventName in translations ? translations[eventName] : eventName;
    };
  }

  function observe(element, eventName, handler) {
    element = $(element);

    var responder = _createResponder(element, eventName, handler);

    if (!responder) return element;

    if (eventName.include(':')) {
      if (element.addEventListener)
        element.addEventListener("dataavailable", responder, false);
      else {
        element.attachEvent("ondataavailable", responder);
        element.attachEvent("onfilterchange", responder);
      }
    } else {
      var actualEventName = _getDOMEventName(eventName);

      if (element.addEventListener)
        element.addEventListener(actualEventName, responder, false);
      else
        element.attachEvent("on" + actualEventName, responder);
    }

    return element;
  }

  function stopObserving(element, eventName, handler) {
    element = $(element);

    var registry = Element.retrieve(element, 'prototype_event_registry');

    if (Object.isUndefined(registry)) return element;

    if (eventName && !handler) {
      var responders = registry.get(eventName);

      if (Object.isUndefined(responders)) return element;

      responders.each( function(r) {
        Element.stopObserving(element, eventName, r.handler);
      });
      return element;
    } else if (!eventName) {
      registry.each( function(pair) {
        var eventName = pair.key, responders = pair.value;

        responders.each( function(r) {
          Element.stopObserving(element, eventName, r.handler);
        });
      });
      return element;
    }

    var responders = registry.get(eventName);

    if (!responders) return;

    var responder = responders.find( function(r) { return r.handler === handler; });
    if (!responder) return element;

    var actualEventName = _getDOMEventName(eventName);

    if (eventName.include(':')) {
      if (element.removeEventListener)
        element.removeEventListener("dataavailable", responder, false);
      else {
        element.detachEvent("ondataavailable", responder);
        element.detachEvent("onfilterchange",  responder);
      }
    } else {
      if (element.removeEventListener)
        element.removeEventListener(actualEventName, responder, false);
      else
        element.detachEvent('on' + actualEventName, responder);
    }

    registry.set(eventName, responders.without(responder));

    return element;
  }

  function fire(element, eventName, memo, bubble) {
    element = $(element);

    if (Object.isUndefined(bubble))
      bubble = true;

    if (element == document && document.createEvent && !element.dispatchEvent)
      element = document.documentElement;

    var event;
    if (document.createEvent) {
      event = document.createEvent('HTMLEvents');
      event.initEvent('dataavailable', true, true);
    } else {
      event = document.createEventObject();
      event.eventType = bubble ? 'ondataavailable' : 'onfilterchange';
    }

    event.eventName = eventName;
    event.memo = memo || { };

    if (document.createEvent)
      element.dispatchEvent(event);
    else
      element.fireEvent(event.eventType, event);

    return Event.extend(event);
  }


  Object.extend(Event, Event.Methods);

  Object.extend(Event, {
    fire:          fire,
    observe:       observe,
    stopObserving: stopObserving
  });

  Element.addMethods({
    fire:          fire,

    observe:       observe,

    stopObserving: stopObserving
  });

  Object.extend(document, {
    fire:          fire.methodize(),

    observe:       observe.methodize(),

    stopObserving: stopObserving.methodize(),

    loaded:        false
  });

  if (window.Event) Object.extend(window.Event, Event);
  else window.Event = Event;
})();

(function() {
  /* Support for the DOMContentLoaded event is based on work by Dan Webb,
     Matthias Miller, Dean Edwards, John Resig, and Diego Perini. */

  var timer;

  function fireContentLoadedEvent() {
    if (document.loaded) return;
    if (timer) window.clearTimeout(timer);
    document.loaded = true;
    document.fire('dom:loaded');
  }

  function checkReadyState() {
    if (document.readyState === 'complete') {
      document.stopObserving('readystatechange', checkReadyState);
      fireContentLoadedEvent();
    }
  }

  function pollDoScroll() {
    try { document.documentElement.doScroll('left'); }
    catch(e) {
      timer = pollDoScroll.defer();
      return;
    }
    fireContentLoadedEvent();
  }

  if (document.addEventListener) {
    document.addEventListener('DOMContentLoaded', fireContentLoadedEvent, false);
  } else {
    document.observe('readystatechange', checkReadyState);
    if (window == top)
      timer = pollDoScroll.defer();
  }

  Event.observe(window, 'load', fireContentLoadedEvent);
})();

Element.addMethods();

/*------------------------------- 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');

var Position = {
  includeScrollOffsets: false,

  prepare: function() {
    this.deltaX =  window.pageXOffset
                || document.documentElement.scrollLeft
                || document.body.scrollLeft
                || 0;
    this.deltaY =  window.pageYOffset
                || document.documentElement.scrollTop
                || document.body.scrollTop
                || 0;
  },

  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);
  },

  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;
  },


  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);

/*--------------------------------------------------------------------------*/
// script.aculo.us scriptaculous.js v1.8.3, Thu Oct 08 11:23:33 +0200 2009

// Copyright (c) 2005-2009 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.3',
  require: function(libraryName) {
    try{
      // inserting via DOM fails in Safari 2.0, so brute force approach
      document.write('<script type="text/javascript" src="'+libraryName+'"><\/script>');
    } catch(e) {
      // for xhtml+xml served content, fall back to DOM methods
      var script = document.createElement('script');
      script.type = 'text/javascript';
      script.src = libraryName;
      document.getElementsByTagName('head')[0].appendChild(script);
    }
  },
  REQUIRED_PROTOTYPE: '1.6.0.3',
  load: function() {
    function convertVersionString(versionString) {
      var v = versionString.replace(/_.*|\./g, '');
      v = parseInt(v + '0'.times(4-v.length));
      return versionString.indexOf('_') > -1 ? v-1 : v;
    }

    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);

    var js = /scriptaculous\.js(\?.*)?$/;
    $$('head script[src]').findAll(function(s) {
      return s.src.match(js);
    }).each(function(s) {
      var path = s.src.replace(js, ''),
      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();
// script.aculo.us effects.js v1.8.3, Thu Oct 08 11:23:33 +0200 2009

// Copyright (c) 2005-2009 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) + .5;
    },
    reverse: function(pos) {
      return 1-pos;
    },
    flicker: function(pos) {
      var pos = ((-Math.cos(pos*Math.PI)/4) + .75) + Math.random()/4;
      return pos > 1 ? 1 : pos;
    },
    wobble: function(pos) {
      return (-Math.cos(pos*Math.PI*(9*pos))/2) + .5;
    },
    pulse: function(pos, pulses) {
      return (-Math.cos((pos*((pulses||5)-.5)*2)*Math.PI)/2) + .5;
    },
    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, options) {
    element = $(element);
    effect  = (effect || 'appear').toLowerCase();
    
    return Effect[ Effect.PAIRS[ effect ][ element.visible() ? 1 : 0 ] ](element, Object.extend({
      queue: { position:'end', scope:(element.id || 'global'), limit: 1 }
    }, 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) {
    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;

    this.render = (function() {
      function dispatch(effect, eventName) {
        if (effect.options[eventName + 'Internal'])
          effect.options[eventName + 'Internal'](effect);
        if (effect.options[eventName])
          effect.options[eventName](effect);
      }

      return function(pos) {
        if (this.state === "idle") {
          this.state = "running";
          dispatch(this, 'beforeSetup');
          if (this.setup) this.setup();
          dispatch(this, 'afterSetup');
        }
        if (this.state === "running") {
          pos = (this.options.transition(pos) * this.fromToDelta) + this.options.from;
          this.position = pos;
          dispatch(this, 'beforeUpdate');
          if (this.update) this.update(pos);
          dispatch(this, '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();

  if (options.offset) elementOffsets[1] += options.offset;

  return new Effect.Tween(null,
    scrollOffsets.top,
    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] || { },
    oldOpacity = element.getInlineOpacity(),
    transition = options.transition || Effect.Transitions.linear,
    reverser   = function(pos){
      return 1 - transition((-Math.cos((pos*(options.pulses||5)*2)*Math.PI)/2) + .5);
    };

  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(results, property) {
      results[property] = css[property];
      return results;
    });
    if (!styles.opacity) styles.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);
/**
 * The Shadowbox class.
 *
 * This file is part of Shadowbox.
 *
 * Shadowbox is an online media viewer application that supports all of the
 * web's most popular media publishing formats. Shadowbox is written entirely
 * in JavaScript and CSS and is highly customizable. Using Shadowbox, website
 * authors can showcase a wide assortment of media in all major browsers without
 * navigating users away from the linking page.
 *
 * You should have received a license with this distribution explaining the terms
 * under which Shadowbox may be used. If you did not, you may obtain a copy of the
 * license at http://shadowbox-js.com/LICENSE
 *
 * @author      Michael J. I. Jackson <michael@mjijackson.com>
 * @copyright   2007-2009 Michael J. I. Jackson
 * @version     SVN: $Id: shadowbox.js 20M 2009-04-29 04:26:23Z (local) $
 */

/**
 * The Shadowbox class. Used to display different media on a web page using a
 * Lightbox-like effect.
 *
 * Known issues:
 *
 * - Location.toString exception in FF3 when loading Flash content into an
 *   iframe (such as a YouTube video). Known Flash bug, will not be fixed.
 *   http://bugs.adobe.com/jira/browse/FP-561
 *
 * Useful resources:
 *
 * - http://www.alistapart.com/articles/byebyeembed
 * - http://www.w3.org/TR/html401/struct/objects.html
 * - http://www.dyn-web.com/dhtml/iframes/
 * - http://www.apple.com/quicktime/player/specs.html
 * - http://www.apple.com/quicktime/tutorials/embed2.html
 * - http://www.howtocreate.co.uk/wrongWithIE/?chapter=navigator.plugins
 * - http://msdn.microsoft.com/en-us/library/ms532969.aspx
 * - http://support.microsoft.com/kb/316992
 * - http://www.alistapart.com/articles/flashembedcagematch
 */
var Shadowbox = function(){

    var ua = navigator.userAgent.toLowerCase(),

    // the Shadowbox object
    S = {

        /**
         * The current version of Shadowbox.
         *
         * @var     String
         * @public
         */
        version: "3.0b",

        /**
         * The name of the adapter currently being used.
         *
         * @var     String
         * @public
         */
        adapter: null,

        /**
         * The array index of the current gallery that is currently being viewed.
         *
         * @var     Number
         * @public
         */
        current: -1,

        /**
         * An array containing the gallery objects currently being viewed. In the
         * case of non-gallery items, this will only hold one object.
         *
         * @var     Array
         * @public
         */
        gallery: [],

        /**
         * A cache of options for links that have been set up for use with
         * Shadowbox.
         *
         * @var     Array
         * @public
         */
        cache: [],

        /**
         * The current content object.
         *
         * @var     Object
         * @public
         */
        content: null,

        /**
         * Holds the current dimensions of Shadowbox as calculated by its skin.
         * Contains the following properties:
         *
         * - height: The total height of #sb-wrapper (including title & info bars)
         * - width: The total width of #sb-wrapper
         * - inner_h: The height of #sb-body
         * - inner_w: The width of #sb-body
         * - top: The top to use for #sb-wrapper
         * - left: The left to use for #sb-wrapper
         * - oversized: True if the content is oversized (too large for the viewport)
         * - resize_h: The height to use for resizable content
         * - resize_w: The width to use for resizable content
         *
         * @var     Object
         * @public
         */
        dimensions: null,

        /**
         * Contains plugin support information. Each property of this object is a
         * boolean indicating whether that plugin is supported.
         *
         * - fla: Flash player
         * - qt: QuickTime player
         * - wmp: Windows Media player
         * - f4m: Flip4Mac plugin
         *
         * @var     Object
         * @public
         */
        plugins: null,

        /**
         * Contains the base path of the Shadowbox script.
         *
         * Note: This property will automatically be populated in Shadowbox.load.
         *
         * @var     String
         * @public
         */
        path: 'js/',

        /**
         * Contains the default options for Shadowbox.
         *
         * @var     Object
         * @public
         */
        options: {
            adapter: null,              // the library adapter to use
            animate: true,              // enable all animations, except for fades
            animateFade: true,          // enable fade animations
            autoplayMovies: true,       // automatically play movies
            autoDimensions: false,      // use the dimensions of the first piece as
                                        // the initial dimensions (if they are
                                        // available)
            continuous: false,          // enables continuous galleries. When enabled,
                                        // user will be able to skip to the first
                                        // gallery item from the last using next and
                                        // vice versa
            counterLimit: 10,           // limit to the number of counter links that
                                        // are displayed in a "skip" style counter
            counterType: 'default',     // counter type. May be either "default" or
                                        // "skip". Skip counter displays a link for
                                        // each item in gallery
            displayCounter: true,       // display the gallery counter
            displayNav: true,           // show the navigation controls

            /**
             * Easing function used for animations. Based on a cubic polynomial.
             *
             * @param   Number      x       The state of the animation (% complete)
             * @return  Number              The adjusted easing value
             */
            ease: function(x){
                return 1 + Math.pow(x - 1, 3);
            },

            enableKeys: true,           // enable keyboard navigation

            /**
             * An object containing names of plugins and links to their respective
             * download pages.
             */
            errors: {
                fla: {
                    name:   'Flash',
                    url:    'http://www.adobe.com/products/flashplayer/'
                },
                qt: {
                    name:   'QuickTime',
                    url:    'http://www.apple.com/quicktime/download/'
                },
                wmp: {
                    name:   'Windows Media Player',
                    url:    'http://www.microsoft.com/windows/windowsmedia/'
                },
                f4m: {
                    name:   'Flip4Mac',
                    url:    'http://www.flip4mac.com/wmv_download.htm'
                }
            },

            /**
             * A map of players to the file extensions they support. Each member of
             * this object is the name of a player (with one exception), whose value
             * is an array of file extensions that player will "play". The one
             * exception to this rule is the "qtwmp" member, which contains extensions
             * that may be played using either QuickTime or Windows Media Player.
             *
             * - img: Image file extensions
             * - swf: Flash SWF file extensions
             * - flv: Flash video file extensions (will be played by JW FLV player)
             * - qt: Movie file extensions supported by QuickTime
             * - wmp: Movie file extensions supported by Windows Media Player
             * - qtwmp: Movie file extensions supported by both QuickTime and Windows Media Player
             * - iframe: File extensions that will be display in an iframe
             *
             * IMPORTANT: If this object is to be modified, it must be copied in its
             * entirety and tweaked because it is not merged recursively with the
             * default. Also, any modifications must be passed into Shadowbox.init
             * for speed reasons.
             */
            ext: {
                img:        ['png', 'jpg', 'jpeg', 'gif', 'bmp'],
                swf:        ['swf'],
                flv:        ['flv'],
                qt:         ['dv', 'mov', 'moov', 'movie', 'mp4'],
                wmp:        ['asf', 'wm', 'wmv'],
                qtwmp:      ['avi', 'mpg', 'mpeg'],
                iframe:     ['asp', 'aspx', 'cgi', 'cfm', 'htm', 'html', 'jsp',
                    'pl', 'php', 'php3', 'php4', 'php5', 'phtml', 'rb', 'rhtml',
                    'shtml', 'txt', 'vbs']
            },

            fadeDuration: 0.35,         // duration of the fading animations (seconds)

            /**
             * Parameters to pass to flash <object>'s.
             */
            flashParams: {
                bgcolor:            '#000000',
                allowFullScreen:    true
            },

            flashVars: {},              // flash vars
            flashVersion: '9.0.115',    // minimum required flash version suggested
                                        // by JW FLV player

            /**
             * How to handle content that is too large to display in its entirety
             * (and is resizable). A value of 'resize' will resize the content while
             * preserving aspect ratio and display it at the smaller resolution. If
             * the content is an image, a value of 'drag' will display the image at
             * its original resolution but it will be draggable within Shadowbox. A
             * value of 'none' will display the content at its original resolution
             * but it may be cropped.
             */
            handleOversize: 'resize',

            /**
             * The mode to use when handling unsupported media. May be either
             * 'remove' or 'link'. If it is 'remove', the unsupported gallery item
             * will merely be removed from the gallery. If it is the only item in
             * the gallery, the link will simply be followed. If it is 'link', a
             * link will be provided to the appropriate plugin page in place of the
             * gallery element.
             */
            handleUnsupported: 'link',

            initialHeight: 160,         // initial height (pixels)
            initialWidth: 320,          // initial width (pixels)
            language: 'en',             // the language to use
            modal: false,               // trigger Shadowbox.close() when overlay is
                                        // clicked
            onChange: null,             // hook function to be fired when changing
                                        // from one item to the next. Is passed the
                                        // item that is about to be displayed
            onClose: null,              // hook function to be fired when closing.
                                        // is passed the most recent item
            onFinish: null,             // hook function to be fired when finished
                                        // loading content. Is passed current
                                        // gallery item
            onOpen: null,               // hook function to be fired when opening.
                                        // is passed the current gallery item
            overlayColor: '#000',       // color to use for modal overlay
            overlayOpacity: 0.8,        // opacity to use for modal overlay
            players: ['img'],           // the players to load
            resizeDuration: 0.35,       // duration of resizing animations (seconds)
            showOverlay: true,          // show the overlay
            showMovieControls: true,    // enable movie controls on movie players
            skipSetup: false,           // skip calling Shadowbox.setup() during
                                        // shadowbox.init()
            slideshowDelay: 0,          // delay to use for slideshows (seconds). If
                                        // set to any duration other than 0, is interval
                                        // at which slideshow will advance
            useSizzle: true,            // use sizzle.js to support css selectors
            viewportPadding: 20         // amount of padding to maintain around the
                                        // edge of the viewport at all times (pixels)
        },

        /**
         * Some simple browser detection variables.
         *
         * @var     Object
         * @public
         */
        client: {
            isIE:       ua.indexOf('msie') > -1,
            isIE6:      ua.indexOf('msie 6') > -1,
            isIE7:      ua.indexOf('msie 7') > -1,
            isGecko:    ua.indexOf('gecko') > -1 && ua.indexOf('safari') == -1,
            isWebkit:   ua.indexOf('applewebkit/') > -1,
            isWindows:  ua.indexOf('windows') > -1 || ua.indexOf('win32') > -1,
            isMac:      ua.indexOf('macintosh') > -1 || ua.indexOf('mac os x') > -1,
            isLinux:    ua.indexOf('linux') > -1
        },

        /**
         * An object containing some regular expressions we'll need later. Compiled
         * up front for speed.
         *
         * @var     Object
         * @public
         */
        regex: {
            domain:         /:\/\/(.*?)[:\/]/,              // domain prefix
            inline:         /#(.+)$/,                       // inline element id
            rel:            /^(light|shadow)box/i,          // rel attribute format
            gallery:        /^(light|shadow)box\[(.*?)\]/i, // rel attribute format for gallery link
            unsupported:    /^unsupported-(\w+)/,           // unsupported media type
            param:          /\s*([a-z_]*?)\s*=\s*(.+)\s*/   // rel string parameter
        },

        /**
         * A map of library object names to their corresponding Shadowbox adapter
         * names.
         *
         * @var     Object
         * @public
         */
        libraries: {
            Prototype:  'prototype',
            jQuery:     'jquery',
            MooTools:   'mootools',
            YAHOO:      'yui',
            dojo:       'dojo',
            Ext:        'ext'
        },

        /**
         * Applies the given set of options to those currently in use.
         *
         * Note: Options will be reset on Shadowbox.open() so this function is
         * only useful after it has already been called (while Shadowbox is
         * open).
         *
         * @param   Object      opts        The options to apply
         * @return  void
         * @public
         */
        applyOptions: function(opts){
            if(opts){
                // store defaults, use apply to break reference
                default_options = apply({}, S.options);
                apply(S.options, opts);
            }
        },

        /**
         * Builds an object from the original link element data to store in cache.
         * These objects contain (most of) the following keys:
         *
         * - el: the link element
         * - title: the object's title
         * - player: the player to use for the object
         * - content: the object's URL
         * - gallery: the gallery the object belongs to (optional)
         * - height: the height of the object (only necessary for movies)
         * - width: the width of the object (only necessary for movies)
         * - options: custom options to use (optional)
         *
         * A custom set of options may be passed in here that will be applied when
         * this object is displayed. However, any options that are specified in
         * the link's HTML markup will trump options given here.
         *
         * @param   HTMLElement     link    The link element to process
         * @param   Object          opts    A set of options to use for the object
         * @return  Object                  An object representing the link
         * @public
         */
        buildCacheObj: function(link, opts){
            var href = link.href, // don't use getAttribute() here
            obj = {
                el:         link,
                title:      link.getAttribute('title'),
                options:    apply({}, opts || {}),
                content:    href
            };

            // remove link-level options from top-level options
            each(['player', 'title', 'height', 'width', 'gallery'], function(o){
                if(typeof obj.options[o] != 'undefined'){
                    obj[o] = obj.options[o];
                    delete obj.options[o];
                }
            });

            if(!obj.player)
                obj.player = getPlayer(href);

            // HTML options always trump JavaScript options, so do these last
            var rel = link.getAttribute('rel');
            if(rel){
                // extract gallery name from shadowbox[name] format
                var m = rel.match(S.regex.gallery);
                if(m)
                    obj.gallery = escape(m[2]);

                // other parameters
                each(rel.split(';'), function(p){
                    m = p.match(S.regex.param);
                    if(m){
                        if(m[1] == 'options')
                            eval('apply(obj.options,' + m[2] + ')');
                        else
                            obj[m[1]] = m[2];
                    }
                });
            }

            return obj;
        },

        /**
         * Jumps to the piece in the current gallery with the given index.
         *
         * @param   Number      n       The gallery index to view
         * @return  void
         * @public
         */
        change: function(n){
            if(!S.gallery) return; // no current gallery
            if(!S.gallery[n]){ // index does not exist
                if(!S.options.continuous){
                    return;
                }else{
                    n = n < 0 ? S.gallery.length - 1 : 0; // loop
                }
            }

            // update current
            S.current = n;

            if(typeof slide_timer == 'number'){
                clearTimeout(slide_timer);
                slide_timer = null;
                slide_delay = slide_start = 0; // reset slideshow variables
            }

            if(S.options.onChange)
                S.options.onChange();

            loadContent();
        },

        /**
         * Removes all onclick listeners from elements that have been setup with
         * Shadowbox and clears all objects from cache.
         *
         * @return  void
         * @public
         */
        clearCache: function(){
            each(S.cache, function(obj){
                if(obj.el)
                    S.lib.removeEvent(obj.el, 'click', handleClick);
            });
            S.cache = [];
        },

        /**
         * Deactivates Shadowbox.
         *
         * @return  void
         * @public
         */
        close: function(){
            if(!active) return; // already closed
            active = false;

            listenKeys(false);

            // remove the content
            if(S.content){
                S.content.remove();
                S.content = null;
            }

            // clear slideshow variables
            if(typeof slide_timer == 'number')
                clearTimeout(slide_timer);
            slide_timer = null;
            slide_delay = 0;

            if(S.options.onClose)
                S.options.onClose();

            S.skin.onClose();

            S.revertOptions();

            // reset troublesome elements to stored visibility settings
            each(v_cache, function(c){
                c[0].style.visibility = c[1];
            });
        },

        /**
         * Gets the id that should be used for content elements.
         *
         * @return  String          The content element id
         * @public
         */
        contentId: function(){
            return content_id;
        },

        /**
         * Gets the values that should appear in the counter (if the skin
         * supports counters). If a "skip" style counter is used, the return
         * value should be an array of all counter indexes that should be
         * displayed. If the "default" counter is used, the return value will
         * be a simple "1 of 5" message as a string. The skin can use the return
         * type to determine how to build the counter.
         *
         * @return  mixed           The counter as described above
         * @public
         */
        getCounter: function(){
            var len = S.gallery.length;

            if(S.options.counterType == 'skip'){
                // limit the counter?
                var c = [],
                    i = 0,
                    end = len,
                    limit = parseInt(S.options.counterLimit) || 0;

                if(limit < len && limit > 2){ // support large galleries
                    var h = Math.floor(limit / 2);
                    i = S.current - h;
                    if(i < 0) i += len;
                    end = S.current + (limit - h);
                    if(end > len) end -= len;
                }
                while(i != end){
                    if(i == len) i = 0;
                    c.push(i++);
                }
            }else
                var c = (S.current + 1) + ' ' + S.lang.of + ' ' + len;

            return c;
        },

        /**
         * Gets the current gallery object.
         *
         * @return  Object          The current gallery item
         * @public
         */
        getCurrent: function(){
            return S.current > -1 ? S.gallery[S.current] : null;
        },

        /**
         * Determines if there is a next piece to display in the current
         * gallery.
         *
         * @return  Boolean         True if there is another piece
         * @public
         */
        hasNext: function(){
            return S.gallery.length > 1 &&
                (S.current != S.gallery.length - 1 || S.options.continuous);
        },

        /**
         * Initializes the Shadowbox environment. Should be called by the user in
         * the <head> of the HTML document.
         *
         * Note: This function attempts to load all Shadowbox dependencies
         * dynamically using document.write. However, if these dependencies are
         * already included, they won't be loaded again.
         *
         * @param   Object      opts    (optional) The default options to use
         * @return  void
         * @public
         */
        init: function(opts){
            if(initialized) return; // don't initialize twice
            initialized = true;

            opts = opts || {};
            init_options = opts;

            // apply options
            if(opts)
                apply(S.options, opts);

            // compile file type regular expressions here for speed
            for(var e in S.options.ext)
                S.regex[e] = new RegExp('\.(' + S.options.ext[e].join('|') + ')\s*$', 'i');

            if(!S.path){
                // determine script path automatically
                var path_re = /(.+)shadowbox\.js/i, path;
                each(document.getElementsByTagName('script'), function(s){
                    if((path = path_re.exec(s.src)) != null){
                        S.path = path[1];
                        return false;
                    }
                });
            }

            // determine adapter
            if(S.options.adapter)
                S.adapter = S.options.adapter;
            else{
                for(var lib in S.libraries){
                    if(typeof window[lib] != 'undefined'){
                        S.adapter = S.libraries[lib];
                        break;
                    }
                }
                if(!S.adapter)
                    S.adapter = 'base';
            }

            // load dependencies
            if(S.options.useSizzle && !window['Sizzle'])
                U.include(S.path + 'libraries/sizzle/sizzle.js');
            if(!S.lang)
                U.include(S.path + 'languages/shadowbox-' + S.options.language + '.js');
            each(S.options.players, function(p){
                if((p == 'swf' || p == 'flv') && !window['swfobject'])
                    U.include(S.path + 'swfobject.js');
                if(!S[p])
                    U.include(S.path + 'players/shadowbox-' + p + '.js');
            });
            if(!S.lib)
                U.include(S.path + 'adapters/shadowbox-' + S.adapter + '.js');
        },

        /**
         * Tells whether or not Shadowbox is currently activated.
         *
         * @return  Boolean         True if activated, false otherwise
         * @public
         */
        isActive: function(){
            return active;
        },

        /**
         * Tells whether or not Shadowbox is currently in the middle of a
         * slideshow in a paused state.
         *
         * @return  Boolean         True if paused, false otherwise
         * @public
         */
        isPaused: function(){
            return slide_timer == 'paused';
        },

        /**
         * Loads Shadowbox into the DOM. Is called automatically by each adapter
         * as soon as the DOM is ready.
         *
         * @return  void
         * @public
         */
        load: function(){
            // apply skin options, re-apply user init options in case they overwrite
            if(S.skin.options){
                apply(S.options, S.skin.options);
                apply(S.options, init_options);
            }

            // append markup and initialize skin
            var markup = S.skin.markup.replace(/\{(\w+)\}/g, function(m, p){
                return S.lang[p];
            });
            S.lib.append(document.body, markup);

            if(S.skin.init)
                S.skin.init();

            // set up window resize event handler
            var id;
            S.lib.addEvent(window, 'resize', function(){
                // use 50 ms event buffering to prevent jerky window resizing
                if(id){
                    clearTimeout(id);
                    id = null;
                }
                // check if activated because IE7 fires window resize event
                // when container display is set to block
                if(active){
                    id = setTimeout(function(){
                        if(S.skin.onWindowResize)
                            S.skin.onWindowResize();
                        var c = S.content;
                        if(c && c.onWindowResize)
                            c.onWindowResize();
                    }, 50);
                }
            });

            if(!S.options.skipSetup)
                S.setup();
        },

        /**
         * Jumps to the next piece in the gallery.
         *
         * @return  void
         * @public
         */
        next: function(){
            S.change(S.current + 1);
        },

        /**
         * Opens the given object in Shadowbox. This object may be either an
         * anchor/area element, or an object similar to the one created by
         * Shadowbox.buildCacheObj().
         *
         * @param   mixed       obj         The object or link element that defines
         *                                  what to display
         * @return  void
         * @public
         */
        open: function(obj){
            // if it's a link element, build an object on the fly
            if(U.isLink(obj))
                obj = S.buildCacheObj(obj);

            // set up the gallery
            if(obj.constructor == Array){
                S.gallery = obj;
                S.current = 0;
            }else{
                if(!obj.gallery){
                    // single item, no gallery
                    S.gallery = [obj];
                    S.current = 0;
                }else{
                    // gallery item, build gallery from cached gallery elements
                    S.current = null;
                    S.gallery = [];
                    each(S.cache, function(c){
                        if(c.gallery && c.gallery == obj.gallery){
                            if(S.current == null && c.content == obj.content && c.title == obj.title)
                                S.current = S.gallery.length;
                            S.gallery.push(c);
                        }
                    });

                    // if not found in cache, prepend to front of gallery
                    if(S.current == null){
                        S.gallery.unshift(obj);
                        S.current = 0;
                    }
                }
            }

            obj = S.getCurrent();
            if(obj.options){
                S.revertOptions();
                S.applyOptions(obj.options);
            }

            // filter gallery for unsupported elements
            var g, r, m, s, a, oe = S.options.errors, msg, el;
            for(var i = 0; i < S.gallery.length; ++i){
                // use apply to break the reference to the original object here
                // because we'll be modifying the properties of the gallery objects
                // directly and we don't want to taint them in case they are used
                // again in a future call
                g = S.gallery[i] = apply({}, S.gallery[i]);
                r = false; // remove the element?
                if(g.player == 'unsupported'){
                    // don't support this at all
                    r = true;
                }else if(m = S.regex.unsupported.exec(g.player)){
                    // handle unsupported elements
                    if(S.options.handleUnsupported == 'link'){
                        g.player = 'html';
                        // generate a link to the appropriate plugin download page(s)
                        switch(m[1]){
                            case 'qtwmp':
                                s = 'either';
                                a = [oe.qt.url, oe.qt.name, oe.wmp.url, oe.wmp.name];
                            break;
                            case 'qtf4m':
                                s = 'shared';
                                a = [oe.qt.url, oe.qt.name, oe.f4m.url, oe.f4m.name];
                            break;
                            default:
                                s = 'single';
                                if(m[1] == 'swf' || m[1] == 'flv') m[1] = 'fla';
                                a = [oe[m[1]].url, oe[m[1]].name];
                        }
                        msg = S.lang.errors[s].replace(/\{(\d+)\}/g, function(m, n){
                            return a[n];
                        });
                        g.content = '<div class="sb-message">' + msg + '</div>';
                    }else
                        r = true;
                }else if(g.player == 'inline'){
                    // inline element, retrieve innerHTML
                    m = S.regex.inline.exec(g.content);
                    if(m){
                        var el = U.get(m[1]);
                        if(el)
                            g.content = el.innerHTML;
                        else
                            throw 'Cannot find element with id ' + m[1];
                    }else
                        throw 'Cannot find element id for inline content';
                }else if(g.player == 'swf' || g.player == 'flv'){
                    var version = (g.options && g.options.flashVersion) || S.options.flashVersion;
                    if(!swfobject.hasFlashPlayerVersion(version)){
                        // express install will be triggered because the client
                        // does not have the minimum required version of flash
                        // installed, set height and width to those of express
                        // install swf
                        g.width = 310;
                        // minimum height is 127, but +20 pixels on top and bottom
                        // looks better
                        g.height = 177;
                    }
                }
                if(r){
                    S.gallery.splice(i, 1); // remove from gallery
                    if(i < S.current)
                        --S.current; // maintain integrity of S.current
                    else if(i == S.current)
                        S.current = i > 0 ? i - 1 : i; // look for supported neighbor
                    --i; // decrement index for next loop
                }
            }

            // anything left to display?
            if(S.gallery.length){
                if(!active){
                    // fire onOpen hook
                    if(typeof S.options.onOpen == 'function' && S.options.onOpen(obj) === false) return;

                    // hide elements troublesome for modal overlays
                    v_cache = [];
                    each(['select', 'object', 'embed', 'canvas'], function(tag){
                        each(document.getElementsByTagName(tag), function(el){
                            v_cache.push([el, el.style.visibility || 'visible']);
                            el.style.visibility = 'hidden';
                        });
                    });

                    // set initial dimensions & load
                    var h = S.options.autoDimensions && 'height' in obj
                        ? obj.height
                        : S.options.initialHeight;
                    var w = S.options.autoDimensions && 'width' in obj
                        ? obj.width
                        : S.options.initialWidth;

                    S.skin.onOpen(h, w, loadContent);
                }else
                    loadContent();

                active = true;
            }
        },

        /**
         * Pauses the current slideshow.
         *
         * @return  void
         * @public
         */
        pause: function(){
            if(typeof slide_timer != 'number') return;

            var time = new Date().getTime();
            slide_delay = Math.max(0, slide_delay - (time - slide_start));

            // if there's any time left on current slide, pause the timer
            if(slide_delay){
                clearTimeout(slide_timer);
                slide_timer = 'paused';

                if(S.skin.onPause)
                    S.skin.onPause();
            }
        },

        /**
         * Sets the timer for the next image in the slideshow to be displayed.
         *
         * @return  void
         * @public
         */
        play: function(){
            if(!S.hasNext()) return;
            if(!slide_delay) slide_delay = S.options.slideshowDelay * 1000;
            if(slide_delay){
                slide_start = new Date().getTime();
                slide_timer = setTimeout(function(){
                    slide_delay = slide_start = 0; // reset slideshow
                    S.next();
                }, slide_delay);

                if(S.skin.onPlay)
                    S.skin.onPlay();
            }
        },

        /**
         * Jumps to the previous piece in the gallery.
         *
         * @return  void
         * @public
         */
        previous: function(){
            S.change(S.current - 1);
        },

        /**
         * Reverts Shadowbox' options to the last default set in use before
         * Shadowbox.applyOptions() was called.
         *
         * @return  void
         * @public
         */
        revertOptions: function(){
            apply(S.options, default_options);
        },

        /**
         * Calculates the dimensions for Shadowbox according to the given
         * parameters. Will determine if content is oversized (too large for the
         * viewport) and will automatically constrain resizable content
         * according to user preference.
         *
         * @param   Number      height      The content height
         * @param   Number      width       The content width
         * @param   Number      max_h       The maximum height available (should
         *                                  be the height of the viewport)
         * @param   Number      max_w       The maximum width available (should
         *                                  be the width of the viewport)
         * @param   Number      tb          The extra top/bottom pixels that are
         *                                  required for borders/toolbars
         * @param   Number      lr          The extra left/right pixels that are
         *                                  required for borders/toolbars
         * @param   Boolean     resizable   True if the content is able to be
         *                                  resized. Defaults to false
         * @return  Object                  The Shadowbox.dimensions object
         * @public
         */
        setDimensions: function(height, width, max_h, max_w, tb, lr, resizable){
            var h = height = parseInt(height),
                w = width = parseInt(width),
                pad = parseInt(S.options.viewportPadding) || 0;

            // calculate the max height/width
            var extra_h = 2 * pad + tb;
            if(h + extra_h >= max_h) h = max_h - extra_h;
            var extra_w = 2 * pad + lr;
            if(w + extra_w >= max_w) w = max_w - extra_w;

            // handle oversized content
            var resize_h = height,
                resize_w = width,
                change_h = (height - h) / height,
                change_w = (width - w) / width,
                oversized = (change_h > 0 || change_w > 0);
            if(resizable && oversized && S.options.handleOversize == 'resize'){
                // adjust resized height/width, preserve original aspect ratio
                if(change_h > change_w)
                    w = Math.round((width / height) * h);
                else if(change_w > change_h)
                    h = Math.round((height / width) * w);
                resize_w = w;
                resize_h = h;
            }

            // update Shadowbox.dimensions
            S.dimensions = {
                height:     h + tb,
                width:      w + lr,
                inner_h:    h,
                inner_w:    w,
                top:        (max_h - (h + extra_h)) / 2 + pad,
                left:       (max_w - (w + extra_w)) / 2 + pad,
                oversized:  oversized,
                resize_h:   resize_h,
                resize_w:   resize_w
            };

            return S.dimensions;
        },

        /**
         * Sets up listeners on the given links that will trigger Shadowbox. If no
         * links are given, this method will set up every anchor element on the page
         * with the appropriate rel attribute. It is important to note that any
         * options given here will be applied to all link elements. Multiple calls
         * to this method may be needed if different options are desired.
         *
         * Note: Because AREA elements do not support the rel attribute, they must
         * be explicitly passed to this method.
         *
         * @param   Array       links       An array (or array-like) list of anchor
         *                                  and/or area elements to set up
         * @param   Object      opts        Some options to use for the given links
         * @return  void
         * @public
         */
        setup: function(links, opts){
            // get links if none specified
            if(!links){
                var links = [], rel;
                each(document.getElementsByTagName('a'), function(a){
                    rel = a.getAttribute('rel');
                    if(rel && S.regex.rel.test(rel)) links.push(a);
                });
            }else{
                var len = links.length;
                if(len){
                    if(window['Sizzle']){
                        if(typeof links == 'string')
                            links = Sizzle(links); // lone selector
                        else if(len == 2 && links.push && typeof links[0] == 'string' && links[1].nodeType)
                            links = Sizzle(links[0], links[1]); // selector + context
                    }
                }else
                    links = [links]; // single link
            }

            each(links, function(link){
                if(typeof link.shadowboxCacheKey == 'undefined'){
                    // assign cache key expando, use integer primitive to avoid
                    // memory leak in IE
                    link.shadowboxCacheKey = S.cache.length;
                    // add onclick listener
                    S.lib.addEvent(link, 'click', handleClick);
                }
                S.cache[link.shadowboxCacheKey] = S.buildCacheObj(link, opts);
            });
        }

    },

    U = S.util = {

        /**
         * Animates any numeric (not color) style of the given element from its
         * current state to the given value. Defaults to using pixel-based
         * measurements.
         *
         * @param   HTMLElement     el      The element to animate
         * @param   String          p       The property to animate (in camelCase)
         * @param   mixed           to      The value to animate to
         * @param   Number          d       The duration of the animation (in
         *                                  seconds)
         * @param   Function        cb      A callback function to call when the
         *                                  animation completes
         * @return  void
         * @public
         */
        animate: function(el, p, to, d, cb){
            var from = parseFloat(S.lib.getStyle(el, p));
            if(isNaN(from)) from = 0;

            var delta = to - from;
            if(delta == 0){
                if(cb) cb();
                return; // nothing to animate
            }

            var op = p == 'opacity';

            function fn(ease){
                var to = from + ease * delta;
                if(op)
                    U.setOpacity(el, to);
                else
                    el.style[p] = to + 'px'; // default unit is px
            }

            // cancel the animation here if duration is 0 or if set in the options
            if(!d || (!op && !S.options.animate) || (op && !S.options.animateFade)){
                fn(1);
                if(cb) cb();
                return;
            }

            d *= 1000; // convert to milliseconds
            var begin = new Date().getTime(),
                end = begin + d,
                time,
                timer = setInterval(function(){
                    time = new Date().getTime();
                    if(time >= end){ // end of animation
                        clearInterval(timer);
                        fn(1);
                        if(cb) cb();
                    }else
                        fn(S.options.ease((time - begin) / d));
                }, 10); // 10 ms interval is minimum on webkit
        },

        /**
         * Applies all properties of e to o.
         *
         * @param   Object      o       The original object
         * @param   Object      e       The extension object
         * @return  Object              The original object with all properties
         *                              of the extension object applied
         * @public
         */
        apply: function(o, e){
            for(var p in e)
                o[p] = e[p];
            return o;
        },

        /**
         * A utility function used by the fade functions to clear the opacity
         * style setting of the given element. Required in some cases for IE.
         *
         * @param   HTMLElement     el      The element
         * @return  void
         * @public
         */
        clearOpacity: function(el){
            var s = el.style;
            if(window.ActiveXObject){
                // be careful not to overwrite other filters!
                if(typeof s.filter == 'string' && (/alpha/i).test(s.filter))
                    s.filter = s.filter.replace(/[\w\.]*alpha\(.*?\);?/i, '');
            }else
                s.opacity = '';
        },

        /**
         * Calls the given function for each element of obj. The obj element must
         * be array-like (meaning it must have a length property and be able to
         * be accessed using the array square bracket syntax). If scope is not
         * explicitly given, the callback will be called with a scope of the
         * current item. Will stop execution if a callback returns false.
         *
         * @param   mixed       obj     An array-like object containing the
         *                              elements
         * @param   Function    fn      The callback function
         * @param   mixed       scope   The scope of the callback
         * @return  void
         * @public
         */
        each: function(obj, fn, scope){
            for(var i = 0, len = obj.length; i < len; ++i)
                if(fn.call(scope || obj[i], obj[i], i, obj) === false) return;
        },

        /**
         * Gets an element by its id.
         *
         * @param   String      id      The element id
         * @return  HTMLElement         A reference to the element with the
         *                              given id
         * @public
         */
        get: function(id){
            return document.getElementById(id);
        },

        /**
         * Dynamically includes a JavaScript file in the current page.
         *
         * @param   String      file    The name of the js file to include
         * @return  void
         * @public
         */
        include: function(){
            var includes = {};
            return function(file){
                if(includes[file]) return; // don't include same file twice
                includes[file] = true;
                document.write('<scr' + 'ipt type="text/javascript" src="' + file + '"><\/script>');
            }
        }(),

        /**
         * Determines if the given object is an anchor/area element.
         *
         * @param   mixed       obj     The object to check
         * @return  Boolean             True if the object is a link element
         * @public
         */
        isLink: function(obj){
            if(!obj || !obj.tagName) return false;
            var up = obj.tagName.toUpperCase();
            return up == 'A' || up == 'AREA';
        },

        /**
         * Removes all child nodes from the given element.
         *
         * @param   HTMLElement     el      The element
         * @return  void
         * @public
         */
        removeChildren: function(el){
            while(el.firstChild)
                el.removeChild(el.firstChild);
        },

        /**
         * Sets the opacity of the given element to the specified level.
         *
         * @param   HTMLElement     el      The element
         * @param   Number          o       The opacity to use
         * @return  void
         * @public
         */
        setOpacity: function(el, o){
            var s = el.style;
            if(window.ActiveXObject){
                s.zoom = 1; // trigger hasLayout
                s.filter = (s.filter || '').replace(/\s*alpha\([^\)]*\)/gi, '') +
                    (o == 1 ? '' : ' alpha(opacity=' + (o * 100) + ')');
            }else
                s.opacity = o;
        }

    },

    // shorthand
    apply = U.apply,
    each = U.each,

    /**
     * The initial options object that was given by the user.
     *
     * @var     Object
     * @private
     */
    init_options,

    /**
     * Keeps track of whether or not Shadowbox.init has been called.
     *
     * @var     Boolean
     * @private
     */
    initialized = false,

    /**
     * Stores the default set of options in case a custom set of options is used
     * on a link-by-link basis so we can restore them later.
     *
     * @var     Object
     * @private
     */
    default_options = {},

    /**
     * The id to use for content objects.
     *
     * @var     String
     * @private
     */
    content_id = 'sb-content',

    /**
     * Keeps track of whether or not Shadowbox is activated.
     *
     * @var     Boolean
     * @private
     */
    active = false,

    /**
     * The timeout id for the slideshow transition function.
     *
     * @var     Number
     * @private
     */
    slide_timer,

    /**
     * Keeps track of the time at which the current slideshow frame was
     * displayed.
     *
     * @var     Number
     * @private
     */
    slide_start,

    /**
     * The delay on which the next slide will display.
     *
     * @var     Number
     * @private
     */
    slide_delay = 0,

    /**
     * A cache for elements that are troublesome for modal overlays.
     *
     * @var     Array
     * @private
     */
    v_cache = [];

    // detect plugin support
    if(navigator.plugins && navigator.plugins.length){
        var names = [];
        each(navigator.plugins, function(p){
            names.push(p.name);
        });
        names = names.join();
        var detectPlugin = function(n){
            return names.indexOf(n) > -1;
        }
        var f4m = detectPlugin('Flip4Mac');
        S.plugins = {
            fla:    detectPlugin('Shockwave Flash'),
            qt:     detectPlugin('QuickTime'),
            wmp:    !f4m && detectPlugin('Windows Media'), // if it's Flip4Mac, it's not really WMP
            f4m:    f4m
        }
    }else{
        function detectPlugin(n){
            try{
                var axo = new ActiveXObject(n);
            }catch(e){}
            return !!axo;
        }
        S.plugins = {
            fla:    detectPlugin('ShockwaveFlash.ShockwaveFlash'),
            qt:     detectPlugin('QuickTime.QuickTime'),
            wmp:    detectPlugin('wmplayer.ocx'),
            f4m:    false
        }
    }

    /**
     * Determines the player needed to display the file at the given URL. If
     * the file type is not supported, the return value will be 'unsupported'.
     * If the file type is not supported but the correct player can be
     * determined, the return value will be 'unsupported-*' where * will be the
     * player abbreviation (e.g. 'qt' = QuickTime).
     *
     * @param   String      url     The url of the file
     * @return  String              The name of the player to use
     * @private
     */
    function getPlayer(url){
        var re = S.regex,
            p = S.plugins,
            m = url.match(re.domain),
            d = m && document.domain == m[1]; // same domain
        if(url.indexOf('#') > -1 && d) return 'inline';
        var q = url.indexOf('?');
        if(q > -1) url = url.substring(0, q); // strip query string for player detection purposes
        if(re.img.test(url)) return 'img';
        if(re.swf.test(url)) return p.fla ? 'swf' : 'unsupported-swf';
        if(re.flv.test(url)) return p.fla ? 'flv' : 'unsupported-flv';
        if(re.qt.test(url)) return p.qt ? 'qt' : 'unsupported-qt';
        if(re.wmp.test(url)){
            if(p.wmp) return 'wmp';
            if(p.f4m) return 'qt';
            if(S.client.isMac) return p.qt ? 'unsupported-f4m' : 'unsupported-qtf4m';
            return 'unsupported-wmp';
        }
        if(re.qtwmp.test(url)){
            if(p.qt) return 'qt';
            if(p.wmp) return 'wmp';
            return S.client.isMac ? 'unsupported-qt' : 'unsupported-qtwmp';
        }
        if(!d || re.iframe.test(url))
            return 'iframe';
        return 'unsupported'; // same domain, not supported
    }

    /**
     * Handles all clicks on links that have been set up to work with Shadowbox
     * and cancels the default event behavior when appropriate.
     *
     * @param   HTMLEvent   e           The click event object
     * @return  void
     * @private
     */
    function handleClick(e){
        // get anchor/area element
        var link;
        if(U.isLink(this)){
            link = this; // jQuery, Prototype, YUI
        }else{
            link = S.lib.getTarget(e); // Ext, standalone
            while(!U.isLink(link) && link.parentNode)
                link = link.parentNode;
        }

        //S.lib.preventDefault(e); // good for debugging

        if(link){
            // if this link has already been set up, use the cached version
            var key = link.shadowboxCacheKey;
            if(typeof key != 'undefined' && typeof S.cache[key] != 'undefined')
                link = S.cache[key];

            S.open(link);
            if(S.gallery.length) S.lib.preventDefault(e); // stop event
        }
    }

    /**
     * Sets up a listener on the document for keystrokes.
     *
     * @param   Boolean     on      True to enable the listener, false to turn
     *                              it off
     * @return  void
     * @private
     */
    function listenKeys(on){
        if(!S.options.enableKeys) return;
        S.lib[(on ? 'add' : 'remove') + 'Event'](document, 'keydown', handleKey);
    }

    /**
     * A listener function that is fired when a key is pressed.
     *
     * @param   mixed       e       The event object
     * @return  void
     * @private
     */
    function handleKey(e){
        var code = S.lib.keyCode(e);

        // attempt to prevent default key action
        S.lib.preventDefault(e);

        switch(code){
            case 81: // q
            case 88: // x
            case 27: // esc
                S.close();
                break;
            case 37: // left
                S.previous();
                break;
            case 39: // right
                S.next();
                break;
            case 32: // space
                S[(typeof slide_timer == 'number' ? 'pause' : 'play')]();
        }
    }

    /**
     * Loads the Shadowbox with the current piece.
     *
     * @return  void
     * @private
     */
    function loadContent(){
        var obj = S.getCurrent();
        if(!obj) return;

        // determine player, inline is really just HTML
        var p = obj.player == 'inline' ? 'html' : obj.player;
        if(typeof S[p] != 'function')
            throw 'Unknown player: ' + p;

        var change = false;
        if(S.content){
            // changing from some previous content
            S.content.remove(); // remove old content
            change = true;

            S.revertOptions();
            if(obj.options)
                S.applyOptions(obj.options);
        }

        // make sure the body element doesn't have any children, just in case
        U.removeChildren(S.skin.bodyEl());

        // load the content
        S.content = new S[p](obj);
        listenKeys(false); // disable the keyboard while content is loading

        S.skin.onLoad(S.content, change, function(){
            if(!S.content) return;

            if(typeof S.content.ready != 'undefined'){
                // if content object has a ready property, wait for it to be
                // ready before loading
                var id = setInterval(function(){
                    if(S.content){
                        if(S.content.ready){
                            clearInterval(id);
                            id = null;
                            S.skin.onReady(contentReady);
                        }
                    }else{ // content has been removed
                        clearInterval(id);
                        id = null;
                    }
                }, 100);
            }else
                S.skin.onReady(contentReady);
        });

        // preload neighboring gallery images
        if(S.gallery.length > 1){
            var next = S.gallery[S.current + 1] || S.gallery[0];
            if(next.player == 'img'){
                var a = new Image();
                a.src = next.content;
            }
            var prev = S.gallery[S.current - 1] || S.gallery[S.gallery.length - 1];
            if(prev.player == 'img'){
                var b = new Image();
                b.src = prev.content;
            }
        }
    }

    /**
     * Callback that should be called with the content is ready to be loaded.
     *
     * @return  void
     * @private
     */
    function contentReady(){
        if(!S.content) return;
        S.content.append(S.skin.bodyEl(), content_id, S.dimensions);
        S.skin.onFinish(finishContent);
    }

    /**
     * Callback that should be called when the content is finished loading.
     *
     * @return  void
     * @private
     */
    function finishContent(){
        if(!S.content) return;

        if(S.content.onLoad)
            S.content.onLoad();
        if(S.options.onFinish)
            S.options.onFinish();
        if(!S.isPaused())
            S.play(); // kick off next slide

        listenKeys(true); // re-enable keyboard when finished
    }

    return S;

}();

/**
 * The default skin for Shadowbox. Separated out into its own class so that it may
 * be customized more easily by skin developers.
 */
Shadowbox.skin = function(){

    var S = Shadowbox,
        U = S.util,

    /**
     * Keeps track of whether or not the overlay is activated.
     *
     * @var     Boolean
     * @private
     */
    overlay_on = false,

    /**
     * Id's of elements that need transparent PNG support in IE6.
     *
     * @var     Array
     * @private
     */
    png = [
        'sb-nav-close',
        'sb-nav-next',
        'sb-nav-play',
        'sb-nav-pause',
        'sb-nav-previous'
    ];

    /**
     * Sets the top of the container element. This is only necessary in IE6
     * where the container uses absolute positioning instead of fixed.
     *
     * @return  void
     * @private
     */
    function fixTop(){
        U.get('sb-container').style.top = document.documentElement.scrollTop + 'px';
    }

    /**
     * Toggles the visibility of #sb-container and sets its size (if on
     * IE6). Also toggles the visibility of elements (<select>, <object>, and
     * <embed>) that are troublesome for semi-transparent modal overlays. IE has
     * problems with <select> elements, while Firefox has trouble with
     * <object>s.
     *
     * @param   Function    cb      A callback to call after toggling on, absent
     *                              when toggling off
     * @return  void
     * @private
     */
    function toggleVisible(cb){
        var so = U.get('sb-overlay'),
            sc = U.get('sb-container'),
            sb = U.get('sb-wrapper');

        if(cb){
            if(S.client.isIE6){
                // fix container top before showing
                fixTop();
                S.lib.addEvent(window, 'scroll', fixTop);
            }
            if(S.options.showOverlay){
                overlay_on = true;

                // set overlay color/opacity
                so.style.backgroundColor = S.options.overlayColor;
                U.setOpacity(so, 0);
                if(!S.options.modal) S.lib.addEvent(so, 'click', S.close);

                sb.style.display = 'none'; // cleared in onLoad
            }
            sc.style.visibility = 'visible';
            if(overlay_on){
                // fade in effect
                var op = parseFloat(S.options.overlayOpacity);
                U.animate(so, 'opacity', op, S.options.fadeDuration, cb);
            }else
                cb();
        }else{
            if(S.client.isIE6)
                S.lib.removeEvent(window, 'scroll', fixTop);
            S.lib.removeEvent(so, 'click', S.close);
            if(overlay_on){
                // fade out effect
                sb.style.display = 'none';
                U.animate(so, 'opacity', 0, S.options.fadeDuration, function(){
                    // the following is commented because it causes the overlay to
                    // be hidden on consecutive activations in IE8, even though we
                    // set the visibility to "visible" when we reactivate
                    //sc.style.visibility = 'hidden';
                    sc.style.display = '';
                    sb.style.display = '';
                    U.clearOpacity(so);
                });
            }else
                sc.style.visibility = 'hidden';
        }
    }

    /**
     * Toggles the display of the nav control with the given id on and off.
     *
     * @param   String      id      The id of the navigation control
     * @param   Boolean     on      True to toggle on, false to toggle off
     * @return  void
     * @private
     */
    function toggleNav(id, on){
        var el = U.get('sb-nav-' + id);
        if(el) el.style.display = on ? '' : 'none';
    }

    /**
     * Toggles the visibility of the "loading" layer.
     *
     * @param   Boolean     on      True to toggle on, false to toggle off
     * @param   Function    cb      The callback function to call when toggling
     *                              completes
     * @return  void
     * @private
     */
    function toggleLoading(on, cb){
        var ld = U.get('sb-loading'),
            p = S.getCurrent().player,
            anim = (p == 'img' || p == 'html'); // fade on images & html

        if(on){
            function fn(){
                U.clearOpacity(ld);
                if(cb) cb();
            }

            U.setOpacity(ld, 0);
            ld.style.display = '';

            if(anim)
                U.animate(ld, 'opacity', 1, S.options.fadeDuration, fn);
            else
                fn();
        }else{
            function fn(){
                ld.style.display = 'none';
                U.clearOpacity(ld);
                if(cb) cb();
            }

            if(anim)
                U.animate(ld, 'opacity', 0, S.options.fadeDuration, fn);
            else
                fn();
        }
    }

    /**
     * Builds the content for the title and information bars.
     *
     * @param   Function    cb      A callback function to execute after the
     *                              bars are built
     * @return  void
     * @private
     */
    function buildBars(cb){
        var obj = S.getCurrent();

        // build the title, if present
        U.get('sb-title-inner').innerHTML = obj.title || '';

        // build the nav
        var c, n, pl, pa, p;
        if(S.options.displayNav){
            c = true;
            // next & previous links
            var len = S.gallery.length;
            if(len > 1){
                if(S.options.continuous)
                    n = p = true; // show both
                else{
                    n = (len - 1) > S.current; // not last in gallery, show next
                    p = S.current > 0; // not first in gallery, show previous
                }
            }
            // in a slideshow?
            if(S.options.slideshowDelay > 0 && S.hasNext()){
                pa = !S.isPaused();
                pl = !pa;
            }
        }else{
            c = n = pl = pa = p = false;
        }
        toggleNav('close', c);
        toggleNav('next', n);
        toggleNav('play', pl);
        toggleNav('pause', pa);
        toggleNav('previous', p);

        // build the counter
        var c = '';
        if(S.options.displayCounter && S.gallery.length > 1){
            var count = S.getCounter();
            if(typeof count == 'string') // default
                c = count;
            else{
                U.each(count, function(i){
                    c += '<a onclick="Shadowbox.change(' + i + ');"'
                    if(i == S.current) c += ' class="sb-counter-current"';
                    c += '>' + (i + 1) + '</a>';
                });
            }
        }
        U.get('sb-counter').innerHTML = c;

        cb();
    }

    /**
     * Hides the title and info bars.
     *
     * @param   Boolean     anim    True to animate the transition
     * @param   Function    cb      A callback function to execute after the
     *                              animation completes
     * @return  void
     * @private
     */
    function hideBars(anim, cb){
        var sw = U.get('sb-wrapper'),
            st = U.get('sb-title'),
            si = U.get('sb-info'),
            ti = U.get('sb-title-inner'),
            ii = U.get('sb-info-inner'),
            t = parseInt(S.lib.getStyle(ti, 'height')) || 0,
            b = parseInt(S.lib.getStyle(ii, 'height')) || 0;

        function fn(){
            // hide bars here in case of overflow, build after hidden
            ti.style.visibility = ii.style.visibility = 'hidden';
            buildBars(cb);
        }

        if(anim){
            U.animate(st, 'height', 0, 0.35);
            U.animate(si, 'height', 0, 0.35);
            U.animate(sw, 'paddingTop', t, 0.35);
            U.animate(sw, 'paddingBottom', b, 0.35, fn);
        }else{
            st.style.height = si.style.height = '0px';
            sw.style.paddingTop = t + 'px';
            sw.style.paddingBottom = b + 'px';
            fn();
        }
    }

    /**
     * Shows the title and info bars.
     *
     * @param   Function    cb      A callback function to execute after the
     *                              animation completes
     * @return  void
     * @private
     */
    function showBars(cb){
        var sw = U.get('sb-wrapper'),
            st = U.get('sb-title'),
            si = U.get('sb-info'),
            ti = U.get('sb-title-inner'),
            ii = U.get('sb-info-inner'),
            t = parseInt(S.lib.getStyle(ti, 'height')) || 0,
            b = parseInt(S.lib.getStyle(ii, 'height')) || 0;

        // clear visibility before animating into view
        ti.style.visibility = ii.style.visibility = '';

        // show title?
        if(ti.innerHTML != ''){
            U.animate(st, 'height', t, 0.35);
            U.animate(sw, 'paddingTop', 0, 0.35);
        }
        U.animate(si, 'height', b, 0.35);
        U.animate(sw, 'paddingBottom', 0, 0.35, cb);
    }

    /**
     * Adjusts the height of #sb-body and centers #sb-wrapper vertically
     * in the viewport.
     *
     * @param   Number      height      The height to use for #sb-body
     * @param   Number      top         The top to use for #sb-wrapper
     * @param   Boolean     anim        True to animate the transition
     * @param   Function    cb          A callback to use when the animation
     *                                  completes
     * @return  void
     * @private
     */
    function adjustHeight(height, top, anim, cb){
        var sb = U.get('sb-body'),
            s = U.get('sb-wrapper'),
            h = parseInt(height),
            t = parseInt(top);

        if(anim){
            U.animate(sb, 'height', h, S.options.resizeDuration);
            U.animate(s, 'top', t, S.options.resizeDuration, cb);
        }else{
            sb.style.height = h + 'px';
            s.style.top = t + 'px';
            if(cb) cb();
        }
    }

    /**
     * Adjusts the width and left of #sb-wrapper.
     *
     * @param   Number      width       The width to use for #sb-wrapper
     * @param   Number      left        The left to use for #sb-wrapper
     * @param   Boolean     anim        True to animate the transition
     * @param   Function    cb          A callback to use when the animation
     *                                  completes
     * @return  void
     * @private
     */
    function adjustWidth(width, left, anim, cb){
        var s = U.get('sb-wrapper'),
            w = parseInt(width),
            l = parseInt(left);

        if(anim){
            U.animate(s, 'width', w, S.options.resizeDuration);
            U.animate(s, 'left', l, S.options.resizeDuration, cb);
        }else{
            s.style.width = w + 'px';
            s.style.left = l + 'px';
            if(cb) cb();
        }
    }

    /**
     * Resizes Shadowbox to the appropriate height and width for the current
     * content.
     *
     * @param   Function    cb      A callback function to execute after the
     *                              resize completes
     * @return  void
     * @private
     */
    function resizeContent(cb){
        var c = S.content;
        if(!c) return;

        // set new dimensions
        var d = setDimensions(c.height, c.width, c.resizable);

        switch(S.options.animSequence){
            case 'hw':
                adjustHeight(d.inner_h, d.top, true, function(){
                    adjustWidth(d.width, d.left, true, cb);
                });
            break;
            case 'wh':
                adjustWidth(d.width, d.left, true, function(){
                    adjustHeight(d.inner_h, d.top, true, cb);
                });
            break;
            default: // sync
                adjustWidth(d.width, d.left, true);
                adjustHeight(d.inner_h, d.top, true, cb);
        }
    }

    /**
     * Calculates the dimensions for Shadowbox, taking into account the borders
     * and surrounding elements of #sb-body.
     *
     * @param   Number      height      The content height
     * @param   Number      width       The content width
     * @param   Boolean     resizable   True if the content is able to be
     *                                  resized. Defaults to false
     * @return  Object                  The new dimensions object
     * @private
     */
    function setDimensions(height, width, resizable){
        var sbi = U.get('sb-body-inner')
            sw = U.get('sb-wrapper'),
            so = U.get('sb-overlay'),
            tb = sw.offsetHeight - sbi.offsetHeight,
            lr = sw.offsetWidth - sbi.offsetWidth,
            max_h = so.offsetHeight, // measure overlay to get viewport size for IE6
            max_w = so.offsetWidth;

        return S.setDimensions(height, width, max_h, max_w, tb, lr, resizable);
    }

    return {

        /**
         * The HTML markup to use.
         *
         * @var     String
         * @public
         */
        markup: '<div id="sb-container">' +
                    '<div id="sb-overlay"></div>' +
                    '<div id="sb-wrapper">' +
                        '<div id="sb-title">' +
                            '<div id="sb-title-inner"></div>' +
                        '</div>' +
                        '<div id="sb-body">' +
                            '<div id="sb-body-inner"></div>' +
                            '<div id="sb-loading">' +
                                '<a onclick="Shadowbox.close()">{cancel}</a>' +
                            '</div>' +
                        '</div>' +
                        '<div id="sb-info">' +
                            '<div id="sb-info-inner">' +
                                '<div id="sb-counter"></div>' +
                                '<div id="sb-nav">' +
                                    '<a id="sb-nav-close" title="{close}" onclick="Shadowbox.close()"></a>' +
                                    '<a id="sb-nav-next" title="{next}" onclick="Shadowbox.next()"></a>' +
                                    '<a id="sb-nav-play" title="{play}" onclick="Shadowbox.play()"></a>' +
                                    '<a id="sb-nav-pause" title="{pause}" onclick="Shadowbox.pause()"></a>' +
                                    '<a id="sb-nav-previous" title="{previous}" onclick="Shadowbox.previous()"></a>' +
                                '</div>' +
                                '<div style="clear:both"></div>' +
                            '</div>' +
                        '</div>' +
                    '</div>' +
                '</div>',

        options: {

            /**
             * Determines the sequence of the resizing animations. A value of
             * "hw" will resize first the height, then the width. Likewise, "wh"
             * will resize the width first, then the height. The default is
             * "sync" and will resize both simultaneously.
             *
             * @var     String
             * @public
             */
            animSequence: 'sync'

        },

        /**
         * Initialization function. Called immediately after this skin's markup
         * has been appended to the document with all of the necessary language
         * replacements done.
         *
         * @return  void
         * @public
         */
        init: function(){
            // several fixes for IE6
            if(S.client.isIE6){
                // trigger hasLayout on sb-body
                U.get('sb-body').style.zoom = 1;

                // support transparent PNG's via AlphaImageLoader
                var el, m, re = /url\("(.*\.png)"\)/;
                U.each(png, function(id){
                    el = U.get(id);
                    if(el){
                        m = S.lib.getStyle(el, 'backgroundImage').match(re);
                        if(m){
                            el.style.backgroundImage = 'none';
                            el.style.filter = 'progid:DXImageTransform.Microsoft.AlphaImageLoader(enabled=true,src=' +
                                m[1] + ',sizingMethod=scale);';
                        }
                    }
                });
            }
        },

        /**
         * Gets the element that content should be appended to.
         *
         * @return  HTMLElement     The body element
         * @public
         */
        bodyEl: function(){
            return U.get('sb-body-inner');
        },

        /**
         * Called when Shadowbox opens from an inactive state.
         *
         * @param   Number      h       The initial height to use
         * @param   Number      w       The initial width to use
         * @param   Function    cb      The function to call when finished
         * @return  void
         * @public
         */
        onOpen: function(h, w, cb){
            U.get('sb-container').style.display = 'block';

            var d = setDimensions(h, w);
            adjustHeight(d.inner_h, d.top, false);
            adjustWidth(d.width, d.left, false);
            toggleVisible(cb);
        },

        /**
         * Called when a new piece of content is being loaded.
         *
         * @param   mixed       content     The content object
         * @param   Boolean     change      True if the content is changing
         *                                  from some previous content
         * @param   Function    cb          A callback that should be fired when
         *                                  this function is finished
         * @return  void
         * @public
         */
        onLoad: function(content, change, cb){
            toggleLoading(true);

            hideBars(change, function(){ // if changing, animate the bars transition
                if(!content) return;

                // if opening, clear #sb-wrapper display
                if(!change) U.get('sb-wrapper').style.display = '';

                cb();
            });
        },

        /**
         * Called when the content is ready to be loaded (e.g. when the image
         * has finished loading). Should resize the content box and make any
         * other necessary adjustments.
         *
         * @param   Function    cb          A callback that should be fired when
         *                                  this function is finished
         * @return  void
         * @public
         */
        onReady: function(cb){
            resizeContent(function(){
                showBars(cb);
            });
        },

        /**
         * Called when the content is loaded into the box and is ready to be
         * displayed.
         *
         * @param   Function    cb          A callback that should be fired when
         *                                  this function is finished
         * @return  void
         * @public
         */
        onFinish: function(cb){
            toggleLoading(false, cb);
        },

        /**
         * Called when Shadowbox is closed.
         *
         * @return  void
         * @public
         */
        onClose: function(){
            toggleVisible(false);
        },

        /**
         * Called in Shadowbox.play().
         *
         * @return  void
         * @public
         */
        onPlay: function(){
            toggleNav('play', false);
            toggleNav('pause', true);
        },

        /**
         * Called in Shadowbox.pause().
         *
         * @return  void
         * @public
         */
        onPause: function(){
            toggleNav('pause', false);
            toggleNav('play', true);
        },

        /**
         * Called when the window is resized.
         *
         * @return  void
         * @public
         */
        onWindowResize: function(){
            var c = S.content;
            if(!c) return;

            // set new dimensions
            var d = setDimensions(c.height, c.width, c.resizable);

            adjustWidth(d.width, d.left, false);
            adjustHeight(d.inner_h, d.top, false);

            var el = U.get(S.contentId());
            if(el){
                // resize resizable content when in resize mode
                if(c.resizable && S.options.handleOversize == 'resize'){
                    el.height = d.resize_h;
                    el.width = d.resize_w;
                }
            }
        }

    };

}();

/*	SWFObject v2.2 <http://code.google.com/p/swfobject/> 
	is released under the MIT License <http://www.opensource.org/licenses/mit-license.php> 
*/
var swfobject=function(){var D="undefined",r="object",S="Shockwave Flash",W="ShockwaveFlash.ShockwaveFlash",q="application/x-shockwave-flash",R="SWFObjectExprInst",x="onreadystatechange",O=window,j=document,t=navigator,T=false,U=[h],o=[],N=[],I=[],l,Q,E,B,J=false,a=false,n,G,m=true,M=function(){var aa=typeof j.getElementById!=D&&typeof j.getElementsByTagName!=D&&typeof j.createElement!=D,ah=t.userAgent.toLowerCase(),Y=t.platform.toLowerCase(),ae=Y?/win/.test(Y):/win/.test(ah),ac=Y?/mac/.test(Y):/mac/.test(ah),af=/webkit/.test(ah)?parseFloat(ah.replace(/^.*webkit\/(\d+(\.\d+)?).*$/,"$1")):false,X=!+"\v1",ag=[0,0,0],ab=null;if(typeof t.plugins!=D&&typeof t.plugins[S]==r){ab=t.plugins[S].description;if(ab&&!(typeof t.mimeTypes!=D&&t.mimeTypes[q]&&!t.mimeTypes[q].enabledPlugin)){T=true;X=false;ab=ab.replace(/^.*\s+(\S+\s+\S+$)/,"$1");ag[0]=parseInt(ab.replace(/^(.*)\..*$/,"$1"),10);ag[1]=parseInt(ab.replace(/^.*\.(.*)\s.*$/,"$1"),10);ag[2]=/[a-zA-Z]/.test(ab)?parseInt(ab.replace(/^.*[a-zA-Z]+(.*)$/,"$1"),10):0}}else{if(typeof O.ActiveXObject!=D){try{var ad=new ActiveXObject(W);if(ad){ab=ad.GetVariable("$version");if(ab){X=true;ab=ab.split(" ")[1].split(",");ag=[parseInt(ab[0],10),parseInt(ab[1],10),parseInt(ab[2],10)]}}}catch(Z){}}}return{w3:aa,pv:ag,wk:af,ie:X,win:ae,mac:ac}}(),k=function(){if(!M.w3){return}if((typeof j.readyState!=D&&j.readyState=="complete")||(typeof j.readyState==D&&(j.getElementsByTagName("body")[0]||j.body))){f()}if(!J){if(typeof j.addEventListener!=D){j.addEventListener("DOMContentLoaded",f,false)}if(M.ie&&M.win){j.attachEvent(x,function(){if(j.readyState=="complete"){j.detachEvent(x,arguments.callee);f()}});if(O==top){(function(){if(J){return}try{j.documentElement.doScroll("left")}catch(X){setTimeout(arguments.callee,0);return}f()})()}}if(M.wk){(function(){if(J){return}if(!/loaded|complete/.test(j.readyState)){setTimeout(arguments.callee,0);return}f()})()}s(f)}}();function f(){if(J){return}try{var Z=j.getElementsByTagName("body")[0].appendChild(C("span"));Z.parentNode.removeChild(Z)}catch(aa){return}J=true;var X=U.length;for(var Y=0;Y<X;Y++){U[Y]()}}function K(X){if(J){X()}else{U[U.length]=X}}function s(Y){if(typeof O.addEventListener!=D){O.addEventListener("load",Y,false)}else{if(typeof j.addEventListener!=D){j.addEventListener("load",Y,false)}else{if(typeof O.attachEvent!=D){i(O,"onload",Y)}else{if(typeof O.onload=="function"){var X=O.onload;O.onload=function(){X();Y()}}else{O.onload=Y}}}}}function h(){if(T){V()}else{H()}}function V(){var X=j.getElementsByTagName("body")[0];var aa=C(r);aa.setAttribute("type",q);var Z=X.appendChild(aa);if(Z){var Y=0;(function(){if(typeof Z.GetVariable!=D){var ab=Z.GetVariable("$version");if(ab){ab=ab.split(" ")[1].split(",");M.pv=[parseInt(ab[0],10),parseInt(ab[1],10),parseInt(ab[2],10)]}}else{if(Y<10){Y++;setTimeout(arguments.callee,10);return}}X.removeChild(aa);Z=null;H()})()}else{H()}}function H(){var ag=o.length;if(ag>0){for(var af=0;af<ag;af++){var Y=o[af].id;var ab=o[af].callbackFn;var aa={success:false,id:Y};if(M.pv[0]>0){var ae=c(Y);if(ae){if(F(o[af].swfVersion)&&!(M.wk&&M.wk<312)){w(Y,true);if(ab){aa.success=true;aa.ref=z(Y);ab(aa)}}else{if(o[af].expressInstall&&A()){var ai={};ai.data=o[af].expressInstall;ai.width=ae.getAttribute("width")||"0";ai.height=ae.getAttribute("height")||"0";if(ae.getAttribute("class")){ai.styleclass=ae.getAttribute("class")}if(ae.getAttribute("align")){ai.align=ae.getAttribute("align")}var ah={};var X=ae.getElementsByTagName("param");var ac=X.length;for(var ad=0;ad<ac;ad++){if(X[ad].getAttribute("name").toLowerCase()!="movie"){ah[X[ad].getAttribute("name")]=X[ad].getAttribute("value")}}P(ai,ah,Y,ab)}else{p(ae);if(ab){ab(aa)}}}}}else{w(Y,true);if(ab){var Z=z(Y);if(Z&&typeof Z.SetVariable!=D){aa.success=true;aa.ref=Z}ab(aa)}}}}}function z(aa){var X=null;var Y=c(aa);if(Y&&Y.nodeName=="OBJECT"){if(typeof Y.SetVariable!=D){X=Y}else{var Z=Y.getElementsByTagName(r)[0];if(Z){X=Z}}}return X}function A(){return !a&&F("6.0.65")&&(M.win||M.mac)&&!(M.wk&&M.wk<312)}function P(aa,ab,X,Z){a=true;E=Z||null;B={success:false,id:X};var ae=c(X);if(ae){if(ae.nodeName=="OBJECT"){l=g(ae);Q=null}else{l=ae;Q=X}aa.id=R;if(typeof aa.width==D||(!/%$/.test(aa.width)&&parseInt(aa.width,10)<310)){aa.width="310"}if(typeof aa.height==D||(!/%$/.test(aa.height)&&parseInt(aa.height,10)<137)){aa.height="137"}j.title=j.title.slice(0,47)+" - Flash Player Installation";var ad=M.ie&&M.win?"ActiveX":"PlugIn",ac="MMredirectURL="+O.location.toString().replace(/&/g,"%26")+"&MMplayerType="+ad+"&MMdoctitle="+j.title;if(typeof ab.flashvars!=D){ab.flashvars+="&"+ac}else{ab.flashvars=ac}if(M.ie&&M.win&&ae.readyState!=4){var Y=C("div");X+="SWFObjectNew";Y.setAttribute("id",X);ae.parentNode.insertBefore(Y,ae);ae.style.display="none";(function(){if(ae.readyState==4){ae.parentNode.removeChild(ae)}else{setTimeout(arguments.callee,10)}})()}u(aa,ab,X)}}function p(Y){if(M.ie&&M.win&&Y.readyState!=4){var X=C("div");Y.parentNode.insertBefore(X,Y);X.parentNode.replaceChild(g(Y),X);Y.style.display="none";(function(){if(Y.readyState==4){Y.parentNode.removeChild(Y)}else{setTimeout(arguments.callee,10)}})()}else{Y.parentNode.replaceChild(g(Y),Y)}}function g(ab){var aa=C("div");if(M.win&&M.ie){aa.innerHTML=ab.innerHTML}else{var Y=ab.getElementsByTagName(r)[0];if(Y){var ad=Y.childNodes;if(ad){var X=ad.length;for(var Z=0;Z<X;Z++){if(!(ad[Z].nodeType==1&&ad[Z].nodeName=="PARAM")&&!(ad[Z].nodeType==8)){aa.appendChild(ad[Z].cloneNode(true))}}}}}return aa}function u(ai,ag,Y){var X,aa=c(Y);if(M.wk&&M.wk<312){return X}if(aa){if(typeof ai.id==D){ai.id=Y}if(M.ie&&M.win){var ah="";for(var ae in ai){if(ai[ae]!=Object.prototype[ae]){if(ae.toLowerCase()=="data"){ag.movie=ai[ae]}else{if(ae.toLowerCase()=="styleclass"){ah+=' class="'+ai[ae]+'"'}else{if(ae.toLowerCase()!="classid"){ah+=" "+ae+'="'+ai[ae]+'"'}}}}}var af="";for(var ad in ag){if(ag[ad]!=Object.prototype[ad]){af+='<param name="'+ad+'" value="'+ag[ad]+'" />'}}aa.outerHTML='<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"'+ah+">"+af+"</object>";N[N.length]=ai.id;X=c(ai.id)}else{var Z=C(r);Z.setAttribute("type",q);for(var ac in ai){if(ai[ac]!=Object.prototype[ac]){if(ac.toLowerCase()=="styleclass"){Z.setAttribute("class",ai[ac])}else{if(ac.toLowerCase()!="classid"){Z.setAttribute(ac,ai[ac])}}}}for(var ab in ag){if(ag[ab]!=Object.prototype[ab]&&ab.toLowerCase()!="movie"){e(Z,ab,ag[ab])}}aa.parentNode.replaceChild(Z,aa);X=Z}}return X}function e(Z,X,Y){var aa=C("param");aa.setAttribute("name",X);aa.setAttribute("value",Y);Z.appendChild(aa)}function y(Y){var X=c(Y);if(X&&X.nodeName=="OBJECT"){if(M.ie&&M.win){X.style.display="none";(function(){if(X.readyState==4){b(Y)}else{setTimeout(arguments.callee,10)}})()}else{X.parentNode.removeChild(X)}}}function b(Z){var Y=c(Z);if(Y){for(var X in Y){if(typeof Y[X]=="function"){Y[X]=null}}Y.parentNode.removeChild(Y)}}function c(Z){var X=null;try{X=j.getElementById(Z)}catch(Y){}return X}function C(X){return j.createElement(X)}function i(Z,X,Y){Z.attachEvent(X,Y);I[I.length]=[Z,X,Y]}function F(Z){var Y=M.pv,X=Z.split(".");X[0]=parseInt(X[0],10);X[1]=parseInt(X[1],10)||0;X[2]=parseInt(X[2],10)||0;return(Y[0]>X[0]||(Y[0]==X[0]&&Y[1]>X[1])||(Y[0]==X[0]&&Y[1]==X[1]&&Y[2]>=X[2]))?true:false}function v(ac,Y,ad,ab){if(M.ie&&M.mac){return}var aa=j.getElementsByTagName("head")[0];if(!aa){return}var X=(ad&&typeof ad=="string")?ad:"screen";if(ab){n=null;G=null}if(!n||G!=X){var Z=C("style");Z.setAttribute("type","text/css");Z.setAttribute("media",X);n=aa.appendChild(Z);if(M.ie&&M.win&&typeof j.styleSheets!=D&&j.styleSheets.length>0){n=j.styleSheets[j.styleSheets.length-1]}G=X}if(M.ie&&M.win){if(n&&typeof n.addRule==r){n.addRule(ac,Y)}}else{if(n&&typeof j.createTextNode!=D){n.appendChild(j.createTextNode(ac+" {"+Y+"}"))}}}function w(Z,X){if(!m){return}var Y=X?"visible":"hidden";if(J&&c(Z)){c(Z).style.visibility=Y}else{v("#"+Z,"visibility:"+Y)}}function L(Y){var Z=/[\\\"<>\.;]/;var X=Z.exec(Y)!=null;return X&&typeof encodeURIComponent!=D?encodeURIComponent(Y):Y}var d=function(){if(M.ie&&M.win){window.attachEvent("onunload",function(){var ac=I.length;for(var ab=0;ab<ac;ab++){I[ab][0].detachEvent(I[ab][1],I[ab][2])}var Z=N.length;for(var aa=0;aa<Z;aa++){y(N[aa])}for(var Y in M){M[Y]=null}M=null;for(var X in swfobject){swfobject[X]=null}swfobject=null})}}();return{registerObject:function(ab,X,aa,Z){if(M.w3&&ab&&X){var Y={};Y.id=ab;Y.swfVersion=X;Y.expressInstall=aa;Y.callbackFn=Z;o[o.length]=Y;w(ab,false)}else{if(Z){Z({success:false,id:ab})}}},getObjectById:function(X){if(M.w3){return z(X)}},embedSWF:function(ab,ah,ae,ag,Y,aa,Z,ad,af,ac){var X={success:false,id:ah};if(M.w3&&!(M.wk&&M.wk<312)&&ab&&ah&&ae&&ag&&Y){w(ah,false);K(function(){ae+="";ag+="";var aj={};if(af&&typeof af===r){for(var al in af){aj[al]=af[al]}}aj.data=ab;aj.width=ae;aj.height=ag;var am={};if(ad&&typeof ad===r){for(var ak in ad){am[ak]=ad[ak]}}if(Z&&typeof Z===r){for(var ai in Z){if(typeof am.flashvars!=D){am.flashvars+="&"+ai+"="+Z[ai]}else{am.flashvars=ai+"="+Z[ai]}}}if(F(Y)){var an=u(aj,am,ah);if(aj.id==ah){w(ah,true)}X.success=true;X.ref=an}else{if(aa&&A()){aj.data=aa;P(aj,am,ah,ac);return}else{w(ah,true)}}if(ac){ac(X)}})}else{if(ac){ac(X)}}},switchOffAutoHideShow:function(){m=false},ua:M,getFlashPlayerVersion:function(){return{major:M.pv[0],minor:M.pv[1],release:M.pv[2]}},hasFlashPlayerVersion:F,createSWF:function(Z,Y,X){if(M.w3){return u(Z,Y,X)}else{return undefined}},showExpressInstall:function(Z,aa,X,Y){if(M.w3&&A()){P(Z,aa,X,Y)}},removeSWF:function(X){if(M.w3){y(X)}},createCSS:function(aa,Z,Y,X){if(M.w3){v(aa,Z,Y,X)}},addDomLoadEvent:K,addLoadEvent:s,getQueryParamValue:function(aa){var Z=j.location.search||j.location.hash;if(Z){if(/\?/.test(Z)){Z=Z.split("?")[1]}if(aa==null){return L(Z)}var Y=Z.split("&");for(var X=0;X<Y.length;X++){if(Y[X].substring(0,Y[X].indexOf("="))==aa){return L(Y[X].substring((Y[X].indexOf("=")+1)))}}}return""},expressInstallCallback:function(){if(a){var X=c(R);if(X&&l){X.parentNode.replaceChild(l,X);if(Q){w(Q,true);if(M.ie&&M.win){l.style.display="block"}}if(E){E(B)}}a=false}}}}();
/*
Copyright (c) 2009 Victor Stanciu - http://www.victorstanciu.ro

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.
*/

Carousel = Class.create(Abstract, {
	initialize: function (scroller, slides, controls, options) {
		this.scrolling	= false;
		this.scroller	= $(scroller);
		this.slides		= slides;
		this.controls	= controls;

		this.options    = Object.extend({
            duration:           1,
            auto:               false,
            frequency:          3,
            visibleSlides:      1,
            controlClassName:   'carousel-control',
            jumperClassName:    'carousel-jumper',
            disabledClassName:  'carousel-disabled',
            selectedClassName:  'carousel-selected',
            circular:           false,
            wheel:              true,
            effect:             'scroll',
            transition:         'sinoidal'
        }, options || {});
        
        if (this.options.effect == 'fade') {
            this.options.circular = true;
        }

		this.slides.each(function(slide, index) {
			slide._index = index;
        });

		if (this.controls) {
            this.controls.invoke('observe', 'click', this.click.bind(this));
        }
        
        if (this.options.wheel) {            
            this.scroller.observe('mousewheel', this.wheel.bindAsEventListener(this)).observe('DOMMouseScroll', this.wheel.bindAsEventListener(this));;
        }

        if (this.options.auto) {
            this.start();
        }

		if (this.options.initial) {
			var initialIndex = this.slides.indexOf($(this.options.initial));
			if (initialIndex > (this.options.visibleSlides - 1) && this.options.visibleSlides > 1) {               
				if (initialIndex > this.slides.length - (this.options.visibleSlides + 1)) {
					initialIndex = this.slides.length - this.options.visibleSlides;
				}
			}
            this.moveTo(this.slides[initialIndex]);
		}
	},

	click: function (event) {
		this.stop();

		var element = event.findElement('a');

		if (!element.hasClassName(this.options.disabledClassName)) {
			if (element.hasClassName(this.options.controlClassName)) {
				eval("this." + element.rel + "()");
            } else if (element.hasClassName(this.options.jumperClassName)) {
                this.moveTo(element.rel);
                if (this.options.selectedClassName) {
                    this.controls.invoke('removeClassName', this.options.selectedClassName);
                    element.addClassName(this.options.selectedClassName);
                }
            }
        }

		this.deactivateControls();
		event.stop();
    },

	moveTo: function (element) {
		if (this.options.beforeMove && (typeof this.options.beforeMove == 'function')) {
			this.options.beforeMove();
        }

		this.previous = this.current ? this.current : this.slides[0];
		this.current  = $(element);

		var scrollerOffset = this.scroller.cumulativeOffset();
		var elementOffset  = this.current.cumulativeOffset();

		if (this.scrolling) {
			this.scrolling.cancel();
		}

        switch (this.options.effect) {
            case 'fade':               
                this.scrolling = new Effect.Opacity(this.scroller, {
                    from:   1.0,
                    to:     0,
                    duration: this.options.duration,
                    afterFinish: (function () {
                        this.scroller.scrollLeft = elementOffset[0] - scrollerOffset[0];
                        this.scroller.scrollTop  = elementOffset[1] - scrollerOffset[1];

                        new Effect.Opacity(this.scroller, {
                            from: 0,
                            to: 1.0,
                            duration: this.options.duration,
                            afterFinish: (function () {
                                if (this.controls) {
                                    this.activateControls();
                                }
                                if (this.options.afterMove && (typeof this.options.afterMove == 'function')) {
                                    this.options.afterMove();
                                }
                            }).bind(this)
                        });
                    }
                ).bind(this)});
            break;
            case 'scroll':
            default:
                var transition;
                switch (this.options.transition) {
                    case 'spring':
                        transition = Effect.Transitions.spring;
                        break;
                    case 'sinoidal':
                    default:
                        transition = Effect.Transitions.sinoidal;
                        break;
                }

                this.scrolling = new Effect.SmoothScroll(this.scroller, {
                    duration: this.options.duration,
                    x: (elementOffset[0] - scrollerOffset[0]),
                    y: (elementOffset[1] - scrollerOffset[1]),
                    transition: transition,
                    afterFinish: (function () {
                        if (this.controls) {
                            this.activateControls();
                        }
                        if (this.options.afterMove && (typeof this.options.afterMove == 'function')) {
                            this.options.afterMove();
                        }                        
                        this.scrolling = false;
                    }).bind(this)});
            break;
        }

		return false;
	},

	prev: function () {
		if (this.current) {
			var currentIndex = this.current._index;
			var prevIndex = (currentIndex == 0) ? (this.options.circular ? this.slides.length - 1 : 0) : currentIndex - 1;
        } else {
            var prevIndex = (this.options.circular ? this.slides.length - 1 : 0);
        }

		if (prevIndex == (this.slides.length - 1) && this.options.circular && this.options.effect != 'fade') {
			this.scroller.scrollLeft =  (this.slides.length - 1) * this.slides.first().getWidth();
			this.scroller.scrollTop =  (this.slides.length - 1) * this.slides.first().getHeight();
			prevIndex = this.slides.length - 2;
        }

		this.moveTo(this.slides[prevIndex]);
	},

	next: function () {
		if (this.current) {
			var currentIndex = this.current._index;
			var nextIndex = (this.slides.length - 1 == currentIndex) ? (this.options.circular ? 0 : currentIndex) : currentIndex + 1;
        } else {
            var nextIndex = 1;
        }

		if (nextIndex == 0 && this.options.circular && this.options.effect != 'fade') {
			this.scroller.scrollLeft = 0;
			this.scroller.scrollTop  = 0;
			nextIndex = 1;
        }

		if (nextIndex > this.slides.length - (this.options.visibleSlides + 1)) {
			nextIndex = this.slides.length - this.options.visibleSlides;
		}		

		this.moveTo(this.slides[nextIndex]);
	},

	first: function () {
		this.moveTo(this.slides[0]);
    },

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

	toggle: function () {
		if (this.previous) {
			this.moveTo(this.slides[this.previous._index]);
        } else {
            return false;
        }
    },

	stop: function () {
		if (this.timer) {
			clearTimeout(this.timer);
		}
	},

	start: function () { 
        this.periodicallyUpdate();
    },

	pause: function () {
		this.stop();
		this.activateControls();
    },

	resume: function (event) {
		if (event) {
			var related = event.relatedTarget || event.toElement;
			if (!related || (!this.slides.include(related) && !this.slides.any(function (slide) { return related.descendantOf(slide); }))) {
				this.start();
            }
        } else {
            this.start();
        }
    },

	periodicallyUpdate: function () {
		if (!this.scroller) {return }
		if (this.timer != null) {
			clearTimeout(this.timer);
			this.next();
        }
		this.timer = setTimeout(this.periodicallyUpdate.bind(this), this.options.frequency * 1000);
    },
    
    wheel: function (event) {
        event.cancelBubble = true;
        event.stop();
        
		var delta = 0;
		if (!event) {
            event = window.event;
        }
		if (event.wheelDelta) {
			delta = event.wheelDelta / 120; 
		} else if (event.detail) { 
            delta = -event.detail / 3;	
        }        
       
        if (!this.scrolling) {
            this.deactivateControls();
            if (delta > 0) {
                this.prev();
            } else {
                this.next();
            }            
        }
        
		return Math.round(delta); //Safari Round
    },

	deactivateControls: function () {
		if (this.controls) {
			this.controls.invoke('addClassName', this.options.disabledClassName);
		}
    },

	activateControls: function () {
		this.controls.invoke('removeClassName', this.options.disabledClassName);
    }
});


Effect.SmoothScroll = Class.create();
Object.extend(Object.extend(Effect.SmoothScroll.prototype, Effect.Base.prototype), {
	initialize: function (element) {
		this.element = $(element);
		var options = Object.extend({ x: 0, y: 0, mode: 'absolute' } , arguments[1] || {});
		this.start(options);
    },

	setup: function () {
		if (this.options.continuous && !this.element._ext) {
			this.element.cleanWhitespace();
			this.element._ext = true;
			this.element.appendChild(this.element.firstChild);
        }

		this.originalLeft = this.element.scrollLeft;
		this.originalTop  = this.element.scrollTop;

		if (this.options.mode == 'absolute') {
			this.options.x -= this.originalLeft;
			this.options.y -= this.originalTop;
        }
    },

	update: function (position) {
		this.element.scrollLeft = this.options.x * position + this.originalLeft;
		this.element.scrollTop  = this.options.y * position + this.originalTop;
    }
});
var Protip = Class.create({
	
	initialize: function(element,options){
		
		this.element 		= $(element);		
		
		this.setOptions(options);
		this.addObservers();
		this.setupProtip();
		
	},
	
	setOptions: function(options) {
		
		this.options = {
			maxWidth: '',
			offsetX: 15,
			offsetY: 20,
			opacity: .90,
			appearDuration: 0.5, 
			hideDuration: 0.5 
		};
		Object.extend(this.options, options || {});
		
	},
	
	setupProtip: function() {
		
		this.content 		= this.element.readAttribute('title');
		this.element.title 	= '';
		this.element.descendants().each(function(el){
			if(Element.readAttribute(el, 'alt'))
				el.alt = "";
		});
		
		this._protip	= new Element('div', {'class':'protip'}).update(this.content);
		$$('body')[0].insert(this._protip.hide());
		
		this.protipWidth  	= (this.options.maxWidth!='' && this._protip.getWidth()>this.options.maxWidth) ? this.options.maxWidth : this._protip.getWidth();
		this._protip.setStyle({ width: this.protipWidth+'px' });

	},
	
	addObservers: function() {
		
		Event.observe(this.element, "mouseover", this.showProtip.bind(this));
   		Event.observe(this.element, "mouseout", this.hideProtip.bind(this));
    	Event.observe(this.element, "mousemove", this.moveProtip.bindAsEventListener(this));
		
	},
	
	showProtip: function() {
		
		this._protip.currentEffect && this._protip.currentEffect.cancel();
		this._protip.currentEffect = new Effect.Appear(this._protip, { duration: this.options.appearDuration, to: this.options.opacity });
			
	},
	
	hideProtip: function() {
		
		this._protip.currentEffect && this._protip.currentEffect.cancel();
      	this._protip.currentEffect = new Effect.Fade(this._protip, { duration: this.options.hideDuration });
		
	},
	
	moveProtip: function(event){
	
		this.mouseX = Event.pointerX(event);
		this.mouseY = Event.pointerY(event);	
		
		if((this.protipWidth+this.mouseX)>=(Element.getWidth(document.body)-this.options.offsetX)) {
			this.mouseX = (this.mouseX - this.protipWidth) - 2*this.options.offsetX;
		}
		
		this._protip.setStyle({ top:this.mouseY + this.options.offsetY + "px", left:this.mouseX + this.options.offsetX + "px" });
	
	}

});
/**
	Protofade 1.2 18/09/09
	Copyright (c) 2009 Filippo Buratti; info [at] cssrevolt.com [dot] com; http://www.filippoburatti.net/

	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.
*/

var Protofade = Class.create({

	initialize: function(element, options) {		
		this.options = {
      		duration: 1,
			delay: 4.0,
			randomize: false,
			autostart:true,
			controls:false,
			eSquare:false,
			eRows: 3, 
			eCols: 5,
			eColor: '#FFFFFF'
    	}
		Object.extend(this.options, options || {});

    	this.element        = $(element);
		this.slides			= this.element.childElements();
		this.num_slides		= this.slides.length;		
		this.current_slide 	= (this.options.randomize) ? (Math.floor(Math.random()*this.num_slides)) : 0;
		this.end_slide		= this.num_slides - 1;
		
		this.slides.invoke('hide');
		this.slides[this.current_slide].show();
				
		if (this.options.autostart) { 
			this.startSlideshow();
		}				
		if (this.options.controls) {
			this.addControls();
		}
		if (this.options.eSquare) {
			this.buildEsquare();
		}
	},
	
	addControls: function() {
		this.wrapper 		= this.element.up();
		this.controls		= new Element('div', { 'class': 'controls' });
		this.wrapper.insert(this.controls);
		
		this.btn_next 		= new Element('a', { 'class': 'next', 'title': 'Next', href: '#' }).update('Next');
		this.btn_previous	= new Element('a', { 'class': 'previous', 'title': 'Previous', href: '#' }).update('Previous');
		this.btn_start		= new Element('a', { 'class': 'start', 'title': 'Start', href: '#' }).update('Start');
		this.btn_stop		= new Element('a', { 'class': 'stop', 'title': 'Stop', href: '#' }).update('Stop');
		
		this.btns = [this.btn_previous, this.btn_next, this.btn_start, this.btn_stop];
		this.btns.each(function(el){
			this.controls.insert(el);
		}.bind(this));
		
		this.btn_previous.observe('click', this.moveToPrevious.bindAsEventListener(this));
		this.btn_next.observe('click', this.moveToNext.bindAsEventListener(this));
		this.btn_start.observe('click', this.startSlideshow.bindAsEventListener(this));
		this.btn_stop.observe('click', this.stopSlideshow.bindAsEventListener(this));
	},
	
	buildEsquare: function() {		
		this.eSquares 	= [];
		var elDimension	 	= this.element.getDimensions();
		var elWidth  		= elDimension.width;
		var elHeight 		= elDimension.height;
				
		var sqWidth 		= elWidth / this.options.eCols;
		var sqHeight 		= elHeight / this.options.eRows;
	
		$R(0, this.options.eCols-1).each(function(col) {
			this.eSquares[col] = [];							 	
			$R(0, this.options.eRows-1).each(function(row) {
				var sqLeft = col * sqWidth;
			    var sqTop  = row * sqHeight;
				this.eSquares[col][row] = new Element('div').setStyle({
 														    opacity: 0, backgroundColor: this.options.eColor,
															position: 'absolute', 'z-index': 5,
															left: sqLeft + 'px', top: sqTop + 'px',
															width: sqWidth + 'px', height: sqHeight + 'px'		
														});
				this.element.insert(this.eSquares[col][row]);				 							 										 
			}.bind(this))
		}.bind(this));			
	},

	startSlideshow: function(event) {
		if (event) { Event.stop(event); }
		if (!this.running)	{
			this.executer = new PeriodicalExecuter(function(){
	  			this.updateSlide(this.current_slide+1);
	 		}.bind(this),this.options.delay);
			this.running=true;
		}
	},
	
	stopSlideshow: function(event) {	
		if (event) { Event.stop(event); } 
		if (this.executer) { 
			this.executer.stop();
			this.running=false;
		}	 
	},

	moveToPrevious: function (event) {
		if (event) { Event.stop(event); }
		this.stopSlideshow();
  		this.updateSlide(this.current_slide-1);
	},

	moveToNext: function (event) {
		if (event) { Event.stop(event); }
		this.stopSlideshow();
  		this.updateSlide(this.current_slide+1);
	},
	
	updateSlide: function(next_slide) {		
		if (next_slide > this.end_slide) { 
			next_slide = 0; 
		} 
		else if ( next_slide == -1 ) {
			next_slide = this.end_slide;
		}	
		this.fadeInOut(next_slide, this.current_slide);		
	},

 	fadeInOut: function (next, current) {		
		new Effect.Parallel([
			new Effect.Fade(this.slides[current], { sync: true }),
			new Effect.Appear(this.slides[next], { sync: true }) 
  		], { duration: this.options.duration });
		
		if (this.options.eSquare) {			
			$R(0, this.options.eCols-1).each(function(col) {	 						 	
				$R(0, this.options.eRows-1).each(function(row) {
					var eSquare = this.eSquares[col][row];
					var delay = Math.random() * 150;				
					setTimeout(this.delayedAppear.bind(this, eSquare), delay);
				}.bind(this))
			}.bind(this));	
		}
		
		this.current_slide = next;		
	},
	
	delayedAppear: function(eSquare)	{
		var opacity = Math.random();
		new Effect.Parallel([ 
			new Effect.Appear ( eSquare, { from: 0, to: opacity, duration: this.options.duration/4 } ),
			new Effect.Appear ( eSquare, { from: opacity, to: 0, duration: this.options.duration/1.25} )
		], { sync: false });			
	}

});
/**
	Protoform(class) v1.1 18/03/2009
	Copyright (c) 2008 Filippo Buratti; info [at] cssrevolt.com [dot] com; http://www.filippoburatti.net/

	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.
*/

REGEX_AUTO_FIELD  = /^[^_]+(_Req)?(_(Tel|Num|Int|Email|Url|Date))?$/;
REGEX_BLANK       = /^\s*$/;
REGEX_EMAIL       = /^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-]{2,})+\.)+([a-zA-Z0-9]{2,})+$/;
REGEX_TEL         = /^([0-9]*\-?\ ?\/?[0-9]*)$/;
REGEX_NUM		  = /^[-+]?\d+(\.\d+)?$/;
REGEX_URL         = /^(http|ftp|https):\/\/[\w\-_]+(\.[\w\-_]+)+([\w\-\.,@?^=%&amp;:/~\+#]*[\w\-\@?^=%&amp;/~\+#])?/;
REGEX_DAY         = /^(0?[1-9]|[1-2][0-9]|3[01])$/;
REGEX_MONTH       = /^(0?[1-9]|1[0-2])$/;
REGEX_YEAR        = /^[0-9]{2,4}$/;
REGEX_TYPED_FIELD = /_(Tel|Num|Int|Email|Url|Date)$/;


var Protoform = Class.create({

initialize: function(form, options) {	  	
	this.options = {
      		ajax: true,
			url:''
    	}
		Object.extend(this.options, options || {});
	this.form      		= $(form);
	this.formProcess 	= this.checkForm.bindAsEventListener(this);
	this.form.observe("submit", this.formProcess );
	this.hoverFocus();
},

hoverFocus: function() { 
 	this.form.select('input', 'textarea').each(function(item) {
    	Event.observe(item,'focus',function() {
      		Element.addClassName(this,'hoverfocus');
    	}.bind(item));
    	Event.observe(item,'blur',function() {
      		Element.removeClassName(this,'hoverfocus');
    	}.bind(item));
	});
},
	
checkForm: function(event) { 
	Event.stop(event);
    var errors	= '';
    var faulty	= null;
	if ($('response')) { $('response').remove(); }
	
	this.form.getElements().each(function(formElements) {
		var value 			= ($F(formElements)!= null) ? $F(formElements) : '' ;
		var idField			= formElements.readAttribute('id') ? formElements.readAttribute('id') : '';
		
		var typedField 		= idField.match(REGEX_TYPED_FIELD);
		var errorMessage	= formElements.readAttribute('title');


		
		if (!idField.match(REGEX_AUTO_FIELD)) {
            return;
		}  
		
		if (idField.match(/_Req/) && value.match(REGEX_BLANK)) {
            errors += '<li>' + errorMessage + '</li>';
            faulty = faulty || formElements;
            return;
        }
		
		if (typedField  && !value.match(REGEX_BLANK)) {
	    	var type = typedField[1];		
	    	var error = this.checkField(value, type);
	    	if (error) {
				errors += '<li>' + errorMessage + '</li>';
				faulty = faulty || formElements;
	    	}
		}
	}.bindAsEventListener(this));
	
	
	if (errors==0) {
		if (this.options.ajax){
			this.sendData(); 
		} else {
			this.form.submit();
		}
	} else {
	
		if (!$('error')) {	
			this.form.insert({before:new Element('ul', {id:'error'}).update(errors)});
		} else {
			$('error').update(errors);	
		}
		faulty.focus();
	}
},
	
checkField: function (value, type) {
	switch (type) {
		case 'Tel':
			var phone= value;
			if (!phone.match(REGEX_TEL)) { return true; }     
			break;
		case 'Num':
			var number= value;
			if (!number.match(REGEX_NUM)) { return true; }     
			break;
		case 'Tel':
			var phone= value;
			if (!phone.match(REGEX_TEL)) { return true; }     
			break;
		case 'Email':
			var address= value;
			if (!address.match(REGEX_EMAIL)) { return true; }     
			break;
		case 'Url':
			var resource= value;
			if (!resource.match(REGEX_URL)) { return true; }
			break;
		case 'Date':
			var comps = value.split('/');
        	if (3 != comps.length || !comps[0].match(REGEX_DAY) || !comps[1].match(REGEX_MONTH) || !comps[2].match(REGEX_YEAR)) { return true; }
			break;
		default:
			return null;
	}

}.bind(this), 
	
sendData: function(event) {
	var url 	= (this.options.url) ? (this.options.url) : this.form.readAttribute('action');
	var reqType	= this.form.readAttribute('method');
	var pars 	= this.form.serialize();
	var myAjax 	= new Ajax.Request( url, { method: reqType, parameters: pars, onCreate: this.showLoad.bind(this), onComplete: this.getResponse.bind(this) });
},
	
showLoad: function() {
	this.form.insert({before:'<p id="working">loading...</p>'});
	if ($('error')) { $('error').remove(); }
},
	
getResponse: function(transport) {
	$('working').remove();
	var newData = transport.responseText;
	this.form.insert({before:newData}).reset();
}	
  
}); 
/*!
 * Copyright (c) 2010 Simo Kinnunen.
 * Licensed under the MIT license.
 *
 * @version ${Version}
 */

var Cufon = (function() {

	var api = function() {
		return api.replace.apply(null, arguments);
	};

	var DOM = api.DOM = {

		ready: (function() {

			var complete = false, readyStatus = { loaded: 1, complete: 1 };

			var queue = [], perform = function() {
				if (complete) return;
				complete = true;
				for (var fn; fn = queue.shift(); fn());
			};

			// Gecko, Opera, WebKit r26101+

			if (document.addEventListener) {
				document.addEventListener('DOMContentLoaded', perform, false);
				window.addEventListener('pageshow', perform, false); // For cached Gecko pages
			}

			// Old WebKit, Internet Explorer

			if (!window.opera && document.readyState) (function() {
				readyStatus[document.readyState] ? perform() : setTimeout(arguments.callee, 10);
			})();

			// Internet Explorer

			if (document.readyState && document.createStyleSheet) (function() {
				try {
					document.body.doScroll('left');
					perform();
				}
				catch (e) {
					setTimeout(arguments.callee, 1);
				}
			})();

			addEvent(window, 'load', perform); // Fallback

			return function(listener) {
				if (!arguments.length) perform();
				else complete ? listener() : queue.push(listener);
			};

		})(),

		root: function() {
			return document.documentElement || document.body;
		}

	};

	var CSS = api.CSS = {

		Size: function(value, base) {

			this.value = parseFloat(value);
			this.unit = String(value).match(/[a-z%]*$/)[0] || 'px';

			this.convert = function(value) {
				return value / base * this.value;
			};

			this.convertFrom = function(value) {
				return value / this.value * base;
			};

			this.toString = function() {
				return this.value + this.unit;
			};

		},

		addClass: function(el, className) {
			var current = el.className;
			el.className = current + (current && ' ') + className;
			return el;
		},

		color: cached(function(value) {
			var parsed = {};
			parsed.color = value.replace(/^rgba\((.*?),\s*([\d.]+)\)/, function($0, $1, $2) {
				parsed.opacity = parseFloat($2);
				return 'rgb(' + $1 + ')';
			});
			return parsed;
		}),

		// has no direct CSS equivalent.
		// @see http://msdn.microsoft.com/en-us/library/system.windows.fontstretches.aspx
		fontStretch: cached(function(value) {
			if (typeof value == 'number') return value;
			if (/%$/.test(value)) return parseFloat(value) / 100;
			return {
				'ultra-condensed': 0.5,
				'extra-condensed': 0.625,
				condensed: 0.75,
				'semi-condensed': 0.875,
				'semi-expanded': 1.125,
				expanded: 1.25,
				'extra-expanded': 1.5,
				'ultra-expanded': 2
			}[value] || 1;
		}),

		getStyle: function(el) {
			var view = document.defaultView;
			if (view && view.getComputedStyle) return new Style(view.getComputedStyle(el, null));
			if (el.currentStyle) return new Style(el.currentStyle);
			return new Style(el.style);
		},

		gradient: cached(function(value) {
			var gradient = {
				id: value,
				type: value.match(/^-([a-z]+)-gradient\(/)[1],
				stops: []
			}, colors = value.substr(value.indexOf('(')).match(/([\d.]+=)?(#[a-f0-9]+|[a-z]+\(.*?\)|[a-z]+)/ig);
			for (var i = 0, l = colors.length, stop; i < l; ++i) {
				stop = colors[i].split('=', 2).reverse();
				gradient.stops.push([ stop[1] || i / (l - 1), stop[0] ]);
			}
			return gradient;
		}),

		quotedList: cached(function(value) {
			// doesn't work properly with empty quoted strings (""), but
			// it's not worth the extra code.
			var list = [], re = /\s*((["'])([\s\S]*?[^\\])\2|[^,]+)\s*/g, match;
			while (match = re.exec(value)) list.push(match[3] || match[1]);
			return list;
		}),

		recognizesMedia: cached(function(media) {
			var el = document.createElement('style'), sheet, container, supported;
			el.type = 'text/css';
			el.media = media;
			try { // this is cached anyway
				el.appendChild(document.createTextNode('/**/'));
			} catch (e) {}
			container = elementsByTagName('head')[0];
			container.insertBefore(el, container.firstChild);
			sheet = (el.sheet || el.styleSheet);
			supported = sheet && !sheet.disabled;
			container.removeChild(el);
			return supported;
		}),

		removeClass: function(el, className) {
			var re = RegExp('(?:^|\\s+)' + className +  '(?=\\s|$)', 'g');
			el.className = el.className.replace(re, '');
			return el;
		},

		supports: function(property, value) {
			var checker = document.createElement('span').style;
			if (checker[property] === undefined) return false;
			checker[property] = value;
			return checker[property] === value;
		},

		textAlign: function(word, style, position, wordCount) {
			if (style.get('textAlign') == 'right') {
				if (position > 0) word = ' ' + word;
			}
			else if (position < wordCount - 1) word += ' ';
			return word;
		},

		textShadow: cached(function(value) {
			if (value == 'none') return null;
			var shadows = [], currentShadow = {}, result, offCount = 0;
			var re = /(#[a-f0-9]+|[a-z]+\(.*?\)|[a-z]+)|(-?[\d.]+[a-z%]*)|,/ig;
			while (result = re.exec(value)) {
				if (result[0] == ',') {
					shadows.push(currentShadow);
					currentShadow = {};
					offCount = 0;
				}
				else if (result[1]) {
					currentShadow.color = result[1];
				}
				else {
					currentShadow[[ 'offX', 'offY', 'blur' ][offCount++]] = result[2];
				}
			}
			shadows.push(currentShadow);
			return shadows;
		}),

		textTransform: (function() {
			var map = {
				uppercase: function(s) {
					return s.toUpperCase();
				},
				lowercase: function(s) {
					return s.toLowerCase();
				},
				capitalize: function(s) {
					return s.replace(/\b./g, function($0) {
						return $0.toUpperCase();
					});
				}
			};
			return function(text, style) {
				var transform = map[style.get('textTransform')];
				return transform ? transform(text) : text;
			};
		})(),

		whiteSpace: (function() {
			var ignore = {
				inline: 1,
				'inline-block': 1,
				'run-in': 1
			};
			var wsStart = /^\s+/, wsEnd = /\s+$/;
			return function(text, style, node, previousElement) {
				if (previousElement) {
					if (previousElement.nodeName.toLowerCase() == 'br') {
						text = text.replace(wsStart, '');
					}
				}
				if (ignore[style.get('display')]) return text;
				if (!node.previousSibling) text = text.replace(wsStart, '');
				if (!node.nextSibling) text = text.replace(wsEnd, '');
				return text;
			};
		})()

	};

	CSS.ready = (function() {

		// don't do anything in Safari 2 (it doesn't recognize any media type)
		var complete = !CSS.recognizesMedia('all'), hasLayout = false;

		var queue = [], perform = function() {
			complete = true;
			for (var fn; fn = queue.shift(); fn());
		};

		var links = elementsByTagName('link'), styles = elementsByTagName('style');

		function isContainerReady(el) {
			return el.disabled || isSheetReady(el.sheet, el.media || 'screen');
		}

		function isSheetReady(sheet, media) {
			// in Opera sheet.disabled is true when it's still loading,
			// even though link.disabled is false. they stay in sync if
			// set manually.
			if (!CSS.recognizesMedia(media || 'all')) return true;
			if (!sheet || sheet.disabled) return false;
			try {
				var rules = sheet.cssRules, rule;
				if (rules) {
					// needed for Safari 3 and Chrome 1.0.
					// in standards-conforming browsers cssRules contains @-rules.
					// Chrome 1.0 weirdness: rules[<number larger than .length - 1>]
					// returns the last rule, so a for loop is the only option.
					search: for (var i = 0, l = rules.length; rule = rules[i], i < l; ++i) {
						switch (rule.type) {
							case 2: // @charset
								break;
							case 3: // @import
								if (!isSheetReady(rule.styleSheet, rule.media.mediaText)) return false;
								break;
							default:
								// only @charset can precede @import
								break search;
						}
					}
				}
			}
			catch (e) {} // probably a style sheet from another domain
			return true;
		}

		function allStylesLoaded() {
			// Internet Explorer's style sheet model, there's no need to do anything
			if (document.createStyleSheet) return true;
			// standards-compliant browsers
			var el, i;
			for (i = 0; el = links[i]; ++i) {
				if (el.rel.toLowerCase() == 'stylesheet' && !isContainerReady(el)) return false;
			}
			for (i = 0; el = styles[i]; ++i) {
				if (!isContainerReady(el)) return false;
			}
			return true;
		}

		DOM.ready(function() {
			// getComputedStyle returns null in Gecko if used in an iframe with display: none
			if (!hasLayout) hasLayout = CSS.getStyle(document.body).isUsable();
			if (complete || (hasLayout && allStylesLoaded())) perform();
			else setTimeout(arguments.callee, 10);
		});

		return function(listener) {
			if (complete) listener();
			else queue.push(listener);
		};

	})();

	function Font(data) {

		var face = this.face = data.face, wordSeparators = {
			'\u0020': 1,
			'\u00a0': 1,
			'\u3000': 1
		};

		this.glyphs = data.glyphs;
		this.w = data.w;
		this.baseSize = parseInt(face['units-per-em'], 10);

		this.family = face['font-family'].toLowerCase();
		this.weight = face['font-weight'];
		this.style = face['font-style'] || 'normal';

		this.viewBox = (function () {
			var parts = face.bbox.split(/\s+/);
			var box = {
				minX: parseInt(parts[0], 10),
				minY: parseInt(parts[1], 10),
				maxX: parseInt(parts[2], 10),
				maxY: parseInt(parts[3], 10)
			};
			box.width = box.maxX - box.minX;
			box.height = box.maxY - box.minY;
			box.toString = function() {
				return [ this.minX, this.minY, this.width, this.height ].join(' ');
			};
			return box;
		})();

		this.ascent = -parseInt(face.ascent, 10);
		this.descent = -parseInt(face.descent, 10);

		this.height = -this.ascent + this.descent;

		this.spacing = function(chars, letterSpacing, wordSpacing) {
			var glyphs = this.glyphs, glyph,
				kerning, k,
				jumps = [],
				width = 0, w,
				i = -1, j = -1, chr;
			while (chr = chars[++i]) {
				glyph = glyphs[chr] || this.missingGlyph;
				if (!glyph) continue;
				if (kerning) {
					width -= k = kerning[chr] || 0;
					jumps[j] -= k;
				}
				w = glyph.w;
				if (isNaN(w)) w = +this.w; // may have been a String in old fonts
				if (w > 0) {
					w += letterSpacing;
					if (wordSeparators[chr]) w += wordSpacing;
				}
				width += jumps[++j] = ~~w; // get rid of decimals
				kerning = glyph.k;
			}
			jumps.total = width;
			return jumps;
		};

	}

	function FontFamily() {

		var styles = {}, mapping = {
			oblique: 'italic',
			italic: 'oblique'
		};

		this.add = function(font) {
			(styles[font.style] || (styles[font.style] = {}))[font.weight] = font;
		};

		this.get = function(style, weight) {
			var weights = styles[style] || styles[mapping[style]]
				|| styles.normal || styles.italic || styles.oblique;
			if (!weights) return null;
			// we don't have to worry about "bolder" and "lighter"
			// because IE's currentStyle returns a numeric value for it,
			// and other browsers use the computed value anyway
			weight = {
				normal: 400,
				bold: 700
			}[weight] || parseInt(weight, 10);
			if (weights[weight]) return weights[weight];
			// http://www.w3.org/TR/CSS21/fonts.html#propdef-font-weight
			// Gecko uses x99/x01 for lighter/bolder
			var up = {
				1: 1,
				99: 0
			}[weight % 100], alts = [], min, max;
			if (up === undefined) up = weight > 400;
			if (weight == 500) weight = 400;
			for (var alt in weights) {
				if (!hasOwnProperty(weights, alt)) continue;
				alt = parseInt(alt, 10);
				if (!min || alt < min) min = alt;
				if (!max || alt > max) max = alt;
				alts.push(alt);
			}
			if (weight < min) weight = min;
			if (weight > max) weight = max;
			alts.sort(function(a, b) {
				return (up
					? (a >= weight && b >= weight) ? a < b : a > b
					: (a <= weight && b <= weight) ? a > b : a < b) ? -1 : 1;
			});
			return weights[alts[0]];
		};

	}

	function HoverHandler() {

		function contains(node, anotherNode) {
			try {
				if (node.contains) return node.contains(anotherNode);
				return node.compareDocumentPosition(anotherNode) & 16;
			}
			catch(e) {} // probably a XUL element such as a scrollbar
			return false;
		}

		function onOverOut(e) {
			var related = e.relatedTarget;
			// there might be no relatedTarget if the element is right next
			// to the window frame
			if (related && contains(this, related)) return;
			trigger(this, e.type == 'mouseover');
		}

		function onEnterLeave(e) {
			trigger(this, e.type == 'mouseenter');
		}

		function trigger(el, hoverState) {
			// A timeout is needed so that the event can actually "happen"
			// before replace is triggered. This ensures that styles are up
			// to date.
			setTimeout(function() {
				var options = sharedStorage.get(el).options;
				api.replace(el, hoverState ? merge(options, options.hover) : options, true);
			}, 10);
		}

		this.attach = function(el) {
			if (el.onmouseenter === undefined) {
				addEvent(el, 'mouseover', onOverOut);
				addEvent(el, 'mouseout', onOverOut);
			}
			else {
				addEvent(el, 'mouseenter', onEnterLeave);
				addEvent(el, 'mouseleave', onEnterLeave);
			}
		};

	}

	function ReplaceHistory() {

		var list = [], map = {};

		function filter(keys) {
			var values = [], key;
			for (var i = 0; key = keys[i]; ++i) values[i] = list[map[key]];
			return values;
		}

		this.add = function(key, args) {
			map[key] = list.push(args) - 1;
		};

		this.repeat = function() {
			var snapshot = arguments.length ? filter(arguments) : list, args;
			for (var i = 0; args = snapshot[i++];) api.replace(args[0], args[1], true);
		};

	}

	function Storage() {

		var map = {}, at = 0;

		function identify(el) {
			return el.cufid || (el.cufid = ++at);
		}

		this.get = function(el) {
			var id = identify(el);
			return map[id] || (map[id] = {});
		};

	}

	function Style(style) {

		var custom = {}, sizes = {};

		this.extend = function(styles) {
			for (var property in styles) {
				if (hasOwnProperty(styles, property)) custom[property] = styles[property];
			}
			return this;
		};

		this.get = function(property) {
			return custom[property] != undefined ? custom[property] : style[property];
		};

		this.getSize = function(property, base) {
			return sizes[property] || (sizes[property] = new CSS.Size(this.get(property), base));
		};

		this.isUsable = function() {
			return !!style;
		};

	}

	function addEvent(el, type, listener) {
		if (el.addEventListener) {
			el.addEventListener(type, listener, false);
		}
		else if (el.attachEvent) {
			el.attachEvent('on' + type, function() {
				return listener.call(el, window.event);
			});
		}
	}

	function attach(el, options) {
		var storage = sharedStorage.get(el);
		if (storage.options) return el;
		if (options.hover && options.hoverables[el.nodeName.toLowerCase()]) {
			hoverHandler.attach(el);
		}
		storage.options = options;
		return el;
	}

	function cached(fun) {
		var cache = {};
		return function(key) {
			if (!hasOwnProperty(cache, key)) cache[key] = fun.apply(null, arguments);
			return cache[key];
		};
	}

	function getFont(el, style) {
		var families = CSS.quotedList(style.get('fontFamily').toLowerCase()), family;
		for (var i = 0; family = families[i]; ++i) {
			if (fonts[family]) return fonts[family].get(style.get('fontStyle'), style.get('fontWeight'));
		}
		return null;
	}

	function elementsByTagName(query) {
		return document.getElementsByTagName(query);
	}

	function hasOwnProperty(obj, property) {
		return obj.hasOwnProperty(property);
	}

	function merge() {
		var merged = {}, arg, key;
		for (var i = 0, l = arguments.length; arg = arguments[i], i < l; ++i) {
			for (key in arg) {
				if (hasOwnProperty(arg, key)) merged[key] = arg[key];
			}
		}
		return merged;
	}

	function process(font, text, style, options, node, el) {
		var fragment = document.createDocumentFragment(), processed;
		if (text === '') return fragment;
		var separate = options.separate;
		var parts = text.split(separators[separate]), needsAligning = (separate == 'words');
		if (needsAligning && HAS_BROKEN_REGEXP) {
			// @todo figure out a better way to do this
			if (/^\s/.test(text)) parts.unshift('');
			if (/\s$/.test(text)) parts.push('');
		}
		for (var i = 0, l = parts.length; i < l; ++i) {
			processed = engines[options.engine](font,
				needsAligning ? CSS.textAlign(parts[i], style, i, l) : parts[i],
				style, options, node, el, i < l - 1);
			if (processed) fragment.appendChild(processed);
		}
		return fragment;
	}

	function replaceElement(el, options) {
		var name = el.nodeName.toLowerCase();
		if (options.ignore[name]) return;
		var replace = !options.textless[name];
		var style = CSS.getStyle(attach(el, options)).extend(options);
		// may cause issues if the element contains other elements
		// with larger fontSize, however such cases are rare and can
		// be fixed by using a more specific selector
		if (parseFloat(style.get('fontSize')) === 0) return;
		var font = getFont(el, style), node, type, next, anchor, text, lastElement;
		if (!font) return;
		for (node = el.firstChild; node; node = next) {
			type = node.nodeType;
			next = node.nextSibling;
			if (replace && type == 3) {
				// Node.normalize() is broken in IE 6, 7, 8
				if (anchor) {
					anchor.appendData(node.data);
					el.removeChild(node);
				}
				else anchor = node;
				if (next) continue;
			}
			if (anchor) {
				el.replaceChild(process(font,
					CSS.whiteSpace(anchor.data, style, anchor, lastElement),
					style, options, node, el), anchor);
				anchor = null;
			}
			if (type == 1) {
				if (node.firstChild) {
					if (node.nodeName.toLowerCase() == 'cufon') {
						engines[options.engine](font, null, style, options, node, el);
					}
					else arguments.callee(node, options);
				}
				lastElement = node;
			}
		}
	}

	var HAS_BROKEN_REGEXP = ' '.split(/\s+/).length == 0;

	var sharedStorage = new Storage();
	var hoverHandler = new HoverHandler();
	var replaceHistory = new ReplaceHistory();
	var initialized = false;

	var engines = {}, fonts = {}, defaultOptions = {
		autoDetect: false,
		engine: null,
		//fontScale: 1,
		//fontScaling: false,
		forceHitArea: false,
		hover: false,
		hoverables: {
			a: true
		},
		ignore: {
			applet: 1,
			canvas: 1,
			col: 1,
			colgroup: 1,
			head: 1,
			iframe: 1,
			map: 1,
			noscript: 1,
			optgroup: 1,
			option: 1,
			script: 1,
			select: 1,
			style: 1,
			textarea: 1,
			title: 1,
			pre: 1
		},
		printable: true,
		//rotation: 0,
		//selectable: false,
		selector: (
				window.Sizzle
			||	(window.jQuery && function(query) { return jQuery(query); }) // avoid noConflict issues
			||	(window.dojo && dojo.query)
			||	(window.glow && glow.dom && glow.dom.get)
			||	(window.Ext && Ext.query)
			||	(window.YAHOO && YAHOO.util && YAHOO.util.Selector && YAHOO.util.Selector.query)
			||	(window.$$ && function(query) { return $$(query); })
			||	(window.$ && function(query) { return $(query); })
			||	(document.querySelectorAll && function(query) { return document.querySelectorAll(query); })
			||	elementsByTagName
		),
		separate: 'words', // 'none' and 'characters' are also accepted
		textless: {
			dl: 1,
			html: 1,
			ol: 1,
			table: 1,
			tbody: 1,
			thead: 1,
			tfoot: 1,
			tr: 1,
			ul: 1
		},
		textShadow: 'none'
	};

	var separators = {
		// The first pattern may cause unicode characters above
		// code point 255 to be removed in Safari 3.0. Luckily enough
		// Safari 3.0 does not include non-breaking spaces in \s, so
		// we can just use a simple alternative pattern.
		words: /\s/.test('\u00a0') ? /[^\S\u00a0]+/ : /\s+/,
		characters: '',
		none: /^/
	};

	api.now = function() {
		DOM.ready();
		return api;
	};

	api.refresh = function() {
		replaceHistory.repeat.apply(replaceHistory, arguments);
		return api;
	};

	api.registerEngine = function(id, engine) {
		if (!engine) return api;
		engines[id] = engine;
		return api.set('engine', id);
	};

	api.registerFont = function(data) {
		if (!data) return api;
		var font = new Font(data), family = font.family;
		if (!fonts[family]) fonts[family] = new FontFamily();
		fonts[family].add(font);
		return api.set('fontFamily', '"' + family + '"');
	};

	api.replace = function(elements, options, ignoreHistory) {
		options = merge(defaultOptions, options);
		if (!options.engine) return api; // there's no browser support so we'll just stop here
		if (!initialized) {
			CSS.addClass(DOM.root(), 'cufon-active cufon-loading');
			CSS.ready(function() {
				// fires before any replace() calls, but it doesn't really matter
				CSS.addClass(CSS.removeClass(DOM.root(), 'cufon-loading'), 'cufon-ready');
			});
			initialized = true;
		}
		if (options.hover) options.forceHitArea = true;
		if (options.autoDetect) delete options.fontFamily;
		if (typeof options.textShadow == 'string') {
			options.textShadow = CSS.textShadow(options.textShadow);
		}
		if (typeof options.color == 'string' && /^-/.test(options.color)) {
			options.textGradient = CSS.gradient(options.color);
		}
		else delete options.textGradient;
		if (!ignoreHistory) replaceHistory.add(elements, arguments);
		if (elements.nodeType || typeof elements == 'string') elements = [ elements ];
		CSS.ready(function() {
			for (var i = 0, l = elements.length; i < l; ++i) {
				var el = elements[i];
				if (typeof el == 'string') api.replace(options.selector(el), options, true);
				else replaceElement(el, options);
			}
		});
		return api;
	};

	api.set = function(option, value) {
		defaultOptions[option] = value;
		return api;
	};

	return api;

})();

Cufon.registerEngine('canvas', (function() {

	// Safari 2 doesn't support .apply() on native methods

	var check = document.createElement('canvas');
	if (!check || !check.getContext || !check.getContext.apply) return;
	check = null;

	var HAS_INLINE_BLOCK = Cufon.CSS.supports('display', 'inline-block');

	// Firefox 2 w/ non-strict doctype (almost standards mode)
	var HAS_BROKEN_LINEHEIGHT = !HAS_INLINE_BLOCK && (document.compatMode == 'BackCompat' || /frameset|transitional/i.test(document.doctype.publicId));

	var styleSheet = document.createElement('style');
	styleSheet.type = 'text/css';
	styleSheet.appendChild(document.createTextNode((
		'cufon{text-indent:0;}' +
		'@media screen,projection{' +
			'cufon{display:inline;display:inline-block;position:relative;vertical-align:middle;' +
			(HAS_BROKEN_LINEHEIGHT
				? ''
				: 'font-size:1px;line-height:1px;') +
			'}cufon cufontext{display:-moz-inline-box;display:inline-block;width:0;height:0;text-indent:-10000in;}' +
			(HAS_INLINE_BLOCK
				? 'cufon canvas{position:relative;}'
				: 'cufon canvas{position:absolute;}') +
		'}' +
		'@media print{' +
			'cufon{padding:0;}' + // Firefox 2
			'cufon canvas{display:none;}' +
		'}'
	).replace(/;/g, '!important;')));
	document.getElementsByTagName('head')[0].appendChild(styleSheet);

	function generateFromVML(path, context) {
		var atX = 0, atY = 0;
		var code = [], re = /([mrvxe])([^a-z]*)/g, match;
		generate: for (var i = 0; match = re.exec(path); ++i) {
			var c = match[2].split(',');
			switch (match[1]) {
				case 'v':
					code[i] = { m: 'bezierCurveTo', a: [ atX + ~~c[0], atY + ~~c[1], atX + ~~c[2], atY + ~~c[3], atX += ~~c[4], atY += ~~c[5] ] };
					break;
				case 'r':
					code[i] = { m: 'lineTo', a: [ atX += ~~c[0], atY += ~~c[1] ] };
					break;
				case 'm':
					code[i] = { m: 'moveTo', a: [ atX = ~~c[0], atY = ~~c[1] ] };
					break;
				case 'x':
					code[i] = { m: 'closePath' };
					break;
				case 'e':
					break generate;
			}
			context[code[i].m].apply(context, code[i].a);
		}
		return code;
	}

	function interpret(code, context) {
		for (var i = 0, l = code.length; i < l; ++i) {
			var line = code[i];
			context[line.m].apply(context, line.a);
		}
	}

	return function(font, text, style, options, node, el) {

		var redraw = (text === null);

		if (redraw) text = node.getAttribute('alt');

		var viewBox = font.viewBox;

		var size = style.getSize('fontSize', font.baseSize);

		var expandTop = 0, expandRight = 0, expandBottom = 0, expandLeft = 0;
		var shadows = options.textShadow, shadowOffsets = [];
		if (shadows) {
			for (var i = shadows.length; i--;) {
				var shadow = shadows[i];
				var x = size.convertFrom(parseFloat(shadow.offX));
				var y = size.convertFrom(parseFloat(shadow.offY));
				shadowOffsets[i] = [ x, y ];
				if (y < expandTop) expandTop = y;
				if (x > expandRight) expandRight = x;
				if (y > expandBottom) expandBottom = y;
				if (x < expandLeft) expandLeft = x;
			}
		}

		var chars = Cufon.CSS.textTransform(text, style).split('');

		var jumps = font.spacing(chars,
			~~size.convertFrom(parseFloat(style.get('letterSpacing')) || 0),
			~~size.convertFrom(parseFloat(style.get('wordSpacing')) || 0)
		);

		if (!jumps.length) return null; // there's nothing to render

		var width = jumps.total;

		expandRight += viewBox.width - jumps[jumps.length - 1];
		expandLeft += viewBox.minX;

		var wrapper, canvas;

		if (redraw) {
			wrapper = node;
			canvas = node.firstChild;
		}
		else {
			wrapper = document.createElement('cufon');
			wrapper.className = 'cufon cufon-canvas';
			wrapper.setAttribute('alt', text);

			canvas = document.createElement('canvas');
			wrapper.appendChild(canvas);

			if (options.printable) {
				var print = document.createElement('cufontext');
				print.appendChild(document.createTextNode(text));
				wrapper.appendChild(print);
			}
		}

		var wStyle = wrapper.style;
		var cStyle = canvas.style;

		var height = size.convert(viewBox.height);
		var roundedHeight = Math.ceil(height);
		var roundingFactor = roundedHeight / height;
		var stretchFactor = roundingFactor * Cufon.CSS.fontStretch(style.get('fontStretch'));
		var stretchedWidth = width * stretchFactor;

		var canvasWidth = Math.ceil(size.convert(stretchedWidth + expandRight - expandLeft));
		var canvasHeight = Math.ceil(size.convert(viewBox.height - expandTop + expandBottom));

		canvas.width = canvasWidth;
		canvas.height = canvasHeight;

		// needed for WebKit and full page zoom
		cStyle.width = canvasWidth + 'px';
		cStyle.height = canvasHeight + 'px';

		// minY has no part in canvas.height
		expandTop += viewBox.minY;

		cStyle.top = Math.round(size.convert(expandTop - font.ascent)) + 'px';
		cStyle.left = Math.round(size.convert(expandLeft)) + 'px';

		var wrapperWidth = Math.max(Math.ceil(size.convert(stretchedWidth)), 0) + 'px';

		if (HAS_INLINE_BLOCK) {
			wStyle.width = wrapperWidth;
			wStyle.height = size.convert(font.height) + 'px';
		}
		else {
			wStyle.paddingLeft = wrapperWidth;
			wStyle.paddingBottom = (size.convert(font.height) - 1) + 'px';
		}

		var g = canvas.getContext('2d'), scale = height / viewBox.height;

		// proper horizontal scaling is performed later
		g.scale(scale, scale * roundingFactor);
		g.translate(-expandLeft, -expandTop);
		g.save();

		function renderText() {
			var glyphs = font.glyphs, glyph, i = -1, j = -1, chr;
			g.scale(stretchFactor, 1);
			while (chr = chars[++i]) {
				var glyph = glyphs[chars[i]] || font.missingGlyph;
				if (!glyph) continue;
				if (glyph.d) {
					g.beginPath();
					if (glyph.code) interpret(glyph.code, g);
					else glyph.code = generateFromVML('m' + glyph.d, g);
					g.fill();
				}
				g.translate(jumps[++j], 0);
			}
			g.restore();
		}

		if (shadows) {
			for (var i = shadows.length; i--;) {
				var shadow = shadows[i];
				g.save();
				g.fillStyle = shadow.color;
				g.translate.apply(g, shadowOffsets[i]);
				renderText();
			}
		}

		var gradient = options.textGradient;
		if (gradient) {
			var stops = gradient.stops, fill = g.createLinearGradient(0, viewBox.minY, 0, viewBox.maxY);
			for (var i = 0, l = stops.length; i < l; ++i) {
				fill.addColorStop.apply(fill, stops[i]);
			}
			g.fillStyle = fill;
		}
		else g.fillStyle = style.get('color');

		renderText();

		return wrapper;

	};

})());

Cufon.registerEngine('vml', (function() {

	var ns = document.namespaces;
	if (!ns) return;
	ns.add('cvml', 'urn:schemas-microsoft-com:vml');
	ns = null;

	var check = document.createElement('cvml:shape');
	check.style.behavior = 'url(#default#VML)';
	if (!check.coordsize) return; // VML isn't supported
	check = null;

	var HAS_BROKEN_LINEHEIGHT = (document.documentMode || 0) < 8;

	document.write(('<style type="text/css">' +
		'cufoncanvas{text-indent:0;}' +
		'@media screen{' +
			'cvml\\:shape,cvml\\:rect,cvml\\:fill,cvml\\:shadow{behavior:url(#default#VML);display:block;antialias:true;position:absolute;}' +
			'cufoncanvas{position:absolute;text-align:left;}' +
			'cufon{display:inline-block;position:relative;vertical-align:' +
			(HAS_BROKEN_LINEHEIGHT
				? 'middle'
				: 'text-bottom') +
			';}' +
			'cufon cufontext{position:absolute;left:-10000in;font-size:1px;}' +
			'a cufon{cursor:pointer}' + // ignore !important here
		'}' +
		'@media print{' +
			'cufon cufoncanvas{display:none;}' +
		'}' +
	'</style>').replace(/;/g, '!important;'));

	function getFontSizeInPixels(el, value) {
		return getSizeInPixels(el, /(?:em|ex|%)$|^[a-z-]+$/i.test(value) ? '1em' : value);
	}

	// Original by Dead Edwards.
	// Combined with getFontSizeInPixels it also works with relative units.
	function getSizeInPixels(el, value) {
		if (!isNaN(value) || /px$/i.test(value)) return parseFloat(value);
		var style = el.style.left, runtimeStyle = el.runtimeStyle.left;
		el.runtimeStyle.left = el.currentStyle.left;
		el.style.left = value.replace('%', 'em');
		var result = el.style.pixelLeft;
		el.style.left = style;
		el.runtimeStyle.left = runtimeStyle;
		return result;
	}

	function getSpacingValue(el, style, size, property) {
		var key = 'computed' + property, value = style[key];
		if (isNaN(value)) {
			value = style.get(property);
			style[key] = value = (value == 'normal') ? 0 : ~~size.convertFrom(getSizeInPixels(el, value));
		}
		return value;
	}

	var fills = {};

	function gradientFill(gradient) {
		var id = gradient.id;
		if (!fills[id]) {
			var stops = gradient.stops, fill = document.createElement('cvml:fill'), colors = [];
			fill.type = 'gradient';
			fill.angle = 180;
			fill.focus = '0';
			fill.method = 'none';
			fill.color = stops[0][1];
			for (var j = 1, k = stops.length - 1; j < k; ++j) {
				colors.push(stops[j][0] * 100 + '% ' + stops[j][1]);
			}
			fill.colors = colors.join(',');
			fill.color2 = stops[k][1];
			fills[id] = fill;
		}
		return fills[id];
	}

	return function(font, text, style, options, node, el, hasNext) {

		var redraw = (text === null);

		if (redraw) text = node.alt;

		var viewBox = font.viewBox;

		var size = style.computedFontSize || (style.computedFontSize = new Cufon.CSS.Size(getFontSizeInPixels(el, style.get('fontSize')) + 'px', font.baseSize));

		var wrapper, canvas;

		if (redraw) {
			wrapper = node;
			canvas = node.firstChild;
		}
		else {
			wrapper = document.createElement('cufon');
			wrapper.className = 'cufon cufon-vml';
			wrapper.alt = text;

			canvas = document.createElement('cufoncanvas');
			wrapper.appendChild(canvas);

			if (options.printable) {
				var print = document.createElement('cufontext');
				print.appendChild(document.createTextNode(text));
				wrapper.appendChild(print);
			}

			// ie6, for some reason, has trouble rendering the last VML element in the document.
			// we can work around this by injecting a dummy element where needed.
			// @todo find a better solution
			if (!hasNext) wrapper.appendChild(document.createElement('cvml:shape'));
		}

		var wStyle = wrapper.style;
		var cStyle = canvas.style;

		var height = size.convert(viewBox.height), roundedHeight = Math.ceil(height);
		var roundingFactor = roundedHeight / height;
		var stretchFactor = roundingFactor * Cufon.CSS.fontStretch(style.get('fontStretch'));
		var minX = viewBox.minX, minY = viewBox.minY;

		cStyle.height = roundedHeight;
		cStyle.top = Math.round(size.convert(minY - font.ascent));
		cStyle.left = Math.round(size.convert(minX));

		wStyle.height = size.convert(font.height) + 'px';

		var color = style.get('color');
		var chars = Cufon.CSS.textTransform(text, style).split('');

		var jumps = font.spacing(chars,
			getSpacingValue(el, style, size, 'letterSpacing'),
			getSpacingValue(el, style, size, 'wordSpacing')
		);

		if (!jumps.length) return null;

		var width = jumps.total;
		var fullWidth = -minX + width + (viewBox.width - jumps[jumps.length - 1]);

		var shapeWidth = size.convert(fullWidth * stretchFactor), roundedShapeWidth = Math.round(shapeWidth);

		var coordSize = fullWidth + ',' + viewBox.height, coordOrigin;
		var stretch = 'r' + coordSize + 'ns';

		var fill = options.textGradient && gradientFill(options.textGradient);

		var glyphs = font.glyphs, offsetX = 0;
		var shadows = options.textShadow;
		var i = -1, j = 0, chr;

		while (chr = chars[++i]) {

			var glyph = glyphs[chars[i]] || font.missingGlyph, shape;
			if (!glyph) continue;

			if (redraw) {
				// some glyphs may be missing so we can't use i
				shape = canvas.childNodes[j];
				while (shape.firstChild) shape.removeChild(shape.firstChild); // shadow, fill
			}
			else {
				shape = document.createElement('cvml:shape');
				canvas.appendChild(shape);
			}

			shape.stroked = 'f';
			shape.coordsize = coordSize;
			shape.coordorigin = coordOrigin = (minX - offsetX) + ',' + minY;
			shape.path = (glyph.d ? 'm' + glyph.d + 'xe' : '') + 'm' + coordOrigin + stretch;
			shape.fillcolor = color;

			if (fill) shape.appendChild(fill.cloneNode(false));

			// it's important to not set top/left or IE8 will grind to a halt
			var sStyle = shape.style;
			sStyle.width = roundedShapeWidth;
			sStyle.height = roundedHeight;

			if (shadows) {
				// due to the limitations of the VML shadow element there
				// can only be two visible shadows. opacity is shared
				// for all shadows.
				var shadow1 = shadows[0], shadow2 = shadows[1];
				var color1 = Cufon.CSS.color(shadow1.color), color2;
				var shadow = document.createElement('cvml:shadow');
				shadow.on = 't';
				shadow.color = color1.color;
				shadow.offset = shadow1.offX + ',' + shadow1.offY;
				if (shadow2) {
					color2 = Cufon.CSS.color(shadow2.color);
					shadow.type = 'double';
					shadow.color2 = color2.color;
					shadow.offset2 = shadow2.offX + ',' + shadow2.offY;
				}
				shadow.opacity = color1.opacity || (color2 && color2.opacity) || 1;
				shape.appendChild(shadow);
			}

			offsetX += jumps[j++];
		}

		// addresses flickering issues on :hover

		var cover = shape.nextSibling, coverFill, vStyle;

		if (options.forceHitArea) {

			if (!cover) {
				cover = document.createElement('cvml:rect');
				cover.stroked = 'f';
				cover.className = 'cufon-vml-cover';
				coverFill = document.createElement('cvml:fill');
				coverFill.opacity = 0;
				cover.appendChild(coverFill);
				canvas.appendChild(cover);
			}

			vStyle = cover.style;

			vStyle.width = roundedShapeWidth;
			vStyle.height = roundedHeight;

		}
		else if (cover) canvas.removeChild(cover);

		wStyle.width = Math.max(Math.ceil(size.convert(width * stretchFactor)), 0);

		if (HAS_BROKEN_LINEHEIGHT) {

			var yAdjust = style.computedYAdjust;

			if (yAdjust === undefined) {
				var lineHeight = style.get('lineHeight');
				if (lineHeight == 'normal') lineHeight = '1em';
				else if (!isNaN(lineHeight)) lineHeight += 'em'; // no unit
				style.computedYAdjust = yAdjust = 0.5 * (getSizeInPixels(el, lineHeight) - parseFloat(wStyle.height));
			}

			if (yAdjust) {
				wStyle.marginTop = Math.ceil(yAdjust) + 'px';
				wStyle.marginBottom = yAdjust + 'px';
			}

		}

		return wrapper;

	};

})());

/*!
 * The following copyright notice may not be removed under any circumstances.
 * 
 * Copyright:
 * © 2000 Adobe Systems Incorporated. All Rights Reserved.
 * 
 * Trademark:
 * Trajan is either a registered trademark or a trademark of Adobe Systems
 * Incorporated in the United States and/or other countries.
 * 
 * Full name:
 * TrajanPro-Regular
 * 
 * Designer:
 * Carol Twombly
 * 
 * Vendor URL:
 * http://www.adobe.com/type
 * 
 * License information:
 * http://www.adobe.com/type/legal.html
 */
Cufon.registerFont({"w":205,"face":{"font-family":"Trajan Pro","font-weight":400,"font-stretch":"normal","units-per-em":"360","panose-1":"2 2 5 2 5 5 6 2 3 1","ascent":"270","descent":"-90","x-height":"5","cap-height":"1","bbox":"-25 -347 546 91","underline-thickness":"18","underline-position":"-18","stemh":"13","stemv":"29","unicode-range":"U+0020-U+00FF"},"glyphs":{" ":{"w":117},"!":{"d":"39,-245v5,-14,19,-26,34,-31v6,6,-2,20,-4,51v-1,15,-3,159,-12,170v-4,0,-5,-5,-6,-19r-5,-96v0,-8,-4,-62,-7,-75xm58,6v-25,-1,-24,-35,0,-37v10,0,18,8,18,18v0,11,-7,19,-18,19","w":115},"\"":{"d":"36,-187v-6,-18,-13,-85,-15,-80v0,-5,6,-5,15,-5v9,0,15,0,15,5xm81,-187v-6,-18,-13,-85,-15,-80v0,-5,6,-5,15,-5v9,0,15,0,15,5","w":117},"#":{"d":"194,-166r-43,0r-9,59r41,0r0,21r-44,0r-13,86r-13,0r14,-86r-59,0r-14,86r-12,0r13,-86r-43,0r0,-21r47,0r9,-59r-45,0r0,-20r48,0r11,-85r13,0r-11,85r57,0r12,-85r12,0r-11,85r40,0r0,20xm138,-166r-57,0r-9,59r58,0"},"$":{"d":"126,-273v21,2,39,-1,43,10v-1,10,3,43,-4,46v-7,-8,-1,-24,-13,-34v-6,-5,-18,-10,-27,-10r-11,107v34,22,63,42,63,82v0,54,-51,72,-76,72v-3,12,3,33,-13,34v-7,-6,1,-24,0,-34v-11,-1,-58,-2,-57,-22v2,-26,1,-41,8,-49v5,11,-1,31,11,41v9,11,25,16,39,16r11,-115v-40,-28,-61,-47,-61,-79v0,-44,43,-65,74,-65v2,-13,-1,-40,16,-33xm103,-163r9,-98v-13,0,-49,7,-49,43v0,22,14,37,40,55xm112,-121r-10,107v31,-1,49,-21,49,-50v0,-24,-15,-41,-39,-57"},"%":{"d":"233,0v-84,-3,-79,-130,2,-132v83,3,79,130,-2,132xm234,-10v28,0,39,-25,39,-54v0,-28,-13,-58,-39,-58v-27,0,-39,25,-39,54v0,28,13,58,39,58xm112,-3v-3,8,-14,4,-21,7v-4,1,-5,-2,-4,-4v36,-81,111,-256,114,-264v-23,1,-79,6,-85,6v40,29,29,122,-38,120v-85,-4,-78,-132,4,-132v64,0,128,-10,139,-7xm79,-148v28,0,38,-24,38,-53v0,-28,-13,-59,-39,-59v-27,0,-38,25,-38,54v0,28,13,58,39,58","w":313},"&":{"d":"214,-54v40,34,54,40,98,53v-53,4,-67,10,-117,-32v-8,8,-37,39,-90,39v-118,0,-101,-134,-32,-166v-40,-52,-12,-116,60,-116v22,0,44,2,48,18v-1,15,2,43,-6,47v-3,-25,-17,-54,-49,-53v-22,0,-46,13,-46,47v0,47,89,122,125,157v10,-14,18,-38,18,-60v0,-16,-17,-23,-29,-26v9,-3,48,-6,56,7v0,29,-20,66,-36,85xm186,-40v-46,-40,-74,-66,-108,-111v-57,29,-30,138,40,138v33,0,56,-14,68,-27","w":279},"(":{"d":"103,-265v-18,23,-54,72,-54,150v0,77,23,119,54,157v0,1,-2,3,-3,3v-32,-22,-78,-77,-78,-155v0,-80,51,-142,79,-158v1,0,2,2,2,3","w":129,"k":{"v":-8,"w":-3,"y":-12,"\u00fd":-12,"\u00ff":-12}},")":{"d":"26,42v20,-22,53,-72,54,-150v1,-77,-24,-118,-53,-157v0,-1,1,-3,2,-3v32,22,78,76,78,154v0,81,-51,141,-78,159v-1,0,-3,-2,-3,-3","w":129},"*":{"d":"59,-239v0,-10,-8,-33,-10,-41v0,-3,24,-18,26,-7v3,9,-12,37,-8,48v20,-6,30,-16,37,-22v2,0,17,24,6,26v-1,1,-35,0,-44,2v4,13,28,26,35,31v0,6,-14,18,-19,18v-11,-5,-14,-39,-23,-43v-3,7,-15,27,-16,38v-5,5,-29,0,-27,-3v1,-13,42,-31,38,-42v-11,-2,-32,-3,-38,-1v-2,0,-8,-26,-1,-27v14,-1,36,23,44,23","w":126},"+":{"d":"168,-87r-66,0r0,67r-19,0r0,-67r-68,0r0,-19r67,0r0,-67r19,0r0,67r67,0r0,19","w":183},",":{"d":"31,34v-5,-9,13,-25,9,-33v0,-17,-12,-22,-12,-26v0,-10,13,-19,22,-19v26,18,3,59,-19,78","w":90},"-":{"d":"128,-108v-18,14,-93,11,-113,25v-3,-6,-2,-30,11,-29v33,2,77,-5,102,4","w":140},".":{"d":"45,0v-27,-1,-27,-38,0,-40v11,0,20,7,20,19v0,12,-8,21,-20,21","w":90},"\/":{"d":"24,4v-4,3,-20,-3,-15,-12r166,-266v5,-4,16,4,16,9","w":198},"0":{"d":"15,-127v0,-85,32,-149,90,-149v66,0,85,86,85,133v0,83,-31,149,-90,149v-56,0,-85,-69,-85,-133xm98,-263v-73,3,-73,257,9,256v77,-3,69,-260,-9,-256"},"1":{"d":"40,-222v24,-20,52,-38,81,-54v11,24,-6,197,3,250v-4,23,28,18,42,25v-53,3,-63,2,-120,0v9,-9,47,3,47,-25r1,-200v-3,-33,-42,17,-54,4"},"2":{"d":"186,-63v2,16,1,63,-32,63r-136,0v-9,-1,-4,-10,1,-14v72,-64,126,-114,126,-183v0,-51,-34,-66,-58,-66v-35,0,-50,25,-54,54v-7,-4,-3,-33,-5,-49v10,-15,35,-18,67,-18v54,0,81,35,81,73v0,75,-80,141,-125,179v-2,1,-1,2,1,2v51,-2,126,10,130,-36v1,-4,2,-5,4,-5"},"3":{"d":"74,6v-20,0,-50,-2,-50,-19v0,-21,-1,-42,6,-50v7,28,14,54,56,54v36,0,65,-21,65,-64v0,-48,-43,-65,-66,-70v-7,-1,-10,-2,-10,-5v23,-9,64,-18,66,-67v0,-15,-10,-48,-52,-48v-31,0,-43,21,-48,47v-5,-8,-4,-32,-5,-40v7,-17,32,-20,63,-20v59,0,71,36,71,54v0,37,-38,59,-48,66v23,5,59,28,59,70v0,50,-43,92,-107,92"},"4":{"d":"150,-81v0,30,-10,84,32,77v2,0,3,2,3,3v-41,3,-55,2,-99,0v8,-6,40,-1,36,-25v1,-16,0,-43,0,-55r-109,0v-10,1,-9,-8,-5,-12v2,-3,119,-161,131,-177v3,-6,11,-10,11,0r0,170v12,0,38,0,42,-4v5,5,-1,24,-9,23r-33,0xm122,-100r0,-128v-5,9,-85,119,-92,128r92,0"},"5":{"d":"28,-10v0,-14,-3,-43,4,-52v2,0,3,2,3,6v0,39,24,46,50,46v30,0,63,-20,63,-70v0,-58,-63,-86,-91,-87v-7,0,-10,-3,-10,-7r8,-91v0,-4,3,-5,7,-5v37,-2,79,2,113,-3v7,3,2,31,-5,53v-5,-14,-1,-28,-34,-27r-68,0r-5,55v46,7,113,35,113,99v0,46,-35,99,-108,99v-14,0,-40,-2,-40,-16"},"6":{"d":"18,-98v1,-72,56,-153,132,-178v6,3,2,8,-4,10v-46,26,-97,83,-97,168v0,42,19,90,60,90v29,0,52,-22,52,-62v0,-65,-39,-88,-86,-70v-4,-13,21,-19,43,-19v50,0,72,41,72,73v0,55,-34,92,-88,92v-50,0,-84,-38,-84,-104"},"7":{"d":"171,-247v-54,3,-131,-16,-136,36v0,3,-1,5,-3,5v-4,-14,1,-63,7,-68v32,7,107,3,150,4v5,0,7,2,7,4v-28,55,-96,186,-96,250v0,6,-33,29,-39,19v13,-67,53,-144,110,-250"},"8":{"d":"19,-64v0,-40,31,-67,64,-80v-66,-29,-73,-132,26,-132v37,0,66,20,66,55v0,38,-31,59,-51,69v24,12,62,35,62,79v0,42,-34,79,-85,79v-45,0,-82,-26,-82,-70xm104,-8v33,0,55,-25,55,-57v0,-39,-32,-56,-64,-73v-27,13,-48,35,-48,71v0,32,24,59,57,59xm105,-264v-32,0,-47,25,-47,45v0,30,24,46,54,62v14,-8,38,-23,38,-60v0,-27,-17,-47,-45,-47"},"9":{"d":"133,-145v5,16,-31,22,-43,22v-51,0,-72,-39,-72,-69v0,-50,36,-84,86,-84v51,0,82,43,82,98v0,104,-79,165,-130,187v-4,-1,-4,-8,1,-9v42,-23,97,-83,97,-168v0,-63,-27,-95,-59,-95v-32,0,-49,27,-49,55v0,78,52,81,87,63"},":":{"d":"45,-11v-27,-1,-27,-38,0,-39v11,0,20,6,20,18v0,12,-8,21,-20,21xm45,-132v-27,-1,-27,-38,0,-40v11,0,20,7,20,19v0,12,-8,21,-20,21","w":90},";":{"d":"33,34v-5,-9,13,-25,9,-33v0,-17,-12,-22,-12,-26v0,-10,13,-19,22,-19v24,20,3,60,-19,78xm45,-132v-27,-1,-27,-38,0,-40v11,0,20,7,20,19v0,12,-8,21,-20,21","w":90},"<":{"d":"9,-85r0,-19r153,-71r0,19r-133,61r133,62r0,19","w":183},"=":{"d":"168,-118r-153,0r0,-19r153,0r0,19xm168,-55r-153,0r0,-18r153,0r0,18","w":183},">":{"d":"168,-85r-153,71r0,-19r134,-62r-134,-61r0,-19r153,71r0,19","w":183},"?":{"d":"58,-94v12,-38,72,-82,64,-123v0,-18,-9,-47,-42,-47v-38,0,-45,27,-50,54v-8,-5,-3,-28,-5,-46v9,-15,33,-20,64,-20v48,0,65,30,65,56v0,47,-60,85,-77,132v-3,8,16,23,7,28v-8,-2,-29,-25,-26,-34xm81,6v-25,-1,-24,-35,0,-37v10,0,18,8,18,18v0,11,-7,19,-18,19","w":175},"@":{"d":"209,-35v-26,0,-28,-25,-28,-55v-24,36,-51,54,-66,54v-10,0,-19,-16,-19,-35v0,-51,33,-77,43,-85v22,-17,44,-25,67,-16v3,-4,13,-14,20,-16v9,5,-7,14,-10,33v-5,30,-28,105,13,105v29,0,57,-35,57,-90v0,-52,-35,-94,-103,-94v-84,0,-135,66,-135,152v0,68,43,108,103,108v48,0,71,-14,95,-33v6,-5,8,-5,9,-3v-15,27,-59,49,-112,49v-64,0,-119,-37,-119,-118v0,-87,75,-164,162,-164v154,0,145,208,23,208xm196,-157v-44,-29,-76,34,-74,78v0,9,3,22,9,22v13,0,39,-30,52,-51v4,-21,6,-29,13,-49","w":326},"A":{"d":"34,-39r82,-223v8,-20,8,-20,16,-1v6,14,61,162,84,217v18,43,21,37,49,44v-8,7,-50,3,-75,0v2,-5,8,-3,5,-12v-13,-29,-21,-65,-37,-91v-26,2,-60,-4,-81,3v-9,28,-22,57,-27,88v-2,13,31,8,16,15v-24,-2,-58,4,-76,-3v22,-3,35,-12,44,-37xm85,-118r68,0v2,0,2,-2,2,-3r-34,-97v-2,-5,-4,-5,-6,0v-9,33,-26,69,-30,100","w":252,"k":{"m":-8,"s":-3,"t":23,"v":26,"w":15,"x":-3,"y":17,"\u00fd":17,"\u00ff":17,"M":-9,"S":-4,"T":25,"V":29,"W":16,"X":-4,"Y":18,"\u00dd":18}},"B":{"d":"62,-25v4,-40,1,-184,1,-219v0,-19,-15,-20,-30,-24v30,-8,48,-3,85,-3v101,0,79,82,39,119v27,8,62,34,62,76v0,60,-69,76,-154,76v-9,0,-33,4,-24,-4v15,1,20,-6,21,-21xm163,-199v4,-38,-33,-78,-70,-56v2,32,-3,71,2,100v2,0,9,2,22,2v36,3,43,-18,46,-46xm188,-60v0,-39,-35,-95,-93,-84v-5,24,2,68,-2,101v-4,32,25,34,44,34v19,0,51,-10,51,-51","w":247,"k":{"v":14,"w":6,"y":12,"\u00fd":12,"\u00ff":12,"V":13,"W":5,"Y":11,"\u00dd":11,"a":2,"\u00e6":2,"\u00e1":2,"\u00e2":2,"\u00e4":2,"\u00e0":2,"\u00e5":2,"\u00e3":2,"b":6,"d":6,"e":6,"f":6,"h":6,"i":6,"k":6,"l":6,"n":6,"p":6,"r":6,"\u00fe":6,"\u00f0":6,"\u00e9":6,"\u00ea":6,"\u00eb":6,"\u00e8":6,"\u00ed":6,"\u00ee":6,"\u00ef":6,"\u00ec":6,"\u00f1":6,"A":2,"\u00c6":2,"\u00c1":2,"\u00c2":2,"\u00c4":2,"\u00c0":2,"\u00c5":2,"\u00c3":2,"B":5,"D":5,"E":5,"F":5,"H":5,"I":5,"K":5,"L":5,"N":5,"P":5,"R":5,"\u00d0":5,"\u00de":5,"\u00c9":5,"\u00ca":5,"\u00cb":5,"\u00c8":5,"\u00cd":5,"\u00ce":5,"\u00cf":5,"\u00cc":5,"\u00d1":5}},"C":{"d":"171,-262v-94,0,-116,49,-116,120v0,69,53,132,130,132v41,0,73,-16,76,-49v1,-6,7,-7,6,0v-1,7,-1,55,-17,57v-14,6,-42,8,-65,8v-141,0,-212,-137,-122,-244v33,-39,133,-44,199,-28v13,2,-3,50,2,61v0,5,-1,7,-3,7v-3,0,-3,-2,-3,-7v-2,-44,-36,-57,-87,-57","w":289,"k":{"t":2,"y":-6,"\u00fd":-6,"\u00ff":-6,"T":2,"Y":-5,"\u00dd":-5,"c":4,"g":4,"o":4,"q":4,"\u00f8":4,"\u00e7":4,"\u00f3":4,"\u00f4":4,"\u00f6":4,"\u00f2":4,"\u00f5":4,"C":4,"\u00c7":4,"O":4,"\u00d8":4,"\u00d3":4,"\u00d4":4,"\u00d6":4,"\u00d2":4,"\u00d5":4,"Q":4}},"D":{"d":"159,4v-39,0,-87,2,-121,-6v10,-4,24,-2,24,-23v0,-40,1,-184,1,-219v0,-19,-15,-20,-30,-24v37,-7,45,-3,95,-3v36,0,101,-3,144,41v18,19,35,48,35,91v0,45,-19,81,-39,102v-15,16,-48,41,-109,41xm122,-259v-12,0,-27,-2,-27,10r0,199v2,41,5,40,65,42v68,2,117,-46,115,-119v-2,-98,-75,-135,-153,-132","w":330,"k":{"m":2,"M":2,"a":4,"\u00e6":4,"\u00e1":4,"\u00e2":4,"\u00e4":4,"\u00e0":4,"\u00e5":4,"\u00e3":4,"b":4,"d":4,"e":4,"f":4,"h":4,"i":4,"k":4,"l":4,"n":4,"p":4,"r":4,"\u00fe":4,"\u00f0":4,"\u00e9":4,"\u00ea":4,"\u00eb":4,"\u00e8":4,"\u00ed":4,"\u00ee":4,"\u00ef":4,"\u00ec":4,"\u00f1":4,"A":4,"\u00c6":4,"\u00c1":4,"\u00c2":4,"\u00c4":4,"\u00c0":4,"\u00c5":4,"\u00c3":4,"B":4,"D":4,"E":4,"F":4,"H":4,"I":4,"K":4,"L":4,"N":4,"P":4,"R":4,"\u00d0":4,"\u00de":4,"\u00c9":4,"\u00ca":4,"\u00cb":4,"\u00c8":4,"\u00cd":4,"\u00ce":4,"\u00cf":4,"\u00cc":4,"\u00d1":4,"j":4,"J":4}},"E":{"d":"190,-48v3,15,7,54,-22,50v-42,-6,-93,4,-130,-4v10,-4,24,-2,24,-23v0,-40,1,-184,1,-219v0,-19,-15,-20,-30,-24v36,-10,107,7,149,-6v3,6,-1,39,-6,48v-2,0,-2,-2,-2,-5v7,-32,-51,-25,-78,-26v-4,29,-3,77,0,107v18,-2,75,6,80,-11v3,5,-1,44,-5,53v-2,0,-3,-1,-3,-3v10,-33,-49,-25,-71,-27v-8,20,-3,63,-3,96v0,25,7,30,42,30v31,0,50,-9,54,-36","w":219,"k":{"v":-10,"w":-12,"x":-14,"y":-10,"\u00fd":-10,"\u00ff":-10,"V":-9,"W":-11,"X":-13,"Y":-9,"\u00dd":-9}},"F":{"d":"172,-110v7,-34,-49,-26,-75,-27v-8,20,-1,93,-1,112v0,20,19,20,33,23v-33,8,-48,-1,-85,3v-6,1,-8,-4,-3,-5v15,1,20,-6,21,-21v4,-40,1,-184,1,-219v0,-19,-15,-20,-30,-24v38,-10,113,6,156,-6v3,6,-1,39,-6,48v-6,-13,-5,-30,-30,-30r-55,-1v-2,0,-4,1,-4,4r0,100v20,6,73,8,86,-8v1,16,-2,41,-5,54v-2,0,-3,-1,-3,-3","w":213,"k":{"y":-8,"\u00fd":-8,"\u00ff":-8,"Y":-7,"\u00dd":-7,"a":12,"\u00e6":12,"\u00e1":12,"\u00e2":12,"\u00e4":12,"\u00e0":12,"\u00e5":12,"\u00e3":12,"A":11,"\u00c6":11,"\u00c1":11,"\u00c2":11,"\u00c4":11,"\u00c0":11,"\u00c5":11,"\u00c3":11,",":36,".":36}},"G":{"d":"187,-9v18,0,48,-1,48,-21v0,-37,16,-107,-28,-99v-1,0,-3,-1,-3,-2v29,-8,46,1,81,-3v6,-1,8,4,3,5v-44,-1,-10,81,-27,119v-74,25,-124,30,-195,-22v-24,-17,-43,-58,-43,-103v-2,-96,73,-144,156,-141v43,2,60,5,88,13v0,5,-2,15,-2,51v0,11,-6,10,-6,2v0,-39,-33,-50,-92,-53v-58,-3,-118,41,-113,115v6,98,60,139,133,139","w":310},"H":{"d":"282,-244r1,219v-3,20,19,19,33,23v-33,8,-48,-1,-85,3v-6,1,-8,-4,-3,-5v15,1,20,-6,21,-21v1,-19,6,-88,0,-118r-155,2r2,116v-3,20,19,20,33,23v-33,8,-48,-1,-85,3v-6,1,-8,-4,-3,-5v15,1,20,-6,21,-21v4,-40,1,-184,1,-219v0,-19,-15,-20,-30,-24v29,-8,46,1,81,-3v6,-1,8,4,3,5v-15,0,-22,5,-22,22v1,28,-4,63,1,87r155,-2r0,-85v2,-19,-16,-20,-31,-24v30,-8,46,1,82,-3v6,-1,6,4,3,5v-15,0,-23,5,-23,22","w":345,"k":{"c":6,"g":6,"o":6,"q":6,"\u00f8":6,"\u00e7":6,"\u00f3":6,"\u00f4":6,"\u00f6":6,"\u00f2":6,"\u00f5":6,"C":5,"\u00c7":5,"O":9,"\u00d8":9,"\u00d3":9,"\u00d4":9,"\u00d6":9,"\u00d2":9,"\u00d5":9,"Q":9,"G":5}},"I":{"d":"95,-244r1,219v-3,20,19,20,33,23v-33,8,-48,-1,-85,3v-6,1,-8,-4,-3,-5v15,1,20,-6,21,-21v4,-40,1,-184,1,-219v0,-20,-12,-21,-26,-24v25,-8,44,1,77,-3v6,-1,8,4,3,5v-15,0,-22,5,-22,22","w":158,"k":{"c":6,"g":6,"o":6,"q":6,"\u00f8":6,"\u00e7":6,"\u00f3":6,"\u00f4":6,"\u00f6":6,"\u00f2":6,"\u00f5":6,"C":5,"\u00c7":5,"O":9,"\u00d8":9,"\u00d3":9,"\u00d4":9,"\u00d6":9,"\u00d2":9,"\u00d5":9,"Q":9,"G":5}},"J":{"d":"12,89v38,-36,52,-40,52,-152r-1,-181v2,-19,-15,-20,-30,-24v29,-8,46,1,81,-3v6,-1,8,4,3,5v-15,0,-22,5,-22,22v0,18,-1,125,-1,164v0,113,-14,129,-80,171v-1,0,-2,-1,-2,-2","w":149,"k":{"c":4,"g":4,"o":4,"q":4,"\u00f8":4,"\u00e7":4,"\u00f3":4,"\u00f4":4,"\u00f6":4,"\u00f2":4,"\u00f5":4,"O":4,"\u00d8":4,"\u00d3":4,"\u00d4":4,"\u00d6":4,"\u00d2":4,"\u00d5":4}},"K":{"d":"198,-258v1,-6,-6,-8,-8,-11v15,-3,47,-2,71,0v-53,12,-103,85,-141,118v29,28,115,127,152,142v12,6,21,3,27,7v-31,9,-77,2,-95,-20v-18,-12,-90,-99,-111,-117r2,114v-2,19,17,20,31,23v-31,8,-47,-1,-82,3v-6,1,-8,-4,-3,-5v15,1,20,-6,21,-21v4,-40,1,-184,1,-219v0,-19,-15,-20,-30,-24v29,-8,46,1,80,-3v6,-1,8,4,3,5v-15,0,-22,5,-22,22r0,99v15,-19,91,-84,104,-113","w":270,"k":{"s":-2,"S":-2,"a":2,"\u00e6":2,"\u00e1":2,"\u00e2":2,"\u00e4":2,"\u00e0":2,"\u00e5":2,"\u00e3":2,"A":2,"\u00c6":2,"\u00c1":2,"\u00c2":2,"\u00c4":2,"\u00c0":2,"\u00c5":2,"\u00c3":2,"c":-1,"g":-1,"o":-1,"q":-1,"\u00f8":-1,"\u00e7":-1,"\u00f3":-1,"\u00f4":-1,"\u00f6":-1,"\u00f2":-1,"\u00f5":-1,"C":-1,"\u00c7":-1,"O":-1,"\u00d8":-1,"\u00d3":-1,"\u00d4":-1,"\u00d6":-1,"\u00d2":-1,"\u00d5":-1,"Q":-1,"G":-1}},"L":{"d":"202,-49v1,15,7,55,-26,51v-45,-5,-99,4,-138,-4v10,-4,24,-2,24,-23v0,-40,1,-184,1,-219v0,-19,-15,-20,-30,-24v30,-8,48,1,85,-3v6,-1,8,4,3,5v-16,0,-26,4,-26,22v0,9,-1,107,-1,141v0,84,-17,88,51,91v30,1,51,-8,53,-32v0,-3,2,-5,4,-5","w":213,"k":{"m":2,"t":24,"v":18,"w":10,"y":14,"\u00fd":14,"\u00ff":14,"M":2,"T":22,"V":16,"W":9,"Y":13,"\u00dd":13,"a":-4,"\u00e6":-4,"\u00e1":-4,"\u00e2":-4,"\u00e4":-4,"\u00e0":-4,"\u00e5":-4,"\u00e3":-4,"A":-4,"\u00c6":-4,"\u00c1":-4,"\u00c2":-4,"\u00c4":-4,"\u00c0":-4,"\u00c5":-4,"\u00c3":-4,"c":9,"g":9,"o":9,"q":9,"\u00f8":9,"\u00e7":9,"\u00f3":9,"\u00f4":9,"\u00f6":9,"\u00f2":9,"\u00f5":9,"C":9,"\u00c7":9,"O":9,"\u00d8":9,"\u00d3":9,"\u00d4":9,"\u00d6":9,"\u00d2":9,"\u00d5":9,"G":9,"u":3,"\u00fa":3,"\u00fb":3,"\u00fc":3,"\u00f9":3,"U":2,"\u00da":2,"\u00db":2,"\u00dc":2,"\u00d9":2}},"M":{"d":"69,-35v-7,23,9,31,25,33v-23,8,-40,-1,-70,3v-7,1,-8,-5,-2,-5v19,2,23,-13,25,-31r26,-235v1,-8,6,-8,9,-1r110,227r106,-226v1,-3,2,-6,5,-6v3,0,4,3,5,10r24,221v1,13,4,33,19,38v12,5,22,0,27,5v-12,6,-66,4,-78,-3v3,-3,6,-6,4,-15r-17,-186r-2,0r-88,187v-14,26,-11,27,-23,3r-89,-186r-2,0","w":378,"k":{"t":8,"w":6,"y":5,"\u00fd":5,"\u00ff":5,"T":7,"W":5,"Y":4,"\u00dd":4,"a":-8,"\u00e6":-8,"\u00e1":-8,"\u00e2":-8,"\u00e4":-8,"\u00e0":-8,"\u00e5":-8,"\u00e3":-8,"A":-7,"\u00c6":-7,"\u00c1":-7,"\u00c2":-7,"\u00c4":-7,"\u00c0":-7,"\u00c5":-7,"\u00c3":-7,"u":-1,"\u00fa":-1,"\u00fb":-1,"\u00fc":-1,"\u00f9":-1,"U":-1,"\u00da":-1,"\u00db":-1,"\u00dc":-1,"\u00d9":-1}},"N":{"d":"313,-269v-15,7,-26,5,-26,36r0,211v0,24,-1,26,-4,26v-72,-64,-147,-152,-214,-224r5,172v-1,45,11,40,35,46v-33,8,-40,-1,-79,3v-6,1,-8,-4,-3,-5v24,-1,25,-6,25,-48r1,-206v0,-14,1,-18,4,-18v24,20,174,188,213,229r-4,-183v4,-37,-16,-31,-35,-39v30,-4,50,-2,82,0","w":340,"k":{"c":6,"g":6,"o":6,"q":6,"\u00f8":6,"\u00e7":6,"\u00f3":6,"\u00f4":6,"\u00f6":6,"\u00f2":6,"\u00f5":6,"C":5,"\u00c7":5,"O":9,"\u00d8":9,"\u00d3":9,"\u00d4":9,"\u00d6":9,"\u00d2":9,"\u00d5":9,"Q":9,"G":5}},"O":{"d":"23,-135v0,-58,43,-141,142,-141v81,0,141,51,141,135v0,81,-56,147,-143,147v-99,0,-140,-76,-140,-141xm57,-145v0,84,50,137,115,137v32,0,100,-18,100,-123v0,-167,-215,-181,-215,-14","w":329,"k":{"m":4,"t":11,"v":4,"w":2,"x":10,"y":4,"\u00fd":4,"\u00ff":4,"M":4,"T":10,"V":4,"W":2,"X":9,"Y":4,"\u00dd":4,"a":8,"\u00e6":8,"\u00e1":8,"\u00e2":8,"\u00e4":8,"\u00e0":8,"\u00e5":8,"\u00e3":8,"b":12,"d":12,"e":12,"f":12,"h":12,"i":12,"k":12,"l":12,"n":12,"p":12,"r":12,"\u00fe":12,"\u00f0":12,"\u00e9":12,"\u00ea":12,"\u00eb":12,"\u00e8":12,"\u00ed":12,"\u00ee":12,"\u00ef":12,"\u00ec":12,"\u00f1":12,"A":7,"\u00c6":7,"\u00c1":7,"\u00c2":7,"\u00c4":7,"\u00c0":7,"\u00c5":7,"\u00c3":7,"B":11,"D":11,"E":11,"F":11,"H":11,"I":11,"K":11,"L":11,"N":11,"P":11,"R":11,"\u00d0":11,"\u00de":11,"\u00c9":11,"\u00ca":11,"\u00cb":11,"\u00c8":11,"\u00cd":11,"\u00ce":11,"\u00cf":11,"\u00cc":11,"\u00d1":11,"j":8,"J":7}},"P":{"d":"112,-260v-9,0,-18,-2,-18,9r1,226v-3,20,20,20,34,23v-34,8,-48,-1,-85,3v-6,1,-8,-4,-3,-5v15,1,20,-6,21,-21v4,-40,1,-184,1,-219v0,-19,-15,-20,-30,-24v32,-8,51,-3,92,-3v45,0,61,15,67,20v47,48,-9,150,-83,126v0,-3,2,-3,10,-3v59,-3,85,-67,42,-114v-18,-20,-41,-18,-49,-18","w":231,"k":{"s":-2,"S":-2,"a":18,"\u00e6":18,"\u00e1":18,"\u00e2":18,"\u00e4":18,"\u00e0":18,"\u00e5":18,"\u00e3":18,"b":6,"d":6,"e":6,"f":6,"h":6,"i":6,"k":6,"l":6,"n":6,"p":6,"r":6,"\u00fe":6,"\u00f0":6,"\u00e9":6,"\u00ea":6,"\u00eb":6,"\u00e8":6,"\u00ed":6,"\u00ee":6,"\u00ef":6,"\u00ec":6,"\u00f1":6,"A":16,"\u00c6":16,"\u00c1":16,"\u00c2":16,"\u00c4":16,"\u00c0":16,"\u00c5":16,"\u00c3":16,"B":5,"D":5,"E":5,"F":5,"H":5,"I":5,"K":5,"L":5,"N":5,"P":5,"R":5,"\u00d0":5,"\u00de":5,"\u00c9":5,"\u00ca":5,"\u00cb":5,"\u00c8":5,"\u00cd":5,"\u00ce":5,"\u00cf":5,"\u00cc":5,"\u00d1":5,",":58,".":58}},"Q":{"d":"546,47v-20,17,-62,26,-117,29v-60,4,-152,-51,-209,-82v-13,7,-37,12,-56,12v-100,0,-141,-76,-141,-141v0,-58,43,-141,142,-141v81,0,141,51,141,135v0,63,-39,106,-63,121r73,38v79,41,134,42,152,42v19,1,50,-7,76,-15v1,0,2,1,2,2xm57,-145v0,84,50,137,115,137v32,0,100,-18,100,-123v0,-167,-215,-181,-215,-14","w":331,"k":{"b":10,"d":10,"e":10,"f":10,"h":10,"i":10,"k":10,"l":10,"n":10,"p":10,"r":10,"\u00fe":10,"\u00f0":10,"\u00e9":10,"\u00ea":10,"\u00eb":10,"\u00e8":10,"\u00ed":10,"\u00ee":10,"\u00ef":10,"\u00ec":10,"\u00f1":10,"B":9,"D":9,"E":9,"F":9,"H":9,"I":9,"K":9,"L":9,"N":9,"P":9,"R":9,"\u00d0":9,"\u00de":9,"\u00c9":9,"\u00ca":9,"\u00cb":9,"\u00c8":9,"\u00cd":9,"\u00ce":9,"\u00cf":9,"\u00cc":9,"\u00d1":9,")":-11,"]":-11,"}":-11}},"R":{"d":"39,-271v81,4,173,-19,173,65v0,27,-11,53,-43,83v48,54,68,111,136,121v-14,7,-61,3,-73,-4v-29,-17,-62,-81,-92,-108r-45,-1v-6,20,0,78,0,90v0,20,19,20,33,23v-34,8,-46,-1,-84,3v-6,1,-8,-4,-3,-5v15,1,20,-6,21,-21v4,-40,1,-184,1,-219v0,-19,-15,-20,-30,-24v0,-2,2,-3,6,-3xm120,-260v-14,0,-24,0,-27,7r0,118v3,10,22,9,40,10v34,1,48,-25,49,-63v0,-45,-23,-72,-62,-72","w":271,"k":{"s":4,"t":20,"v":10,"w":1,"x":2,"y":8,"\u00fd":8,"\u00ff":8,"S":4,"T":18,"V":9,"W":1,"X":2,"Y":7,"\u00dd":7,"a":-2,"\u00e6":-2,"\u00e1":-2,"\u00e2":-2,"\u00e4":-2,"\u00e0":-2,"\u00e5":-2,"\u00e3":-2,"A":-2,"\u00c6":-2,"\u00c1":-2,"\u00c2":-2,"\u00c4":-2,"\u00c0":-2,"\u00c5":-2,"\u00c3":-2,"c":-6,"g":-6,"o":-6,"q":-6,"\u00f8":-6,"\u00e7":-6,"\u00f3":-6,"\u00f4":-6,"\u00f6":-6,"\u00f2":-6,"\u00f5":-6,"C":-5,"\u00c7":-5,"O":-5,"\u00d8":-5,"\u00d3":-5,"\u00d4":-5,"\u00d6":-5,"\u00d2":-5,"\u00d5":-5,"Q":-5,"G":-5}},"S":{"d":"165,-222v-12,-23,-2,-42,-53,-42v-25,0,-44,16,-44,42v-5,21,25,47,54,69v42,33,52,55,52,84v0,15,-5,42,-30,60v-15,11,-36,15,-55,15v-19,0,-53,2,-53,-23v0,-23,-2,-36,4,-44v2,0,3,1,3,4v-1,34,26,50,54,50v35,0,52,-25,52,-48v0,-28,-31,-57,-58,-78v-38,-31,-47,-54,-47,-78v0,-56,66,-76,121,-60v8,5,0,12,2,41v0,6,0,8,-2,8","k":{"m":3,"v":1,"M":3,"V":1}},"T":{"d":"21,-276v60,11,154,8,214,2v5,11,1,43,-1,49v-8,-16,-2,-30,-48,-30r-45,-1r2,231v-3,20,19,20,33,23v-34,8,-48,-1,-86,3v-5,1,-7,-4,-3,-5v15,1,21,-6,22,-21v4,-60,1,-162,2,-231r-54,1v-32,-3,-35,13,-46,26v-5,-8,6,-41,10,-47","w":248,"k":{"m":6,"s":14,"t":-5,"w":-3,"x":-7,"y":-9,"\u00fd":-9,"\u00ff":-9,"M":5,"S":4,"T":-4,"W":-2,"X":-6,"Y":-8,"\u00dd":-8,"a":25,"\u00e6":25,"\u00e1":25,"\u00e2":25,"\u00e4":25,"\u00e0":25,"\u00e5":25,"\u00e3":25,"b":7,"d":7,"e":7,"f":7,"h":7,"i":7,"k":7,"l":7,"n":7,"p":7,"r":7,"\u00fe":7,"\u00f0":7,"\u00e9":7,"\u00ea":7,"\u00eb":7,"\u00e8":7,"\u00ed":7,"\u00ee":7,"\u00ef":7,"\u00ec":7,"\u00f1":7,"A":16,"\u00c6":16,"\u00c1":16,"\u00c2":16,"\u00c4":16,"\u00c0":16,"\u00c5":16,"\u00c3":16,"c":10,"g":10,"o":10,"q":10,"\u00f8":10,"\u00e7":10,"\u00f3":10,"\u00f4":10,"\u00f6":10,"\u00f2":10,"\u00f5":10,"C":9,"\u00c7":9,"O":11,"\u00d8":11,"\u00d3":11,"\u00d4":11,"\u00d6":11,"\u00d2":11,"\u00d5":11,",":41,".":41,"G":9,":":11,";":11,"-":11}},"U":{"d":"156,-8v73,0,77,-77,77,-159r0,-77v0,-19,-16,-20,-31,-24v27,-8,43,1,74,-3v6,-1,8,4,3,5v-15,0,-22,5,-22,22v0,86,17,174,-34,223v-25,24,-53,27,-74,27v-12,0,-48,-1,-74,-25v-43,-13,-33,-174,-33,-225v0,-19,-15,-20,-30,-24v29,-8,48,1,83,-3v6,-1,6,4,3,5v-15,0,-23,5,-23,22r0,128v0,78,25,108,81,108","w":298,"k":{"m":6,"M":6,"a":7,"\u00e6":7,"\u00e1":7,"\u00e2":7,"\u00e4":7,"\u00e0":7,"\u00e5":7,"\u00e3":7,"b":11,"d":11,"e":11,"f":11,"h":11,"i":11,"k":11,"l":11,"n":11,"p":11,"r":11,"\u00fe":11,"\u00f0":11,"\u00e9":11,"\u00ea":11,"\u00eb":11,"\u00e8":11,"\u00ed":11,"\u00ee":11,"\u00ef":11,"\u00ec":11,"\u00f1":11,"A":6,"\u00c6":6,"\u00c1":6,"\u00c2":6,"\u00c4":6,"\u00c0":6,"\u00c5":6,"\u00c3":6}},"V":{"d":"85,-269v-3,7,-26,2,-22,12r79,214v21,-48,67,-175,77,-200v8,-20,-4,-23,-19,-25v24,-6,50,-2,78,-1v-18,9,-26,2,-42,41r-87,207v-16,36,-15,38,-28,5r-88,-221v-8,-28,-22,-24,-42,-32v34,-4,59,-2,94,0","w":267,"k":{"y":-4,"\u00fd":-4,"\u00ff":-4,"Y":-4,"\u00dd":-4,"a":30,"\u00e6":30,"\u00e1":30,"\u00e2":30,"\u00e4":30,"\u00e0":30,"\u00e5":30,"\u00e3":30,"A":27,"\u00c6":27,"\u00c1":27,"\u00c2":27,"\u00c4":27,"\u00c0":27,"\u00c5":27,"\u00c3":27,"c":2,"g":2,"o":2,"q":2,"\u00f8":2,"\u00e7":2,"\u00f3":2,"\u00f4":2,"\u00f6":2,"\u00f2":2,"\u00f5":2,"O":2,"\u00d8":2,"\u00d3":2,"\u00d4":2,"\u00d6":2,"\u00d2":2,"\u00d5":2,",":52,".":52,")":-9,"]":-9,"}":-9,"-":7}},"W":{"d":"88,-269v-4,8,-24,-1,-22,14v4,44,46,169,55,207r77,-205v9,-26,10,-21,18,0r71,204r2,0r55,-183v8,-28,6,-29,-20,-37v31,-4,48,-2,77,0v-1,6,-8,2,-15,5v-11,4,-16,19,-23,39r-67,200v-14,39,-15,43,-26,12r-71,-200r-75,200v-13,29,-14,27,-25,-9r-64,-214v-7,-29,-20,-25,-39,-33v37,-4,53,-2,92,0","w":396,"k":{"m":10,"t":8,"y":-4,"\u00fd":-4,"\u00ff":-4,"M":9,"T":7,"Y":-4,"\u00dd":-4,"a":22,"\u00e6":22,"\u00e1":22,"\u00e2":22,"\u00e4":22,"\u00e0":22,"\u00e5":22,"\u00e3":22,"A":20,"\u00c6":20,"\u00c1":20,"\u00c2":20,"\u00c4":20,"\u00c0":20,"\u00c5":20,"\u00c3":20,",":40,".":40,")":-4,"]":-4,"}":-4,":":-5,";":-5}},"X":{"d":"185,-258v2,-10,-18,-5,-20,-11v26,-3,46,-2,74,0v-17,7,-28,12,-43,34r-58,87v27,28,60,145,113,146v-19,7,-57,4,-74,-1v2,-4,8,-3,4,-12v-19,-35,-40,-72,-62,-108v-20,37,-45,69,-61,111v-1,9,13,4,15,11v-23,3,-47,2,-75,0v18,-8,30,-8,47,-34r65,-103r-58,-97v-10,-18,-20,-31,-43,-31v-2,0,-3,-2,-3,-3v27,-4,57,-2,88,0v-2,7,-20,0,-17,10v10,38,33,62,52,98v14,-23,54,-75,56,-97","w":249,"k":{"t":11,"w":-4,"x":-4,"y":-5,"\u00fd":-5,"\u00ff":-5,"T":10,"W":-4,"X":-4,"Y":-5,"\u00dd":-5,"a":8,"\u00e6":8,"\u00e1":8,"\u00e2":8,"\u00e4":8,"\u00e0":8,"\u00e5":8,"\u00e3":8,"A":7,"\u00c6":7,"\u00c1":7,"\u00c2":7,"\u00c4":7,"\u00c0":7,"\u00c5":7,"\u00c3":7,"c":8,"g":8,"o":8,"q":8,"\u00f8":8,"\u00e7":8,"\u00f3":8,"\u00f4":8,"\u00f6":8,"\u00f2":8,"\u00f5":8,"C":7,"\u00c7":7,"O":7,"\u00d8":7,"\u00d3":7,"\u00d4":7,"\u00d6":7,"\u00d2":7,"\u00d5":7,"Q":7,"G":7}},"Y":{"d":"81,-4v36,1,23,-52,23,-88v0,-19,-3,-28,-8,-38v-19,-21,-59,-128,-104,-136v-2,0,-3,-1,-3,-3v23,-3,47,-2,75,0v-7,4,-13,11,-5,24r66,114v11,-27,60,-95,66,-124v2,-9,-9,-9,-11,-14v19,-3,46,-2,69,0v-50,7,-89,105,-109,141v-11,20,-5,41,-6,67v-1,22,-3,67,32,57v2,0,3,1,3,2v-33,8,-48,-1,-85,3v-6,1,-8,-4,-3,-5","w":235,"k":{"m":3,"t":-2,"v":-9,"w":-11,"x":-5,"M":3,"T":-2,"V":-8,"W":-10,"X":-4,"a":18,"\u00e6":18,"\u00e1":18,"\u00e2":18,"\u00e4":18,"\u00e0":18,"\u00e5":18,"\u00e3":18,"A":16,"\u00c6":16,"\u00c1":16,"\u00c2":16,"\u00c4":16,"\u00c0":16,"\u00c5":16,"\u00c3":16,"c":14,"g":14,"o":14,"q":14,"\u00f8":14,"\u00e7":14,"\u00f3":14,"\u00f4":14,"\u00f6":14,"\u00f2":14,"\u00f5":14,"C":4,"\u00c7":4,"O":7,"\u00d8":7,"\u00d3":7,"\u00d4":7,"\u00d6":7,"\u00d2":7,"\u00d5":7,",":36,".":36,"G":4,")":-13,"]":-13,"}":-13,"-":11}},"Z":{"d":"35,-214v-5,-8,3,-50,9,-60v64,11,125,-3,185,7r-163,253r98,0v55,0,55,-13,67,-43v6,13,2,58,-15,59v-60,0,-120,-2,-183,-2v-4,0,-7,0,-7,-3r163,-253v-55,3,-140,-15,-150,35v-1,5,-2,7,-4,7","w":249,"k":{"a":4,"\u00e6":4,"\u00e1":4,"\u00e2":4,"\u00e4":4,"\u00e0":4,"\u00e5":4,"\u00e3":4,"A":4,"\u00c6":4,"\u00c1":4,"\u00c2":4,"\u00c4":4,"\u00c0":4,"\u00c5":4,"\u00c3":4,"c":12,"g":12,"o":12,"q":12,"\u00f8":12,"\u00e7":12,"\u00f3":12,"\u00f4":12,"\u00f6":12,"\u00f2":12,"\u00f5":12,"O":11,"\u00d8":11,"\u00d3":11,"\u00d4":11,"\u00d6":11,"\u00d2":11,"\u00d5":11}},"[":{"d":"35,39r0,-302v0,-4,1,-5,6,-5v21,2,50,-4,66,3v-10,7,-33,3,-46,10v-5,78,0,171,-2,253v0,15,0,26,2,34v13,7,35,3,45,10v-15,8,-45,1,-65,3v-5,0,-6,-1,-6,-6","w":129,"k":{"v":-8,"w":-3,"y":-12,"\u00fd":-12,"\u00ff":-12}},"\\":{"d":"181,-7v3,8,-11,14,-15,11r-158,-259v4,-1,10,-9,15,-5","w":188},"]":{"d":"95,-262r0,302v0,4,-1,5,-6,5v-21,-2,-50,4,-66,-3v9,-7,33,-3,45,-10v6,-87,4,-198,0,-287v-13,-7,-35,-3,-45,-10v15,-8,45,-1,66,-3v5,0,6,1,6,6","w":129},"^":{"d":"82,-270r19,0r72,153r-20,0r-61,-134r-62,134r-19,0","w":183},"_":{"d":"0,27r180,0r0,18r-180,0r0,-18","w":180},"a":{"d":"30,-33r74,-191v7,-17,9,-15,15,-1v6,13,56,140,76,186v16,38,21,28,44,38v-9,5,-47,2,-69,-1v2,-3,8,-3,5,-10v-11,-23,-17,-52,-31,-72v-25,1,-55,-3,-76,2v-7,22,-20,46,-23,70v-1,10,14,5,17,11v-21,4,-44,2,-71,0v16,-7,31,-10,39,-32xm74,-99v15,4,50,3,66,0r-31,-84v-2,-5,-3,-5,-5,0","w":224},"b":{"d":"33,-1v42,-10,23,-82,23,-141v0,-48,0,-56,-1,-66v2,-18,-15,-15,-26,-20v20,-5,51,-2,79,-2v91,0,74,70,34,100v24,7,56,29,56,64v0,55,-65,78,-140,66v-8,-1,-21,4,-25,-1xm148,-171v4,-30,-31,-63,-65,-45v2,27,-3,61,2,84v34,5,67,-4,63,-39xm84,-36v-5,26,21,27,38,27v21,0,46,-8,46,-47v0,-27,-32,-77,-83,-65v-6,14,0,77,-1,85","w":221,"k":{"v":12,"w":5,"y":10,"\u00fd":10,"\u00ff":10,"a":2,"\u00e6":2,"\u00e1":2,"\u00e2":2,"\u00e4":2,"\u00e0":2,"\u00e5":2,"\u00e3":2,"b":11,"d":11,"e":11,"f":11,"h":11,"i":11,"k":11,"l":11,"n":11,"p":11,"r":11,"\u00fe":11,"\u00f0":11,"\u00e9":11,"\u00ea":11,"\u00eb":11,"\u00e8":11,"\u00ed":11,"\u00ee":11,"\u00ef":11,"\u00ec":11,"\u00f1":11}},"c":{"d":"150,-222v-80,-1,-99,41,-99,101v0,59,46,111,114,111v36,0,60,-13,64,-40v1,-5,6,-6,6,0v-2,5,-2,47,-15,48v-13,5,-36,7,-57,7v-86,0,-145,-56,-143,-123v2,-55,46,-123,132,-117v25,2,63,4,82,12v-2,18,2,42,-5,55v-6,-38,-29,-54,-79,-54","w":254,"k":{"t":2,"y":-5,"\u00fd":-5,"\u00ff":-5,"c":3,"g":3,"o":3,"q":3,"\u00f8":3,"\u00e7":3,"\u00f3":3,"\u00f4":3,"\u00f6":3,"\u00f2":3,"\u00f5":3}},"d":{"d":"141,4v-35,0,-76,1,-108,-5v6,-6,23,-1,21,-21v4,-33,2,-157,1,-186v0,-14,-8,-19,-24,-17v-3,-2,-4,-6,3,-5v106,-2,237,-16,237,112v0,39,-16,68,-34,86v-14,14,-42,36,-96,36xm108,-219v-10,0,-23,-2,-23,8r0,169v3,34,5,32,56,34v57,2,101,-38,99,-100v-2,-84,-64,-113,-132,-111","w":291,"k":{"m":2,"a":3,"\u00e6":3,"\u00e1":3,"\u00e2":3,"\u00e4":3,"\u00e0":3,"\u00e5":3,"\u00e3":3,"b":3,"d":3,"e":3,"f":3,"h":3,"i":3,"k":3,"l":3,"n":3,"p":3,"r":3,"\u00fe":3,"\u00f0":3,"\u00e9":3,"\u00ea":3,"\u00eb":3,"\u00e8":3,"\u00ed":3,"\u00ee":3,"\u00ef":3,"\u00ec":3,"\u00f1":3,"j":3}},"e":{"d":"46,-5v22,-22,9,-158,9,-203v0,-14,-8,-19,-24,-17v-3,-2,-4,-5,3,-5v43,0,92,3,131,-3v1,6,0,34,-6,41v-2,0,-2,-1,-2,-4v7,-28,-48,-19,-71,-21v-2,26,-2,65,0,89v16,-2,68,5,73,-9v4,11,0,35,-5,45v-1,0,-2,-1,-2,-3v8,-28,-48,-18,-65,-21v-6,18,2,53,-2,80v-4,32,42,26,69,22v11,-2,10,-20,18,-26v3,12,5,49,-20,42v-39,-2,-84,2,-119,-3v0,-4,9,-3,13,-4","w":198,"k":{"v":-8,"w":-10,"x":-12,"y":-8,"\u00fd":-8,"\u00ff":-8}},"f":{"d":"46,-5v22,-22,9,-158,9,-203v0,-14,-8,-19,-24,-17v-3,-2,-4,-6,3,-5r137,-3v3,1,0,50,-8,37v2,-30,-49,-18,-76,-21v-4,24,-3,66,0,90v26,-2,64,5,76,-10v3,5,-2,38,-5,46v-2,0,-2,-2,-2,-3v7,-29,-49,-19,-69,-21v-6,18,0,79,-1,93v-2,19,19,15,28,21v-32,4,-49,2,-81,0v0,-4,9,-3,13,-4","w":192,"k":{"y":-6,"\u00fd":-6,"\u00ff":-6,"a":10,"\u00e6":10,"\u00e1":10,"\u00e2":10,"\u00e4":10,"\u00e0":10,"\u00e5":10,"\u00e3":10,",":33,".":33}},"g":{"d":"164,-9v15,0,38,0,41,-15v-5,-31,16,-92,-25,-85v-1,0,-2,-1,-2,-2v26,-8,41,1,73,-3v6,-1,6,4,3,5v-33,-2,-20,50,-20,84v0,14,-1,14,-5,16v-87,39,-206,-1,-209,-106v-3,-112,122,-138,215,-109v0,4,-2,13,-2,44v1,8,-6,8,-5,1v-6,-31,-27,-40,-81,-43v-49,-2,-101,32,-97,96v5,83,51,117,114,117","w":273},"h":{"d":"107,-228v-8,6,-22,1,-22,20r1,75v43,-2,95,4,134,-2r0,-73v0,-14,-8,-19,-24,-17v-3,-2,-4,-6,3,-5v23,1,52,-3,72,2v-5,6,-21,1,-21,20v0,27,-2,152,1,186v-4,19,18,15,28,21v-31,3,-50,2,-81,0v7,-6,21,-2,21,-21r0,-98v-43,2,-95,-4,-134,2r1,96v-3,19,19,15,28,21v-32,4,-49,2,-81,0v6,-6,23,-1,21,-21v4,-33,2,-157,1,-186v0,-14,-8,-19,-24,-17v-3,-2,-4,-6,3,-5v24,1,53,-3,73,2","w":304,"k":{"b":7,"d":7,"e":7,"f":7,"h":7,"i":7,"k":7,"l":7,"n":7,"p":7,"r":7,"\u00fe":7,"\u00f0":7,"\u00e9":7,"\u00ea":7,"\u00eb":7,"\u00e8":7,"\u00ed":7,"\u00ee":7,"\u00ef":7,"\u00ec":7,"\u00f1":7,"c":5,"g":5,"o":5,"q":5,"\u00f8":5,"\u00e7":5,"\u00f3":5,"\u00f4":5,"\u00f6":5,"\u00f2":5,"\u00f5":5}},"i":{"d":"107,-228v-8,6,-22,1,-22,20r1,186v-3,19,19,15,28,21v-32,4,-49,2,-81,0v6,-6,23,-1,21,-21v3,-34,1,-158,1,-186v0,-18,-14,-14,-22,-20v17,-4,53,-3,74,0","w":140,"k":{"b":7,"d":7,"e":7,"f":7,"h":7,"i":7,"k":7,"l":7,"n":7,"p":7,"r":7,"\u00fe":7,"\u00f0":7,"\u00e9":7,"\u00ea":7,"\u00eb":7,"\u00e8":7,"\u00ed":7,"\u00ee":7,"\u00ef":7,"\u00ec":7,"\u00f1":7,"c":5,"g":5,"o":5,"q":5,"\u00f8":5,"\u00e7":5,"\u00f3":5,"\u00f4":5,"\u00f6":5,"\u00f2":5,"\u00f5":5}},"j":{"d":"107,-228v-8,6,-22,1,-22,20r0,140v2,96,-13,110,-72,145v-1,0,-3,-1,-3,-2v34,-30,46,-33,46,-128r-1,-155v0,-14,-8,-19,-24,-17v-3,-2,-4,-6,3,-5v24,1,53,-3,73,2","w":132,"k":{"c":3,"g":3,"o":3,"q":3,"\u00f8":3,"\u00e7":3,"\u00f3":3,"\u00f4":3,"\u00f6":3,"\u00f2":3,"\u00f5":3}},"k":{"d":"85,-123v13,-16,78,-73,91,-96v2,-8,-13,-6,-4,-11v19,1,43,-3,59,2v-47,11,-89,70,-122,99v35,28,97,121,152,125v2,0,4,2,4,3v-30,6,-66,2,-84,-17v-15,-11,-80,-83,-97,-100r1,96v-3,18,17,16,27,21v-29,3,-50,2,-79,0v6,-6,23,-1,21,-21v4,-33,2,-157,1,-186v0,-14,-8,-19,-24,-17v-3,-2,-4,-6,3,-5v23,1,52,-3,72,2v-6,6,-22,1,-22,20","w":239,"k":{"s":-2,"a":2,"\u00e6":2,"\u00e1":2,"\u00e2":2,"\u00e4":2,"\u00e0":2,"\u00e5":2,"\u00e3":2,"c":-1,"g":-1,"o":-1,"q":-1,"\u00f8":-1,"\u00e7":-1,"\u00f3":-1,"\u00f4":-1,"\u00f6":-1,"\u00f2":-1,"\u00f5":-1}},"l":{"d":"182,-42v2,14,9,48,-23,44v-41,-5,-88,2,-126,-3v6,-6,23,-1,21,-21v4,-33,2,-157,1,-186v0,-14,-8,-19,-24,-17v-3,-2,-4,-6,3,-5v25,1,55,-3,76,2v-9,5,-25,1,-25,20r0,121v4,75,-14,72,48,76v30,2,42,-11,49,-31","w":192,"k":{"m":2,"t":20,"v":15,"w":8,"y":12,"\u00fd":12,"\u00ff":12,"a":-3,"\u00e6":-3,"\u00e1":-3,"\u00e2":-3,"\u00e4":-3,"\u00e0":-3,"\u00e5":-3,"\u00e3":-3,"c":8,"g":8,"o":8,"q":8,"\u00f8":8,"\u00e7":8,"\u00f3":8,"\u00f4":8,"\u00f6":8,"\u00f2":8,"\u00f5":8,"u":2,"\u00fa":2,"\u00fb":2,"\u00fc":2,"\u00f9":2}},"m":{"d":"61,-14v-2,12,18,7,22,12v-19,7,-36,-1,-62,3v-5,1,-7,-5,-2,-5v16,1,20,-10,22,-26r23,-199v0,-8,7,-7,10,-1r96,190r92,-190v4,-7,8,-7,9,4r22,187v1,11,3,27,16,32v11,4,20,0,23,5v-8,7,-58,2,-69,-2v3,-3,4,-3,3,-13r-15,-155r-77,156v-11,22,-12,23,-22,2r-77,-154r-2,0","w":332,"k":{"t":6,"w":5,"y":4,"\u00fd":4,"\u00ff":4,"a":-6,"\u00e6":-6,"\u00e1":-6,"\u00e2":-6,"\u00e4":-6,"\u00e0":-6,"\u00e5":-6,"\u00e3":-6,"u":-1,"\u00fa":-1,"\u00fb":-1,"\u00fc":-1,"\u00f9":-1}},"n":{"d":"280,-228v-12,6,-23,3,-23,30r0,179v-2,41,0,21,-27,4r-164,-170r3,144v-2,40,13,32,31,40v-30,4,-44,2,-75,0v16,-9,24,0,24,-43r0,-175v-1,-25,10,-14,17,-6r175,183r-3,-153v2,-28,-8,-30,-28,-30v-2,0,-2,-2,-2,-3v17,-4,51,-3,72,0","w":299,"k":{"b":7,"d":7,"e":7,"f":7,"h":7,"i":7,"k":7,"l":7,"n":7,"p":7,"r":7,"\u00fe":7,"\u00f0":7,"\u00e9":7,"\u00ea":7,"\u00eb":7,"\u00e8":7,"\u00ed":7,"\u00ee":7,"\u00ef":7,"\u00ec":7,"\u00f1":7,"c":5,"g":5,"o":5,"q":5,"\u00f8":5,"\u00e7":5,"\u00f3":5,"\u00f4":5,"\u00f6":5,"\u00f2":5,"\u00f5":5}},"o":{"d":"20,-115v0,-49,38,-120,125,-120v71,0,126,44,126,115v0,68,-51,125,-127,125v-87,0,-124,-65,-124,-120xm53,-123v0,71,43,115,100,115v28,0,85,-14,85,-103v0,-142,-185,-152,-185,-12","w":290,"k":{"m":3,"t":9,"v":3,"w":2,"x":9,"y":3,"\u00fd":3,"\u00ff":3,"a":6,"\u00e6":6,"\u00e1":6,"\u00e2":6,"\u00e4":6,"\u00e0":6,"\u00e5":6,"\u00e3":6,"b":10,"d":10,"e":10,"f":10,"h":10,"i":10,"k":10,"l":10,"n":10,"p":10,"r":10,"\u00fe":10,"\u00f0":10,"\u00e9":10,"\u00ea":10,"\u00eb":10,"\u00e8":10,"\u00ed":10,"\u00ee":10,"\u00ef":10,"\u00ec":10,"\u00f1":10,"j":6}},"p":{"d":"54,-22v4,-33,2,-157,1,-186v0,-14,-8,-19,-24,-17v-3,-2,-4,-6,3,-5v42,-1,135,-2,142,17v44,42,-11,131,-78,106v0,-3,2,-3,8,-3v56,-2,82,-55,41,-96v-24,-24,-37,-14,-61,-12v-6,53,-1,141,-1,196v0,19,19,15,29,21v-32,3,-49,2,-81,0v6,-6,23,-1,21,-21","w":210,"k":{"s":-2,"a":15,"\u00e6":15,"\u00e1":15,"\u00e2":15,"\u00e4":15,"\u00e0":15,"\u00e5":15,"\u00e3":15,"b":5,"d":5,"e":5,"f":5,"h":5,"i":5,"k":5,"l":5,"n":5,"p":5,"r":5,"\u00fe":5,"\u00f0":5,"\u00e9":5,"\u00ea":5,"\u00eb":5,"\u00e8":5,"\u00ed":5,"\u00ee":5,"\u00ef":5,"\u00ec":5,"\u00f1":5,",":53,".":53}},"q":{"d":"481,40v-60,33,-162,34,-235,-16r-52,-28v-12,6,-33,9,-50,9v-87,0,-125,-65,-125,-120v0,-49,39,-120,126,-120v71,0,125,44,125,115v0,54,-34,90,-55,103r64,32v114,46,115,43,200,23v1,0,2,1,2,2xm52,-123v0,71,43,115,100,115v28,0,86,-15,86,-103v0,-141,-186,-152,-186,-12","w":291,"k":{"b":8,"d":8,"e":8,"f":8,"h":8,"i":8,"k":8,"l":8,"n":8,"p":8,"r":8,"\u00fe":8,"\u00f0":8,"\u00e9":8,"\u00ea":8,"\u00eb":8,"\u00e8":8,"\u00ed":8,"\u00ee":8,"\u00ef":8,"\u00ec":8,"\u00f1":8,")":-10,"]":-10,"}":-10}},"r":{"d":"153,-105v40,42,58,95,113,101v2,0,3,2,3,3v-78,22,-106,-57,-139,-94v-13,-1,-36,-4,-47,0r2,73v-3,19,18,15,29,21v-32,3,-49,2,-81,0v6,-6,23,-1,21,-21v4,-33,2,-157,1,-186v0,-14,-8,-19,-24,-17v-3,-2,-4,-6,3,-5v70,3,158,-17,158,55v0,23,-9,45,-39,70xm108,-220v-12,0,-23,-1,-25,6r0,98v3,10,21,9,37,9v29,0,43,-19,43,-52v0,-38,-21,-61,-55,-61","w":241,"k":{"s":3,"t":17,"v":8,"w":1,"x":2,"y":6,"\u00fd":6,"\u00ff":6,"a":-2,"\u00e6":-2,"\u00e1":-2,"\u00e2":-2,"\u00e4":-2,"\u00e0":-2,"\u00e5":-2,"\u00e3":-2,"c":-5,"g":-5,"o":-5,"q":-5,"\u00f8":-5,"\u00e7":-5,"\u00f3":-5,"\u00f4":-5,"\u00f6":-5,"\u00f2":-5,"\u00f5":-5}},"s":{"d":"144,-189v-11,-20,-5,-34,-49,-34v-23,0,-42,11,-42,33v-4,19,23,41,50,58v39,26,52,48,52,74v0,33,-37,69,-80,63v-18,-3,-51,3,-51,-20v0,-19,-1,-31,5,-37v2,0,3,0,3,3v-2,31,26,42,51,42v31,0,47,-18,47,-41v0,-44,-110,-83,-99,-129v-5,-53,70,-69,117,-51v0,1,-1,12,-1,33v0,5,-1,6,-3,6","w":188,"k":{"m":3,"v":1,"b":7,"d":7,"e":7,"f":7,"h":7,"i":7,"k":7,"l":7,"n":7,"p":7,"r":7,"\u00fe":7,"\u00f0":7,"\u00e9":7,"\u00ea":7,"\u00eb":7,"\u00e8":7,"\u00ed":7,"\u00ee":7,"\u00ef":7,"\u00ec":7,"\u00f1":7}},"t":{"d":"18,-235v52,9,136,6,190,2v6,7,-1,61,-5,34v4,-20,-51,-17,-78,-17r1,194v-3,18,19,15,30,21v-32,3,-52,2,-83,0v7,-6,22,-2,22,-21r1,-194r-46,0v-30,-2,-31,11,-40,23v-5,-6,5,-35,8,-42","w":219,"k":{"m":5,"s":4,"t":-4,"w":-2,"x":-6,"y":-7,"\u00fd":-7,"\u00ff":-7,"a":15,"\u00e6":15,"\u00e1":15,"\u00e2":15,"\u00e4":15,"\u00e0":15,"\u00e5":15,"\u00e3":15,"c":8,"g":8,"o":8,"q":8,"\u00f8":8,"\u00e7":8,"\u00f3":8,"\u00f4":8,"\u00f6":8,"\u00f2":8,"\u00f5":8,",":38,".":38,":":10,";":10,"-":10}},"u":{"d":"140,-8v63,0,67,-64,67,-134v0,-48,-1,-56,-1,-66v0,-18,-15,-15,-26,-20v17,-4,50,-3,71,0v-6,5,-25,2,-22,20v-4,75,15,150,-30,191v-22,21,-47,22,-66,22v-10,0,-44,-1,-66,-22v-36,-10,-26,-148,-28,-191v-1,-14,-8,-19,-24,-17v-3,-2,-4,-6,3,-5v24,1,53,-3,73,2v-5,6,-23,1,-21,20v-2,4,-1,81,-1,109v0,67,22,91,71,91","w":263,"k":{"m":5,"a":6,"\u00e6":6,"\u00e1":6,"\u00e2":6,"\u00e4":6,"\u00e0":6,"\u00e5":6,"\u00e3":6}},"v":{"d":"75,-228v-2,7,-21,0,-18,9r68,180v18,-41,60,-145,67,-167v9,-17,-5,-18,-16,-22v15,-4,49,-3,68,0v-14,8,-22,1,-36,34v-26,65,-56,142,-90,199v-4,0,-6,-4,-12,-19r-78,-187v-9,-21,-14,-23,-34,-24v-2,0,-2,-2,-2,-3v20,-4,59,-3,83,0","w":235,"k":{"y":-3,"\u00fd":-3,"\u00ff":-3,"a":24,"\u00e6":24,"\u00e1":24,"\u00e2":24,"\u00e4":24,"\u00e0":24,"\u00e5":24,"\u00e3":24,"c":2,"g":2,"o":2,"q":2,"\u00f8":2,"\u00e7":2,"\u00f3":2,"\u00f4":2,"\u00f6":2,"\u00f2":2,"\u00f5":2,",":48,".":48,")":-8,"]":-8,"}":-8,"-":6}},"w":{"d":"78,-228v-3,7,-20,-2,-19,11v5,35,40,144,48,173r67,-171v9,-22,10,-18,17,0r63,171v9,-33,43,-123,51,-172v4,-8,-14,-6,-20,-12v16,-4,47,-2,68,-1v0,6,-7,3,-14,5v-9,3,-14,15,-20,32v-14,39,-45,137,-58,171v-12,33,-14,36,-24,10r-62,-167v-11,27,-53,139,-65,167v-11,25,-14,23,-24,-8r-56,-182v-4,-26,-18,-20,-34,-27v20,-4,58,-3,82,0","w":348,"k":{"m":8,"t":6,"y":-3,"\u00fd":-3,"\u00ff":-3,"a":18,"\u00e6":18,"\u00e1":18,"\u00e2":18,"\u00e4":18,"\u00e0":18,"\u00e5":18,"\u00e3":18,",":36,".":36,")":-3,"]":-3,"}":-3,":":-5,";":-5}},"x":{"d":"162,-220v1,-8,-16,-2,-17,-8v15,-4,48,-3,66,0v-15,6,-25,9,-38,28r-51,74v22,22,53,122,96,122v3,1,3,5,-2,5v-21,-1,-47,2,-62,-3v1,-5,8,-3,4,-11r-54,-91v-17,32,-39,58,-52,94v-2,7,23,5,10,11r-61,0v-3,0,-2,-1,-2,-2v13,-8,26,-7,40,-29r57,-87r-51,-82v-7,-20,-24,-23,-40,-29v19,-4,56,-3,79,0v0,6,-16,-2,-16,8v13,30,27,52,45,82v12,-21,47,-64,49,-82","w":219,"k":{"t":9,"w":-3,"x":-3,"y":-4,"\u00fd":-4,"\u00ff":-4,"a":6,"\u00e6":6,"\u00e1":6,"\u00e2":6,"\u00e4":6,"\u00e0":6,"\u00e5":6,"\u00e3":6,"c":6,"g":6,"o":6,"q":6,"\u00f8":6,"\u00e7":6,"\u00f3":6,"\u00f4":6,"\u00f6":6,"\u00f2":6,"\u00f5":6}},"y":{"d":"72,-4v30,1,20,-44,20,-74v0,-17,-2,-23,-7,-32v-17,-17,-51,-109,-90,-115v-4,0,-6,-5,0,-5v20,1,46,-3,63,2v-8,2,-12,11,-4,20r57,95v9,-23,53,-79,57,-104v2,-7,-9,-8,-9,-12v16,-2,43,-2,62,0v-9,8,-26,7,-35,23v-20,37,-79,87,-65,154v-1,18,-2,57,27,48v2,0,3,2,3,3v-32,3,-50,2,-81,0v0,-1,0,-3,2,-3","w":207,"k":{"m":3,"t":-2,"v":-7,"w":-9,"x":-4,"a":15,"\u00e6":15,"\u00e1":15,"\u00e2":15,"\u00e4":15,"\u00e0":15,"\u00e5":15,"\u00e3":15,"c":3,"g":3,"o":3,"q":3,"\u00f8":3,"\u00e7":3,"\u00f3":3,"\u00f4":3,"\u00f6":3,"\u00f2":3,"\u00f5":3,",":33,".":33,")":-12,"]":-12,"}":-12,"-":10}},"z":{"d":"206,-49v3,13,2,50,-14,50v-53,0,-107,-1,-162,-1v-10,0,-6,-3,-1,-12r138,-205v-47,3,-121,-14,-130,29v-1,6,-6,10,-6,2v1,-6,3,-40,9,-47v56,10,111,-4,164,6r-142,214r84,0v50,2,46,-13,60,-36","w":219,"k":{"a":3,"\u00e6":3,"\u00e1":3,"\u00e2":3,"\u00e4":3,"\u00e0":3,"\u00e5":3,"\u00e3":3,"c":10,"g":10,"o":10,"q":10,"\u00f8":10,"\u00e7":10,"\u00f3":10,"\u00f4":10,"\u00f6":10,"\u00f2":10,"\u00f5":10}},"{":{"d":"73,-218v0,51,2,77,-25,92v21,15,25,36,25,83v0,69,14,74,35,86v0,1,-2,2,-7,2v-33,-10,-58,-34,-55,-107v0,-11,2,-26,2,-38v0,-20,-18,-17,-28,-23v0,-2,0,-4,4,-4v36,7,22,-41,22,-63v-2,-51,27,-78,61,-76v-12,7,-34,12,-34,48","w":129,"k":{"v":-8,"w":-3,"y":-12,"\u00fd":-12,"\u00ff":-12}},"|":{"d":"102,90r-20,0r0,-360r20,0r0,360","w":183},"}":{"d":"57,-43v0,-43,2,-70,24,-83v-25,-14,-24,-42,-24,-92v0,-36,-22,-41,-35,-48v34,-3,66,26,62,76v-2,24,-12,72,21,63v6,0,6,7,0,6v-32,-1,-23,31,-21,59v2,75,-21,96,-56,107v-5,0,-6,-1,-6,-2v20,-11,35,-16,35,-86","w":129},"~":{"d":"161,-114v-2,76,-70,26,-106,18v-10,0,-15,7,-15,24r-18,0v0,-75,72,-29,107,-19v10,0,15,-8,15,-23r17,0","w":183},"\u00a1":{"d":"58,-240v25,1,24,35,0,37v-10,0,-18,-8,-18,-18v0,-11,7,-19,18,-19xm75,11v-5,14,-20,25,-34,31v-1,-24,11,-167,12,-209v0,-5,0,-12,4,-12v15,51,4,128,18,190","w":115},"\u00a2":{"d":"115,-59v36,5,60,-5,68,-32v4,5,0,38,-8,43v-22,5,-40,6,-63,6v-3,17,-1,39,-8,52v-4,0,-12,5,-12,0r7,-55v-43,-8,-77,-40,-77,-92v0,-69,37,-85,98,-91v3,-14,-3,-47,18,-39r-4,39v12,0,32,3,49,9v7,7,3,37,-2,43v-5,-23,-12,-37,-50,-39xm101,-63r16,-152v-43,0,-68,29,-68,68v0,51,27,75,52,84"},"\u00a3":{"d":"193,-220v-7,-19,-13,-48,-47,-44v-46,-5,-56,72,-60,123v16,0,45,1,56,-2v6,23,-36,13,-58,15v-2,35,-13,74,-41,108r112,-1v23,2,29,-15,37,-33v5,7,-2,32,-4,49v-37,18,-121,-1,-182,5v-12,1,-13,-9,-3,-10v48,-10,46,-68,54,-119v-11,0,-26,-1,-35,1v-6,-17,20,-13,37,-13v-2,-78,50,-161,136,-129v6,14,3,46,-2,50"},"\u00a5":{"d":"170,-256v2,-7,-10,-9,-12,-13v18,-3,44,-2,66,0v-12,7,-30,7,-38,26v-12,15,-56,97,-69,119r58,0v7,0,1,8,1,12v-15,5,-41,0,-60,2r0,86v-4,20,24,17,36,23v-40,4,-53,2,-98,0v12,-7,41,-2,36,-23r0,-86r-58,0v-6,0,0,-9,0,-12v15,-5,40,0,58,-2v-19,-26,-63,-114,-89,-137v-8,-6,-26,-3,-16,-10v22,2,51,-4,68,3v-8,4,-16,12,-6,23v6,10,53,95,61,107v12,-25,55,-91,62,-118"},"\u00a7":{"d":"165,-229v-12,-21,-1,-35,-50,-35v-23,0,-45,12,-45,38v-1,46,114,79,114,132v0,29,-16,49,-37,61v49,47,-1,113,-59,110v-30,-2,-53,3,-57,-20v2,-19,-1,-31,5,-37v2,0,3,0,3,3v-1,31,23,42,52,42v29,0,50,-17,50,-44v0,-54,-110,-80,-110,-138v0,-28,22,-46,41,-54v-50,-38,-12,-110,49,-105v26,2,33,3,48,7v0,1,-1,12,-1,33v0,5,-1,7,-3,7xm138,-42v65,-46,-17,-92,-56,-121v-17,5,-31,21,-31,38v0,34,62,59,87,83","w":214},"\u00a4":{"d":"175,-162r-24,22v13,15,13,61,-1,75r24,22r-15,16r-22,-25v-18,18,-52,17,-70,1r-22,24r-14,-16r23,-22v-15,-16,-15,-60,0,-75r-24,-22r15,-15r22,24v17,-17,53,-18,71,-1r22,-23xm137,-103v0,-21,-13,-41,-35,-41v-21,0,-35,19,-35,42v2,56,69,58,70,-1"},"'":{"d":"36,-187v-6,-18,-13,-85,-15,-80v0,-5,6,-5,15,-5v9,0,15,0,15,5","w":72},"\u00ab":{"d":"118,-110v6,7,40,42,57,57v-4,6,-10,12,-16,16r-65,-71v10,-12,64,-63,71,-71v4,-4,8,-6,10,-1v-3,11,-43,49,-57,70xm51,-110v6,7,39,42,56,57v-6,8,-12,24,-23,8v-10,-15,-49,-49,-57,-63r77,-75v1,0,4,2,4,3v-5,10,-43,49,-57,70","w":201},"\u00b7":{"d":"45,-84v-27,-1,-26,-37,0,-39v11,0,20,7,20,19v0,12,-8,20,-20,20","w":90},"\u00b6":{"d":"134,71v8,-86,2,-218,4,-317v0,-9,-1,-14,-6,-14v-62,1,-66,133,-12,149v-48,13,-104,-25,-101,-76v4,-93,98,-84,203,-84v6,-1,8,4,3,5v-15,0,-22,7,-23,22r0,291v-2,8,-15,14,-22,11v9,-79,2,-212,4,-304v0,-8,-4,-14,-14,-14v-8,0,-14,3,-14,13r1,307v-2,9,-17,16,-23,11","w":256},"\u00bb":{"d":"83,-109v-6,-7,-39,-42,-56,-57v6,-8,13,-27,23,-9v8,9,44,48,51,55v5,5,6,7,6,9r-77,74v-10,-12,42,-49,53,-72xm150,-109v-6,-7,-39,-42,-56,-57r15,-17v17,15,53,56,66,72v-10,12,-64,62,-71,70v-4,4,-8,6,-10,1v4,-9,43,-49,56,-69","w":201},"\u00bf":{"d":"118,-140v-14,39,-65,80,-65,124v0,17,9,46,42,46v39,1,44,-28,51,-54v8,5,2,28,4,46v-6,15,-32,20,-63,20v-48,0,-65,-31,-65,-56v0,-47,61,-83,76,-132v4,-7,-17,-24,-6,-28v8,2,27,25,26,34xm95,-240v26,1,23,36,-1,37v-10,0,-18,-8,-18,-18v0,-11,8,-19,19,-19","w":175},"`":{"d":"138,-338v6,10,31,24,47,37v-12,5,-69,-19,-78,-25v7,-6,24,-8,31,-12","w":327},"\u00b4":{"d":"145,-301v17,-16,49,-32,61,-38v5,2,16,18,11,23v-25,-4,-57,17,-72,15","w":327},"\u00af":{"d":"120,-322v24,-6,60,0,88,-2v7,1,1,8,0,12v-24,6,-60,0,-88,2v-7,-1,0,-8,0,-12","w":327},"\u00a8":{"d":"200,-299v-21,-1,-20,-29,0,-31v9,0,16,6,16,15v0,9,-6,16,-16,16xm127,-299v-22,-1,-19,-30,1,-31v9,0,15,6,15,15v0,9,-6,16,-16,16","w":327},"\u00b8":{"d":"169,57v4,-12,-15,-22,-31,-29v13,-10,21,-29,46,-28v-4,2,-24,20,-27,24v22,2,36,11,36,26v0,23,-38,42,-58,33v10,-8,36,-7,34,-26","w":327},"\u00c6":{"d":"299,-47v2,13,5,56,-22,49v-42,-2,-93,4,-129,-4v10,-4,25,-3,24,-23v2,-15,2,-62,2,-95v-17,-7,-55,-4,-74,0v-10,17,-55,80,-56,103v-1,14,21,10,27,16v-40,5,-48,-1,-92,2v-4,0,-4,-1,-4,-3v24,-6,41,-18,57,-44r144,-225v35,1,84,5,115,-3v0,7,-1,39,-6,48v-2,0,-3,-2,-3,-5v9,-33,-51,-24,-77,-26v-4,34,-4,87,0,121v19,-1,74,6,80,-10v4,12,-2,37,-5,49v-2,0,-3,-1,-3,-4v6,-28,-48,-21,-71,-22v-8,15,-3,55,-3,82v0,24,7,29,42,29v30,0,49,-9,54,-35xm174,-139r0,-97v0,-2,-3,-2,-4,0v-4,13,-64,92,-57,100v20,-2,47,4,61,-3","w":328,"k":{"v":-10,"w":-12,"x":-14,"y":-10,"\u00fd":-10,"\u00ff":-10,"V":-9,"W":-11,"X":-13,"Y":-9,"\u00dd":-9}},"\u00aa":{"d":"90,-186v-10,-4,-36,-3,-47,0v-2,10,-19,32,-3,36v1,0,2,0,2,1v-11,3,-30,2,-46,0v11,-1,18,-4,24,-17r46,-106v4,-6,6,-6,10,2v12,11,34,116,71,121v-4,5,-28,1,-45,0v7,-9,-9,-25,-12,-37xm49,-199v11,-1,26,2,35,-1r-16,-40v-1,-3,-3,-3,-4,0","w":144},"\u00d8":{"d":"73,-24v-12,10,-21,27,-35,34v-2,-3,-9,-6,-8,-11r31,-34v-75,-87,-40,-241,104,-241v39,0,69,10,93,29v13,-10,25,-42,42,-25v-2,15,-22,23,-30,36v78,81,21,242,-107,242v-38,0,-68,-12,-90,-30xm250,-214r-159,170v21,23,49,36,81,36v32,0,100,-18,100,-123v0,-34,-9,-62,-22,-83xm82,-57r158,-171v-64,-71,-183,-35,-183,83v0,36,10,65,25,88","w":329,"k":{"m":4,"t":11,"v":4,"w":2,"x":10,"y":4,"\u00fd":4,"\u00ff":4,"M":4,"T":10,"V":4,"W":2,"X":9,"Y":4,"\u00dd":4,"a":8,"\u00e6":8,"\u00e1":8,"\u00e2":8,"\u00e4":8,"\u00e0":8,"\u00e5":8,"\u00e3":8,"b":12,"d":12,"e":12,"f":12,"h":12,"i":12,"k":12,"l":12,"n":12,"p":12,"r":12,"\u00fe":12,"\u00f0":12,"\u00e9":12,"\u00ea":12,"\u00eb":12,"\u00e8":12,"\u00ed":12,"\u00ee":12,"\u00ef":12,"\u00ec":12,"\u00f1":12,"A":7,"\u00c6":7,"\u00c1":7,"\u00c2":7,"\u00c4":7,"\u00c0":7,"\u00c5":7,"\u00c3":7,"B":11,"D":11,"E":11,"F":11,"H":11,"I":11,"K":11,"L":11,"N":11,"P":11,"R":11,"\u00d0":11,"\u00de":11,"\u00c9":11,"\u00ca":11,"\u00cb":11,"\u00c8":11,"\u00cd":11,"\u00ce":11,"\u00cf":11,"\u00cc":11,"\u00d1":11,"j":8,"J":7}},"\u00ba":{"d":"78,-146v-96,-2,-95,-130,1,-130v42,0,71,23,71,62v0,37,-28,68,-72,68xm83,-156v13,0,42,-7,42,-53v1,-70,-90,-81,-92,-6v0,34,23,59,50,59","w":157},"\u00e6":{"d":"133,-4v36,-5,14,-49,21,-96v-14,-7,-47,-3,-65,-1v-9,15,-47,68,-49,86v-2,13,18,7,23,14v-34,3,-50,2,-85,0v19,-4,36,-16,50,-38r127,-191v34,-2,74,2,105,-3v1,5,-2,31,-5,41v-2,0,-4,-1,-4,-4v7,-27,-47,-19,-68,-21v-4,27,-3,73,0,101v11,-1,59,4,66,-4v2,-4,5,-6,7,-2v-3,2,-2,52,-9,35v5,-23,-45,-15,-64,-16v-6,13,-2,47,-2,69v0,21,7,22,38,22v26,0,43,-7,47,-28v5,10,4,49,-19,42v-38,-2,-82,2,-116,-3v0,-1,0,-3,2,-3xm151,-115v9,-21,0,-59,3,-86v-10,3,-55,79,-54,86r51,0","w":293,"k":{"v":-8,"w":-10,"x":-12,"y":-8,"\u00fd":-8,"\u00ff":-8}},"\u00f8":{"d":"64,-20v-12,8,-23,39,-37,23v0,-13,20,-21,27,-32v-67,-75,-36,-206,91,-206v35,0,61,9,82,25v11,-9,24,-38,37,-21v-1,12,-18,20,-25,30v70,71,17,206,-95,206v-34,0,-61,-10,-80,-25xm220,-182r-138,144v18,20,42,30,70,30v29,0,86,-15,86,-103v0,-29,-6,-53,-18,-71xm73,-48r138,-145v-55,-60,-159,-29,-159,70v0,30,7,55,21,75","w":290,"k":{"m":3,"t":9,"v":3,"w":2,"x":9,"y":3,"\u00fd":3,"\u00ff":3,"a":6,"\u00e6":6,"\u00e1":6,"\u00e2":6,"\u00e4":6,"\u00e0":6,"\u00e5":6,"\u00e3":6,"b":10,"d":10,"e":10,"f":10,"h":10,"i":10,"k":10,"l":10,"n":10,"p":10,"r":10,"\u00fe":10,"\u00f0":10,"\u00e9":10,"\u00ea":10,"\u00eb":10,"\u00e8":10,"\u00ed":10,"\u00ee":10,"\u00ef":10,"\u00ec":10,"\u00f1":10,"j":6}},"\u00df":{"d":"144,-189v-11,-20,-5,-34,-49,-34v-23,0,-42,11,-42,33v-4,19,23,41,50,58v39,26,52,48,52,74v0,33,-37,69,-80,63v-18,-3,-51,3,-51,-20v0,-19,-1,-31,5,-37v2,0,3,0,3,3v-2,31,26,42,51,42v31,0,47,-18,47,-41v0,-44,-110,-83,-99,-129v-5,-53,70,-69,117,-51v0,1,-1,12,-1,33v0,5,-1,6,-3,6xm333,-189v-11,-20,-5,-34,-49,-34v-23,0,-42,11,-42,33v-4,19,23,41,50,58v39,26,52,48,52,74v0,32,-37,69,-80,63v-18,-3,-51,3,-51,-20v0,-19,0,-29,4,-37v2,0,3,0,3,3v-2,31,26,42,51,42v31,0,48,-18,48,-41v0,-44,-110,-84,-100,-129v-5,-54,71,-68,118,-51","w":377},"\u00b9":{"d":"13,-235v-6,-11,51,-34,58,-41v5,4,1,71,1,101v0,41,-3,61,31,63v-36,8,-36,-1,-83,3v-5,1,-7,-5,-2,-5v10,-1,35,-1,32,-13r0,-115v0,-3,0,-5,-4,-5v-5,1,-27,7,-33,12","w":118},"\u00ac":{"d":"167,-57r-18,0r0,-58r-133,0r0,-19r151,0r0,77","w":183},"\u00b5":{"d":"25,-54r0,-108r27,0v0,0,-11,144,49,144v22,0,47,-9,47,-54r0,-90r27,0r0,129v-2,24,17,26,23,9r6,2v-3,17,-14,27,-28,27v-14,0,-25,-7,-27,-41v-9,37,-74,59,-100,22v2,32,5,68,9,86v-12,4,-24,19,-37,16v3,-52,4,-88,4,-142","w":207},"\u03bc":{"d":"25,-54r0,-108r27,0v0,0,-11,144,49,144v22,0,47,-9,47,-54r0,-90r27,0r0,129v-2,24,17,26,23,9r6,2v-3,17,-14,27,-28,27v-14,0,-25,-7,-27,-41v-9,37,-74,59,-100,22v2,32,5,68,9,86v-12,4,-24,19,-37,16v3,-52,4,-88,4,-142","w":207},"\u00d0":{"d":"159,4v-39,0,-87,2,-121,-6v10,-4,26,-2,24,-23v3,-17,2,-72,2,-105r-32,0v-5,0,-1,-8,-1,-10v5,-7,22,-1,33,-3r-1,-101v2,-19,-15,-20,-30,-24v37,-7,45,-3,95,-3v36,0,101,-3,144,41v18,19,35,48,35,91v0,45,-19,81,-39,102v-15,16,-48,41,-109,41xm122,-259v-13,0,-27,-2,-27,10r-1,106r74,0v6,0,1,8,1,11v-18,6,-52,0,-75,2r1,80v2,41,5,40,65,42v68,2,117,-46,115,-119v-3,-98,-74,-134,-153,-132","w":330,"k":{"m":2,"M":2,"a":4,"\u00e6":4,"\u00e1":4,"\u00e2":4,"\u00e4":4,"\u00e0":4,"\u00e5":4,"\u00e3":4,"b":4,"d":4,"e":4,"f":4,"h":4,"i":4,"k":4,"l":4,"n":4,"p":4,"r":4,"\u00fe":4,"\u00f0":4,"\u00e9":4,"\u00ea":4,"\u00eb":4,"\u00e8":4,"\u00ed":4,"\u00ee":4,"\u00ef":4,"\u00ec":4,"\u00f1":4,"A":4,"\u00c6":4,"\u00c1":4,"\u00c2":4,"\u00c4":4,"\u00c0":4,"\u00c5":4,"\u00c3":4,"B":4,"D":4,"E":4,"F":4,"H":4,"I":4,"K":4,"L":4,"N":4,"P":4,"R":4,"\u00d0":4,"\u00de":4,"\u00c9":4,"\u00ca":4,"\u00cb":4,"\u00c8":4,"\u00cd":4,"\u00ce":4,"\u00cf":4,"\u00cc":4,"\u00d1":4,"j":4,"J":4}},"\u00bd":{"d":"12,-224v-4,-8,47,-32,55,-38v5,13,-2,110,2,141v-2,13,21,10,29,15v-19,4,-59,3,-83,0v5,-6,32,1,32,-15r1,-108v0,-3,0,-6,-4,-6v-6,0,-26,8,-32,11xm51,4v-5,4,-15,-3,-11,-10r194,-254v3,-5,12,3,12,7xm286,-36v5,8,-4,37,-19,36v-29,-3,-67,5,-90,-3v32,-32,83,-64,82,-108v-1,-52,-61,-48,-65,-10v0,3,-1,4,-2,4v-6,-2,-3,-18,-4,-28v23,-27,102,-8,94,28v0,41,-43,76,-76,102v8,3,39,-1,51,0v20,0,22,-11,29,-21","w":306},"\u00b1":{"d":"83,-189r18,0r0,68r67,0r0,18r-66,0r0,68r-19,0r0,-68r-68,0r0,-18r68,0r0,-68xm168,-18r0,18r-153,0r0,-18r153,0","w":183},"\u00de":{"d":"112,-203v-9,0,-18,-2,-18,9r1,169v-3,20,20,20,34,23v-34,8,-48,-1,-85,3v-6,1,-8,-4,-3,-5v15,1,20,-6,21,-21v4,-40,1,-184,1,-219v0,-19,-15,-20,-30,-24v33,-6,53,-3,94,-1v-10,7,-37,4,-33,23r0,34v70,-1,114,2,116,62v2,53,-47,96,-101,83v0,-3,2,-4,10,-4v59,-2,85,-66,42,-114v-18,-20,-41,-18,-49,-18","w":232},"\u00bc":{"d":"139,-48v7,-11,81,-95,96,-110v2,0,3,1,3,3r0,97v10,2,26,-4,29,0v-1,1,0,14,-6,13r-23,0v0,15,-6,46,19,41v1,0,3,1,3,2v-15,4,-47,4,-65,0v5,-5,26,-1,23,-14v0,-9,1,-24,1,-29v-26,-2,-60,4,-80,-3xm219,-58v-1,-22,2,-48,-1,-68v-4,4,-53,61,-59,68r60,0xm12,-224v-4,-8,47,-32,55,-38v5,13,-2,110,2,141v-2,13,21,10,29,15v-19,4,-59,3,-83,0v5,-6,32,1,32,-15r1,-108v0,-3,0,-6,-4,-6v-6,0,-26,8,-32,11xm62,4v-4,4,-14,-4,-11,-10r195,-254v3,-5,8,3,11,4v-59,89,-132,173,-195,260","w":285},"\u00f7":{"d":"111,-152v0,10,-7,19,-19,19v-10,0,-17,-8,-17,-18v0,-11,7,-18,17,-18v10,0,19,7,19,17xm168,-106r0,19r-153,0r0,-19r153,0xm92,-24v-10,0,-17,-8,-17,-18v0,-11,7,-18,17,-18v10,0,19,8,19,18v0,10,-8,18,-19,18","w":183},"\u00a6":{"d":"102,-117r-20,0r0,-126r20,0r0,126xm102,63r-20,0r0,-126r20,0r0,126","w":183},"\u00b0":{"d":"91,-214v0,22,-18,38,-38,38v-22,0,-38,-18,-38,-37v0,-21,17,-38,39,-38v23,0,37,18,37,37xm74,-214v0,-10,-7,-23,-22,-23v-29,1,-26,47,1,46v12,0,21,-10,21,-23","w":110},"\u00fe":{"d":"99,-171v-7,1,-16,-1,-15,8r1,141v-2,18,18,16,29,21v-32,4,-50,2,-81,0v7,-6,23,-2,21,-21v4,-33,2,-157,1,-186v0,-14,-8,-19,-24,-17v-3,-2,-4,-6,3,-5v26,1,57,-3,79,2v-8,7,-28,1,-28,19v0,13,-1,23,-1,29v8,-1,15,-1,27,-1v64,0,68,12,80,55v1,45,-46,78,-94,69v0,-3,2,-4,8,-4v50,-1,80,-54,40,-96v-16,-16,-39,-14,-46,-14","w":210},"\u00be":{"d":"143,-48r97,-110v2,0,3,1,3,3r0,97v10,2,26,-4,29,0v-1,1,0,14,-6,13r-23,0v1,14,-7,47,19,41v2,1,4,4,-1,4r-58,0v-3,0,-2,-1,-2,-2v4,-5,25,-1,22,-14r0,-29v-26,-2,-59,4,-80,-3xm223,-58r0,-68v-4,4,-53,61,-59,68r59,0xm30,-227v-15,-25,3,-36,37,-35v71,3,42,57,13,66v11,5,41,13,40,40v0,28,-29,53,-66,53v-17,0,-35,3,-34,-14v1,-7,-2,-30,5,-22v1,14,9,26,35,26v21,0,38,-13,38,-37v0,-27,-30,-33,-48,-39v12,-8,40,-11,41,-39v0,-7,-6,-25,-30,-25v-18,0,-31,11,-31,26xm62,4v-5,4,-15,-3,-11,-10r194,-254v3,-5,8,3,11,4v1,1,2,2,1,3","w":290},"\u00b2":{"d":"134,-148v2,9,-3,40,-20,38v-30,-3,-70,5,-95,-3v34,-33,87,-67,86,-113v-1,-54,-64,-52,-68,-11v0,5,-5,5,-5,0v0,-2,-2,-19,-2,-25v23,-29,108,-9,99,29v0,43,-45,79,-80,107v9,3,41,-1,54,0v22,1,22,-12,31,-22","w":159},"\u00ae":{"d":"37,-213v-19,0,-33,-13,-33,-31v0,-18,14,-32,33,-32v19,0,33,14,33,32v0,18,-14,31,-33,31xm37,-219v15,0,27,-11,27,-26v0,-15,-12,-26,-27,-26v-15,0,-27,11,-27,26v0,15,11,26,27,26xm19,-229v10,-3,5,-20,5,-31v1,-3,-10,-3,-1,-4v17,-4,37,6,21,21v2,5,18,15,11,15v-10,4,-11,-16,-24,-14v3,13,7,17,-12,13xm31,-246v5,4,13,1,13,-6v0,-6,-6,-11,-13,-8r0,14","w":74},"\u00f0":{"d":"141,4v-35,0,-76,1,-108,-5v6,-6,23,-1,21,-21v3,-15,2,-60,2,-88v-11,-2,-35,7,-29,-9v4,-7,20,-1,29,-3r-1,-86v0,-14,-8,-19,-24,-17v-3,-2,-4,-6,3,-5v106,-2,237,-16,237,112v0,39,-16,68,-34,86v-14,14,-42,36,-96,36xm107,-219v-12,0,-21,-2,-22,8r0,89r64,0v3,1,3,14,-4,13r-60,0r0,67v3,34,5,32,56,34v57,2,101,-37,99,-100v-2,-85,-65,-113,-133,-111","w":291,"k":{"m":2,"a":3,"\u00e6":3,"\u00e1":3,"\u00e2":3,"\u00e4":3,"\u00e0":3,"\u00e5":3,"\u00e3":3,"b":3,"d":3,"e":3,"f":3,"h":3,"i":3,"k":3,"l":3,"n":3,"p":3,"r":3,"\u00fe":3,"\u00f0":3,"\u00e9":3,"\u00ea":3,"\u00eb":3,"\u00e8":3,"\u00ed":3,"\u00ee":3,"\u00ef":3,"\u00ec":3,"\u00f1":3,"j":3}},"\u00d7":{"d":"20,-155r13,-13r58,60r59,-60r14,13r-59,60r59,60r-14,13r-58,-59r-59,59r-13,-13r58,-60","w":183},"\u00b3":{"d":"31,-239v-14,-26,3,-38,39,-37v75,2,43,60,14,70v13,2,43,15,43,42v0,30,-30,56,-70,56v-18,0,-36,2,-36,-15v0,-7,-2,-33,6,-23v1,14,9,27,37,27v22,0,39,-13,39,-39v0,-28,-31,-35,-50,-41v11,-8,41,-12,42,-41v0,-8,-6,-27,-31,-27v-20,0,-31,14,-33,28","w":148},"\u00a9":{"d":"163,6v-78,0,-141,-63,-141,-141v0,-78,63,-141,141,-141v77,0,141,63,141,141v0,78,-64,141,-141,141xm163,-10v69,0,120,-57,120,-125v0,-69,-51,-125,-120,-125v-69,0,-120,56,-120,125v0,68,51,125,120,125xm81,-138v0,-80,72,-89,142,-72v-1,2,2,51,-9,34v-4,-22,-8,-29,-50,-29v-36,0,-56,20,-56,58v0,51,32,78,66,78v36,0,32,-15,45,-29v7,2,1,38,-9,40v-72,17,-129,-16,-129,-80","w":326},"\u00c1":{"d":"34,-39r82,-223v8,-20,8,-20,16,-1v6,14,61,162,84,217v18,43,21,37,49,44v-8,7,-50,3,-75,0v2,-5,8,-3,5,-12v-13,-29,-21,-65,-37,-91v-26,2,-60,-4,-81,3v-9,28,-22,57,-27,88v-2,13,31,8,16,15v-24,-2,-58,4,-76,-3v22,-3,35,-12,44,-37xm85,-118r68,0v2,0,2,-2,2,-3r-34,-97v-2,-5,-4,-5,-6,0v-9,33,-26,69,-30,100xm107,-301v17,-16,49,-32,61,-38v5,2,15,17,12,23v-25,-4,-57,17,-73,15","w":252,"k":{"m":-8,"s":-3,"t":23,"v":26,"w":15,"x":-3,"y":17,"\u00fd":17,"\u00ff":17,"M":-9,"S":-4,"T":25,"V":29,"W":16,"X":-4,"Y":18,"\u00dd":18}},"\u00c2":{"d":"34,-39r82,-223v8,-20,8,-20,16,-1v6,14,61,162,84,217v18,43,21,37,49,44v-8,7,-50,3,-75,0v2,-5,8,-3,5,-12v-13,-29,-21,-65,-37,-91v-26,2,-60,-4,-81,3v-9,28,-22,57,-27,88v-2,13,31,8,16,15v-24,-2,-58,4,-76,-3v22,-3,35,-12,44,-37xm85,-118r68,0v2,0,2,-2,2,-3r-34,-97v-2,-5,-4,-5,-6,0v-9,33,-26,69,-30,100xm127,-342r47,35v-3,5,-8,10,-13,13v-11,-8,-27,-26,-37,-28v-15,3,-29,22,-43,28v-4,-14,38,-39,46,-48","w":252,"k":{"m":-8,"s":-3,"t":23,"v":26,"w":15,"x":-3,"y":17,"\u00fd":17,"\u00ff":17,"M":-9,"S":-4,"T":25,"V":29,"W":16,"X":-4,"Y":18,"\u00dd":18}},"\u00c4":{"d":"34,-39r82,-223v8,-20,8,-20,16,-1v6,14,61,162,84,217v18,43,21,37,49,44v-8,7,-50,3,-75,0v2,-5,8,-3,5,-12v-13,-29,-21,-65,-37,-91v-26,2,-60,-4,-81,3v-9,28,-22,57,-27,88v-2,13,31,8,16,15v-24,-2,-58,4,-76,-3v22,-3,35,-12,44,-37xm85,-118r68,0v2,0,2,-2,2,-3r-34,-97v-2,-5,-4,-5,-6,0v-9,33,-26,69,-30,100xm162,-299v-21,-1,-20,-29,0,-31v9,0,16,6,16,15v0,9,-6,16,-16,16xm90,-299v-21,-1,-20,-29,0,-31v9,0,15,6,15,15v0,9,-5,16,-15,16","w":252,"k":{"m":-8,"s":-3,"t":23,"v":26,"w":15,"x":-3,"y":17,"\u00fd":17,"\u00ff":17,"M":-9,"S":-4,"T":25,"V":29,"W":16,"X":-4,"Y":18,"\u00dd":18}},"\u00c0":{"d":"34,-39r82,-223v8,-20,8,-20,16,-1v6,14,61,162,84,217v18,43,21,37,49,44v-8,7,-50,3,-75,0v2,-5,8,-3,5,-12v-13,-29,-21,-65,-37,-91v-26,2,-60,-4,-81,3v-9,28,-22,57,-27,88v-2,13,31,8,16,15v-24,-2,-58,4,-76,-3v22,-3,35,-12,44,-37xm85,-118r68,0v2,0,2,-2,2,-3r-34,-97v-2,-5,-4,-5,-6,0v-9,33,-26,69,-30,100xm100,-338v6,10,31,25,48,37v-13,6,-69,-19,-79,-25v7,-6,24,-8,31,-12","w":252,"k":{"m":-8,"s":-3,"t":23,"v":26,"w":15,"x":-3,"y":17,"\u00fd":17,"\u00ff":17,"M":-9,"S":-4,"T":25,"V":29,"W":16,"X":-4,"Y":18,"\u00dd":18}},"\u00c5":{"d":"34,-39r82,-223v8,-20,8,-20,16,-1v6,14,61,162,84,217v18,43,21,37,49,44v-8,7,-50,3,-75,0v2,-5,8,-3,5,-12v-13,-29,-21,-65,-37,-91v-26,2,-60,-4,-81,3v-9,28,-22,57,-27,88v-2,13,31,8,16,15v-24,-2,-58,4,-76,-3v22,-3,35,-12,44,-37xm85,-118r68,0v2,0,2,-2,2,-3r-34,-97v-2,-5,-4,-5,-6,0v-9,33,-26,69,-30,100xm162,-327v0,33,-70,46,-72,11v0,-16,18,-31,43,-31v18,0,29,8,29,20xm124,-304v24,2,30,-35,3,-35v-8,0,-21,6,-21,18v0,11,9,17,18,17","w":252,"k":{"m":-8,"s":-3,"t":23,"v":26,"w":15,"x":-3,"y":17,"\u00fd":17,"\u00ff":17,"M":-9,"S":-4,"T":25,"V":29,"W":16,"X":-4,"Y":18,"\u00dd":18}},"\u00c3":{"d":"34,-39r82,-223v8,-20,8,-20,16,-1v6,14,61,162,84,217v18,43,21,37,49,44v-8,7,-50,3,-75,0v2,-5,8,-3,5,-12v-13,-29,-21,-65,-37,-91v-26,2,-60,-4,-81,3v-9,28,-22,57,-27,88v-2,13,31,8,16,15v-24,-2,-58,4,-76,-3v22,-3,35,-12,44,-37xm85,-118r68,0v2,0,2,-2,2,-3r-34,-97v-2,-5,-4,-5,-6,0v-9,33,-26,69,-30,100xm180,-330v8,8,-17,31,-28,31v-26,0,-29,-15,-53,-17v-19,-1,-19,20,-30,14v5,-12,19,-30,34,-31v15,-1,33,17,51,17v18,0,19,-11,26,-14","w":252,"k":{"m":-8,"s":-3,"t":23,"v":26,"w":15,"x":-3,"y":17,"\u00fd":17,"\u00ff":17,"M":-9,"S":-4,"T":25,"V":29,"W":16,"X":-4,"Y":18,"\u00dd":18}},"\u00c7":{"d":"171,-262v-94,0,-116,49,-116,120v0,69,53,132,130,132v41,0,73,-16,76,-49v1,-6,7,-7,6,0v-1,7,-1,55,-17,57v-16,7,-47,8,-73,8v-6,5,-17,15,-20,18v22,2,36,11,36,26v0,23,-38,42,-58,33v10,-8,36,-7,34,-26v4,-12,-15,-22,-31,-29v5,-8,18,-16,25,-23v-125,-7,-186,-144,-100,-243v33,-39,133,-44,199,-28v13,2,-3,50,2,61v0,5,-1,7,-3,7v-3,0,-3,-2,-3,-7v-2,-44,-36,-57,-87,-57","w":289,"k":{"t":2,"y":-6,"\u00fd":-6,"\u00ff":-6,"T":2,"Y":-5,"\u00dd":-5,"c":4,"g":4,"o":4,"q":4,"\u00f8":4,"\u00e7":4,"\u00f3":4,"\u00f4":4,"\u00f6":4,"\u00f2":4,"\u00f5":4,"C":4,"\u00c7":4,"O":4,"\u00d8":4,"\u00d3":4,"\u00d4":4,"\u00d6":4,"\u00d2":4,"\u00d5":4,"Q":4}},"\u00c9":{"d":"190,-48v3,15,7,54,-22,50v-42,-6,-93,4,-130,-4v10,-4,24,-2,24,-23v0,-40,1,-184,1,-219v0,-19,-15,-20,-30,-24v36,-10,107,7,149,-6v3,6,-1,39,-6,48v-2,0,-2,-2,-2,-5v7,-32,-51,-25,-78,-26v-4,29,-3,77,0,107v18,-2,75,6,80,-11v3,5,-1,44,-5,53v-2,0,-3,-1,-3,-3v10,-33,-49,-25,-71,-27v-8,20,-3,63,-3,96v0,25,7,30,42,30v31,0,50,-9,54,-36xm94,-301v18,-16,49,-33,62,-38v4,3,14,17,11,23v-25,-4,-57,17,-73,15","w":219,"k":{"v":-10,"w":-12,"x":-14,"y":-10,"\u00fd":-10,"\u00ff":-10,"V":-9,"W":-11,"X":-13,"Y":-9,"\u00dd":-9}},"\u00ca":{"d":"190,-48v3,15,7,54,-22,50v-42,-6,-93,4,-130,-4v10,-4,24,-2,24,-23v0,-40,1,-184,1,-219v0,-19,-15,-20,-30,-24v36,-10,107,7,149,-6v3,6,-1,39,-6,48v-2,0,-2,-2,-2,-5v7,-32,-51,-25,-78,-26v-4,29,-3,77,0,107v18,-2,75,6,80,-11v3,5,-1,44,-5,53v-2,0,-3,-1,-3,-3v10,-33,-49,-25,-71,-27v-8,20,-3,63,-3,96v0,25,7,30,42,30v31,0,50,-9,54,-36xm118,-342v8,7,37,25,46,35v-4,4,-7,10,-12,13v-11,-8,-28,-25,-37,-28v-15,4,-30,20,-43,28v-1,0,-3,-2,-3,-3v8,-10,38,-38,49,-45","w":219,"k":{"v":-10,"w":-12,"x":-14,"y":-10,"\u00fd":-10,"\u00ff":-10,"V":-9,"W":-11,"X":-13,"Y":-9,"\u00dd":-9}},"\u00cb":{"d":"190,-48v3,15,7,54,-22,50v-42,-6,-93,4,-130,-4v10,-4,24,-2,24,-23v0,-40,1,-184,1,-219v0,-19,-15,-20,-30,-24v36,-10,107,7,149,-6v3,6,-1,39,-6,48v-2,0,-2,-2,-2,-5v7,-32,-51,-25,-78,-26v-4,29,-3,77,0,107v18,-2,75,6,80,-11v3,5,-1,44,-5,53v-2,0,-3,-1,-3,-3v10,-33,-49,-25,-71,-27v-8,20,-3,63,-3,96v0,25,7,30,42,30v31,0,50,-9,54,-36xm153,-299v-21,-1,-20,-29,0,-31v9,0,15,6,15,15v0,9,-5,16,-15,16xm80,-299v-22,-1,-19,-30,1,-31v9,0,15,6,15,15v0,9,-6,16,-16,16","w":219,"k":{"v":-10,"w":-12,"x":-14,"y":-10,"\u00fd":-10,"\u00ff":-10,"V":-9,"W":-11,"X":-13,"Y":-9,"\u00dd":-9}},"\u00c8":{"d":"190,-48v3,15,7,54,-22,50v-42,-6,-93,4,-130,-4v10,-4,24,-2,24,-23v0,-40,1,-184,1,-219v0,-19,-15,-20,-30,-24v36,-10,107,7,149,-6v3,6,-1,39,-6,48v-2,0,-2,-2,-2,-5v7,-32,-51,-25,-78,-26v-4,29,-3,77,0,107v18,-2,75,6,80,-11v3,5,-1,44,-5,53v-2,0,-3,-1,-3,-3v10,-33,-49,-25,-71,-27v-8,20,-3,63,-3,96v0,25,7,30,42,30v31,0,50,-9,54,-36xm91,-338v6,10,30,25,47,37v-13,5,-69,-20,-79,-25v7,-6,25,-8,32,-12","w":219,"k":{"v":-10,"w":-12,"x":-14,"y":-10,"\u00fd":-10,"\u00ff":-10,"V":-9,"W":-11,"X":-13,"Y":-9,"\u00dd":-9}},"\u00cd":{"d":"95,-244r1,219v-3,20,19,20,33,23v-33,8,-48,-1,-85,3v-6,1,-8,-4,-3,-5v15,1,20,-6,21,-21v4,-40,1,-184,1,-219v0,-20,-12,-21,-26,-24v25,-8,44,1,77,-3v6,-1,8,4,3,5v-15,0,-22,5,-22,22xm60,-301v18,-15,50,-32,62,-38v4,3,14,17,11,23v-25,-4,-57,17,-73,15","w":158,"k":{"c":6,"g":6,"o":6,"q":6,"\u00f8":6,"\u00e7":6,"\u00f3":6,"\u00f4":6,"\u00f6":6,"\u00f2":6,"\u00f5":6,"C":5,"\u00c7":5,"O":9,"\u00d8":9,"\u00d3":9,"\u00d4":9,"\u00d6":9,"\u00d2":9,"\u00d5":9,"Q":9,"G":5}},"\u00ce":{"d":"95,-244r1,219v-3,20,19,20,33,23v-33,8,-48,-1,-85,3v-6,1,-8,-4,-3,-5v15,1,20,-6,21,-21v4,-40,1,-184,1,-219v0,-20,-12,-21,-26,-24v25,-8,44,1,77,-3v6,-1,8,4,3,5v-15,0,-22,5,-22,22xm80,-342r47,35v-3,5,-8,10,-13,13v-11,-8,-27,-26,-37,-28v-14,4,-29,20,-42,28v-1,0,-3,-2,-3,-3v6,-11,39,-36,48,-45","w":158,"k":{"c":6,"g":6,"o":6,"q":6,"\u00f8":6,"\u00e7":6,"\u00f3":6,"\u00f4":6,"\u00f6":6,"\u00f2":6,"\u00f5":6,"C":5,"\u00c7":5,"O":9,"\u00d8":9,"\u00d3":9,"\u00d4":9,"\u00d6":9,"\u00d2":9,"\u00d5":9,"Q":9,"G":5}},"\u00cf":{"d":"95,-244r1,219v-3,20,19,20,33,23v-33,8,-48,-1,-85,3v-6,1,-8,-4,-3,-5v15,1,20,-6,21,-21v4,-40,1,-184,1,-219v0,-20,-12,-21,-26,-24v25,-8,44,1,77,-3v6,-1,8,4,3,5v-15,0,-22,5,-22,22xm115,-299v-22,-1,-19,-30,1,-31v9,0,15,6,15,15v0,9,-6,16,-16,16xm43,-299v-21,-1,-20,-29,0,-31v9,0,16,6,16,15v0,9,-6,16,-16,16","w":158,"k":{"c":6,"g":6,"o":6,"q":6,"\u00f8":6,"\u00e7":6,"\u00f3":6,"\u00f4":6,"\u00f6":6,"\u00f2":6,"\u00f5":6,"C":5,"\u00c7":5,"O":9,"\u00d8":9,"\u00d3":9,"\u00d4":9,"\u00d6":9,"\u00d2":9,"\u00d5":9,"Q":9,"G":5}},"\u00cc":{"d":"95,-244r1,219v-3,20,19,20,33,23v-33,8,-48,-1,-85,3v-6,1,-8,-4,-3,-5v15,1,20,-6,21,-21v4,-40,1,-184,1,-219v0,-20,-12,-21,-26,-24v25,-8,44,1,77,-3v6,-1,8,4,3,5v-15,0,-22,5,-22,22xm53,-338v8,9,30,25,48,37v-12,5,-70,-19,-79,-25v7,-6,25,-7,31,-12","w":158,"k":{"c":6,"g":6,"o":6,"q":6,"\u00f8":6,"\u00e7":6,"\u00f3":6,"\u00f4":6,"\u00f6":6,"\u00f2":6,"\u00f5":6,"C":5,"\u00c7":5,"O":9,"\u00d8":9,"\u00d3":9,"\u00d4":9,"\u00d6":9,"\u00d2":9,"\u00d5":9,"Q":9,"G":5}},"\u00d1":{"d":"313,-269v-15,7,-26,5,-26,36r0,211v0,24,-1,26,-4,26v-72,-64,-147,-152,-214,-224r5,172v-1,45,11,40,35,46v-33,8,-40,-1,-79,3v-6,1,-8,-4,-3,-5v24,-1,25,-6,25,-48r1,-206v0,-14,1,-18,4,-18v24,20,174,188,213,229r-4,-183v4,-37,-16,-31,-35,-39v30,-4,50,-2,82,0xm228,-330v8,8,-18,31,-29,31v-26,0,-28,-15,-52,-17v-19,-1,-19,20,-30,14v5,-12,19,-30,34,-31v15,-1,33,17,51,17v18,0,19,-11,26,-14","w":340,"k":{"c":6,"g":6,"o":6,"q":6,"\u00f8":6,"\u00e7":6,"\u00f3":6,"\u00f4":6,"\u00f6":6,"\u00f2":6,"\u00f5":6,"C":5,"\u00c7":5,"O":9,"\u00d8":9,"\u00d3":9,"\u00d4":9,"\u00d6":9,"\u00d2":9,"\u00d5":9,"Q":9,"G":5}},"\u00d3":{"d":"23,-135v0,-58,43,-141,142,-141v81,0,141,51,141,135v0,81,-56,147,-143,147v-99,0,-140,-76,-140,-141xm57,-145v0,84,50,137,115,137v32,0,100,-18,100,-123v0,-167,-215,-181,-215,-14xm145,-301v18,-15,50,-32,62,-38v5,2,16,18,11,23v-26,-4,-57,17,-73,15","w":329,"k":{"m":4,"t":11,"v":4,"w":2,"x":10,"y":4,"\u00fd":4,"\u00ff":4,"M":4,"T":10,"V":4,"W":2,"X":9,"Y":4,"\u00dd":4,"a":8,"\u00e6":8,"\u00e1":8,"\u00e2":8,"\u00e4":8,"\u00e0":8,"\u00e5":8,"\u00e3":8,"b":12,"d":12,"e":12,"f":12,"h":12,"i":12,"k":12,"l":12,"n":12,"p":12,"r":12,"\u00fe":12,"\u00f0":12,"\u00e9":12,"\u00ea":12,"\u00eb":12,"\u00e8":12,"\u00ed":12,"\u00ee":12,"\u00ef":12,"\u00ec":12,"\u00f1":12,"A":7,"\u00c6":7,"\u00c1":7,"\u00c2":7,"\u00c4":7,"\u00c0":7,"\u00c5":7,"\u00c3":7,"B":11,"D":11,"E":11,"F":11,"H":11,"I":11,"K":11,"L":11,"N":11,"P":11,"R":11,"\u00d0":11,"\u00de":11,"\u00c9":11,"\u00ca":11,"\u00cb":11,"\u00c8":11,"\u00cd":11,"\u00ce":11,"\u00cf":11,"\u00cc":11,"\u00d1":11,"j":8,"J":7}},"\u00d4":{"d":"23,-135v0,-58,43,-141,142,-141v81,0,141,51,141,135v0,81,-56,147,-143,147v-99,0,-140,-76,-140,-141xm57,-145v0,84,50,137,115,137v32,0,100,-18,100,-123v0,-167,-215,-181,-215,-14xm166,-342v8,7,37,25,46,35v-4,4,-7,11,-13,13v-9,-9,-28,-25,-36,-28v-15,4,-30,20,-43,28v-1,0,-3,-2,-3,-3v8,-10,38,-38,49,-45","w":329,"k":{"m":4,"t":11,"v":4,"w":2,"x":10,"y":4,"\u00fd":4,"\u00ff":4,"M":4,"T":10,"V":4,"W":2,"X":9,"Y":4,"\u00dd":4,"a":8,"\u00e6":8,"\u00e1":8,"\u00e2":8,"\u00e4":8,"\u00e0":8,"\u00e5":8,"\u00e3":8,"b":12,"d":12,"e":12,"f":12,"h":12,"i":12,"k":12,"l":12,"n":12,"p":12,"r":12,"\u00fe":12,"\u00f0":12,"\u00e9":12,"\u00ea":12,"\u00eb":12,"\u00e8":12,"\u00ed":12,"\u00ee":12,"\u00ef":12,"\u00ec":12,"\u00f1":12,"A":7,"\u00c6":7,"\u00c1":7,"\u00c2":7,"\u00c4":7,"\u00c0":7,"\u00c5":7,"\u00c3":7,"B":11,"D":11,"E":11,"F":11,"H":11,"I":11,"K":11,"L":11,"N":11,"P":11,"R":11,"\u00d0":11,"\u00de":11,"\u00c9":11,"\u00ca":11,"\u00cb":11,"\u00c8":11,"\u00cd":11,"\u00ce":11,"\u00cf":11,"\u00cc":11,"\u00d1":11,"j":8,"J":7}},"\u00d6":{"d":"23,-135v0,-58,43,-141,142,-141v81,0,141,51,141,135v0,81,-56,147,-143,147v-99,0,-140,-76,-140,-141xm57,-145v0,84,50,137,115,137v32,0,100,-18,100,-123v0,-167,-215,-181,-215,-14xm201,-299v-22,-1,-21,-29,0,-31v9,0,15,6,15,15v0,9,-5,16,-15,16xm128,-299v-22,-1,-19,-30,1,-31v9,0,15,6,15,15v0,9,-6,16,-16,16","w":329,"k":{"m":4,"t":11,"v":4,"w":2,"x":10,"y":4,"\u00fd":4,"\u00ff":4,"M":4,"T":10,"V":4,"W":2,"X":9,"Y":4,"\u00dd":4,"a":8,"\u00e6":8,"\u00e1":8,"\u00e2":8,"\u00e4":8,"\u00e0":8,"\u00e5":8,"\u00e3":8,"b":12,"d":12,"e":12,"f":12,"h":12,"i":12,"k":12,"l":12,"n":12,"p":12,"r":12,"\u00fe":12,"\u00f0":12,"\u00e9":12,"\u00ea":12,"\u00eb":12,"\u00e8":12,"\u00ed":12,"\u00ee":12,"\u00ef":12,"\u00ec":12,"\u00f1":12,"A":7,"\u00c6":7,"\u00c1":7,"\u00c2":7,"\u00c4":7,"\u00c0":7,"\u00c5":7,"\u00c3":7,"B":11,"D":11,"E":11,"F":11,"H":11,"I":11,"K":11,"L":11,"N":11,"P":11,"R":11,"\u00d0":11,"\u00de":11,"\u00c9":11,"\u00ca":11,"\u00cb":11,"\u00c8":11,"\u00cd":11,"\u00ce":11,"\u00cf":11,"\u00cc":11,"\u00d1":11,"j":8,"J":7}},"\u00d2":{"d":"23,-135v0,-58,43,-141,142,-141v81,0,141,51,141,135v0,81,-56,147,-143,147v-99,0,-140,-76,-140,-141xm57,-145v0,84,50,137,115,137v32,0,100,-18,100,-123v0,-167,-215,-181,-215,-14xm139,-338v6,10,30,25,47,37v-13,5,-69,-20,-79,-25v7,-6,25,-8,32,-12","w":329,"k":{"m":4,"t":11,"v":4,"w":2,"x":10,"y":4,"\u00fd":4,"\u00ff":4,"M":4,"T":10,"V":4,"W":2,"X":9,"Y":4,"\u00dd":4,"a":8,"\u00e6":8,"\u00e1":8,"\u00e2":8,"\u00e4":8,"\u00e0":8,"\u00e5":8,"\u00e3":8,"b":12,"d":12,"e":12,"f":12,"h":12,"i":12,"k":12,"l":12,"n":12,"p":12,"r":12,"\u00fe":12,"\u00f0":12,"\u00e9":12,"\u00ea":12,"\u00eb":12,"\u00e8":12,"\u00ed":12,"\u00ee":12,"\u00ef":12,"\u00ec":12,"\u00f1":12,"A":7,"\u00c6":7,"\u00c1":7,"\u00c2":7,"\u00c4":7,"\u00c0":7,"\u00c5":7,"\u00c3":7,"B":11,"D":11,"E":11,"F":11,"H":11,"I":11,"K":11,"L":11,"N":11,"P":11,"R":11,"\u00d0":11,"\u00de":11,"\u00c9":11,"\u00ca":11,"\u00cb":11,"\u00c8":11,"\u00cd":11,"\u00ce":11,"\u00cf":11,"\u00cc":11,"\u00d1":11,"j":8,"J":7}},"\u00d5":{"d":"23,-135v0,-58,43,-141,142,-141v81,0,141,51,141,135v0,81,-56,147,-143,147v-99,0,-140,-76,-140,-141xm57,-145v0,84,50,137,115,137v32,0,100,-18,100,-123v0,-167,-215,-181,-215,-14xm219,-330v7,10,-18,29,-29,31v-26,-1,-29,-16,-53,-17v-18,-1,-19,19,-29,14v5,-12,18,-30,33,-31v15,-1,34,17,52,17v18,0,19,-11,26,-14","w":329,"k":{"m":4,"t":11,"v":4,"w":2,"x":10,"y":4,"\u00fd":4,"\u00ff":4,"M":4,"T":10,"V":4,"W":2,"X":9,"Y":4,"\u00dd":4,"a":8,"\u00e6":8,"\u00e1":8,"\u00e2":8,"\u00e4":8,"\u00e0":8,"\u00e5":8,"\u00e3":8,"b":12,"d":12,"e":12,"f":12,"h":12,"i":12,"k":12,"l":12,"n":12,"p":12,"r":12,"\u00fe":12,"\u00f0":12,"\u00e9":12,"\u00ea":12,"\u00eb":12,"\u00e8":12,"\u00ed":12,"\u00ee":12,"\u00ef":12,"\u00ec":12,"\u00f1":12,"A":7,"\u00c6":7,"\u00c1":7,"\u00c2":7,"\u00c4":7,"\u00c0":7,"\u00c5":7,"\u00c3":7,"B":11,"D":11,"E":11,"F":11,"H":11,"I":11,"K":11,"L":11,"N":11,"P":11,"R":11,"\u00d0":11,"\u00de":11,"\u00c9":11,"\u00ca":11,"\u00cb":11,"\u00c8":11,"\u00cd":11,"\u00ce":11,"\u00cf":11,"\u00cc":11,"\u00d1":11,"j":8,"J":7}},"\u00da":{"d":"156,-8v73,0,77,-77,77,-159r0,-77v0,-19,-16,-20,-31,-24v27,-8,43,1,74,-3v6,-1,8,4,3,5v-15,0,-22,5,-22,22v0,86,17,174,-34,223v-25,24,-53,27,-74,27v-12,0,-48,-1,-74,-25v-43,-13,-33,-174,-33,-225v0,-19,-15,-20,-30,-24v29,-8,48,1,83,-3v6,-1,6,4,3,5v-15,0,-23,5,-23,22r0,128v0,78,25,108,81,108xm137,-301v18,-15,50,-32,62,-38v4,3,14,17,11,23v-25,-4,-57,17,-73,15","w":298,"k":{"m":6,"M":6,"a":7,"\u00e6":7,"\u00e1":7,"\u00e2":7,"\u00e4":7,"\u00e0":7,"\u00e5":7,"\u00e3":7,"b":11,"d":11,"e":11,"f":11,"h":11,"i":11,"k":11,"l":11,"n":11,"p":11,"r":11,"\u00fe":11,"\u00f0":11,"\u00e9":11,"\u00ea":11,"\u00eb":11,"\u00e8":11,"\u00ed":11,"\u00ee":11,"\u00ef":11,"\u00ec":11,"\u00f1":11,"A":6,"\u00c6":6,"\u00c1":6,"\u00c2":6,"\u00c4":6,"\u00c0":6,"\u00c5":6,"\u00c3":6}},"\u00db":{"d":"156,-8v73,0,77,-77,77,-159r0,-77v0,-19,-16,-20,-31,-24v27,-8,43,1,74,-3v6,-1,8,4,3,5v-15,0,-22,5,-22,22v0,86,17,174,-34,223v-25,24,-53,27,-74,27v-12,0,-48,-1,-74,-25v-43,-13,-33,-174,-33,-225v0,-19,-15,-20,-30,-24v29,-8,48,1,83,-3v6,-1,6,4,3,5v-15,0,-23,5,-23,22r0,128v0,78,25,108,81,108xm156,-342v8,7,37,25,46,35v-4,4,-7,11,-13,13v-11,-8,-27,-25,-36,-28v-15,4,-30,20,-43,28v-1,0,-3,-2,-3,-3v7,-11,39,-37,49,-45","w":298,"k":{"m":6,"M":6,"a":7,"\u00e6":7,"\u00e1":7,"\u00e2":7,"\u00e4":7,"\u00e0":7,"\u00e5":7,"\u00e3":7,"b":11,"d":11,"e":11,"f":11,"h":11,"i":11,"k":11,"l":11,"n":11,"p":11,"r":11,"\u00fe":11,"\u00f0":11,"\u00e9":11,"\u00ea":11,"\u00eb":11,"\u00e8":11,"\u00ed":11,"\u00ee":11,"\u00ef":11,"\u00ec":11,"\u00f1":11,"A":6,"\u00c6":6,"\u00c1":6,"\u00c2":6,"\u00c4":6,"\u00c0":6,"\u00c5":6,"\u00c3":6}},"\u00dc":{"d":"156,-8v73,0,77,-77,77,-159r0,-77v0,-19,-16,-20,-31,-24v27,-8,43,1,74,-3v6,-1,8,4,3,5v-15,0,-22,5,-22,22v0,86,17,174,-34,223v-25,24,-53,27,-74,27v-12,0,-48,-1,-74,-25v-43,-13,-33,-174,-33,-225v0,-19,-15,-20,-30,-24v29,-8,48,1,83,-3v6,-1,6,4,3,5v-15,0,-23,5,-23,22r0,128v0,78,25,108,81,108xm192,-299v-22,-1,-19,-30,1,-31v9,0,15,6,15,15v0,9,-6,16,-16,16xm120,-299v-21,-1,-20,-29,0,-31v9,0,16,6,16,15v0,9,-6,16,-16,16","w":298,"k":{"m":6,"M":6,"a":7,"\u00e6":7,"\u00e1":7,"\u00e2":7,"\u00e4":7,"\u00e0":7,"\u00e5":7,"\u00e3":7,"b":11,"d":11,"e":11,"f":11,"h":11,"i":11,"k":11,"l":11,"n":11,"p":11,"r":11,"\u00fe":11,"\u00f0":11,"\u00e9":11,"\u00ea":11,"\u00eb":11,"\u00e8":11,"\u00ed":11,"\u00ee":11,"\u00ef":11,"\u00ec":11,"\u00f1":11,"A":6,"\u00c6":6,"\u00c1":6,"\u00c2":6,"\u00c4":6,"\u00c0":6,"\u00c5":6,"\u00c3":6}},"\u00d9":{"d":"156,-8v73,0,77,-77,77,-159r0,-77v0,-19,-16,-20,-31,-24v27,-8,43,1,74,-3v6,-1,8,4,3,5v-15,0,-22,5,-22,22v0,86,17,174,-34,223v-25,24,-53,27,-74,27v-12,0,-48,-1,-74,-25v-43,-13,-33,-174,-33,-225v0,-19,-15,-20,-30,-24v29,-8,48,1,83,-3v6,-1,6,4,3,5v-15,0,-23,5,-23,22r0,128v0,78,25,108,81,108xm125,-338v6,10,31,24,47,37v-12,5,-69,-19,-78,-25v7,-6,24,-8,31,-12","w":298,"k":{"m":6,"M":6,"a":7,"\u00e6":7,"\u00e1":7,"\u00e2":7,"\u00e4":7,"\u00e0":7,"\u00e5":7,"\u00e3":7,"b":11,"d":11,"e":11,"f":11,"h":11,"i":11,"k":11,"l":11,"n":11,"p":11,"r":11,"\u00fe":11,"\u00f0":11,"\u00e9":11,"\u00ea":11,"\u00eb":11,"\u00e8":11,"\u00ed":11,"\u00ee":11,"\u00ef":11,"\u00ec":11,"\u00f1":11,"A":6,"\u00c6":6,"\u00c1":6,"\u00c2":6,"\u00c4":6,"\u00c0":6,"\u00c5":6,"\u00c3":6}},"\u00dd":{"d":"81,-4v36,1,23,-52,23,-88v0,-19,-3,-28,-8,-38v-19,-21,-59,-128,-104,-136v-2,0,-3,-1,-3,-3v23,-3,47,-2,75,0v-7,4,-13,11,-5,24r66,114v11,-27,60,-95,66,-124v2,-9,-9,-9,-11,-14v19,-3,46,-2,69,0v-50,7,-89,105,-109,141v-11,20,-5,41,-6,67v-1,22,-3,67,32,57v2,0,3,1,3,2v-33,8,-48,-1,-85,3v-6,1,-8,-4,-3,-5xm109,-301v18,-15,50,-32,62,-38v4,3,14,17,11,23v-25,-4,-57,17,-73,15","w":235,"k":{"m":3,"t":-2,"v":-9,"w":-11,"x":-5,"M":3,"T":-2,"V":-8,"W":-10,"X":-4,"a":18,"\u00e6":18,"\u00e1":18,"\u00e2":18,"\u00e4":18,"\u00e0":18,"\u00e5":18,"\u00e3":18,"A":16,"\u00c6":16,"\u00c1":16,"\u00c2":16,"\u00c4":16,"\u00c0":16,"\u00c5":16,"\u00c3":16,"c":14,"g":14,"o":14,"q":14,"\u00f8":14,"\u00e7":14,"\u00f3":14,"\u00f4":14,"\u00f6":14,"\u00f2":14,"\u00f5":14,"C":4,"\u00c7":4,"O":7,"\u00d8":7,"\u00d3":7,"\u00d4":7,"\u00d6":7,"\u00d2":7,"\u00d5":7,",":36,".":36,"G":4,")":-13,"]":-13,"}":-13,"-":11}},"\u00e1":{"d":"30,-33r74,-191v7,-17,9,-15,15,-1v6,13,56,140,76,186v16,38,21,28,44,38v-9,5,-47,2,-69,-1v2,-3,8,-3,5,-10v-11,-23,-17,-52,-31,-72v-25,1,-55,-3,-76,2v-7,22,-20,46,-23,70v-1,10,14,5,17,11v-21,4,-44,2,-71,0v16,-7,31,-10,39,-32xm74,-99v15,4,50,3,66,0r-31,-84v-2,-5,-3,-5,-5,0xm93,-260r62,-38v3,7,15,17,11,24v-24,-1,-55,10,-71,17v-1,0,-2,-2,-2,-3","w":224},"\u00e2":{"d":"30,-33r74,-191v7,-17,9,-15,15,-1v6,13,56,140,76,186v16,38,21,28,44,38v-9,5,-47,2,-69,-1v2,-3,8,-3,5,-10v-11,-23,-17,-52,-31,-72v-25,1,-55,-3,-76,2v-7,22,-20,46,-23,70v-1,10,14,5,17,11v-21,4,-44,2,-71,0v16,-7,31,-10,39,-32xm74,-99v15,4,50,3,66,0r-31,-84v-2,-5,-3,-5,-5,0xm113,-301r47,35v-3,5,-8,10,-13,13r-36,-28v-15,3,-28,22,-43,28v-1,0,-3,-2,-3,-3v6,-11,39,-36,48,-45","w":224},"\u00e4":{"d":"30,-33r74,-191v7,-17,9,-15,15,-1v6,13,56,140,76,186v16,38,21,28,44,38v-9,5,-47,2,-69,-1v2,-3,8,-3,5,-10v-11,-23,-17,-52,-31,-72v-25,1,-55,-3,-76,2v-7,22,-20,46,-23,70v-1,10,14,5,17,11v-21,4,-44,2,-71,0v16,-7,31,-10,39,-32xm74,-99v15,4,50,3,66,0r-31,-84v-2,-5,-3,-5,-5,0xm148,-257v-21,-2,-20,-30,1,-31v9,0,15,5,15,14v0,9,-6,17,-16,17xm76,-257v-20,-1,-21,-30,0,-31v9,0,16,5,16,14v0,9,-6,17,-16,17","w":224},"\u00e0":{"d":"30,-33r74,-191v7,-17,9,-15,15,-1v6,13,56,140,76,186v16,38,21,28,44,38v-9,5,-47,2,-69,-1v2,-3,8,-3,5,-10v-11,-23,-17,-52,-31,-72v-25,1,-55,-3,-76,2v-7,22,-20,46,-23,70v-1,10,14,5,17,11v-21,4,-44,2,-71,0v16,-7,31,-10,39,-32xm74,-99v15,4,50,3,66,0r-31,-84v-2,-5,-3,-5,-5,0xm86,-296v9,8,30,26,48,37v-13,5,-69,-21,-79,-26v7,-7,25,-6,31,-11","w":224},"\u00e5":{"d":"30,-33r74,-191v7,-17,9,-15,15,-1v6,13,56,140,76,186v16,38,21,28,44,38v-9,5,-47,2,-69,-1v2,-3,8,-3,5,-10v-11,-23,-17,-52,-31,-72v-25,1,-55,-3,-76,2v-7,22,-20,46,-23,70v-1,10,14,5,17,11v-21,4,-44,2,-71,0v16,-7,31,-10,39,-32xm74,-99v15,4,50,3,66,0r-31,-84v-2,-5,-3,-5,-5,0xm149,-285v0,33,-71,44,-72,10v0,-16,17,-31,42,-31v18,0,30,9,30,21xm111,-262v24,1,31,-36,2,-35v-8,0,-20,5,-20,17v0,11,9,18,18,18","w":224},"\u00e3":{"d":"30,-33r74,-191v7,-17,9,-15,15,-1v6,13,56,140,76,186v16,38,21,28,44,38v-9,5,-47,2,-69,-1v2,-3,8,-3,5,-10v-11,-23,-17,-52,-31,-72v-25,1,-55,-3,-76,2v-7,22,-20,46,-23,70v-1,10,14,5,17,11v-21,4,-44,2,-71,0v16,-7,31,-10,39,-32xm74,-99v15,4,50,3,66,0r-31,-84v-2,-5,-3,-5,-5,0xm167,-289v7,11,-18,30,-29,32v-26,-2,-29,-16,-53,-18v-18,-1,-19,19,-29,14v4,-12,19,-30,33,-31v15,-1,33,17,51,17v19,0,20,-10,27,-14","w":224},"\u00e7":{"d":"150,-222v-80,-1,-99,41,-99,101v0,59,46,111,114,111v36,0,60,-13,64,-40v1,-5,6,-6,6,0v-2,5,-2,47,-15,48v-16,6,-45,7,-70,7v-7,6,-18,16,-21,19v22,2,36,11,36,26v0,23,-38,42,-58,33v10,-8,36,-7,34,-26v4,-12,-15,-23,-32,-29v7,-8,20,-17,28,-24v-68,-2,-120,-63,-117,-122v3,-55,46,-123,132,-117v25,2,63,4,82,12v-2,18,2,42,-5,55v-6,-38,-29,-54,-79,-54","w":254,"k":{"t":2,"y":-5,"\u00fd":-5,"\u00ff":-5,"c":3,"g":3,"o":3,"q":3,"\u00f8":3,"\u00e7":3,"\u00f3":3,"\u00f4":3,"\u00f6":3,"\u00f2":3,"\u00f5":3}},"\u00e9":{"d":"46,-5v22,-22,9,-158,9,-203v0,-14,-8,-19,-24,-17v-3,-2,-4,-5,3,-5v43,0,92,3,131,-3v1,6,0,34,-6,41v-2,0,-2,-1,-2,-4v7,-28,-48,-19,-71,-21v-2,26,-2,65,0,89v16,-2,68,5,73,-9v4,11,0,35,-5,45v-1,0,-2,-1,-2,-3v8,-28,-48,-18,-65,-21v-6,18,2,53,-2,80v-4,32,42,26,69,22v11,-2,10,-20,18,-26v3,12,5,49,-20,42v-39,-2,-84,2,-119,-3v0,-4,9,-3,13,-4xm80,-260v19,-14,48,-33,61,-38v4,4,15,17,12,24v-24,-1,-55,10,-71,17v-1,0,-2,-2,-2,-3","w":198,"k":{"v":-8,"w":-10,"x":-12,"y":-8,"\u00fd":-8,"\u00ff":-8}},"\u00ea":{"d":"46,-5v22,-22,9,-158,9,-203v0,-14,-8,-19,-24,-17v-3,-2,-4,-5,3,-5v43,0,92,3,131,-3v1,6,0,34,-6,41v-2,0,-2,-1,-2,-4v7,-28,-48,-19,-71,-21v-2,26,-2,65,0,89v16,-2,68,5,73,-9v4,11,0,35,-5,45v-1,0,-2,-1,-2,-3v8,-28,-48,-18,-65,-21v-6,18,2,53,-2,80v-4,32,42,26,69,22v11,-2,10,-20,18,-26v3,12,5,49,-20,42v-39,-2,-84,2,-119,-3v0,-4,9,-3,13,-4xm104,-301v8,7,37,25,46,35v-4,4,-7,10,-12,13v-10,-9,-29,-23,-37,-28v-15,3,-28,22,-43,28v-1,0,-3,-2,-3,-3v8,-10,38,-38,49,-45","w":198,"k":{"v":-8,"w":-10,"x":-12,"y":-8,"\u00fd":-8,"\u00ff":-8}},"\u00eb":{"d":"46,-5v22,-22,9,-158,9,-203v0,-14,-8,-19,-24,-17v-3,-2,-4,-5,3,-5v43,0,92,3,131,-3v1,6,0,34,-6,41v-2,0,-2,-1,-2,-4v7,-28,-48,-19,-71,-21v-2,26,-2,65,0,89v16,-2,68,5,73,-9v4,11,0,35,-5,45v-1,0,-2,-1,-2,-3v8,-28,-48,-18,-65,-21v-6,18,2,53,-2,80v-4,32,42,26,69,22v11,-2,10,-20,18,-26v3,12,5,49,-20,42v-39,-2,-84,2,-119,-3v0,-4,9,-3,13,-4xm135,-257v-20,-1,-21,-30,0,-31v9,0,16,5,16,14v0,9,-6,17,-16,17xm63,-257v-20,-1,-21,-30,0,-31v9,0,15,5,15,14v0,9,-5,17,-15,17","w":198,"k":{"v":-8,"w":-10,"x":-12,"y":-8,"\u00fd":-8,"\u00ff":-8}},"\u00e8":{"d":"46,-5v22,-22,9,-158,9,-203v0,-14,-8,-19,-24,-17v-3,-2,-4,-5,3,-5v43,0,92,3,131,-3v1,6,0,34,-6,41v-2,0,-2,-1,-2,-4v7,-28,-48,-19,-71,-21v-2,26,-2,65,0,89v16,-2,68,5,73,-9v4,11,0,35,-5,45v-1,0,-2,-1,-2,-3v8,-28,-48,-18,-65,-21v-6,18,2,53,-2,80v-4,32,42,26,69,22v11,-2,10,-20,18,-26v3,12,5,49,-20,42v-39,-2,-84,2,-119,-3v0,-4,9,-3,13,-4xm80,-296v9,8,30,26,48,37v-12,5,-69,-20,-79,-26v7,-7,25,-6,31,-11","w":198,"k":{"v":-8,"w":-10,"x":-12,"y":-8,"\u00fd":-8,"\u00ff":-8}},"\u00ed":{"d":"107,-228v-8,6,-22,1,-22,20r1,186v-3,19,19,15,28,21v-32,4,-49,2,-81,0v6,-6,23,-1,21,-21v3,-34,1,-158,1,-186v0,-18,-14,-14,-22,-20v17,-4,53,-3,74,0xm51,-260v19,-14,48,-33,61,-38v4,4,17,18,11,24v-24,-1,-54,11,-70,17v-1,0,-2,-2,-2,-3","w":140,"k":{"b":7,"d":7,"e":7,"f":7,"h":7,"i":7,"k":7,"l":7,"n":7,"p":7,"r":7,"\u00fe":7,"\u00f0":7,"\u00e9":7,"\u00ea":7,"\u00eb":7,"\u00e8":7,"\u00ed":7,"\u00ee":7,"\u00ef":7,"\u00ec":7,"\u00f1":7,"c":5,"g":5,"o":5,"q":5,"\u00f8":5,"\u00e7":5,"\u00f3":5,"\u00f4":5,"\u00f6":5,"\u00f2":5,"\u00f5":5}},"\u00ee":{"d":"107,-228v-8,6,-22,1,-22,20r1,186v-3,19,19,15,28,21v-32,4,-49,2,-81,0v6,-6,23,-1,21,-21v3,-34,1,-158,1,-186v0,-18,-14,-14,-22,-20v17,-4,53,-3,74,0xm71,-301v9,10,66,33,34,48v-11,-9,-27,-24,-37,-28v-15,3,-27,23,-43,28v-4,-14,38,-39,46,-48","w":140,"k":{"b":7,"d":7,"e":7,"f":7,"h":7,"i":7,"k":7,"l":7,"n":7,"p":7,"r":7,"\u00fe":7,"\u00f0":7,"\u00e9":7,"\u00ea":7,"\u00eb":7,"\u00e8":7,"\u00ed":7,"\u00ee":7,"\u00ef":7,"\u00ec":7,"\u00f1":7,"c":5,"g":5,"o":5,"q":5,"\u00f8":5,"\u00e7":5,"\u00f3":5,"\u00f4":5,"\u00f6":5,"\u00f2":5,"\u00f5":5}},"\u00ef":{"d":"107,-228v-8,6,-22,1,-22,20r1,186v-3,19,19,15,28,21v-32,4,-49,2,-81,0v6,-6,23,-1,21,-21v3,-34,1,-158,1,-186v0,-18,-14,-14,-22,-20v17,-4,53,-3,74,0xm106,-257v-20,-1,-21,-30,0,-31v9,0,16,5,16,14v0,9,-6,17,-16,17xm33,-257v-21,-2,-20,-30,1,-31v9,0,15,5,15,14v0,9,-6,17,-16,17","w":140,"k":{"b":7,"d":7,"e":7,"f":7,"h":7,"i":7,"k":7,"l":7,"n":7,"p":7,"r":7,"\u00fe":7,"\u00f0":7,"\u00e9":7,"\u00ea":7,"\u00eb":7,"\u00e8":7,"\u00ed":7,"\u00ee":7,"\u00ef":7,"\u00ec":7,"\u00f1":7,"c":5,"g":5,"o":5,"q":5,"\u00f8":5,"\u00e7":5,"\u00f3":5,"\u00f4":5,"\u00f6":5,"\u00f2":5,"\u00f5":5}},"\u00ec":{"d":"107,-228v-8,6,-22,1,-22,20r1,186v-3,19,19,15,28,21v-32,4,-49,2,-81,0v6,-6,23,-1,21,-21v3,-34,1,-158,1,-186v0,-18,-14,-14,-22,-20v17,-4,53,-3,74,0xm44,-296v7,9,31,25,47,37v-12,5,-68,-20,-78,-26v7,-6,24,-7,31,-11","w":140,"k":{"b":7,"d":7,"e":7,"f":7,"h":7,"i":7,"k":7,"l":7,"n":7,"p":7,"r":7,"\u00fe":7,"\u00f0":7,"\u00e9":7,"\u00ea":7,"\u00eb":7,"\u00e8":7,"\u00ed":7,"\u00ee":7,"\u00ef":7,"\u00ec":7,"\u00f1":7,"c":5,"g":5,"o":5,"q":5,"\u00f8":5,"\u00e7":5,"\u00f3":5,"\u00f4":5,"\u00f6":5,"\u00f2":5,"\u00f5":5}},"\u00f1":{"d":"280,-228v-12,6,-23,3,-23,30r0,179v-2,41,0,21,-27,4r-164,-170r3,144v-2,40,13,32,31,40v-30,4,-44,2,-75,0v16,-9,24,0,24,-43r0,-175v-1,-25,10,-14,17,-6r175,183r-3,-153v2,-28,-8,-30,-28,-30v-2,0,-2,-2,-2,-3v17,-4,51,-3,72,0xm204,-289v9,9,-18,30,-29,32v-25,-2,-28,-17,-53,-18v-18,-1,-19,19,-29,14v6,-11,20,-30,34,-31v15,-1,33,17,51,17v18,0,20,-9,26,-14","w":299,"k":{"b":7,"d":7,"e":7,"f":7,"h":7,"i":7,"k":7,"l":7,"n":7,"p":7,"r":7,"\u00fe":7,"\u00f0":7,"\u00e9":7,"\u00ea":7,"\u00eb":7,"\u00e8":7,"\u00ed":7,"\u00ee":7,"\u00ef":7,"\u00ec":7,"\u00f1":7,"c":5,"g":5,"o":5,"q":5,"\u00f8":5,"\u00e7":5,"\u00f3":5,"\u00f4":5,"\u00f6":5,"\u00f2":5,"\u00f5":5}},"\u00f3":{"d":"20,-115v0,-49,38,-120,125,-120v71,0,126,44,126,115v0,68,-51,125,-127,125v-87,0,-124,-65,-124,-120xm53,-123v0,71,43,115,100,115v28,0,85,-14,85,-103v0,-142,-185,-152,-185,-12xm126,-260r62,-38v4,4,17,18,11,24v-25,-1,-54,11,-71,17v-1,0,-2,-2,-2,-3","w":290,"k":{"m":3,"t":9,"v":3,"w":2,"x":9,"y":3,"\u00fd":3,"\u00ff":3,"a":6,"\u00e6":6,"\u00e1":6,"\u00e2":6,"\u00e4":6,"\u00e0":6,"\u00e5":6,"\u00e3":6,"b":10,"d":10,"e":10,"f":10,"h":10,"i":10,"k":10,"l":10,"n":10,"p":10,"r":10,"\u00fe":10,"\u00f0":10,"\u00e9":10,"\u00ea":10,"\u00eb":10,"\u00e8":10,"\u00ed":10,"\u00ee":10,"\u00ef":10,"\u00ec":10,"\u00f1":10,"j":6}},"\u00f4":{"d":"20,-115v0,-49,38,-120,125,-120v71,0,126,44,126,115v0,68,-51,125,-127,125v-87,0,-124,-65,-124,-120xm53,-123v0,71,43,115,100,115v28,0,85,-14,85,-103v0,-142,-185,-152,-185,-12xm147,-301v8,7,37,25,46,35v-4,4,-7,11,-13,13r-36,-28v-15,3,-28,22,-43,28v-1,0,-3,-2,-3,-3v7,-11,39,-37,49,-45","w":290,"k":{"m":3,"t":9,"v":3,"w":2,"x":9,"y":3,"\u00fd":3,"\u00ff":3,"a":6,"\u00e6":6,"\u00e1":6,"\u00e2":6,"\u00e4":6,"\u00e0":6,"\u00e5":6,"\u00e3":6,"b":10,"d":10,"e":10,"f":10,"h":10,"i":10,"k":10,"l":10,"n":10,"p":10,"r":10,"\u00fe":10,"\u00f0":10,"\u00e9":10,"\u00ea":10,"\u00eb":10,"\u00e8":10,"\u00ed":10,"\u00ee":10,"\u00ef":10,"\u00ec":10,"\u00f1":10,"j":6}},"\u00f6":{"d":"20,-115v0,-49,38,-120,125,-120v71,0,126,44,126,115v0,68,-51,125,-127,125v-87,0,-124,-65,-124,-120xm53,-123v0,71,43,115,100,115v28,0,85,-14,85,-103v0,-142,-185,-152,-185,-12xm181,-257v-21,-2,-20,-30,1,-31v9,0,15,5,15,14v0,9,-6,17,-16,17xm109,-257v-20,-1,-21,-30,0,-31v9,0,16,5,16,14v0,9,-6,17,-16,17","w":290,"k":{"m":3,"t":9,"v":3,"w":2,"x":9,"y":3,"\u00fd":3,"\u00ff":3,"a":6,"\u00e6":6,"\u00e1":6,"\u00e2":6,"\u00e4":6,"\u00e0":6,"\u00e5":6,"\u00e3":6,"b":10,"d":10,"e":10,"f":10,"h":10,"i":10,"k":10,"l":10,"n":10,"p":10,"r":10,"\u00fe":10,"\u00f0":10,"\u00e9":10,"\u00ea":10,"\u00eb":10,"\u00e8":10,"\u00ed":10,"\u00ee":10,"\u00ef":10,"\u00ec":10,"\u00f1":10,"j":6}},"\u00f2":{"d":"20,-115v0,-49,38,-120,125,-120v71,0,126,44,126,115v0,68,-51,125,-127,125v-87,0,-124,-65,-124,-120xm53,-123v0,71,43,115,100,115v28,0,85,-14,85,-103v0,-142,-185,-152,-185,-12xm120,-296v7,8,30,26,47,37v-13,5,-69,-21,-79,-26v7,-7,25,-7,32,-11","w":290,"k":{"m":3,"t":9,"v":3,"w":2,"x":9,"y":3,"\u00fd":3,"\u00ff":3,"a":6,"\u00e6":6,"\u00e1":6,"\u00e2":6,"\u00e4":6,"\u00e0":6,"\u00e5":6,"\u00e3":6,"b":10,"d":10,"e":10,"f":10,"h":10,"i":10,"k":10,"l":10,"n":10,"p":10,"r":10,"\u00fe":10,"\u00f0":10,"\u00e9":10,"\u00ea":10,"\u00eb":10,"\u00e8":10,"\u00ed":10,"\u00ee":10,"\u00ef":10,"\u00ec":10,"\u00f1":10,"j":6}},"\u00f5":{"d":"20,-115v0,-49,38,-120,125,-120v71,0,126,44,126,115v0,68,-51,125,-127,125v-87,0,-124,-65,-124,-120xm53,-123v0,71,43,115,100,115v28,0,85,-14,85,-103v0,-142,-185,-152,-185,-12xm203,-289v9,9,-18,30,-29,32v-25,-2,-28,-17,-53,-18v-18,-1,-19,19,-29,14v6,-11,20,-30,34,-31v15,-1,33,17,51,17v18,0,20,-9,26,-14","w":290,"k":{"m":3,"t":9,"v":3,"w":2,"x":9,"y":3,"\u00fd":3,"\u00ff":3,"a":6,"\u00e6":6,"\u00e1":6,"\u00e2":6,"\u00e4":6,"\u00e0":6,"\u00e5":6,"\u00e3":6,"b":10,"d":10,"e":10,"f":10,"h":10,"i":10,"k":10,"l":10,"n":10,"p":10,"r":10,"\u00fe":10,"\u00f0":10,"\u00e9":10,"\u00ea":10,"\u00eb":10,"\u00e8":10,"\u00ed":10,"\u00ee":10,"\u00ef":10,"\u00ec":10,"\u00f1":10,"j":6}},"\u00fa":{"d":"140,-8v63,0,67,-64,67,-134v0,-48,-1,-56,-1,-66v0,-18,-15,-15,-26,-20v17,-4,50,-3,71,0v-6,5,-25,2,-22,20v-4,75,15,150,-30,191v-22,21,-47,22,-66,22v-10,0,-44,-1,-66,-22v-36,-10,-26,-148,-28,-191v-1,-14,-8,-19,-24,-17v-3,-2,-4,-6,3,-5v24,1,53,-3,73,2v-5,6,-23,1,-21,20v-2,4,-1,81,-1,109v0,67,22,91,71,91xm113,-260v19,-14,48,-33,61,-38v4,4,17,18,11,24v-24,-1,-54,11,-71,17v-1,0,-1,-2,-1,-3","w":263,"k":{"m":5,"a":6,"\u00e6":6,"\u00e1":6,"\u00e2":6,"\u00e4":6,"\u00e0":6,"\u00e5":6,"\u00e3":6}},"\u00fb":{"d":"140,-8v63,0,67,-64,67,-134v0,-48,-1,-56,-1,-66v0,-18,-15,-15,-26,-20v17,-4,50,-3,71,0v-6,5,-25,2,-22,20v-4,75,15,150,-30,191v-22,21,-47,22,-66,22v-10,0,-44,-1,-66,-22v-36,-10,-26,-148,-28,-191v-1,-14,-8,-19,-24,-17v-3,-2,-4,-6,3,-5v24,1,53,-3,73,2v-5,6,-23,1,-21,20v-2,4,-1,81,-1,109v0,67,22,91,71,91xm133,-301v9,6,37,26,46,35v-4,4,-7,10,-12,13v-11,-9,-27,-24,-37,-28v-15,3,-27,23,-43,28v-4,-14,38,-39,46,-48","w":263,"k":{"m":5,"a":6,"\u00e6":6,"\u00e1":6,"\u00e2":6,"\u00e4":6,"\u00e0":6,"\u00e5":6,"\u00e3":6}},"\u00fc":{"d":"140,-8v63,0,67,-64,67,-134v0,-48,-1,-56,-1,-66v0,-18,-15,-15,-26,-20v17,-4,50,-3,71,0v-6,5,-25,2,-22,20v-4,75,15,150,-30,191v-22,21,-47,22,-66,22v-10,0,-44,-1,-66,-22v-36,-10,-26,-148,-28,-191v-1,-14,-8,-19,-24,-17v-3,-2,-4,-6,3,-5v24,1,53,-3,73,2v-5,6,-23,1,-21,20v-2,4,-1,81,-1,109v0,67,22,91,71,91xm175,-257v-21,-1,-22,-30,0,-31v9,0,15,5,15,14v0,9,-5,17,-15,17xm102,-257v-21,-2,-20,-30,1,-31v9,0,15,5,15,14v0,9,-6,17,-16,17","w":263,"k":{"m":5,"a":6,"\u00e6":6,"\u00e1":6,"\u00e2":6,"\u00e4":6,"\u00e0":6,"\u00e5":6,"\u00e3":6}},"\u00f9":{"d":"140,-8v63,0,67,-64,67,-134v0,-48,-1,-56,-1,-66v0,-18,-15,-15,-26,-20v17,-4,50,-3,71,0v-6,5,-25,2,-22,20v-4,75,15,150,-30,191v-22,21,-47,22,-66,22v-10,0,-44,-1,-66,-22v-36,-10,-26,-148,-28,-191v-1,-14,-8,-19,-24,-17v-3,-2,-4,-6,3,-5v24,1,53,-3,73,2v-5,6,-23,1,-21,20v-2,4,-1,81,-1,109v0,67,22,91,71,91xm113,-296v7,8,30,26,47,37v-13,5,-69,-21,-79,-26v7,-7,25,-7,32,-11","w":263,"k":{"m":5,"a":6,"\u00e6":6,"\u00e1":6,"\u00e2":6,"\u00e4":6,"\u00e0":6,"\u00e5":6,"\u00e3":6}},"\u00fd":{"d":"72,-4v30,1,20,-44,20,-74v0,-17,-2,-23,-7,-32v-17,-17,-51,-109,-90,-115v-4,0,-6,-5,0,-5v20,1,46,-3,63,2v-8,2,-12,11,-4,20r57,95v9,-23,53,-79,57,-104v2,-7,-9,-8,-9,-12v16,-2,43,-2,62,0v-9,8,-26,7,-35,23v-20,37,-79,87,-65,154v-1,18,-2,57,27,48v2,0,3,2,3,3v-32,3,-50,2,-81,0v0,-1,0,-3,2,-3xm85,-260v19,-14,48,-33,61,-38v4,4,17,18,11,24v-24,-1,-54,11,-71,17v-1,0,-1,-2,-1,-3","w":207,"k":{"m":3,"t":-2,"v":-7,"w":-9,"x":-4,"a":15,"\u00e6":15,"\u00e1":15,"\u00e2":15,"\u00e4":15,"\u00e0":15,"\u00e5":15,"\u00e3":15,"c":3,"g":3,"o":3,"q":3,"\u00f8":3,"\u00e7":3,"\u00f3":3,"\u00f4":3,"\u00f6":3,"\u00f2":3,"\u00f5":3,",":33,".":33,")":-12,"]":-12,"}":-12,"-":10}},"\u00ff":{"d":"72,-4v30,1,20,-44,20,-74v0,-17,-2,-23,-7,-32v-17,-17,-51,-109,-90,-115v-4,0,-6,-5,0,-5v20,1,46,-3,63,2v-8,2,-12,11,-4,20r57,95v9,-23,53,-79,57,-104v2,-7,-9,-8,-9,-12v16,-2,43,-2,62,0v-9,8,-26,7,-35,23v-20,37,-79,87,-65,154v-1,18,-2,57,27,48v2,0,3,2,3,3v-32,3,-50,2,-81,0v0,-1,0,-3,2,-3xm143,-257v-20,-1,-21,-30,0,-31v9,0,16,5,16,14v0,9,-6,17,-16,17xm71,-257v-21,-1,-22,-30,0,-31v9,0,15,5,15,14v0,9,-5,17,-15,17","w":207,"k":{"m":3,"t":-2,"v":-7,"w":-9,"x":-4,"a":15,"\u00e6":15,"\u00e1":15,"\u00e2":15,"\u00e4":15,"\u00e0":15,"\u00e5":15,"\u00e3":15,"c":3,"g":3,"o":3,"q":3,"\u00f8":3,"\u00e7":3,"\u00f3":3,"\u00f4":3,"\u00f6":3,"\u00f2":3,"\u00f5":3,",":33,".":33,")":-12,"]":-12,"}":-12,"-":10}},"\u00a0":{"w":117},"\u00ad":{"d":"128,-108v-18,14,-93,11,-113,25v-3,-6,-2,-30,11,-29v33,2,77,-5,102,4","w":140}}});

function initmap() {
    var address = "Vocabolo Buio Monte Santa Maria Tiberina, Perugia";
	var geocoder = new google.maps.Geocoder();
	
	geocoder.geocode( {'address': address}, function(results,status) {
        if (status == google.maps.GeocoderStatus.OK) {
		
		  	var myOptions = {
				zoom: 14,
      			center: results[0].geometry.location,
      			mapTypeId: google.maps.MapTypeId.ROADMAP
    			};
		
			var map = new google.maps.Map($("map"), myOptions);
	
			var marker = new google.maps.Marker({
    			position: results[0].geometry.location, 
      			map: map, 
      			title:"Hello World!"
			}); 
			
			var tooltip = '<div id="tooltip">'+
   				'<p><strong>Agriturismo il Monte</strong></p>'+
				'<p>Loc. il Buio, 53 - 06010 Monte S.Maria Tiberina, Perugia</p>'+
    		'</div>';

			var infowindow = new google.maps.InfoWindow({
    			content: tooltip
			});
	
			google.maps.event.addListener(marker, 'click', function() {
  				infowindow.open(map,marker);
			});       	
		  
        } else {
          alert("Problema nella ricerca dell'indirizzo: " + status);
        }
      });
    
}

var ilMonte = function() {
	
	$$('div.carousel-wrapper').each(function(node) {
											 
		var vis_slides = 3;
		
		if(node.readAttribute('id')=='carousel-full') { vis_slides = 5;  }
											 
		new Carousel(node.down('div.carousel'), node.down('div.carousel').select('img'), node.select('a.carousel-control'), {  duration:0.5, circular:false, wheel:false, visibleSlides:vis_slides });
									 
	});
		
	if ($('protofade')) { new Protofade('protofade', { delay: 5.0, randomize:true }); }
	
	if ($('map')) { initmap(); }
	
	if ($('form')) { new Protoform('form', { ajax: false }); }

	Cufon.replace('h1')('h3')('h4')('h5')('legend')('strong.nice-text');
	Cufon.replace('div#navigation a, ul.side-nav a, h2', { hover:true });	

}

Shadowbox.init({
	language: "en",
	useSizzle: false,
    players: ["img", "iframe", "swf"]
});


document.observe ('dom:loaded', ilMonte);
