/*  Prototype JavaScript framework, version 1.6.1_rc3
 *  (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_rc3',

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

  function getClass(object) {
    return Object.prototype.toString.call(object)
     .match(/^\[object\s(.*)\]$/)[1];
  }

  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 getClass(object) === "Array";
  }


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

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

  function isString(object) {
    return getClass(object) === "String";
  }

  function isNumber(object) {
    return getClass(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();
      } catch(e) {
        /* empty catch for clients that don't support try/finally */
      }
      finally {
        this.currentlyExecuting = false;
      }
    }
  }
});
Object.extend(String, {
  interpret: function(value) {
    return value == null ? '' : String(value);
  },
  specialChar: {
    '\b': '\\b',
    '\t': '\\t',
    '\n': '\\n',
    '\f': '\\f',
    '\r': '\\r',
    '\\': '\\\\'
  }
});

Object.extend(String.prototype, (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() {
    escapeHTML.text.data = this;
    return escapeHTML.div.innerHTML;
  }

  function unescapeHTML() {
    var div = document.createElement('div');
    div.innerHTML = this.stripTags();
    return div.childNodes[0] ? (div.childNodes.length > 1 ?
      $A(div.childNodes).inject('', function(memo, node) { return memo+node.nodeValue }) :
      div.childNodes[0].nodeValue) : '';
  }


  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.gsub(/::/, '/').gsub(/([A-Z]+)([A-Z][a-z])/,'#{1}_#{2}').gsub(/([a-z\d])([A-Z])/,'#{1}_#{2}').gsub(/-/,'_').toLowerCase();
  }

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

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

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

  function unfilterJSON(filter) {
    return this.sub(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
  };
})());

Object.extend(String.prototype.escapeHTML, {
  div:  document.createElement('div'),
  text: document.createTextNode('')
});

String.prototype.escapeHTML.div.appendChild(String.prototype.escapeHTML.text);

if ('<\n>'.escapeHTML() !== '&lt;\n&gt;') {
  String.prototype.escapeHTML = function() {
    return this.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');
  };
}

if ('&lt;\n&gt;'.unescapeHTML() !== '<\n>') {
  String.prototype.unescapeHTML = function() {
    return this.stripTags().replace(/&lt;/g,'<').replace(/&gt;/g,'>').replace(/&amp;/g,'&');
  };
}
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].gsub('\\\\]', ']') : match[1];
        ctx = ctx[comp];
        if (null == ctx || '' == match[3]) break;
        expr = expr.substring('[' == match[3] ? match[1].length : match[0].length);
        match = pattern.exec(expr);
      }

      return before + String.interpret(ctx);
    });
  }
});
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(){

    var iframeGetAttributeThrowsError = (function(){
      var el = document.createElement('iframe'),
          isBuggy = false;

      document.documentElement.appendChild(el);
      try {
        el.getAttribute('type', 2);
      } catch(e) {
        isBuggy = true;
      }
      document.documentElement.removeChild(el);
      el = null;
      return isBuggy;
    })();

    return function(element, name) {
      element = $(element);
      if (iframeGetAttributeThrowsError &&
          name === 'type' &&
          element.tagName.toUpperCase() == 'IFRAME') {
        return element.getAttribute('type');
      }
      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, 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._getAttr,
      src:         v._getAttr,
      type:        v._getAttr,
      action:      v._getAttrNode,
      disabled:    v._flag,
      checked:     v._flag,
      readonly:    v._flag,
      multiple:    v._flag,
      onload:      v._getEv,
      onunload:    v._getEv,
      onclick:     v._getEv,
      ondblclick:  v._getEv,
      onmousedown: v._getEv,
      onmouseup:   v._getEv,
      onmouseover: v._getEv,
      onmousemove: v._getEv,
      onmouseout:  v._getEv,
      onfocus:     v._getEv,
      onblur:      v._getEv,
      onkeypress:  v._getEv,
      onkeydown:   v._getEv,
      onkeyup:     v._getEv,
      onsubmit:    v._getEv,
      onreset:     v._getEv,
      onselect:    v._getEv,
      onchange:    v._getEv
    });
  })(Element._attributeTranslations.read.values);

  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');
  var HTMLAPPLETELEMENT_PROTOTYPE_BUGGY = checkDeficiency('applet');

  if (Prototype.BrowserFeatures.SpecificElementExtensions) {
    if (HTMLOBJECTELEMENT_PROTOTYPE_BUGGY &&
        HTMLAPPLETELEMENT_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, "\\$0");
          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);

/*--------------------------------------------------------------------------*/
var load_aditional_views = true;
var ddh_data = null;

/**
    @class This class is the interface to all the data sources available. It handles advertisements, category lists and view lists
    @author Micha Surber, futureLAB AG
    @constructor
 */
function default_data_handler() {
	var self = this;
	self.next_condition_number = 1;
	self.next_advertisement = new Array;
	
	new Ajax.Request('/data/init', {
		method:'get',
		asynchronous:false,
		onSuccess: function(transport){
			ddh_data = transport.responseText.evalJSON();
		}
	});
}

/**
	@description this function is used to get advertisement of a certain type and a certain aspectratio
	@return an advertisement object with the keys 'data' containing the url to the advertisement data which should be displayed and the key 'url' with the url of the website
	@param type the type of the advertisement (can be 'video' or 'picture' at the moment)
	@param aspectratio the aspectratio of the advertisement. 
 */
default_data_handler.prototype.get_advertisement_for_type_and_aspectratio = function(/** string */type, /** string */aspectratio) {
	var self = this;
	if(!(aspectratio)){
		aspectratio = '4:3';
	}
	var adds = self.get_advertisements(type);
	if (!(adds)) {
		return null;
	}
	if (!(self.next_advertisement[type])) {
		self.next_advertisement[type] = 0;
	}
	var return_value = adds[self.next_advertisement[type]][aspectratio];

	self.next_advertisement[type]++;
	if (self.next_advertisement[type] == adds.length) {
		self.next_advertisement[type] = 0;
	}
	return return_value;
}

/**
	@description this function is used to get advertisements of a certain type
	@return a hash with different advertisements for different aspectratios.
	@param type the type of the advertisement (can be 'video' or 'picture' at the moment)
	@private
 */
default_data_handler.prototype.get_advertisements = function(/** string */type) {
	var self = this;
	if (!(ddh_data.advertisements)) {
		return null;
	}
	return ddh_data.advertisements[type];
}

/**
	@description this function is used to get the list of different movie categories
	@return an array with category objects. ready to be used with the toolbar_item_dropdown_category class.
	@private
 */
default_data_handler.prototype.get_categories = function() {
	var self = this;
	var cat_array = ddh_data.category_menu;
	var new_cat_array = new Array();
	for (var i = 0; i < cat_array.length ; i++) {
		var item_id = cat_array[i];
		var item_string = cat_array[i].replace("^[0-9]*\s*","");
		new_cat_array[i] = {
			'id' : item_id,
			'string' : item_string
		};
	}
	return new_cat_array;
}


var the_local_flat_orders = [
	/*{
		'next': 'relevance_des', 
	 	'string': 'Relevanz'
	},*/{
		'next': 'newest_des', 
		'string': 'neuste'
	},{
		'next': 'rating_des', 
		'string': 'bestbewertete'
	},{
		'next': 'view_count_des', 
		'string': 'meistgesehene'
	},/*{
		'next': 'random', 
		'string': 'zufĂ€llig'
	},*/
	{
		'next': 'reset_des', 
		'string': 'zurĂŒcksetzen'
	}	
];

/**
	@description this function is used to get the list of different flat order criterias
	@return an array with a string and a order id
	@private
 */
default_data_handler.prototype.get_flat_orders = function() {
	var self = this;
	var ord_array = the_local_flat_orders;
	var new_ord_array = new Array();
	for (var i = 0; i < ord_array.length ; i++) {
		var item_id = ord_array[i].next;
		var item_string = ord_array[i].string;
		new_ord_array[i] = {
			'id' : item_id,
			'string' : item_string
		};
	}
	return new_ord_array;
}





/**
	@description this function is used to get the list all the views available
	@return an array with view objects. ready to be used with the toolbar_item_scaling_list class.
	@private
 */
default_data_handler.prototype.get_views = function() {
	var self = this;
	var the_views = ddh_data.views;
	if (load_aditional_views) {
		var the_id = getQueryVariable('vid');
		if (!(the_id)) {
			the_id = 'additional';
		}

		var the_icon = getQueryVariable('vicon');
		if (!(the_icon)) {
			the_icon = 'img/views/view5.jpg';
		}

		var the_javascript = getQueryVariable('vjs');
		if (!(the_javascript)) {
			// we realy need a javascript file for a new view. 
			return the_views;
		}

		var the_css = getQueryVariable('vcss');

		var the_classname = getQueryVariable('vclass');
		if (!(the_classname)) {
			// we realy need a class name
			return the_views;
		}
		
		var the_new_view = {
			'id' : the_id ,
			'icon' : the_icon,
			'javascript' : the_javascript, 
			'css' : the_css,
			'classname' : the_classname
		};
		the_views[the_views.length] = the_new_view;
		load_aditional_views = false;
	}
	return the_views;
}

/**
	@description this function is used to the items displayed in the 'save' menu like saved views and search results (not yet implemented on the server)
	@return an array with menu item information. ready to be used with the toolbar_item_drop_up class. 
	@private
 */
default_data_handler.prototype.get_save = function() {
	var self = this;
	return ddh_data.store_menu;
}

/**
	@description this function returns the first toolbar_item used for filtering the search results. 
	@return a toolbar item to build up filters for the data
	@type toolbar_item_dropdown_dynamic
	@private
 */
default_data_handler.prototype.get_filter_start_item = function() {
	var self = this;

	var example = new toolbar_item_dropdown_dynamic('filter');
	var filters = ddh_data.filters.root.values;
	example.setTitle('Kriterium');
	for (var i = 0; i < filters.length ; i++) {
		example.addItem(filters[i].string , filters[i].next);
	}
	example.set_condition_id(self.next_condition_number);
	example.set_condition_position(0);
	
	/* register the new search condition in the search handler */
	sh.register_new_condition(self.next_condition_number , example);

	self.next_condition_number++

	return example;
}


/**
	@description this function returns the requested toolbar item for a specific filter. 
	@return a toolbar item to build up filters for the data
	@param filter_id the id of the requested filter
	@type toolbar_item
	@private
 */
default_data_handler.prototype.get_next_filter_item = function(/** string */filter_id) {
	var self = this;
	var item = null;
	var filter_data = ddh_data.filters[filter_id];
	if (filter_data) {
		if (filter_data.type == 'toolbar_item_dropdown_dynamic') {
			item = new toolbar_item_dropdown_dynamic();
			item.setTitle('WĂ€hlen');/*filter_data.values[0].string*/
			for(var i = 0; i < filter_data.values.length ; i++) {
				item.addItem(filter_data.values[i].string , filter_data.values[i].next);
			}
		}
		if (filter_data.type == 'toolbar_item_text_input') {
			item = new toolbar_item_text_input();
			item.set_check_option(filter_data.check_input);
		}
	}
	return item;
}



/**
	@description this function returns the first toolbar_item used for setting the order the search results. 
	@return a toolbar item to build up order settings for the data
	@type toolbar_item_dropdown_dynamic_order
	@private
 */
default_data_handler.prototype.get_order_start_item = function() {
	var self = this;

	var example = new toolbar_item_dropdown_dynamic_order('order');
	var orders = ddh_data.orders.root.values;
	example.setTitle('Kriterium');
	for (var i = 0; i < orders.length ; i++) {
		example.addItem(orders[i].string , orders[i].next);
	}

	example.set_condition_id(0);
	example.set_condition_position(0);	

	sh.register_new_condition(0 , example);
	
	return example;
}


/**
	@description this function returns requested toolbar item for a specific ordering type
	@return a toolbar item to build up order settings for the data
	@param order_id the id of the requested toolbar item
	@type toolbar_item
	@private
 */
default_data_handler.prototype.get_next_order_item = function(/** string */order_id) {
	var self = this;
	var item = null;
	var order_data = ddh_data.orders[order_id];
	if (order_data) {
		if (order_data.type == 'toolbar_item_dropdown_dynamic') {
			item = new toolbar_item_dropdown_dynamic_order();
			item.setTitle('WĂ€hlen');/*order_data.values[0].string*/
			for(var i = 0; i < order_data.values.length ; i++) {
				item.addItem(order_data.values[i].string , order_data.values[i].next);
			}
		}
	}
	return item;
}/**
    @class handles window resize events, and sends notifications to objects that registered for this event. 
    @author Micha Surber, futureLAB AG
    @constructor
 */
function window_resize_handler() {
	var self = this;
	self.to_execute_on_resize = new Array();
	self.next_position = 0;
	
	/** 
		@ignore
	*/
	window.onresize = function() {
		self.handle_resize();
    };
}

/**
	@description this function adds an object to the list of objects that have to be notified if a window resize event occurs  . 
    @param handler a function wich will be executed if a window resize event occurs
 */
window_resize_handler.prototype.add_on_resize_handler = function(/** function */handler) {
	var self = this;
	self.to_execute_on_resize[self.next_position] = handler;
	self.next_position++;
}

/**
	@description this function will will execute all the handlers registered on the window resize events
	@private
*/
window_resize_handler.prototype.handle_resize = function() {
	var self = this;
	for (var i = 0; i < self.next_position; i++) {
		self.to_execute_on_resize[i]();
	}
}
var render_view_in = 'the_view_container';

var search_types_text = 0;
var search_types_kanal = 1;
var search_types_random = 2;
var search_types_all = 3

var current_search_type = 3;

var order_types_relevance = 0;
var order_types_favorites = 1;
var order_types_age = 2;
var order_types_random = 3;
var order_types_rating = 4;
var order_types_reset = 5;

var current_order_type = 3;

var last_search_movies = '';

var search_handler_is_active = false;
/**
    @class a class to collect the search information and notify the views about search updates
    @author Micha Surber, futureLAB AG
    @constructor
 */
function search_handler() {
	var self = this;
	self.view = '';
	self.view_id = '';
	self.next_view = '';
	
	self.search_obj = null;
	self.search_string = '';
	
	self.category_obj = null;
	self.category = '';
	
	self.random_obj = null;
	self.random = false;
	
	self.all_obj = null;
	self.all = false;

	self.order_obj = null;

	self.conditions = new Array();
	self.conditions_objs_to_reset = new Array();
	self.elements_to_destroy_on_reset = new Array();
	
	self.search_in_process = false;
	self.search_request_in_queue = false;
	
	self.similar_search_string_in_loop = false;
	
	/* preload all the view javascripts */
	var views = ddh.get_views();
	for (var i = 0; i < views.length ; i++ ) {
		/* we load the script in the index html now */
		//loadScript(views[i].javascript);
		/*
		if (views[i].css) {
			loadCss(views[i].css);
		}
		*/
	}
	
	/*
	setTimeout("sh.set_view('flview1')" , 2000);
	setTimeout("Effect.Fade('waiting_start', { duration: 1.0 , afterFinish : function() {$('waiting_start').remove();}});" , 3000);
	*/
}

/**
    @description this function is called when the user hits the 'Alle' Button. All the search parameters need to be resetted
    @private
 */
search_handler.prototype.display_all = function() {
	var self = this;
	if (self.search_obj) {
		self.search_obj.reset_content();
		self.search_obj.dehighlight();
		self.search_string = '';
	}
	if (self.category_obj) {
		self.category_obj.reset_content();
		self.category = '';
		self.category_obj.dehighlight();
	}
	if (self.random_obj) {
		self.random = false;
		self.random_obj.dehighlight();
	}
	if (self.all_obj) {
		self.all = false;
		self.all_obj.dehighlight();
	}

	for (var i = 0; i < self.conditions_objs_to_reset.length ; i++) {
		self.conditions_objs_to_reset[i].reset_content();
	}
	
	for (var i = 0; i < self.elements_to_destroy_on_reset.length ; i++ ) {
		if (self.elements_to_destroy_on_reset[i]) {
			self.elements_to_destroy_on_reset[i].removeit();
		}
	}

	/* reset the values wich would be sent to the search action */
	var tmp_cond = new Array();
	tmp_cond[0] = self.conditions[0];
	self.conditions = tmp_cond;
	self.conditions_objs_to_reset = new Array();
	self.elements_to_destroy_on_reset = new Array();

	/* we don't remove the order attribute anymore*/
	/* we still need the order drop down menu */
	/*var order_drop_down = self.conditions_objs_to_reset[0]*/
	/* register the order condition again */
	/*sh.register_new_condition(0 , order_drop_down);*/

	//sh.update_search();
}

search_handler.prototype.reset_cat_all_rand = function() {
	var self = this;
	if (self.category_obj) {
		self.category_obj.reset_content();
		self.category = '';
		self.category_obj.dehighlight();
	}
	if (self.random_obj) {
		self.random = false;
		self.random_obj.dehighlight();
	}
	if (self.all_obj) {
		self.all = false;
		self.all_obj.dehighlight();
	}

}

/**
    @description use this function to add an element to the list of items which will be reseted when the 'Alle' Button is pressed. The Items have to implement the reset_content() function
    @param obj the element to reset
    @private
 */
search_handler.prototype.add_elements_to_destroy_on_reset = function(/** object */obj) {
	var self = this;
	self.elements_to_destroy_on_reset.push(obj);
}


/**
    @description register a new search condition 
    @param id the id of the search condition (the order condition has always the id '0')
    @param obj the condition object (for example a toolbar_item_dropdown_dynamic)
    @private
 */
search_handler.prototype.register_new_condition = function(/** int */id , /** object */obj) {
	var self = this;
	self.conditions[id] = new Array();
	if (id > 0) {
		self.conditions_objs_to_reset.push(obj);
	}
	if (id == 0) {
		self.order_obj = obj;
	}
}

/**
    @description add a value to an existing condition 
    @param id the id of the search condition (the order condition has always the id '0')
    @param position the position of the new value
    @param value the value 
    @private
 */
search_handler.prototype.add_value_to_condition = function(/** int */id , /** int */position , /** string */value) {
	var self = this;
	if (id == 0) {
		if (/relevance/.test(value)) {
			current_order_type = order_types_relevance;
		}
		if (/view_count/.test(value)) {
			current_order_type = order_types_favorites;
		}
		if (/newest/.test(value)) {
			current_order_type = order_types_age;
		}
		if (/random/.test(value)) {
			current_order_type = order_types_random;
		}
		if (/rating/.test(value)) {
			current_order_type = order_types_rating;
		}
		if (/reset/.test(value)) {
			current_order_type = order_types_reset;
		}
	}
	self.conditions[id][position] = value;
	sh.update_search();
}




/**
    @description the search handler need to have access to the toolbar_item_search object to be able to reset it. This is the setter of this value
    @param new_obj the toolbar_item_search object
    @private
 */
search_handler.prototype.set_search_obj = function(/** object */new_obj) {
	var self = this;
	self.search_obj = new_obj;
}

/**
    @description the search handler need to have access to the toolbar_item_drop_down_category object to be able to reset it. This is the setter of this value
    @param new_obj the toolbar_item_drop_down_category object
    @private
 */
search_handler.prototype.set_category_obj = function(/** object */new_obj) {
	var self = this;
	self.category_obj = new_obj;
}

/**
    @description the search handler need to have access to the toolbar_item 'Random' to be able to reset it. This is the setter of this value
    @param new_obj the toolbar_item object for the 'Random' Button
    @private
 */
search_handler.prototype.set_random_obj = function(/** object */new_obj) {
	var self = this;
	self.random_obj = new_obj;
}

/**
    @description the search handler need to have access to the toolbar_item 'all' to be able to reset it. This is the setter of this value
    @param new_obj the toolbar_item object for the 'All' Button
    @private
 */
search_handler.prototype.set_all_obj = function(/** object */new_obj) {
	var self = this;
	self.all_obj = new_obj;
}

/**
    @description the setter for the search string
    @param new_string the new search string
    @private
 */
search_handler.prototype.set_search_string = function(/** string */new_string) {
	var self = this;
	self.reset_cat_all_rand();
	self.search_string = new_string;
	self.order_obj.set_items_inactive([],0);
	current_search_type = search_types_text;
	self.search_obj.highlight();
	if (search_while_typing) {
		if (self.similar_search_string_in_loop) {
			/* we are already observing the search string */
		} else {
			this.similar_search_string_in_loop = true;
			setTimeout("sh.check_similar_search_string('" + new_string + "')",200);
		}
	} else {
		sh.update_search();
	}
}

/**
    @description the setter for the category 
    @param new_cat the new search string
    @private
 */
search_handler.prototype.set_category = function(/** string */new_cat) {
	var self = this;
	if (new_cat != '') {
		self.display_all();
	}
	current_search_type = search_types_kanal;

	/*self.inactivate_order_item('relevance_des');*/
	
	self.category = new_cat;
	/* we don't highlight the category, because we don't know the id of it 
	self.category_obj.highlight();
	*/
	sh.update_search();
}

/**
    @description the setter the 'all' button
    @private
 */
search_handler.prototype.set_all = function() {
	var self = this;
	current_search_type = search_types_all;

	/*self.inactivate_order_item('relevance_des');*/

	self.display_all();
	self.all_obj.highlight();
	sh.update_search();
}

/**
    @description the setter for the random mode.
    @private
 */
search_handler.prototype.set_random = function() {
	var self = this;
	self.display_all();
	current_search_type = search_types_random;
	
	/*self.inactivate_order_item('relevance_des');*/

	self.random = true;
	self.random_obj.highlight();
	self.update_search();
}

/**
    @description this function is used to inactivate a specific order item and set the currently selected order item to 'random' if the item to deactivate was item_id before
    @param item_id the id of the item to set inactive
    @private
 */
search_handler.prototype.inactivate_order_item = function(/** string */ item_id) {
	var self = this;
	if (self.order_obj.get_selected_item_id() == item_id || self.order_obj.get_selected_item_id() == '') {
		self.order_obj.set_items_inactive([item_id],'random');
	} else {
		self.order_obj.set_items_inactive([item_id],0);
	}
}


/**
    @description this function is called when the search string is updated, to check if the search string changed. We only perform a search if we are really looking for something new. 
    @param old_string the last search string we performed a search with
    @private
 */
search_handler.prototype.check_similar_search_string = function(/* string */old_string) {
	var self = this;
	if (old_string == this.search_string) {
		setTimeout("sh.check_similar_search_string('" + this.search_string + "')",200);
	} else {
		self.similar_search_string_in_loop = false;
		sh.update_search();
	}
}


/**
    @description tell the view that the slider size did change 
    @private
 */
search_handler.prototype.tell_view_that_slider_size_changed = function() {
	var self = this;
	if (self.view) {
		if (self.view.toolbar_size_changed) {
			self.view.toolbar_size_changed();
		}
	}
}


search_handler.prototype.tell_view_that_it_is_active_again = function() {
	var self = this;
	if (self.view) {
		if (self.view.setactivate) {
			self.view.setactivate();
		}
	}
}


/**
    @description the user wants to change the view. this function will unload the old view. 
    @param new_id the id of the new view
    @private
 */
var flab_current_view_id = '';
search_handler.prototype.set_view = function(new_id) {
	var self = this;
	
	console.log('new_id = ' , new_id);
	var views = ddh.get_views();
	for (var i = 0; i < views.length ; i++ ) {
		if (views[i].id == new_id) {
			/* change the visible view selection */
			if (self.view) {
				/*$(self.view_id + 'container').writeAttribute({'class' : 'vs_viewContainer'});*/
				if ($('selected_view')) {
					var children = $('selected_view').childElements();
					if (children[0]) {
						children[0].setStyle({'opacity' : '0.5'});
					}
					$('selected_view').id = self.view_id + 'container';
				}
				/*$(self.view_id + 'container').removeClassName('current');*/
			}
			self.view_id = new_id;
			eval('self.next_view = new ' + views[i].classname + '()');
		}
	}
	flab_current_view_id = new_id;
	
	Y.History.navigate("swissmadetv", 'BU'); 
	if (self.view) {
		self.view.unload();
	} else {
		self.view_did_unload();
	}
}

/**
    @description a getter for the view object
    @return the current view object
 */
search_handler.prototype.get_view = function() {
	var self = this;
	return self.view;	
}


/**
    @description this function should be called by the view when she did unload. This function will tell the new view to load. 
 */
search_handler.prototype.view_did_unload = function() {
	var self = this;
	/*$(self.view_id + 'container').addClassName('current');*/
	/*$(self.view_id + 'container').writeAttribute({'class' : 'vs_viewContainercurrent'});*/
	$(self.view_id + 'container').id = 'selected_view';
	var children = $('selected_view').childElements();
	if (children[0]) {
		children[0].setStyle({'opacity' : '1'});
	}
	$(render_view_in).innerHTML = '';
/* should not need to change anything here. Views should not touch this */
/*	$(render_view_in).style.backgroundColor = '#FFFFFF';*/

	self.view = self.next_view;
	self.view.load(render_view_in);
}


/**
    @description this function should be called by the view, when everything is ready to accest update calls. The first search is initialied afterwards. 
 */
search_handler.prototype.view_did_load = function() {
	var self = this;
	/* reset the last_search_movies variable to really update the view */
	
	/*if (!last_search_movies) {
		if (self.view.needs_to_update_before_loading && !self.view.needs_to_update_before_loading()) {
			self.update_view();	
		} else {
			last_search_movies = new Array();
			self.search();
		}
	} else {*/
	
		last_search_movies = new Array();
		self.search();
		
	/*}*/
}

/**
    @description this is a 'search'-function which should be used by all the other fcuntions in this class. If a search request is in process, we wait for a response until we perform a new search. (To not have more then one request running at the time)
    @private
 */
search_handler.prototype.update_search = function() {
	var self = this;
	
	/* we update the UI of the toolbar container after each update_search, because IE6 is a programming error */
	update_toolbar_ui();
	
	if (self.search_in_process) {
		/* we are already searching... posting a request for another search */
		self.search_request_in_queue = true;
	} else {
		/* we are not searching. yet */
		self.search();
	}
}

search_handler.prototype.activate = function() {
	var self = this;
	search_handler_is_active = true;
	self.search();
}
/**
    @description this is the real search function sending the Ajax.Request. this function should only be called by the update_search function. 
    @private
 */
search_handler.prototype.search = function() {
	var self = this;
	if (!(search_handler_is_active)) {
		return true;
	}
	self.search_in_process = true;

	var params = {
				'search_string':self.search_string,
				'category':self.category
			};
			
	if (self.random || current_search_type == search_types_all) { /* we want random order if 'alle' is selected 
																	 but only random order (no limitation) */
		params['order'] = 'random';
	}
	
	if (self.view.maximum_movies_displayed) {
		params['maximum_movies_displayed_int'] = (self.view.maximum_movies_displayed(current_search_type , current_order_type))/1;
	}

	for (var i = 1; i < self.conditions.length ; i++) {
		if (self.conditions[i] && self.conditions[i][self.conditions[i].length - 1] && self.conditions[i][self.conditions[i].length - 2]) {
			params[self.conditions[i][self.conditions[i].length - 2]] = self.conditions[i][self.conditions[i].length - 1];
		}
	}

	if (self.conditions[0]) {
		if (self.conditions[0][self.conditions[0].length - 1]) {
			params['order'] = self.conditions[0][self.conditions[0].length - 1];
		}
		
		if (params['order'] == 'reset_des' || params['order'] == 'reset_asc') {
			if (self.search_string != '') {
				params['order'] = 'relevance_des';
			} else {
					/* no order param 
					if (current_search_type != search_types_all) {
						delete(params['order']);
					}
					*/
					params['order'] = 'newest_des';
			}
		}
	} 
	/* we don't want the random order here. Default is 'newest_des' */
	if (params['order'] == 'random') {
		params['order'] = 'newest_des';
	}

	/* if we don't have an order param yet, and we have a search string, we want ascending relevance as order */
	if ((!params['order'] || params['order'] == '') && current_search_type == search_types_text) {
		params['order'] = 'relevance_des';
	}
	
	/* this is kind of a dirty hack... we don't have real tv yet */
	if (flab_current_view_id == 'tvview') {
		params['order'] = 'random';
		params['search_string'] = '';
		params['category'] = '';
	}
	
	new Ajax.Request('/data/search', { method:'get',
		parameters:params,
		onSuccess: function(transport){
			var to_compare_last_search_movies = last_search_movies;	
/*			if(!(to_compare_last_search_movies[to_compare_last_search_movies.length])) {
				var new_movie_array_for_ie = new Array();
				for (var i = 0; i < to_compare_last_search_movies.length - 1 ; i++) {
					new_movie_array_for_ie[i] = to_compare_last_search_movies[i];
				}
				to_compare_last_search_movies = new Array();
				to_compare_last_search_movies = new_movie_array_for_ie;
			}*/
			last_search_movies = transport.responseText.evalJSON(false);

			/* check if a search request has been posted before */
			self.search_in_process = false;
			if (self.search_request_in_queue) {
				self.search_request_in_queue = false;
				sh.update_search();
			}
			
			/* 	try to find out if something changed because of the new search. 
				we don't need to update the view if nothing did change */
			var something_did_change = false;
			if (to_compare_last_search_movies.length != last_search_movies.length) {
				something_did_change = true;
			} else {
				for (var i = to_compare_last_search_movies.length; i > 0 ; i--) {
					var mobj = to_compare_last_search_movies[i - 1];
					var mobj2 = last_search_movies[i - 1];
					if (mobj.id != mobj2.id) {
						something_did_change = true;
					}
				}
			}
			if (something_did_change) {
				sh.update_view();
			}
		}
	});
}

/**
    @description if a search request has new movies as a result, this function is called, and it will send the new movies array to the view.
    @private
 */
search_handler.prototype.update_view = function() {
	var self = this;
	self.view.update(last_search_movies);
}
var slider;
/**
    @class a class to a slider containing toolbars. 
    @author Micha Surber, futureLAB AG
    @constructor
    @param id the id of the element where the slider will be rendered
 */
function main_menu_slider(/** string */id) {
}

/**
	@description this function adds a toolbar to a slider. The toolbars will be rendered when calling the render function. 
    @param newItem an instance of toolbar. 
    @private
 */
main_menu_slider.prototype.addItem = function(/** toolbar */newItem) {
	sh.tell_view_that_slider_size_changed();
}


/**
	@description this method does render the toolbar inside ot the element with the id myId. All the toolbar_items added using the addItem method, are rendered too. 
    @private
 */
main_menu_slider.prototype.render = function() {
}

/**
	@description does make the slider limiter div as small as the banner is.
    @private
 */
main_menu_slider.prototype.hide_limitter = function() {
	var self = this;
}
/**
	@description does make the slider limiter div smaller, to allow menus in the bottom toolbar to be displayed
    @private
 */
main_menu_slider.prototype.shrink_limitter = function() {
	var self = this;
}

/**
	@description get the bottom coordinate of the menu slider. Can be used by a view to avoid having important data hidden behind the slider
	@return the coordinate of the lowest pixel of the menu slider
	@type integer
 */
main_menu_slider.prototype.get_bottom_coordinate = function() {
	var self = this;
	return 152;
}
/**
	@description does make the slider limiter div bigger, to allow menus in the top toolbar to be displayed
    @private
 */
main_menu_slider.prototype.grow_limitter = function() {
	var self = this;
}

/**
	@description the function does hide the slider and all the containing toolbars
 */
main_menu_slider.prototype.hide = function(){
	var self = this;
}

/**
	@description the function does show the slider and all the containing toolbars, and resets the timer 
 */
main_menu_slider.prototype.show = function(){
}


/**
	@description helper function to stop the timer (used e.g. when the user is editing the search input field)
    @private
 */
main_menu_slider.prototype.stopTimer = function(){
	var self = this;
}

/**
	@description helper function to reset the timer (used e.g. when mouse is moved inside the toolbar slider)
    @private
 */
main_menu_slider.prototype.resetTimer = function(){
	var self = this;
}

/**
	@description helper function to init the timer and activate mousemove observation on the toolbar slider
    @private
 */
main_menu_slider.prototype.initTimer = function(){
	var self = this;
}





/**
	@description set the slider inactive (remove the mouseover and click events of the toolbars)
    @private
 */
main_menu_slider.prototype.setInactive = function() {
	var self = this;
}

/**
	@description activate the slider (add the mouseover and click events to the toolbars)
    @private
 */
main_menu_slider.prototype.setActive = function() {
	var self = this;
}


/**
	@description activate the slider controller (add the mouseover events)
    @private
 */
main_menu_slider.prototype.setSliderControllerActive = function() {
	var self = this;
}

/**
	@description set the slider controller inactive (remove the mouseover events)
    @private
 */
main_menu_slider.prototype.setSliderControllerInactive = function() {
	var self = this;
}








/**    @class This class is used  to render overlay screens like the detail information screen or the highquality view of a movie    @author Micha Surber, futureLAB AG    @constructor */function additional_screens() {	var self = this;	self.current_movie;}var did_count_for_movie_with_id = new Array();var is_large_video_player = false;var is_playing_large_movie = false;/**	@description this function does render an alert overlay screen, and hides it again after two seconds.	@return void.  */additional_screens.prototype.render_alert = function(text) {	var self = this;		var max_container = new Element('div' , {'class' : 'overlay_container_alert' , 'id' : 'additional_screens_overlay_max_alert' , 'style' : 'display:none;'});	document.body.appendChild(max_container);	var content_container = new Element('div' , {'class' : 'overlay_content_alert' , 'id' : 'additional_screens_overlay_content_alert'});	max_container.appendChild(content_container);		var content_container_d = new Element('div' , {'class' : 'overlay_content_d_alert' , 'id' : 'additional_screens_overlay_content_d_alert'});	content_container.appendChild(content_container_d);			content_container_d.appendChild(document.createTextNode(text));	Effect.Appear('additional_screens_overlay_max_alert', { duration: 1.0 , afterFinish: 		function() {			setTimeout("screen_handler.hide_alert()" , 2000);		}	});}additional_screens.prototype.hide_alert = function() {	var self = this;	Effect.Fade('additional_screens_overlay_max_alert' , {		duration: 1.0	});}/**	@description this function does render a general overlay screen with a close button.	@return the id of the DOM element where the content of the overlay can be rendered in.  */additional_screens.prototype.render_overlay = function() {	var self = this;	var max_container = new Element('div' , {'class' : 'overlay_container' , 'id' : 'additional_screens_overlay_max' , 'style' : 'display:none;'});	document.body.appendChild(max_container);		var content_container_close = new Element('div' , {'class' : 'overlay_close' , 'id' : 'additional_screens_overlay_close' , 'style' : 'cursor:pointer;display:none;'});	document.body.appendChild(content_container_close);	$('additional_screens_overlay_close').observe('click' , function() {		is_large_video_player = false;		console.log('onclick!!!');		screen_handler.hide_overlay();	});	var content_container = new Element('div' , {'class' : 'overlay_content' , 'id' : 'additional_screens_overlay_content'});	max_container.appendChild(content_container);			var content_container_d = new Element('div' , {'class' : 'overlay_content_d' , 'id' : 'additional_screens_overlay_content_d'});	content_container.appendChild(content_container_d);			return 'additional_screens_overlay_content_d';}/**	@description this function does display the agb screen.	@private*/additional_screens.prototype.show_agbs = function() {	var self = this;	var overlay_id = self.render_overlay();		var content_container_d = new Element('div' , {'class' : 'agb_container' , 'id' : 'agb_container'});	$(overlay_id).appendChild(content_container_d);		content_container_d.appendChild(document.createTextNode('AGBs'));	Effect.Appear('additional_screens_overlay_max', { duration: 1.0 , afterFinish: function() {			$('additional_screens_overlay_close').setStyle({'display': 'block'});		}	});}/**	@description this function does display the 'about swissmadetv' screen.	@private*/additional_screens.prototype.show_about = function() {	var self = this;	Y.History.navigate("swissmadetv", 'about');}additional_screens.prototype.show_about_yui = function() {	var self = this;	var overlay_id = self.render_overlay();		var content_container_d = new Element('div' , {'class' : 'agb_container' , 'id' : 'agb_container'});	$(overlay_id).appendChild(content_container_d);		var theFrame = new Element('iframe' , {'src' : '/info.html' , 'frameborder' : '0' , 'class' : 'iframe_with_info_window_information' , 'width' : '730px' , 'height' : '550px' , 'border' : '0' , 'noborder' : 'true'});	content_container_d.appendChild(theFrame);	/*var theFrame = new Element('iframe' , {'src' : '/info.html' , 'width' : '730px' , 'height' : '550px' , 'style' : 'width:730px;height:550px;border:0px' , 'border' : '0' , 'noborder' : 'true'});	content_container_d.appendChild(theFrame);*/		Effect.Appear('additional_screens_overlay_max', { duration: 1.0 , afterFinish: function() {			$('additional_screens_overlay_close').setStyle({'display': 'block'});		}	});}/**	@description this function does display detail information about a view if the view implements the get_about_this_view_object function. */additional_screens.prototype.show_about_this_view = function() {	var self = this;		var the_view = sh.get_view();	var about_obj = null;	if (the_view.get_about_this_view_object) {		about_obj = the_view.get_about_this_view_object();	}	var overlay_id = self.render_overlay();		var content_container_d = new Element('div' , {'class' : 'agb_container' , 'id' : 'agb_container'});	$(overlay_id).appendChild(content_container_d);		if (about_obj) {		content_container_d.appendChild(document.createTextNode('Autor: ' + about_obj.author.name + ' Design: ' + about_obj.author.name + ' Idee: ' + about_obj.idea.name));	} else {		content_container_d.appendChild(document.createTextNode('Leider sind keine Informationen verfĂŒgbar.'));	}	Effect.Appear('additional_screens_overlay_max', { duration: 1.0 , afterFinish: function() {			$('additional_screens_overlay_close').setStyle({'display': 'block'});		}	});}/**	@description this function does display the detail view of a movie. This is the function a view should call, when the user 'selects' a movie.    @param id the id of the movie */additional_screens.prototype.show_details_of_movie = function(/** int */id) {	var self = this;	Y.History.navigate("swissmadetv", 'BU' + id); }additional_screens.prototype.show_details_of_movie_yui = function(/** int */id) {	var self = this;	self.current_movie = self.get_movie_for_id(id);	var overlay_id = self.render_overlay();	/* new version. we display only the title. Subtitle is not used at the moment */	var title_str = self.current_movie.title;	if (title_str.length > 66) {		title_str = title_str.substr(0,66) + '...';	}	var main_html_dom = get_detail_dom(title_str);	$(overlay_id).appendChild(main_html_dom);		var ar_parts;	if (self.current_movie.aspectratio) {		ar_parts = self.current_movie.aspectratio.split(':');	} else {		ar_parts = [4,3];	}	var width = (720/2); 	var height = ((720/2) / (ar_parts[0] / ar_parts[1])) + 24; /* the 24 pixels are needed for the flowplayer controlls;*/	var width_l = (720); 	var height_l = ((720) / (ar_parts[0] / ar_parts[1])) + 24; /* the 24 pixels are needed for the flowplayer controlls;*/		console.log('width = ' + width_l + ' height = ' + height_l);	/* scale down not 16/9 movies */	if (height_l > 429) {		width_l = width_l/height_l * 429;		height_l = 429; 	}		/*if (width_l < 550) {		width_l = 473;	} else {		width_l = 681;	}*/		/* just a try... we will display all the movies in a 16:9 movie player*/	height_l = 423;	width_l = 720;		console.log('width = ' + width_l + ' height = ' + height_l);	var player_container = new Element('div' , {'class' : 'flow_small' , 'id' : 'player_small' , 'style' : 'width:' + width_l + 'px;height:' + height_l + 'px;'});	$('player_small_container').appendChild(player_container);		var left_p_v = ((720 - width_l)/2);	var padding_value = '0px ' + Math.round(left_p_v) + 'px 24px ' + Math.round(left_p_v) + 'px';	$('player_small').setStyle({'width' : width_l + 'px' , 'height' : height_l + 'px' , 'padding' : padding_value});	/* build up the navigation pannel */	var objects_array_left = new Array();	if (self.current_movie.dvdlink && self.current_movie.dvdlink.length > 1) {		var elem = document.createTextNode('DVD');		objects_array_left.push(elem);	} else {		console.log('no dvdlink in current movie!');	}	/* build up the right part of the navigation panel */	var objects_array_right = new Array();					var rating = new flrating();	var ratval = 0;	if (self.current_movie.ratings) {		ratval = self.current_movie.ratings;	}	rating.setValue(ratval);	rating.setMovieId(self.current_movie.id);	rating.setUpdateHandler(function(count , avg) {		console.log('new count = ' + count);		/* updating the current movie object */		self.current_movie.ratings = avg;		self.current_movie.ratingscount = count;		/* end of updating the current movie object */		var amountRatings = count;		if (amountRatings == 1) {			amountRatings = amountRatings + ' Bewertung';		} else {			amountRatings = amountRatings + ' Bewertungen';		}		amountRatings = '(' + amountRatings + ')';		console.log('new text = ' + amountRatings);		$('ratingdivcontainer' + self.current_movie.id).innerHTML = amountRatings;	});	var ratingNode = document.createTextNode('Bewertung');	objects_array_right.push(ratingNode);	var ratingDiv = rating.render(self.current_movie.id + 'overlay');	var ratingContainerDiv = new Element('div' , {'class' : 'rating_container_div' , 'style' : 'width:70px;height:12px;margin-left:5px;margin-right:5px;'});	ratingContainerDiv.appendChild(ratingDiv);	objects_array_right.push(ratingContainerDiv);		var amountRatings = 0;	if (self.current_movie.ratingscount) {		amountRatings = self.current_movie.ratingscount;	}	if (amountRatings == 1) {		amountRatings = amountRatings + ' Bewertung';	} else {		amountRatings = amountRatings + ' Bewertungen';	}	amountRatings = '(' + amountRatings + ')';	var ratingAmountNode = document.createTextNode(amountRatings);	var ratingAmountDiv = new Element('div' , {'id' : 'ratingdivcontainer' + self.current_movie.id});	ratingAmountDiv.appendChild(ratingAmountNode);	objects_array_right.push(ratingAmountDiv);	var viewCount = 0;	if (self.current_movie.viewcount) {		viewCount = self.current_movie.viewcount;	}	if (viewCount == 1) {		viewCount = viewCount + ' Aufruf';	} else {		viewCount = viewCount + ' Aufrufe';	}	objects_array_right.push(document.createTextNode(viewCount));		objects_array_right.push(document.createTextNode('Share'));		var mail_share_element = new Element('div' , {'name' : 'mail_share' , 'class' : 'mail_share_icon' , 'id' : 'mail_share_icon'});	objects_array_right.push(mail_share_element);	var fb_share_element = new Element('div' , {'name' : 'fb_share' , 'class' : 'fb_share_icon' , 'type' : 'icon'});	objects_array_right.push(fb_share_element);		var tw_share_element = new Element('div' , {'name' : 'tw_share' , 'class' : 'tw_share_icon' , 'id' : 'tw_share_icon'});	objects_array_right.push(tw_share_element);		var dts2_dom = self.get_new_navigation_html('2' , objects_array_left , objects_array_right);	document.body.appendChild(dts2_dom);	if (self.current_movie.dvdlink && self.current_movie.dvdlink.length > 0) {		console.log("dvdlink = '" + self.current_movie.dvdlink + "'");		$('2_dsn_d1').stopObserving('click');		if (self.current_movie.dvdlink) {			$('2_dsn_d1').observe('click' , function() {window.open(self.current_movie.dvdlink);});		}	}	/* enable email sharing */	$('mail_share_icon').stopObserving('click');	var url = document.location.href;	url = url.replace('#' , '%23');	$('mail_share_icon').observe('click' , function() {document.location.href='mailto:?subject=SwissMadeTV%20-%20' + escape(self.current_movie.title) + '&body=' + url;});		/* enable twitter sharing */	$('tw_share_icon').stopObserving('click');	$('tw_share_icon').observe('click' , function() {window.open('http://twitter.com/home?status=' + escape(document.location.href))});	/* enable facebook sharing */	if (FB) {		FB.Share.renderAll();	}	/* enable rating */	rating.enableVoting();			/* build up the subtitle and the additional information on the screen below the videoplayer */	var addition_information_div = new Element('div' , {'class' : 'addition_information_main_container' , 'id' : 'addition_information_main_container' , 'style' : 'display:none'});	document.body.appendChild(addition_information_div);		var addition_information_div_header = new Element('div' , {'class' : 'addition_information_subtitle'});	addition_information_div_header.appendChild(document.createTextNode(self.get_short_text()));	addition_information_div.appendChild(addition_information_div_header);	var additional_info_string = '<span id="autor"></span>';	if (self.current_movie.date) {		if (additional_info_string != '<span id="autor"></span>'){			additional_info_string = additional_info_string + ' / ';		}		additional_info_string = additional_info_string + 'Jahr: ' + self.current_movie.date.substring(0,4);	}	if (self.current_movie.nzzformaturl && self.current_movie.nzzformattitle) {		if (additional_info_string != '<span id="autor"></span>'){			additional_info_string = additional_info_string + ' / ';		}		additional_info_string = additional_info_string + 'Aus der Sendung: <a href="' + self.current_movie.nzzformaturl + '" target="_blank">' + self.current_movie.nzzformattitle + '</a>';	}	var addition_information_div_add = new Element('div' , {'class' : 'addition_information_rest_info'});	addition_information_div.appendChild(addition_information_div_add);	addition_information_div_add.innerHTML = additional_info_string;	new Ajax.Request('/data/load?table=people&id=' + self.current_movie.id, { method:'get',		onSuccess: function(transport){			json_person = transport.responseText.evalJSON();			var autor_string = 'Realisation: ';			for (var i = 0; i < json_person.length ; i++ ) {				if (autor_string != 'Realisation: ') {					autor_string = autor_string + ', ';				}				var name = json_person[i][2];				var surname = json_person[i][3];				autor_string = autor_string + name + ' ' + surname;			}			if (autor_string != 'Realisation: ') {				$('autor').innerHTML = autor_string + ' / ';			}		}	});	Effect.Appear('additional_screens_overlay_max', { duration: 1.0 , afterFinish: 		function() {			$('additional_screens_overlay_close').setStyle({'display': 'block'});			$('navidiv2').setStyle({'display' : 'block'});			$('addition_information_main_container').setStyle({'display': 'block'});			screen_handler.show_small_flow_player();			$f("player_small").onBeforeFullscreen(function(){ 				return self.handle_fullscreen_button();			});		}	});}additional_screens.prototype.get_new_navigation_html = function(id , items_left , items_right) {	var ret_val = new Element('div' , {'class' : 'detail_small_navi_div wide' , 'id' : 'navidiv2' , 'style' : 'display:none;margin-top:239px'});	var table = new Element('table' , {'class' : 'detail_small_navi_table' , 'cellpadding' : '0' , 'cellspacing' : '0' , 'border' : '0' });	ret_val.appendChild(table);	var tbody = new Element('tbody');	table.appendChild(tbody);	var tr = new Element('tr' , {'class' : 'detail_small_navi_tr'});	tbody.appendChild(tr);	for (var i = 0; i < items_left.length; i++) {		var td = new Element('td' , {'class' : 'detail_small_navi_td' , 'id' : '2dsn_' + (i + 1.0)});		tr.appendChild(td);		var div = new Element('div' , {'id' : '2_dsn_d' + (i + 1.0)});		td.appendChild(div);		div.appendChild(items_left[i]);	}	var td1 = new Element('td' , {'class' : 'detail_small_navi_td' , 'id' : '2dsn_' + items_left.length});	tr.appendChild(td1);		var tableright = new Element('table' , {'class' : 'detail_small_view_table_right' , 'cellpadding' : '0' , 'cellspacing' : '0' , 'border' : '0' , 'style' : 'margin-top:-27px;' });	ret_val.appendChild(tableright);	var tbodyr = new Element('tbody');	tableright.appendChild(tbodyr);	var trr = new Element('tr' , {'class' : 'detail_small_navi_tr'});	tbodyr.appendChild(trr);	for (var i = 0; i < items_right.length; i++) {		var the_class = 'detail_small_navi_td';		if (i == 0 || i == 1 ) {			the_class = the_class + ' detail_small_navi_td_no_padding_right';		}		if (i == 1 || i == 2 || i == 5 || i == 6 || i == 7) {			the_class = the_class + ' detail_small_navi_td_no_border_left';		}				var td = new Element('td' , {'class' : the_class , 'id' : id + 'rdsn_' + (i + 1.0)});		trr.appendChild(td);		var div = new Element('div' , {'id' : id + '_rdsn_dv' + (i + 1.0)});		td.appendChild(div);		div.appendChild(items_right[i]);	}	/*var td1r = new Element('td' , {'class' : 'detail_small_navi_td' , 'id' : id + 'rdsn_' + items_right.length});	trr.appendChild(td1r);*/		return ret_val;}additional_screens.prototype.handle_fullscreen_button = function () {	var self = this;	return true;}/**	@description this function is used to hide the overlay.	@private */additional_screens.prototype.hide_overlay = function() {	var self = this;	console.log('testing1');	Y.History.navigate("swissmadetv", 'BU'); }additional_screens.prototype.hide_overlay_yui = function() {	var self = this;	console.log('testing2');	if (!($('additional_screens_overlay_close'))) {		console.log('could not ')		return true;	}		/*$f("player_small").getPlugin().fadeOut();*/	$('additional_screens_overlay_close').setStyle({'display': 'none'});	if ($('player_small')) {		$f("player_small").stop();		$f("player_small").close();		$f("player_small").unload();			$('player_small').remove();	}	if ($('back_to_detail_button_id')) {		$('back_to_detail_button_id').remove();	}	if ($('navi1_target')) {		$('navi1_target').remove();	}	if ($('navidiv2')) {		$('navidiv2').remove();	}	if ($('addition_information_main_container')) {		$('addition_information_main_container').remove();	}	if ($('navidivrating')) {		$('navidivrating').remove();	}	Effect.Fade('additional_screens_overlay_max', { duration: 1.0 , afterFinish : function() {if ($('additional_screens_overlay_max')) {$('additional_screens_overlay_max').remove();}}});	sh.tell_view_that_it_is_active_again();}/**	@description a wrapper used to get a short text about the current movie. 	@private */additional_screens.prototype.get_short_text = function() {	var self = this;	if (self.current_movie.description) {		return self.current_movie.description;	}	return '';}/**	@description this function is used inside the additional_screens class to get a movie object 	@returns a movie object	@private    @param id the id of the movie */additional_screens.prototype.get_movie_for_id = function(/** int */id) {	var self = this;	for (var i = 0; i < last_search_movies.length ; i++ ) {		if (last_search_movies[i].id == id) {			return last_search_movies[i];		}	}}/**#nocode+*//* these functions are used to render the detail information screen of a movie */additional_screens.prototype.show_small_flow_player = function(pw,ph) {	var self = this;	/* only one video source */	is_playing_large_movie = true;	var length = 300;	if (self.current_movie.length) {		length = self.current_movie.length;	}	var startTime = 0;	if (self.current_movie.starttime) {		startTime = self.current_movie.starttime;	}	var urlparts = self.current_movie.files.mov_pal.split('pal');	var ending = urlparts[urlparts.length - 1];	var fileparts = self.current_movie.files.mov_pal.split('/movies/');	var oriclip = fileparts[fileparts.length - 1];	var url = 'mp4:' + oriclip;		//var hackurl = url.replace(new RegExp("pal[^.]*" + ending), "p" + ending);	var hackurl = url;		console.log('hackurl = ' , hackurl);	var plistitem = {		url : hackurl	};	if (self.current_movie.starttime) {		plistitem.start = self.current_movie.starttime / 1000;	}	if (self.current_movie.length > 1000) {		if (plistitem.start) {			plistitem.duration = plistitem.start + self.current_movie.length / 1000;		} else {			plistitem.duration = self.current_movie.length / 1000;		}	}			$f("player_small", "/swf/flowplayer.commercial-3.2.7.swf",		{	     			key:'#$4b5ebe5e5c3146d8626',			clip: { 				provider: 'rtmp' ,				/*urlResolvers: 'bwcheck',*/				scaling : 'fit',				live : false,				autoBuffering : true,				accelerated : true,				autoPlay : true,				bufferLength : 3			}, 			playlist: [ 				plistitem			],			canvas: {				/*					backgroundColor: '#202020' ,*/									backgroundColor: '#000000',				backgroundGradient : 'none'			},			plugins: { 				rtmp: { 					url: '/swf/flowplayer.rtmp-3.2.3.swf',					netConnectionUrl: 'rtmp://46.4.8.119/vod/foo/'				},				controls:{					url:'/swf/flowplayer.controls-3.2.5.swf',					bufferGradient: 'none',					bufferColor: '#454545',					sliderColor: '#595959',					buttonOverColor: '#595959',					sliderGradient: 'none',					durationColor: '#ffffff',					progressColor: '#696969',					buttonColor: '#595959',					backgroundGradient: 'none',					borderRadius: '0',					progressGradient: 'medium',					backgroundColor: '#f6f4f3',					timeColor: '#ffffff',					opacity:1.0				}/*,				bwcheck: {   					url: '/swf/flowplayer.bwcheck-3.2.5.swf',    					netConnectionUrl: '/img/test.png', 					serverType: 'http',					//netConnectionUrl: 'rtmp://46.4.8.119/vod/foo/',					//serverType: 'fms',					bitrates: {qpal : 600}, // pal : 1200 ,					//bitrates: {pal : 400 , qpal : 200},					rememberBitrate: false,					dynamic : false,					urlExtension: ending,					urlPattern: '{0}{1}{2}', 					defaultBitrate: 'qpal',					onBwDone: function(url, chosenBitrate, bitrate) {						console.log(url, chosenBitrate, bitrate);					} 				} */			} 		}	);	var milsec = Math.round(length/3 * 1000);	if ($f("player_small")) {		$f("player_small").onCuepoint(milsec,function(){			if (!(did_count_for_movie_with_id[self.current_movie.id])) {					var params = {							'movie':self.current_movie.id						};				new Ajax.Request('/data/IncreasePlayCount', { 					method:'post', 					parameters : params,					onSuccess: function(transport){						console.log('did increase playcount of movie!');					}				});							did_count_for_movie_with_id[self.current_movie.id] = true;			} else {				console.log('this user seems to like this movie...  watching it over and over again! :-) ');			}		});	}}function get_detail_dom(title) {	var table = new Element('table' , {'cellpadding' : '0' , 'cellspacing' : '0' , 'border' : '0' });		var tbody1 = new Element('tbody');	table.appendChild(tbody1);	var tr1 = new Element('tr');	tbody1.appendChild(tr1);	var td1 = new Element('td' , {'id' : 'detail_title'});	tr1.appendChild(td1);	td1.appendChild(document.createTextNode(title));		var tr2 = new Element('tr');	tbody1.appendChild(tr2);	var td2 = new Element('td' , {'id' : 'detail_top_container'});	tr2.appendChild(td2);			var table_sub = new Element('table' , {'cellpadding' : '0' , 'cellspacing' : '0' , 'border' : '0' });			td2.appendChild(table_sub);		var tbody2 = new Element('tbody');		table_sub.appendChild(tbody2);		var tr_sub = new Element('tr');		tbody2.appendChild(tr_sub);		var td_sub1 = new Element('td' , {'id' : 'player_small_container'});		tr_sub.appendChild(td_sub1);	var tr3 = new Element('tr');	tbody1.appendChild(tr3);	var td3 = new Element('td' , {'id' : 'detail_links' , 'style' : 'padding-top:20px;'});	tr3.appendChild(td3);	return table;}function get_detail_small_view(id , texts , textsright) {	var ret_val = new Element('div' , {'class' : 'detail_small_view' , 'id' : 'navidiv' + id , 'style' : 'display:none;'});	var table = new Element('table' , {'class' : 'detail_small_view_table' , 'cellpadding' : '0' , 'cellspacing' : '0' , 'border' : '0' });	ret_val.appendChild(table);	var tbody = new Element('tbody');	table.appendChild(tbody);	var tr = new Element('tr' , {'class' : 'detail_small_view_tr'});	tbody.appendChild(tr);	for (var i = 0; i < texts.length; i++) {		var td = new Element('td' , {'class' : 'detail_small_view_td' , 'id' : id + 'dsn_' + (i + 1.0)});		tr.appendChild(td);		var div = new Element('div' , {'id' : id + '_dsn_dv' + (i + 1.0)});		td.appendChild(div);		div.appendChild(texts[i]);	}	var td1 = new Element('td' , {'class' : 'detail_small_view_td' , 'id' : id + 'dsn_' + texts.length});	tr.appendChild(td1);	var tableright = new Element('table' , {'class' : 'detail_small_view_table_right' , 'cellpadding' : '0' , 'cellspacing' : '0' , 'border' : '0' });	ret_val.appendChild(tableright);	var tbodyr = new Element('tbody');	tableright.appendChild(tbodyr);	var trr = new Element('tr' , {'class' : 'detail_small_view_tr'});	tbodyr.appendChild(trr);	for (var i = 0; i < textsright.length; i++) {		var td = new Element('td' , {'class' : 'detail_small_view_td' , 'id' : id + 'rdsn_' + (i + 1.0)});		trr.appendChild(td);		var div = new Element('div' , {'id' : id + '_rdsn_dv' + (i + 1.0)});		td.appendChild(div);		div.appendChild(textsright[i]);	}	var td1r = new Element('td' , {'class' : 'detail_small_view_td' , 'id' : id + 'rdsn_' + textsright.length});	trr.appendChild(td1r);	return ret_val;}function get_detail_small_navi(id , texts) {	var ret_val = new Element('div' , {'class' : 'detail_small_navi_div' , 'id' : 'navidiv' + id , 'style' : 'display:none;'});	var table = new Element('table' , {'class' : 'detail_small_navi_table' , 'cellpadding' : '0' , 'cellspacing' : '0' , 'border' : '0' });	ret_val.appendChild(table);	var tbody = new Element('tbody');	table.appendChild(tbody);	var tr = new Element('tr' , {'class' : 'detail_small_navi_tr'});	tbody.appendChild(tr);	for (var i = 0; i < texts.length; i++) {		var td = new Element('td' , {'class' : 'detail_small_navi_td' , 'id' : id + 'dsn_' + (i + 1.0)});		tr.appendChild(td);		var div = new Element('div' , {'id' : id + '_dsn_d' + (i + 1.0)});		td.appendChild(div);		div.appendChild(document.createTextNode(texts[i]));	}	var td1 = new Element('td' , {'class' : 'detail_small_navi_td' , 'id' : id + 'dsn_' + texts.length});	tr.appendChild(td1);	return ret_val;}/**#nocode-*//*plugins: 			{				canvas: 				{					backgroundColor: "#454545"				}, 				controls: 				{					bufferGradient: 'none',					bufferColor: '#454545',					sliderColor: '#595959',					buttonOverColor: '#595959',					sliderGradient: 'none',					durationColor: '#ffffff',					progressColor: '#696969',					buttonColor: '#595959',					backgroundGradient: 'none',					borderRadius: '0',					progressGradient: 'medium',					backgroundColor: '#f6f4f3',					timeColor: '#ffffff',					opacity:1.0				}			}*//**#nocode+*/
try { console.log('init console... done'); } catch(e) { console = { log: function() {} } }

extend = function(subClass, baseClass) {
   function inheritance() {}
   inheritance.prototype = baseClass.prototype;

   subClass.prototype = new inheritance();
   subClass.prototype.constructor = subClass;
   subClass.baseConstructor = baseClass;
   subClass.superClass = baseClass.prototype;
}

function loadScript(url)
{
   var e = document.createElement("script");
   var time = new Date;
   e.src = url + '?time=' + time.getTime();
   e.type="text/javascript";
   document.getElementsByTagName("head")[0].appendChild(e); 
}


function loadCss(url)
{
   var e = document.createElement("link");
   e.href = url;
   e.type="text/css";
   e.rel="stylesheet";
   document.getElementsByTagName("head")[0].appendChild(e); 
}

function isdefined( variable)
{
    return (typeof(window[variable]) == "undefined")?  false: true;
}

function findDuplicateIds() {
	var all = document.body.descendants();
	for(var i = 0; i < all.length; i++) {
		if (all[i].id.length > 0 && $$('#' + all[i].id).length > 1) {
			console.log('!!!! found a duplicate id in dom tree! id= ' + all[i].id);
		}
	}
}

function getWindowSize() {
  var myWidth = 0, myHeight = 0;
  if( typeof( window.innerWidth ) == 'number' ) {
    //Non-IE
    myWidth = window.innerWidth;
    myHeight = window.innerHeight;
  } else if( document.documentElement && ( document.documentElement.clientWidth || document.documentElement.clientHeight ) ) {
    //IE 6+ in 'standards compliant mode'
    myWidth = document.documentElement.clientWidth;
    myHeight = document.documentElement.clientHeight;
  } else if( document.body && ( document.body.clientWidth || document.body.clientHeight ) ) {
    //IE 4 compatible
    myWidth = document.body.clientWidth;
    myHeight = document.body.clientHeight;
  }
  return {'width' : myWidth , 'height' : myHeight};
}

function recalc_ie7() {
	try{IE7.recalc();} catch(e){}
}

function update_toolbar_ui() {
/*	if (Prototype.Browser.IE) {
		$(slider.myId + '_list').setStyle({'display' : 'none'});
		$(slider.myId + '_list').setStyle({'display' : 'block'});
	}*/
}
Prototype.Browser.IE6=Prototype.Browser.IE && parseInt(navigator.userAgent.substring (navigator.userAgent.indexOf("MSIE")+5))==6;
Prototype.Browser.IE7=Prototype.Browser.IE && parseInt(navigator.userAgent.substring (navigator.userAgent.indexOf("MSIE")+5))==7;
Prototype.Browser.IE8=Prototype.Browser.IE && parseInt(navigator.userAgent.substring (navigator.userAgent.indexOf("MSIE")+5))==8;
Prototype.Browser.OldIE=Prototype.Browser.IE && !Prototype.Browser.IE8;


var tooltip=function(){
	var id = 'tt';
	var top = 3;
	var left = 3;
	var maxw = 300;
	var speed = 10;
	var timer = 20;
	var endalpha = 95;
	var alpha = 0;
	var tt,t,c,b,h;
	var ie = document.all ? true : false;
	return{
		show:function(v,w){
			if(tt == null){
				tt = document.createElement('div');
				tt.setAttribute('id',id);
				t = document.createElement('div');
				t.setAttribute('id',id + 'top');
				c = document.createElement('div');
				c.setAttribute('id',id + 'cont');
				b = document.createElement('div');
				b.setAttribute('id',id + 'bot');
				tt.appendChild(t);
				tt.appendChild(c);
				tt.appendChild(b);
				document.body.appendChild(tt);
				tt.style.opacity = 0;
				tt.style.filter = 'alpha(opacity=0)';
				document.onmousemove = this.pos;
			}
			tt.style.display = 'block';
			c.innerHTML = v;
			tt.style.width = w ? w + 'px' : 'auto';
			if(!w && ie){
				t.style.display = 'none';
				b.style.display = 'none';
				tt.style.width = tt.offsetWidth;
				t.style.display = 'block';
				b.style.display = 'block';
			}
			if(tt.offsetWidth > maxw){tt.style.width = maxw + 'px'}
			h = parseInt(tt.offsetHeight) + top;
			clearInterval(tt.timer);
			tt.timer = setInterval(function(){tooltip.fade(1)},timer);
		},
		pos:function(e){
			var u = ie ? event.clientY + document.documentElement.scrollTop : e.pageY;
			var l = ie ? event.clientX + document.documentElement.scrollLeft : e.pageX;
			tt.style.top = (u - h) + 'px';
			tt.style.left = (l + left) + 'px';
		},
		fade:function(d){
			var a = alpha;
			if((a != endalpha && d == 1) || (a != 0 && d == -1)){
				var i = speed;
				if(endalpha - a < speed && d == 1){
					i = endalpha - a;
				}else if(alpha < speed && d == -1){
					i = a;
				}
				alpha = a + (i * d);
				tt.style.opacity = alpha * .01;
				tt.style.filter = 'alpha(opacity=' + alpha + ')';
			}else{
				clearInterval(tt.timer);
				if(d == -1){tt.style.display = 'none'}
			}
		},
		hide:function(){
			clearInterval(tt.timer);
			tt.timer = setInterval(function(){tooltip.fade(-1)},timer);
		}
	};
}();

function getQueryVariable(variable) { 
	var query = window.location.search.substring(1); 
	var vars = query.split("&"); 
	for (var i=0;i<vars.length;i++) { 
		var pair = vars[i].split("="); 
		if (pair[0] == variable) { 
			return pair[1]; 
		} 
	} 
}
/**#nocode-*//**
    @class a dropdown menu
    @author Micha Surber, futureLAB AG
    @constructor
	@private
 */
function dropdown(/** string */id) {
	var self = this;
	self.drop_items = new Array();
	self.drop_next_item_position = 0;
	self.id = id;
	self.selected_item_id = '';
	self.isvisible = false;
}

/**
	@description this function adds an option to the dropdown menu. The items will be rendered when calling the render function. 
    @param newItem an option for the dropdown menu
    @param value an optional parameter with a value 
	@public
 */
dropdown.prototype.addItem = function(/** string */newItem , /** value */value) {
	var self = this;
	self.drop_items[self.drop_next_item_position] = newItem;
	if (value) {
		self.drop_items[self.drop_next_item_position] = {'string' : newItem , 'id' : value};
	}
	self.drop_next_item_position++;
}

/**
	@description get the currently selected items id
	@public
	@return the items id
 */
dropdown.prototype.get_selected_item_id = function() {
	var self = this;
	return self.selected_item_id;
}

/**
	@description this function is used to inactivate drop down menu items, and select a new one. 
    @param ids_inactive an array of item ids wich should be inactivated (all the other items will be active after the function call. )
    @param new_id the id of the newly selected item
	@public
 */
dropdown.prototype.set_items_inactive = function( /** array */ids_inactive , /** string */ new_id) {
	var self = this;
	console.log('set_items_inactive = ' , ids_inactive , new_id);
	for (var i = 0; i < self.drop_items.length ; i++){
		if ($(self.drop_items[i].id).hasClassName('inactive')) {
			/* was inactive before... ataching the onclick handler again */
			$(self.drop_items[i].id).observe('click' , function(event) {
				self.item_onclick_handler(event);
			});
		}
		$(self.drop_items[i].id).removeClassName('inactive');
	}
	for (var i = 0; i < ids_inactive.length ; i++){
		if ($(ids_inactive[i])) {
			$(ids_inactive[i]).addClassName('inactive');
			$(ids_inactive[i]).stopObserving('click');
		}
	}
	if (new_id != 0) {
		self.item_onclick_handler(new_id);
	}
}

/**
    @description this function does construct the html elements used for the drop down menu 
	@private
 */
dropdown.prototype.render = function() {
	var self = this;
	
	var main = new Element('div' , {'id': self.id + 'button'});
	main.addClassName(self.id + 'button');
	main.addClassName('button');
	$('the_body').appendChild(main);

	var ul = new Element('ul' , {'id' : self.id + 'dropdown' , 'style' : 'display:none;'});
	ul.addClassName('dropdown');
	$('the_body').appendChild(ul);

	var kdropdown = $(self.id + 'dropdown');
	var head = new Element('li');
	head.addClassName('head');
	kdropdown.appendChild(head);
	for (var i = 0; i < self.drop_items.length ; i++) {
		var li = new Element('li' , {'id' : self.drop_items[i].id , 'string_value' : self.drop_items[i].string});
		li.innerHTML = self.drop_items[i].string;
		kdropdown.appendChild(li);
		$(self.drop_items[i].id).observe('click' , function(event) {
			self.item_onclick_handler(event);
		});
	}
	var last = new Element('li');
	last.addClassName('last');
	last.innerHTML = '&nbsp;';
	kdropdown.appendChild(last);
	
	$(self.id + 'button').observe('click', function(event) {
		self.show();
		Event.stop(event);
	});
	
	$(self.id + 'dropdown').observe('mouseover', function(event) {
		Event.stop(event);
	});
}

/**
	@description does show the drop down menu. 
	@private
 */
dropdown.prototype.show = function() {
	var self = this;
	self.isvisible = true;
	$(self.id + 'dropdown').style.display = 'block';
}

/**
	@description does hide the drop down menu. This method is used by the display_notification_center hiding all the unused menues. 
	@private
 */
dropdown.prototype.hide = function() {
	var self = this;
	if (self.isvisible) {
		//$(self.id + 'dropdown').style.display = 'none';
		self.isvisible = false;
		new Effect.Fade(self.id + 'dropdown' , {duration : 0.1});
	}
}


/**
    @description the onclick item of a drop down menu. Subclasses should overwrite this
	@private
 */
dropdown.prototype.item_onclick_handler = function(event) {
	var self = this;
	var element = event.element();
}

dropdown.prototype.get_id_from_event = function(event) {
	var self = this;
	if (event.element) {
		var element = event.element();
		return element.getAttribute('id')
	}
	return event;
}
/**
    @description remove the dropdown menu from the DOM tree
	@private
 */
dropdown.prototype.removeit = function() {
	var self = this;
}
/**
    @class a toolbar_item implementing a dropdown menu for a category. (Special case, because we want a special onclick handler)
    @author Micha Surber, futureLAB AG
    @constructor
	@augments toolbar_item_dropdown
	@private
 */
function dropdown_category(/** string */id) {
	var self = this;
	self.selectedItem = '';
	dropdown_category.baseConstructor.call(self, id);
	self.current_dom_id = self.id + 'button';
}

extend(dropdown_category , dropdown);

/**
    @description this function is called when a user selects a category. 
	@private
 */
dropdown_category.prototype.item_onclick_handler = function(event) {
	var self = this;

	var id = self.get_id_from_event(event);
	self.selected_item_id = id;
	var str = $(id).getAttribute('string_value');


	sh.set_category(str);
	self.highlight(id);

	self.hide();
}

/**
    @description this function will hightlight the category menu and change color of the selected category string to green
    @param id the id of the dropdown item to highlight
	@private
 */
dropdown_category.prototype.highlight = function(/** string */id) {
	var self = this;
	if (self.selectedItem != '') {
		$(self.selectedItem).removeClassName('current');
	}
	self.selectedItem = id;
	$(self.selectedItem).addClassName('current');
	$(self.current_dom_id).id = self.id + 'buttoncurrent';
	self.current_dom_id =  self.id + 'buttoncurrent';
}

/**
	@description the function does remove the highlighting of the dropdown 
	@private
*/
dropdown_category.prototype.dehighlight = function() {
	var self = this;
	if (self.selectedItem != '') {
		$(self.selectedItem).removeClassName('current');
	}
	$(self.current_dom_id).id = self.id + 'button';
	self.current_dom_id =  self.id + 'button';
}


/**
    @description this function is used to reset the content of the category drop down menu
	@private
 */
dropdown_category.prototype.reset_content = function(event) {
	var self = this;
	if (self.selectedItem != '') {
		$(self.selectedItem).removeClassName('current');
		self.selectedItem = '';
	}
	$(self.current_dom_id).id = self.id + 'button';
	self.current_dom_id =  self.id + 'button';
	if (event) {
		sh.set_category('');
	}
}
/**
    @class a toolbar_item implementing a dropdown menu for a category. (Special case, because we want a special onclick handler)
    @author Micha Surber, futureLAB AG
    @constructor
	@augments toolbar_item_dropdown
	@private
 */
function dropdown_order(/** string */id) {
	var self = this;
	self.selectedItem = '';
	self.direction = 'des';
	dropdown_order.baseConstructor.call(self, id);
}

extend(dropdown_order , dropdown);

/**
    @description this function does construct the html elements used for the drop down menu 
	@private
 */
dropdown_order.prototype.render = function() {
	var self = this;
	
	var main2 = new Element('div' , {'id': self.id + 'button_direction'});
	main2.addClassName(self.id + 'button_direction');
	main2.addClassName('button_direction');
	$('the_body').appendChild(main2);
	$(self.id + 'button_direction').observe('click' , function(event) {
		self.direction_onclick_handler(event);
	});

	dropdown_order.superClass.render.call(self);
}

/**
	@description does show the drop down menu. 
	@private
 */
dropdown_order.prototype.show = function() {
	var self = this;
	self.isvisible = true;
	$(self.id + 'dropdown').style.display = 'block';
}


dropdown_order.prototype.direction_onclick_handler = function(event) {
	var self = this;
	if (self.direction == 'des') {
		$(self.id + 'button_direction').removeClassName(self.id + self.selected_item_id + 'button_direction');
		$(self.id + 'dropdown').removeClassName(self.id + self.selected_item_id + 'dropdown');
		self.direction = 'asc';
		$(self.id + 'button_direction').addClassName(self.id + self.selected_item_id + 'button_direction_asc');
		$(self.id + 'dropdown').addClassName(self.id + self.selected_item_id + 'dropdown_asc');
		var children = $('rangdropdown').childElements();
		children.each(function(item){
			if (item.hasClassName('head')) {
				item.removeClassName('head');
				item.addClassName('head_asc');
			}
		});
	} else { /* asc */
		$(self.id + 'button_direction').removeClassName(self.id + self.selected_item_id + 'button_direction_asc');
		$(self.id + 'dropdown').removeClassName(self.id + self.selected_item_id + 'dropdown_asc');
		self.direction = 'des';
		$(self.id + 'button_direction').addClassName(self.id + self.selected_item_id + 'button_direction');
		$(self.id + 'dropdown').addClassName(self.id + self.selected_item_id + 'dropdown');
		var children = $('rangdropdown').childElements();
		children.each(function(item){
			if (item.hasClassName('head_asc')) {
				item.removeClassName('head_asc');
				item.addClassName('head');
			}
		});
	}
	self.item_onclick_handler(self.selectedItem);
}

/**
    @description this function is called when a user selects a category. 
	@private
 */
dropdown_order.prototype.item_onclick_handler = function(event) {
	var self = this;
	
	var id = self.get_id_from_event(event);
	
	/* remove old classes */
	$(self.id + 'button').removeClassName(self.id + self.selected_item_id + 'button');
	if (self.direction == 'des') {
		$(self.id + 'button_direction').removeClassName(self.id + self.selected_item_id + 'button_direction');
		$(self.id + 'dropdown').removeClassName(self.id + self.selected_item_id + 'dropdown');
	} else {
		$(self.id + 'button_direction').removeClassName(self.id + self.selected_item_id + 'button_direction_asc');
		$(self.id + 'dropdown').removeClassName(self.id + self.selected_item_id + 'dropdown_asc');
	}

	self.selected_item_id = id;
	/* add new classes */
	$(self.id + 'button').addClassName(self.id + self.selected_item_id + 'button');
	if (self.direction == 'des') {
		$(self.id + 'button_direction').addClassName(self.id + self.selected_item_id + 'button_direction');
		$(self.id + 'dropdown').addClassName(self.id + self.selected_item_id + 'dropdown');
	} else {
		$(self.id + 'button_direction').addClassName(self.id + self.selected_item_id + 'button_direction_asc');
		$(self.id + 'dropdown').addClassName(self.id + self.selected_item_id + 'dropdown_asc');
	}
	
	
	id = self.get_condition_from_id(id);
	

	sh.add_value_to_condition(0,0,id);
	self.highlight(id);

	self.hide();
}

/**
    @description this function will hightlight the category menu and change color of the selected category string to green
    @param id the id of the dropdown item to highlight
	@private
 */
dropdown_order.prototype.highlight = function(/** string */id) {
	var self = this;
	if (self.selectedItem != '') {
		$(self.selectedItem).removeClassName('current');
	}
	self.selectedItem = self.get_condition_from_id(id);
	if (id != 'reset_des' && id != 'reset_asc' ) {
		$(self.selectedItem).addClassName('current');
	}
	//$(self.id + 'button').addClassName('current');
}

/**
	@description the function does remove the highlighting of the dropdown 
	@private
*/
dropdown_order.prototype.dehighlight = function() {
	var self = this;
	if (self.selectedItem != '') {
		$(self.selectedItem).removeClassName('current');
	}
	//$(self.id + 'button').removeClassName('current');
}


/**
    @description this function is used to reset the content of the category drop down menu
	@private
 */
dropdown_order.prototype.reset_content = function(event) {
	var self = this;
	if (self.selectedItem != '') {
		$(self.selectedItem).removeClassName('current');
		self.selectedItem = '';
	}
	//$(self.id + 'button').removeClassName('current');
	//if (event) {
	//	sh.set_category('');
	//}
}


dropdown_order.prototype.get_condition_from_id = function(/** string */id) {
	var self = this;
	if (self.direction != 'des') {
		/* not the default sort direction... changing it...*/
		if (/asc/.test(id)) {
			/* found asc. replacing with des*/
			id = id.replace('asc' , 'des');
		} else {
			/* we assume to have a des. replacing it with asc */
			id = id.replace('des' , 'asc');
		}
	}
	
	return id;
}

/**
    @class the main class used to render a button.
    @author Micha Surber, futureLAB AG
    @constructor
    @private
 */
function button(/** string */id) {
	var self = this;
	self.myId = id;
	self.current_dom_id = self.myId + 'button';
	self.onclick_handler = null;
}

/**
    @param id the id of the element where the button will be rendered into.
    @private
 */
button.prototype.setId = function(/** string */id) {
	var self = this;
	self.myId = id;
}

/**
    @description this function does construct the html elements used for the button
    @private
 */
button.prototype.render = function() {
	var self = this;

	var div = new Element('div' , {'id' : self.myId + 'button'});
	div.addClassName(self.myId + 'button');
	div.addClassName('button');
	$('the_body').appendChild(div);

	if (self.onclick_handler) {
		$(self.current_dom_id).observe('click' , self.onclick_handler);
	}
}

/**
	@description the function does set the item inactive. Subclasses should overwrite this
	@private
*/
button.prototype.setInactive = function() {
	var self = this;
}

/**
	@description the function does activate the item. Subclasses should overwrite this
	@private
*/
button.prototype.setActive = function() {
	var self = this;
}

/**
	@description the setter of the onclick handler of the item 
	@param handler the handler
	@private
*/
button.prototype.setOnclickHandler = function(/** function */handler) {
	var self = this;
	self.onclick_handler = handler;
}

/**
	@description the function does remove the button from the DOM tree
	@private
*/
button.prototype.removeit = function() {
	var self = this;
	if ($(self.current_dom_id)) {
		$(self.current_dom_id).remove();
	}
}

/**
	@description the function does hightlight the button (make the button green)
	@private
*/
button.prototype.highlight = function() {
	var self = this;
	/*$(self.current_dom_id).addClassName('current');*/
	$(self.current_dom_id).id = self.myId + 'buttoncurrent';
	self.current_dom_id = self.myId + 'buttoncurrent';
	
}

/**
	@description the function does remove the highlighting of the button 
	@private
*/
button.prototype.dehighlight = function() {
	var self = this;
	/*$(self.current_dom_id).removeClassName('current');*/
	$(self.current_dom_id).id = self.myId + 'button';
	self.current_dom_id = self.myId + 'button';
}

/**
    @class a toolbar_item generating an input field and a 'search' button
    @author Micha Surber, futureLAB AG
    @constructor
	@augments toolbar_item
	@private
 */
function search_field() {
	var self = this;
	self.current_dom_id = 'searchbutton';
}

/**
    @description this function does construct the html elements used for the input field and the search button inside of the element with id set using setId
	@private
 */
search_field.prototype.render = function() {
	var self = this;
	
	if (search_while_typing) {
		if (Prototype.Browser.IE) {
			$(self.current_dom_id).observe('click' , function() {
				sh.set_search_string($('search').value);
			});
		} else {
			$('search').observe('keyup' , function() {
				sh.set_search_string($('search').value);
			});
		}
	} else {
		$(self.current_dom_id).observe('click' , function() {
			sh.set_search_string($('search').value);
		});
	}

	/* Build up the ajax Autocompleter for the search field */
	new Ajax.Autocompleter("search" , "search_completion", "/data/CompletionLoad", {
		parameters: "iehack=true&table=tags&column=tag",
		paramName: "value"
	});
}

/**
    @description this function does highlight the search toolbar item. 
	@private
 */
search_field.prototype.highlight = function() {
	var self = this;
	$(self.current_dom_id).id = 'searchbuttoncurrent';
	self.current_dom_id =  'searchbuttoncurrent';
}

/**
    @description this function does dehighlight the search toolbar item. 
	@private
 */
search_field.prototype.dehighlight = function() {
	var self = this;
	$(self.current_dom_id).id = 'searchbutton';
	self.current_dom_id =  'searchbutton';
}

/**
    @description this function does reset the content of the search field
	@private
 */
search_field.prototype.reset_content = function(event) {
	var self = this;
	$('search').value = '';
}
/**
    @class a tooltipp 
    @author Micha Surber, futureLAB AG
    @constructor
	@public
 */
function tooltipp(/** string */theText) {
	var self = this;
	self.text = theText;
	var idc = theText;
	idc.replace(" " , "");
	self.id = idc;
}

/**
	@public
	@param theText the Text of the tooltipp
	@param newx the x position of the tooltipp
	@param newy the y position of tha tooltipp
	@description this constructor does create a tooltip, tender it, move it to the requested position and shows it.
 */
function greate_tooltipp(/** string */theText , /** int */ newx , /** int */ newy) {
	var self = this;
	var tooltip = new tooltipp(theText);
	tooltip.render();
	tooltip.msmove(newx , newy);
	tooltip.show();
	return tooltip;
}

/**
    @description this function does construct the html elements used for the tooltip
	@private
 */
tooltipp.prototype.render = function() {
	var self = this;
		var container = new Element('div' , {'id' : self.id + 'fltooltipp' , 'style' : 'display:none;position:absolute;'});
		container.innerHTML = '<table cellpadding="0" cellspacing="0" border="0" id="' + self.id + 'fltooltipp_table">\
			<tr>\
				<td style="width:10px;height:21px;background-image:url(\'img/tooltip_left-trans.png\')">\
				</td>\
				<td colspan="3" nowrap="nowrap" id="' + self.id + 'fltooltipptext" style="background-color:#000000;color:#FFFFFF;font-size:10px;height:21px;line-height:21px;text-align:center;width:auto;">\
					' + self.text + '\
				</td>\
				<td style="width:10px;height:21px;background-image:url(\'img/tooltip_right-trans.png\')">\
				</td>\
			</tr>\
			<tr>\
				<td style="height:8px;width:10px;"></td>\
				<td style="height:8px;" id="' + self.id + 'fltooltipp_to_resize1"></td>\
				<td style="vertical-align:center;height:8px;width:13px;background-image:url(\'img/tooltip_bottom-trans.png\');background-repeat:no-repeat;"></td>\
				<td style="height:8px;" id="' + self.id + 'fltooltipp_to_resize2"></td>\
				<td style="height:8px;width:10px;"></td>\
			</tr>\
		</table>';
		$('the_body').appendChild(container);
		var widthOfText = $(self.id + 'fltooltipp').getWidth();
		if (Prototype.Browser.IE7) {
			widthOfText = 100;
		}

		$(self.id + 'fltooltipp_to_resize1').style.width = Math.floor((widthOfText - 33)/2) + 'px';
		$(self.id + 'fltooltipp_to_resize2').style.width = Math.floor((widthOfText - 33)/2) + 'px';
		recalc_ie7();
}

/**
	@description does show the tooltip. 
	@private
 */
tooltipp.prototype.msmove = function(/** int */newx , /** int */newy) {
	var self = this;
	var widthOfText = $(self.id + 'fltooltipp').getWidth();
	if (Prototype.Browser.IE7) {
		widthOfText = 100;
	}
	$(self.id + 'fltooltipp').setStyle({'left' : (newx - (widthOfText/2)) + 'px'});
	$(self.id + 'fltooltipp').setStyle({'top' : (newy - 29) + 'px'});
}

/**
	@description does show the tooltip. 
	@private
 */
tooltipp.prototype.show = function() {
	var self = this;
	self.isvisible = true;
	if (Prototype.Browser.IE) {
		$(self.id + 'fltooltipp').style.display = 'block';
	} else {
		new Effect.Appear(self.id + 'fltooltipp' , {duration : 0.2});
	}
}

/**
	@description does hide the tooltip, and remove the html from the document afterwards
	@private
 */
tooltipp.prototype.hide_and_remove = function() {
	var self = this;
	if (self.isvisible) {
		self.isvisible = false;
		if (Prototype.Browser.IE) {
			$(self.id + 'fltooltipp').style.display = 'none';
			$(self.id + 'fltooltipp').remove();
		} else {
			new Effect.Fade(self.id + 'fltooltipp' , {
				duration : 0.2 , 
				afterFinish:function(){
					$(self.id + 'fltooltipp').remove();
				}
			});
		}
	}
}

/**
	@description does hide and remove the tooltip.
	@private
 */
tooltipp.prototype.hide = function() {
	var self = this;
	if (self.isvisible) {
		self.isvisible = false;
		new Effect.Fade(self.id + 'fltooltipp' , {duration : 0.2});
	}
}

/**
    @description remove the tooltipp from the DOM tree
	@private
 */
tooltipp.prototype.removeit = function() {
	var self = this;
	$(self.id + 'fltooltipp').remove();
}
var did_rate_movie_width_id = new Array();

/**
    @class a flrating display item 
    @author Micha Surber, futureLAB AG
    @constructor
	@private
 */
function flrating() {
	var self = this;
	self.value = 0;
	self.votable = false;
	self.movieId = 0;
	self.updateHandler = 0;
}

flrating.prototype.setValue = function(/** float */ newValue) {
	var self = this;
	self.value = newValue;
}

flrating.prototype.setMovieId = function(/** float */ newValue) {
	var self = this;
	self.movieId = newValue;
}

flrating.prototype.setUpdateHandler = function(/** function */ func) {
	var self = this;
	self.updateHandler = func;
}

flrating.prototype.enableVoting = function(/** boolean */ newValue) {
	var self = this;
	self.votable = newValue;
	$('rating' + self.renderingId).observe('click' , function(event) {
		var mousex = event.pointerX();
		/* the left margin seems to influence the rating calculation so we just add 5 to the value of the left coordinate */
		var originx = ($('rating' + self.renderingId).cumulativeOffset().left) + 5;
		var diff = mousex - originx;
		var flvalue = 1 + Math.round(diff / 14);
		console.log('value was: ' + flvalue);
		if (!(did_rate_movie_width_id[self.movieId])) {
			var params = {
						'movie':self.movieId,
						'value':flvalue
					};
			new Ajax.Request('/data/addrating', { 
				method:'post', 
				parameters : params,
				onSuccess: function(transport){
					var res = transport.responseText.evalJSON(false);
					console.log('response = ' , res);
					console.log('avg = ' + res.avg);
					self.updateValue(res.avg);
					console.log('updateHandler = ' , self.updateHandler);
					if (self.updateHandler) {
						self.updateHandler(res.count , res.avg);
					}
				}
			});		
			did_rate_movie_width_id[self.movieId] = true;
		} else {
			console.log('this user seems to try influencing the rating of the movie...  rating it over and over again! :-) ');
		}
	});

	$('rating' + self.renderingId).observe('mousemove' , function(event) {
		var mousex = event.pointerX();
		/* the left margin seems to influence the rating calculation so we just add 5 to the value of the left coordinate */
		var originx = ($('rating' + self.renderingId).cumulativeOffset().left) + 5;
		var diff = mousex - originx;
		var flvalue = 1 + Math.round(diff / 14);
		console.log('value was: ' + flvalue);
		if (!(did_rate_movie_width_id[self.movieId])) {
			if (flvalue > 5) {
				flvalue = 5;
			}
			$('ratingover' + self.renderingId).setStyle({'width' : flvalue * 14 + 'px'});
		} else {
			console.log('did already rate the movie. No mouse over effect anymore');
		}
	});

	$('rating' + self.renderingId).observe('mouseout' , function(event) {
		$('ratingover' + self.renderingId).setStyle({'width' : '0px'});
	});

}

flrating.prototype.updateValue = function(/** int */ newValue) {
	var self = this;
	self.value = newValue;
	var width = Math.round(self.value) * 14;
	$('ratinggood' + self.renderingId).setStyle({'width' : width + 'px'});
	/* we try to update the rating component of the view here. */
	/* the additional_screens javascript class adds a 'overlay' to the id of the rating component
	   so we try to just remove this string from the id, and assume that the view does use the movie id as 
	   the id of the rating component */
	var parts = self.renderingId.split('overlay');
	var viewRating = $('ratinggood' + parts[0] );
	if (viewRating) {
		viewRating.setStyle({'width' : width + 'px'});
	}
}

/**
    @description this function does construct the html elements used for the ratin display component. 
	@public
	@return the generated dom element
	@param id the id of the element
 */
flrating.prototype.render = function(/** string */ id) {
	var self = this;
	self.renderingId = id;
	
	var div = new Element('div' , {'id' : 'rating' + id , 'class' : 'rating_container' , 'style' : 'position:relative;'});
	
	var dots = new Element('div' , {'id' : 'ratingnone' + id , 'class' : 'rating_none' , 'style' : 'position:absolute;left:0px;top:0px;width:70px;height:12px;'});
	div.appendChild(dots);
	
	var width = Math.round(self.value) * 14;
	var stars = new Element('div' , {'id' : 'ratinggood' + id , 'class' : 'rating_good' , 'style' : 'position:absolute;left:0px;top:0px;height:12px;width:' + width + 'px;'});
	div.appendChild(stars);

	var over = new Element('div' , {'id' : 'ratingover' + id , 'class' : 'rating_over' , 'style' : 'position:absolute;left:0px;top:0px;height:12px;width:0px;'});
	div.appendChild(over);
	
	return div;
}
/* globals for old js classes */
var ddh;
var sh;
var resize_handler;
var slider;
var screen_handler;
var search_while_typing = false;

/* the view slider controll js function */
var number_of_steps_in_x_direction_to_move = 0;
var current_move_position = 0;
var view_is_moving = false;

var moving_step = -118;
var initial_moving_position = 0;

function move_view(direction) {
	if (!(view_is_moving)) {
		var tmp = current_move_position;
		current_move_position = current_move_position + direction;
		if (current_move_position < 0 || current_move_position > number_of_steps_in_x_direction_to_move) {
			current_move_position = tmp;
		} else {
			var x_dir = moving_step * direction;
			view_is_moving = true;
			new Effect.MoveBy($('viewSelectorContainer'), 0 , x_dir , {duration:0.5 , afterFinish:function(e){view_is_moving = false;}});
		}
	}
}
/* end of the view slider controll js function */

/* js code to show and hide the drop down menus */
var cat_menu;
var rang_menu;
var random_item;
var allItem;
var searchItem;
var func_visible = false;

function show_func() {
	if (!(func_visible)) {
		$('funcdropdown').style.display = 'block';
		func_visible = true;
	}
}
function hide_all() {
	cat_menu.hide();
	rang_menu.hide();
	if (func_visible) {
		$('funcdropdown').style.display = 'none';
		func_visible = false;
	}
}

var view_tooltip_strings = new Array();
var view_tooltips = new Array();
var history_manager_disabled = false;
var Y;

function init() {

	var dimensions = getWindowSize();
	var ws = dimensions.width;
	var hs = dimensions.height;

	$('the_body').setStyle({'margin' : '0px'});
	
	
	var loading_img = $('loading_logo2');
	loading_img.src = "img/loading_bar_02.gif?hack=" + new Date().getTime();

	YUI({combine: true, timeout: 10000}).use('history', function(Y) {
		initWithY(Y);
	});
}

var view_alt_imgs = new Array();
var view_imgs = new Array();

var timedMovieId = '';
function timedMovieDetail() {
	if (last_search_movies && (last_search_movies.length > 0)) {
		screen_handler.show_details_of_movie_yui(timedMovieId);
	} else {
		setTimeout('timedMovieDetail()' , 200);
	}
}

function initWithY(theY) {
	Y = theY;
	
	var bookmarkedState = Y.History.getBookmarkedState("swissmadetv"); 
	var initialState = bookmarkedState || "BU";
	
	ddh = new default_data_handler();
	sh = new search_handler();
	resize_handler = new window_resize_handler();	
	slider = new main_menu_slider();
	screen_handler = new additional_screens();
	
	function updateSwissmadetv(state) {
		if (!history_manager_disabled) {
			console.log('state = ' , state);
			if (state == 'about') {
				screen_handler.show_about_yui();
			} else {
				var stateParts = state.split('BU');
				if (stateParts[1].length > 0) {
					/* its a movie id */
					if (last_search_movies && (last_search_movies.length > 0)) {
						screen_handler.show_details_of_movie_yui(stateParts[1]);
					} else {
						/* we did not search movies jet. */
						timedMovieId = stateParts[1];
						setTimeout('timedMovieDetail()' , 200);
					}
				} else {
					/* its a view id */
					screen_handler.hide_overlay_yui();
				}
			}
		}
	}
	
	Y.History.register("swissmadetv", initialState).subscribe( "history:moduleStateChange", updateSwissmadetv);

	Y.History.subscribe("history:ready", function () {
		var currentState = Y.History.getCurrentState("swissmadetv");
		updateSwissmadetv(currentState);
	});
	
	Y.History.initialize('#yui-history-field', '#yui-history-iframe');

	/* fill the view selector div with the view icons */
	
	var views = ddh.get_views();
	var slider_container = $('viewSelectorContainer');
	if (views.length > 4) {
		number_of_steps_in_x_direction_to_move = views.length - 4;
	}
	for (var i = 0; i < views.length ; i++) {
		var container = new Element('div', {'id' : views[i].id + 'container'});
		container.addClassName('vs_viewContainer')
		slider_container.appendChild(container);
		var img = new Element('img' , {'src' : views[i].icon , 'id' : 'view_icon' + views[i].id , 'width' : 96 , 'height' : 58});
		view_tooltip_strings['view_icon' + views[i].id] = views[i].title;
		img.addClassName('vs_viewIcon');
		img.observe('click' , function() {
			var theId = this.id.substring(9 , this.id.length );
			sh.set_view(theId);
		});

		view_alt_imgs['view_icon' + views[i].id] = views[i].overicon
		view_imgs['view_icon' + views[i].id] = views[i].icon;

		img.observe('mouseover' , function(ev) {
			
			var ele = ev.element();
			var offset = ele.cumulativeOffset();
			var tstring = view_tooltip_strings[ele.id];
			if (tstring) {
				view_tooltips[ele.id] = greate_tooltipp(tstring , offset.left/1 + 50 , offset.top/1 - 1);
			}
			$(ele).setStyle({'opacity' : '1'});
			if (view_alt_imgs[ele.id]) {
				$(ele).writeAttribute({'src' : view_alt_imgs[ele.id]});
			}
		});
		img.observe('mouseout' , function(ev) {
			var ele = ev.element();
			if (view_tooltips[ele.id]) {
				view_tooltips[ele.id].hide_and_remove();
			}
			if (!($(ele).parentNode.id == 'selected_view')) {
				$(ele).setStyle({'opacity' : '0.5'});
			}
			if (view_alt_imgs[ele.id]) {
				$(ele).writeAttribute({'src' : view_imgs[ele.id]});
			}
		});
		container.appendChild(img);
		$('view_icon' + views[i].id).setStyle({'opacity' : '0.5'});
	}
	
	/* end of filling the view selector div with the view icons */
	
	rang_menu = new dropdown_order('rang');
	var rangs = ddh.get_flat_orders();
	for (var i = 0; i < rangs.length ; i++) {
		rang_menu.addItem(rangs[i]);
	}
	sh.register_new_condition(0 , rang_menu);
	rang_menu.render();
	/* an example on how to use the set_items_inactive method of the drop down menuee. 
	   setting 'newest_des' and 'view_count_des' to inactive and 'random' to the default value. */
	/*rang_menu.set_items_inactive(['newest_des' , 'view_count_des'] , 'random');*/
	
	
	/* fill the 'kanal' drop down menue with the real values */
	cat_menu = new dropdown_category('kanal');
	var cats = ddh.get_categories();
	for (var i = 0; i < cats.length ; i++) {
		cat_menu.addItem(cats[i]);
	}	
	cat_menu.render();
	sh.set_category_obj(cat_menu);
	/* end of filling the 'kanal' drop down menue with the real values */

	/* generate the dynamic random button */
	/*random_item = new button('random');
	random_item.setOnclickHandler(function(){sh.set_random();});
	random_item.render();
	sh.set_random_obj(random_item);*/
	
	/* generate the dynamic all button */
	allItem = new button('all');
	allItem.setOnclickHandler(function(){sh.set_all();});
	allItem.render();
	sh.set_all_obj(allItem);
	
	searchItem = new search_field();
	searchItem.render();
	sh.set_search_obj(searchItem);

	/*allItem.highlight();*/
	sh.set_all();
	
	

	/* add mouseover events to the drop down menues to avoid removing them when mouse is over */
	Event.observe('funcdropdown' , 'mouseover' , function(event) {
		Event.stop(event);
	});
	Event.observe('rangdropdown' , 'mouseover' , function(event) {
		Event.stop(event);
	});
	Event.observe('the_view_container' , 'mouseover' , function(event){
		hide_all();
	});

	/*sh.set_view('flview1');*/ /* Map */
	sh.set_view('flview1'); 
		
	/*hide_waiting_screen();*/
	setTimeout('hide_waiting_screen()' , 4000);
}

function hide_waiting_screen() {
	$('loading_logo1').style.display = 'none';
	$('loading_logo2').style.display = 'none';
	if (Prototype.Browser.IE) {
		$('waiting').style.display = 'none';
		sh.activate();
	} else {
		new Effect.Fade('waiting' , {
			duration : 1,
			afterFinish:function(e){
				sh.activate();
			}
		});
	}
}
/*
CSS Browser Selector v0.3.1
Rafael Lima (http://rafael.adm.br)
http://rafael.adm.br/css_browser_selector
License: http://creativecommons.org/licenses/by/2.5/
Contributors: http://rafael.adm.br/css_browser_selector#contributors
*/
function css_browser_selector(u){var ua = u.toLowerCase(),is=function(t){return ua.indexOf(t)>-1;},g='gecko',w='webkit',s='safari',h=document.getElementsByTagName('html')[0],b=[(!(/opera|webtv/i.test(ua))&&/msie\s(\d)/.test(ua))?('ie ie'+RegExp.$1):is('firefox/2')?g+' ff2':is('firefox/3')?g+' ff3':is('gecko/')?g:/opera(\s|\/)(\d+)/.test(ua)?'opera opera'+RegExp.$2:is('konqueror')?'konqueror':is('chrome')?w+' '+s+' chrome':is('applewebkit/')?w+' '+s+(/version\/(\d+)/.test(ua)?' '+s+RegExp.$1:''):is('mozilla/')?g:'',is('j2me')?'mobile':is('iphone')?'iphone':is('ipod')?'ipod':is('mac')?'mac':is('darwin')?'mac':is('webtv')?'webtv':is('win')?'win':is('freebsd')?'freebsd':(is('x11')||is('linux'))?'linux':'','js']; c = b.join(' '); h.className += ' '+c; return c;}; css_browser_selector(navigator.userAgent);
// script.aculo.us effects.js v1.8.2, Tue Nov 18 18:30:58 +0100 2008

// Copyright (c) 2005-2008 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) {
    element = $(element);
    effect = (effect || 'appear').toLowerCase();
    var options = Object.extend({
      queue: { position:'end', scope:(element.id || 'global'), limit: 1 }
    }, arguments[2] || { });
    Effect[element.visible() ?
      Effect.PAIRS[effect][1] : Effect.PAIRS[effect][0]](element, options);
  }
};

Effect.DefaultOptions.transition = Effect.Transitions.sinoidal;

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

Effect.ScopedQueue = Class.create(Enumerable, {
  initialize: function() {
    this.effects  = [];
    this.interval = null;
  },
  _each: function(iterator) {
    this.effects._each(iterator);
  },
  add: function(effect) {
    var timestamp = new Date().getTime();

    var position = Object.isString(effect.options.queue) ?
      effect.options.queue : effect.options.queue.position;

    switch(position) {
      case 'front':
        // move unstarted effects after this effect
        this.effects.findAll(function(e){ return e.state=='idle' }).each( function(e) {
            e.startOn  += effect.finishOn;
            e.finishOn += effect.finishOn;
          });
        break;
      case 'with-last':
        timestamp = this.effects.pluck('startOn').max() || timestamp;
        break;
      case 'end':
        // start effect after last queued effect has finished
        timestamp = this.effects.pluck('finishOn').max() || timestamp;
        break;
    }

    effect.startOn  += timestamp;
    effect.finishOn += timestamp;

    if (!effect.options.queue.limit || (this.effects.length < effect.options.queue.limit))
      this.effects.push(effect);

    if (!this.interval)
      this.interval = setInterval(this.loop.bind(this), 15);
  },
  remove: function(effect) {
    this.effects = this.effects.reject(function(e) { return e==effect });
    if (this.effects.length == 0) {
      clearInterval(this.interval);
      this.interval = null;
    }
  },
  loop: function() {
    var timePos = new Date().getTime();
    for(var i=0, len=this.effects.length;i<len;i++)
      this.effects[i] && this.effects[i].loop(timePos);
  }
});

Effect.Queues = {
  instances: $H(),
  get: function(queueName) {
    if (!Object.isString(queueName)) return queueName;

    return this.instances.get(queueName) ||
      this.instances.set(queueName, new Effect.ScopedQueue());
  }
};
Effect.Queue = Effect.Queues.get('global');

Effect.Base = Class.create({
  position: null,
  start: function(options) {
    function codeForEvent(options,eventName){
      return (
        (options[eventName+'Internal'] ? 'this.options.'+eventName+'Internal(this);' : '') +
        (options[eventName] ? 'this.options.'+eventName+'(this);' : '')
      );
    }
    if (options && options.transition === false) options.transition = Effect.Transitions.linear;
    this.options      = Object.extend(Object.extend({ },Effect.DefaultOptions), options || { });
    this.currentFrame = 0;
    this.state        = 'idle';
    this.startOn      = this.options.delay*1000;
    this.finishOn     = this.startOn+(this.options.duration*1000);
    this.fromToDelta  = this.options.to-this.options.from;
    this.totalTime    = this.finishOn-this.startOn;
    this.totalFrames  = this.options.fps*this.options.duration;

    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);// script.aculo.us slider.js v1.8.2, Tue Nov 18 18:30:58 +0100 2008

// Copyright (c) 2005-2008 Marty Haught, Thomas Fuchs
//
// script.aculo.us is freely distributable under the terms of an MIT-style license.
// For details, see the script.aculo.us web site: http://script.aculo.us/

if (!Control) var Control = { };

// options:
//  axis: 'vertical', or 'horizontal' (default)
//
// callbacks:
//  onChange(value)
//  onSlide(value)
Control.Slider = Class.create({
  initialize: function(handle, track, options) {
    var slider = this;

    if (Object.isArray(handle)) {
      this.handles = handle.collect( function(e) { return $(e) });
    } else {
      this.handles = [$(handle)];
    }

    this.track   = $(track);
    this.options = options || { };

    this.axis      = this.options.axis || 'horizontal';
    this.increment = this.options.increment || 1;
    this.step      = parseInt(this.options.step || '1');
    this.range     = this.options.range || $R(0,1);

    this.value     = 0; // assure backwards compat
    this.values    = this.handles.map( function() { return 0 });
    this.spans     = this.options.spans ? this.options.spans.map(function(s){ return $(s) }) : false;
    this.options.startSpan = $(this.options.startSpan || null);
    this.options.endSpan   = $(this.options.endSpan || null);

    this.restricted = this.options.restricted || false;

    this.maximum   = this.options.maximum || this.range.end;
    this.minimum   = this.options.minimum || this.range.start;

    // Will be used to align the handle onto the track, if necessary
    this.alignX = parseInt(this.options.alignX || '0');
    this.alignY = parseInt(this.options.alignY || '0');

    this.trackLength = this.maximumOffset() - this.minimumOffset();

    this.handleLength = this.isVertical() ?
      (this.handles[0].offsetHeight != 0 ?
        this.handles[0].offsetHeight : this.handles[0].style.height.replace(/px$/,"")) :
      (this.handles[0].offsetWidth != 0 ? this.handles[0].offsetWidth :
        this.handles[0].style.width.replace(/px$/,""));

    this.active   = false;
    this.dragging = false;
    this.disabled = false;

    if (this.options.disabled) this.setDisabled();

    // Allowed values array
    this.allowedValues = this.options.values ? this.options.values.sortBy(Prototype.K) : false;
    if (this.allowedValues) {
      this.minimum = this.allowedValues.min();
      this.maximum = this.allowedValues.max();
    }

    this.eventMouseDown = this.startDrag.bindAsEventListener(this);
    this.eventMouseUp   = this.endDrag.bindAsEventListener(this);
    this.eventMouseMove = this.update.bindAsEventListener(this);

    // Initialize handles in reverse (make sure first handle is active)
    this.handles.each( function(h,i) {
      i = slider.handles.length-1-i;
      slider.setValue(parseFloat(
        (Object.isArray(slider.options.sliderValue) ?
          slider.options.sliderValue[i] : slider.options.sliderValue) ||
         slider.range.start), i);
      h.makePositioned().observe("mousedown", slider.eventMouseDown);
    });

    this.track.observe("mousedown", this.eventMouseDown);
    document.observe("mouseup", this.eventMouseUp);
    document.observe("mousemove", this.eventMouseMove);

    this.initialized = true;
  },
  dispose: function() {
    var slider = this;
    Event.stopObserving(this.track, "mousedown", this.eventMouseDown);
    Event.stopObserving(document, "mouseup", this.eventMouseUp);
    Event.stopObserving(document, "mousemove", this.eventMouseMove);
    this.handles.each( function(h) {
      Event.stopObserving(h, "mousedown", slider.eventMouseDown);
    });
  },
  setDisabled: function(){
    this.disabled = true;
  },
  setEnabled: function(){
    this.disabled = false;
  },
  getNearestValue: function(value){
    if (this.allowedValues){
      if (value >= this.allowedValues.max()) return(this.allowedValues.max());
      if (value <= this.allowedValues.min()) return(this.allowedValues.min());

      var offset = Math.abs(this.allowedValues[0] - value);
      var newValue = this.allowedValues[0];
      this.allowedValues.each( function(v) {
        var currentOffset = Math.abs(v - value);
        if (currentOffset <= offset){
          newValue = v;
          offset = currentOffset;
        }
      });
      return newValue;
    }
    if (value > this.range.end) return this.range.end;
    if (value < this.range.start) return this.range.start;
    return value;
  },
  setValue: function(sliderValue, handleIdx){
    if (!this.active) {
      this.activeHandleIdx = handleIdx || 0;
      this.activeHandle    = this.handles[this.activeHandleIdx];
      this.updateStyles();
    }
    handleIdx = handleIdx || this.activeHandleIdx || 0;
    if (this.initialized && this.restricted) {
      if ((handleIdx>0) && (sliderValue<this.values[handleIdx-1]))
        sliderValue = this.values[handleIdx-1];
      if ((handleIdx < (this.handles.length-1)) && (sliderValue>this.values[handleIdx+1]))
        sliderValue = this.values[handleIdx+1];
    }
    sliderValue = this.getNearestValue(sliderValue);
    this.values[handleIdx] = sliderValue;
    this.value = this.values[0]; // assure backwards compat

    this.handles[handleIdx].style[this.isVertical() ? 'top' : 'left'] =
      this.translateToPx(sliderValue);

    this.drawSpans();
    if (!this.dragging || !this.event) this.updateFinished();
  },
  setValueBy: function(delta, handleIdx) {
    this.setValue(this.values[handleIdx || this.activeHandleIdx || 0] + delta,
      handleIdx || this.activeHandleIdx || 0);
  },
  translateToPx: function(value) {
    return Math.round(
      ((this.trackLength-this.handleLength)/(this.range.end-this.range.start)) *
      (value - this.range.start)) + "px";
  },
  translateToValue: function(offset) {
    return ((offset/(this.trackLength-this.handleLength) *
      (this.range.end-this.range.start)) + this.range.start);
  },
  getRange: function(range) {
    var v = this.values.sortBy(Prototype.K);
    range = range || 0;
    return $R(v[range],v[range+1]);
  },
  minimumOffset: function(){
    return(this.isVertical() ? this.alignY : this.alignX);
  },
  maximumOffset: function(){
    return(this.isVertical() ?
      (this.track.offsetHeight != 0 ? this.track.offsetHeight :
        this.track.style.height.replace(/px$/,"")) - this.alignY :
      (this.track.offsetWidth != 0 ? this.track.offsetWidth :
        this.track.style.width.replace(/px$/,"")) - this.alignX);
  },
  isVertical:  function(){
    return (this.axis == 'vertical');
  },
  drawSpans: function() {
    var slider = this;
    if (this.spans)
      $R(0, this.spans.length-1).each(function(r) { slider.setSpan(slider.spans[r], slider.getRange(r)) });
    if (this.options.startSpan)
      this.setSpan(this.options.startSpan,
        $R(0, this.values.length>1 ? this.getRange(0).min() : this.value ));
    if (this.options.endSpan)
      this.setSpan(this.options.endSpan,
        $R(this.values.length>1 ? this.getRange(this.spans.length-1).max() : this.value, this.maximum));
  },
  setSpan: function(span, range) {
    if (this.isVertical()) {
      span.style.top = this.translateToPx(range.start);
      span.style.height = this.translateToPx(range.end - range.start + this.range.start);
    } else {
      span.style.left = this.translateToPx(range.start);
      span.style.width = this.translateToPx(range.end - range.start + this.range.start);
    }
  },
  updateStyles: function() {
    this.handles.each( function(h){ Element.removeClassName(h, 'selected') });
    Element.addClassName(this.activeHandle, 'selected');
  },
  startDrag: function(event) {
    if (Event.isLeftClick(event)) {
      if (!this.disabled){
        this.active = true;

        var handle = Event.element(event);
        var pointer  = [Event.pointerX(event), Event.pointerY(event)];
        var track = handle;
        if (track==this.track) {
          var offsets  = Position.cumulativeOffset(this.track);
          this.event = event;
          this.setValue(this.translateToValue(
           (this.isVertical() ? pointer[1]-offsets[1] : pointer[0]-offsets[0])-(this.handleLength/2)
          ));
          var offsets  = Position.cumulativeOffset(this.activeHandle);
          this.offsetX = (pointer[0] - offsets[0]);
          this.offsetY = (pointer[1] - offsets[1]);
        } else {
          // find the handle (prevents issues with Safari)
          while((this.handles.indexOf(handle) == -1) && handle.parentNode)
            handle = handle.parentNode;

          if (this.handles.indexOf(handle)!=-1) {
            this.activeHandle    = handle;
            this.activeHandleIdx = this.handles.indexOf(this.activeHandle);
            this.updateStyles();

            var offsets  = Position.cumulativeOffset(this.activeHandle);
            this.offsetX = (pointer[0] - offsets[0]);
            this.offsetY = (pointer[1] - offsets[1]);
          }
        }
      }
      Event.stop(event);
    }
  },
  update: function(event) {
   if (this.active) {
      if (!this.dragging) this.dragging = true;
      this.draw(event);
      if (Prototype.Browser.WebKit) window.scrollBy(0,0);
      Event.stop(event);
   }
  },
  draw: function(event) {
    var pointer = [Event.pointerX(event), Event.pointerY(event)];
    var offsets = Position.cumulativeOffset(this.track);
    pointer[0] -= this.offsetX + offsets[0];
    pointer[1] -= this.offsetY + offsets[1];
    this.event = event;
    this.setValue(this.translateToValue( this.isVertical() ? pointer[1] : pointer[0] ));
    if (this.initialized && this.options.onSlide)
      this.options.onSlide(this.values.length>1 ? this.values : this.value, this);
  },
  endDrag: function(event) {
    if (this.active && this.dragging) {
      this.finishDrag(event, true);
      Event.stop(event);
    }
    this.active = false;
    this.dragging = false;
  },
  finishDrag: function(event, success) {
    this.active = false;
    this.dragging = false;
    this.updateFinished();
  },
  updateFinished: function() {
    if (this.initialized && this.options.onChange)
      this.options.onChange(this.values.length>1 ? this.values : this.value, this);
    this.event = null;
  }
});// script.aculo.us controls.js v1.8.2, Tue Nov 18 18:30:58 +0100 2008

// Copyright (c) 2005-2008 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
//           (c) 2005-2008 Ivan Krstic (http://blogs.law.harvard.edu/ivan)
//           (c) 2005-2008 Jon Tirsen (http://www.tirsen.com)
// Contributors:
//  Richard Livsey
//  Rahul Bhargava
//  Rob Wills
//
// script.aculo.us is freely distributable under the terms of an MIT-style license.
// For details, see the script.aculo.us web site: http://script.aculo.us/

// Autocompleter.Base handles all the autocompletion functionality
// that's independent of the data source for autocompletion. This
// includes drawing the autocompletion menu, observing keyboard
// and mouse events, and similar.
//
// Specific autocompleters need to provide, at the very least,
// a getUpdatedChoices function that will be invoked every time
// the text inside the monitored textbox changes. This method
// should get the text for which to provide autocompletion by
// invoking this.getToken(), NOT by directly accessing
// this.element.value. This is to allow incremental tokenized
// autocompletion. Specific auto-completion logic (AJAX, etc)
// belongs in getUpdatedChoices.
//
// Tokenized incremental autocompletion is enabled automatically
// when an autocompleter is instantiated with the 'tokens' option
// in the options parameter, e.g.:
// new Ajax.Autocompleter('id','upd', '/url/', { tokens: ',' });
// will incrementally autocomplete with a comma as the token.
// Additionally, ',' in the above example can be replaced with
// a token array, e.g. { tokens: [',', '\n'] } which
// enables autocompletion on multiple tokens. This is most
// useful when one of the tokens is \n (a newline), as it
// allows smart autocompletion after linebreaks.

if(typeof Effect == 'undefined')
  throw("controls.js requires including script.aculo.us' effects.js library");

var Autocompleter = { };
Autocompleter.Base = Class.create({
  baseInitialize: function(element, update, options) {
    element          = $(element);
    this.element     = element;
    this.update      = $(update);
    this.hasFocus    = false;
    this.changed     = false;
    this.active      = false;
    this.index       = 0;
    this.entryCount  = 0;
    this.oldElementValue = this.element.value;

    if(this.setOptions)
      this.setOptions(options);
    else
      this.options = options || { };

    this.options.paramName    = this.options.paramName || this.element.name;
    this.options.tokens       = this.options.tokens || [];
    this.options.frequency    = this.options.frequency || 0.4;
    this.options.minChars     = this.options.minChars || 1;
    this.options.onShow       = this.options.onShow ||
      function(element, update){
        if(!update.style.position || update.style.position=='absolute') {
          update.style.position = 'absolute';
          Position.clone(element, update, {
            setHeight: false,
            offsetTop: element.offsetHeight
          });
        }
        Effect.Appear(update,{duration:0.15});
      };
    this.options.onHide = this.options.onHide ||
      function(element, update){ new Effect.Fade(update,{duration:0.15}) };

    if(typeof(this.options.tokens) == 'string')
      this.options.tokens = new Array(this.options.tokens);
    // Force carriage returns as token delimiters anyway
    if (!this.options.tokens.include('\n'))
      this.options.tokens.push('\n');

    this.observer = null;

    this.element.setAttribute('autocomplete','off');

    Element.hide(this.update);

    Event.observe(this.element, 'blur', this.onBlur.bindAsEventListener(this));
    Event.observe(this.element, 'keydown', this.onKeyPress.bindAsEventListener(this));
  },

  show: function() {
    if(Element.getStyle(this.update, 'display')=='none') this.options.onShow(this.element, this.update);
    if(!this.iefix &&
      (Prototype.Browser.IE) &&
      (Element.getStyle(this.update, 'position')=='absolute')) {
      new Insertion.After(this.update,
       '<iframe id="' + this.update.id + '_iefix" '+
       'style="display:none;position:absolute;filter:progid:DXImageTransform.Microsoft.Alpha(opacity=0);" ' +
       'src="javascript:false;" frameborder="0" scrolling="no"></iframe>');
      this.iefix = $(this.update.id+'_iefix');
    }
    if(this.iefix) setTimeout(this.fixIEOverlapping.bind(this), 50);
  },

  fixIEOverlapping: function() {
    Position.clone(this.update, this.iefix, {setTop:(!this.update.style.height)});
    this.iefix.style.zIndex = 1;
    this.update.style.zIndex = 2;
    Element.show(this.iefix);
  },

  hide: function() {
    this.stopIndicator();
    if(Element.getStyle(this.update, 'display')!='none') this.options.onHide(this.element, this.update);
    if(this.iefix) Element.hide(this.iefix);
  },

  startIndicator: function() {
    if(this.options.indicator) Element.show(this.options.indicator);
  },

  stopIndicator: function() {
    if(this.options.indicator) Element.hide(this.options.indicator);
  },

  onKeyPress: function(event) {
    if(this.active)
      switch(event.keyCode) {
       case Event.KEY_TAB:
       case Event.KEY_RETURN:
         this.selectEntry();
         Event.stop(event);
       case Event.KEY_ESC:
         this.hide();
         this.active = false;
         Event.stop(event);
         return;
       case Event.KEY_LEFT:
       case Event.KEY_RIGHT:
         return;
       case Event.KEY_UP:
         this.markPrevious();
         this.render();
         Event.stop(event);
         return;
       case Event.KEY_DOWN:
         this.markNext();
         this.render();
         Event.stop(event);
         return;
      }
     else
       if(event.keyCode==Event.KEY_TAB || event.keyCode==Event.KEY_RETURN ||
         (Prototype.Browser.WebKit > 0 && event.keyCode == 0)) return;

    this.changed = true;
    this.hasFocus = true;

    if(this.observer) clearTimeout(this.observer);
      this.observer =
        setTimeout(this.onObserverEvent.bind(this), this.options.frequency*1000);
  },

  activate: function() {
    this.changed = false;
    this.hasFocus = true;
    this.getUpdatedChoices();
  },

  onHover: function(event) {
    var element = Event.findElement(event, 'LI');
    if(this.index != element.autocompleteIndex)
    {
        this.index = element.autocompleteIndex;
        this.render();
    }
    Event.stop(event);
  },

  onClick: function(event) {
    var element = Event.findElement(event, 'LI');
    this.index = element.autocompleteIndex;
    this.selectEntry();
    this.hide();
  },

  onBlur: function(event) {
    // needed to make click events working
    setTimeout(this.hide.bind(this), 250);
    this.hasFocus = false;
    this.active = false;
  },

  render: function() {
    if(this.entryCount > 0) {
      for (var i = 0; i < this.entryCount; i++)
        this.index==i ?
          Element.addClassName(this.getEntry(i),"selected") :
          Element.removeClassName(this.getEntry(i),"selected");
      if(this.hasFocus) {
        this.show();
        this.active = true;
      }
    } else {
      this.active = false;
      this.hide();
    }
  },

  markPrevious: function() {
    if(this.index > 0) this.index--;
      else this.index = this.entryCount-1;
    this.getEntry(this.index).scrollIntoView(true);
  },

  markNext: function() {
    if(this.index < this.entryCount-1) this.index++;
      else this.index = 0;
    this.getEntry(this.index).scrollIntoView(false);
  },

  getEntry: function(index) {
    return this.update.firstChild.childNodes[index];
  },

  getCurrentEntry: function() {
    return this.getEntry(this.index);
  },

  selectEntry: function() {
    this.active = false;
    this.updateElement(this.getCurrentEntry());
  },

  updateElement: function(selectedElement) {
    if (this.options.updateElement) {
      this.options.updateElement(selectedElement);
      return;
    }
    var value = '';
    if (this.options.select) {
      var nodes = $(selectedElement).select('.' + this.options.select) || [];
      if(nodes.length>0) value = Element.collectTextNodes(nodes[0], this.options.select);
    } else
      value = Element.collectTextNodesIgnoreClass(selectedElement, 'informal');

    var bounds = this.getTokenBounds();
    if (bounds[0] != -1) {
      var newValue = this.element.value.substr(0, bounds[0]);
      var whitespace = this.element.value.substr(bounds[0]).match(/^\s+/);
      if (whitespace)
        newValue += whitespace[0];
      this.element.value = newValue + value + this.element.value.substr(bounds[1]);
    } else {
      this.element.value = value;
    }
    this.oldElementValue = this.element.value;
    this.element.focus();

    if (this.options.afterUpdateElement)
      this.options.afterUpdateElement(this.element, selectedElement);
  },

  updateChoices: function(choices) {
    if(!this.changed && this.hasFocus) {
      this.update.innerHTML = choices;
      Element.cleanWhitespace(this.update);
      Element.cleanWhitespace(this.update.down());

      if(this.update.firstChild && this.update.down().childNodes) {
        this.entryCount =
          this.update.down().childNodes.length;
        for (var i = 0; i < this.entryCount; i++) {
          var entry = this.getEntry(i);
          entry.autocompleteIndex = i;
          this.addObservers(entry);
        }
      } else {
        this.entryCount = 0;
      }

      this.stopIndicator();
      this.index = 0;

      if(this.entryCount==1 && this.options.autoSelect) {
        this.selectEntry();
        this.hide();
      } else {
        this.render();
      }
    }
  },

  addObservers: function(element) {
    Event.observe(element, "mouseover", this.onHover.bindAsEventListener(this));
    Event.observe(element, "click", this.onClick.bindAsEventListener(this));
  },

  onObserverEvent: function() {
    this.changed = false;
    this.tokenBounds = null;
    if(this.getToken().length>=this.options.minChars) {
      this.getUpdatedChoices();
    } else {
      this.active = false;
      this.hide();
    }
    this.oldElementValue = this.element.value;
  },

  getToken: function() {
    var bounds = this.getTokenBounds();
    return this.element.value.substring(bounds[0], bounds[1]).strip();
  },

  getTokenBounds: function() {
    if (null != this.tokenBounds) return this.tokenBounds;
    var value = this.element.value;
    if (value.strip().empty()) return [-1, 0];
    var diff = arguments.callee.getFirstDifferencePos(value, this.oldElementValue);
    var offset = (diff == this.oldElementValue.length ? 1 : 0);
    var prevTokenPos = -1, nextTokenPos = value.length;
    var tp;
    for (var index = 0, l = this.options.tokens.length; index < l; ++index) {
      tp = value.lastIndexOf(this.options.tokens[index], diff + offset - 1);
      if (tp > prevTokenPos) prevTokenPos = tp;
      tp = value.indexOf(this.options.tokens[index], diff + offset);
      if (-1 != tp && tp < nextTokenPos) nextTokenPos = tp;
    }
    return (this.tokenBounds = [prevTokenPos + 1, nextTokenPos]);
  }
});

Autocompleter.Base.prototype.getTokenBounds.getFirstDifferencePos = function(newS, oldS) {
  var boundary = Math.min(newS.length, oldS.length);
  for (var index = 0; index < boundary; ++index)
    if (newS[index] != oldS[index])
      return index;
  return boundary;
};

Ajax.Autocompleter = Class.create(Autocompleter.Base, {
  initialize: function(element, update, url, options) {
    this.baseInitialize(element, update, options);
    this.options.asynchronous  = true;
    this.options.onComplete    = this.onComplete.bind(this);
    this.options.defaultParams = this.options.parameters || null;
    this.url                   = url;
  },

  getUpdatedChoices: function() {
    this.startIndicator();

    var entry = encodeURIComponent(this.options.paramName) + '=' +
      encodeURIComponent(this.getToken());

    this.options.parameters = this.options.callback ?
      this.options.callback(this.element, entry) : entry;

    if(this.options.defaultParams)
      this.options.parameters += '&' + this.options.defaultParams;

    new Ajax.Request(this.url, this.options);
  },

  onComplete: function(request) {
    this.updateChoices(request.responseText);
  }
});

// The local array autocompleter. Used when you'd prefer to
// inject an array of autocompletion options into the page, rather
// than sending out Ajax queries, which can be quite slow sometimes.
//
// The constructor takes four parameters. The first two are, as usual,
// the id of the monitored textbox, and id of the autocompletion menu.
// The third is the array you want to autocomplete from, and the fourth
// is the options block.
//
// Extra local autocompletion options:
// - choices - How many autocompletion choices to offer
//
// - partialSearch - If false, the autocompleter will match entered
//                    text only at the beginning of strings in the
//                    autocomplete array. Defaults to true, which will
//                    match text at the beginning of any *word* in the
//                    strings in the autocomplete array. If you want to
//                    search anywhere in the string, additionally set
//                    the option fullSearch to true (default: off).
//
// - fullSsearch - Search anywhere in autocomplete array strings.
//
// - partialChars - How many characters to enter before triggering
//                   a partial match (unlike minChars, which defines
//                   how many characters are required to do any match
//                   at all). Defaults to 2.
//
// - ignoreCase - Whether to ignore case when autocompleting.
//                 Defaults to true.
//
// It's possible to pass in a custom function as the 'selector'
// option, if you prefer to write your own autocompletion logic.
// In that case, the other options above will not apply unless
// you support them.

Autocompleter.Local = Class.create(Autocompleter.Base, {
  initialize: function(element, update, array, options) {
    this.baseInitialize(element, update, options);
    this.options.array = array;
  },

  getUpdatedChoices: function() {
    this.updateChoices(this.options.selector(this));
  },

  setOptions: function(options) {
    this.options = Object.extend({
      choices: 10,
      partialSearch: true,
      partialChars: 2,
      ignoreCase: true,
      fullSearch: false,
      selector: function(instance) {
        var ret       = []; // Beginning matches
        var partial   = []; // Inside matches
        var entry     = instance.getToken();
        var count     = 0;

        for (var i = 0; i < instance.options.array.length &&
          ret.length < instance.options.choices ; i++) {

          var elem = instance.options.array[i];
          var foundPos = instance.options.ignoreCase ?
            elem.toLowerCase().indexOf(entry.toLowerCase()) :
            elem.indexOf(entry);

          while (foundPos != -1) {
            if (foundPos == 0 && elem.length != entry.length) {
              ret.push("<li><strong>" + elem.substr(0, entry.length) + "</strong>" +
                elem.substr(entry.length) + "</li>");
              break;
            } else if (entry.length >= instance.options.partialChars &&
              instance.options.partialSearch && foundPos != -1) {
              if (instance.options.fullSearch || /\s/.test(elem.substr(foundPos-1,1))) {
                partial.push("<li>" + elem.substr(0, foundPos) + "<strong>" +
                  elem.substr(foundPos, entry.length) + "</strong>" + elem.substr(
                  foundPos + entry.length) + "</li>");
                break;
              }
            }

            foundPos = instance.options.ignoreCase ?
              elem.toLowerCase().indexOf(entry.toLowerCase(), foundPos + 1) :
              elem.indexOf(entry, foundPos + 1);

          }
        }
        if (partial.length)
          ret = ret.concat(partial.slice(0, instance.options.choices - ret.length));
        return "<ul>" + ret.join('') + "</ul>";
      }
    }, options || { });
  }
});

// AJAX in-place editor and collection editor
// Full rewrite by Christophe Porteneuve <tdd@tddsworld.com> (April 2007).

// Use this if you notice weird scrolling problems on some browsers,
// the DOM might be a bit confused when this gets called so do this
// waits 1 ms (with setTimeout) until it does the activation
Field.scrollFreeActivate = function(field) {
  setTimeout(function() {
    Field.activate(field);
  }, 1);
};

Ajax.InPlaceEditor = Class.create({
  initialize: function(element, url, options) {
    this.url = url;
    this.element = element = $(element);
    this.prepareOptions();
    this._controls = { };
    arguments.callee.dealWithDeprecatedOptions(options); // DEPRECATION LAYER!!!
    Object.extend(this.options, options || { });
    if (!this.options.formId && this.element.id) {
      this.options.formId = this.element.id + '-inplaceeditor';
      if ($(this.options.formId))
        this.options.formId = '';
    }
    if (this.options.externalControl)
      this.options.externalControl = $(this.options.externalControl);
    if (!this.options.externalControl)
      this.options.externalControlOnly = false;
    this._originalBackground = this.element.getStyle('background-color') || 'transparent';
    this.element.title = this.options.clickToEditText;
    this._boundCancelHandler = this.handleFormCancellation.bind(this);
    this._boundComplete = (this.options.onComplete || Prototype.emptyFunction).bind(this);
    this._boundFailureHandler = this.handleAJAXFailure.bind(this);
    this._boundSubmitHandler = this.handleFormSubmission.bind(this);
    this._boundWrapperHandler = this.wrapUp.bind(this);
    this.registerListeners();
  },
  checkForEscapeOrReturn: function(e) {
    if (!this._editing || e.ctrlKey || e.altKey || e.shiftKey) return;
    if (Event.KEY_ESC == e.keyCode)
      this.handleFormCancellation(e);
    else if (Event.KEY_RETURN == e.keyCode)
      this.handleFormSubmission(e);
  },
  createControl: function(mode, handler, extraClasses) {
    var control = this.options[mode + 'Control'];
    var text = this.options[mode + 'Text'];
    if ('button' == control) {
      var btn = document.createElement('input');
      btn.type = 'submit';
      btn.value = text;
      btn.className = 'editor_' + mode + '_button';
      if ('cancel' == mode)
        btn.onclick = this._boundCancelHandler;
      this._form.appendChild(btn);
      this._controls[mode] = btn;
    } else if ('link' == control) {
      var link = document.createElement('a');
      link.href = '#';
      link.appendChild(document.createTextNode(text));
      link.onclick = 'cancel' == mode ? this._boundCancelHandler : this._boundSubmitHandler;
      link.className = 'editor_' + mode + '_link';
      if (extraClasses)
        link.className += ' ' + extraClasses;
      this._form.appendChild(link);
      this._controls[mode] = link;
    }
  },
  createEditField: function() {
    var text = (this.options.loadTextURL ? this.options.loadingText : this.getText());
    var fld;
    if (1 >= this.options.rows && !/\r|\n/.test(this.getText())) {
      fld = document.createElement('input');
      fld.type = 'text';
      var size = this.options.size || this.options.cols || 0;
      if (0 < size) fld.size = size;
    } else {
      fld = document.createElement('textarea');
      fld.rows = (1 >= this.options.rows ? this.options.autoRows : this.options.rows);
      fld.cols = this.options.cols || 40;
    }
    fld.name = this.options.paramName;
    fld.value = text; // No HTML breaks conversion anymore
    fld.className = 'editor_field';
    if (this.options.submitOnBlur)
      fld.onblur = this._boundSubmitHandler;
    this._controls.editor = fld;
    if (this.options.loadTextURL)
      this.loadExternalText();
    this._form.appendChild(this._controls.editor);
  },
  createForm: function() {
    var ipe = this;
    function addText(mode, condition) {
      var text = ipe.options['text' + mode + 'Controls'];
      if (!text || condition === false) return;
      ipe._form.appendChild(document.createTextNode(text));
    };
    this._form = $(document.createElement('form'));
    this._form.id = this.options.formId;
    this._form.addClassName(this.options.formClassName);
    this._form.onsubmit = this._boundSubmitHandler;
    this.createEditField();
    if ('textarea' == this._controls.editor.tagName.toLowerCase())
      this._form.appendChild(document.createElement('br'));
    if (this.options.onFormCustomization)
      this.options.onFormCustomization(this, this._form);
    addText('Before', this.options.okControl || this.options.cancelControl);
    this.createControl('ok', this._boundSubmitHandler);
    addText('Between', this.options.okControl && this.options.cancelControl);
    this.createControl('cancel', this._boundCancelHandler, 'editor_cancel');
    addText('After', this.options.okControl || this.options.cancelControl);
  },
  destroy: function() {
    if (this._oldInnerHTML)
      this.element.innerHTML = this._oldInnerHTML;
    this.leaveEditMode();
    this.unregisterListeners();
  },
  enterEditMode: function(e) {
    if (this._saving || this._editing) return;
    this._editing = true;
    this.triggerCallback('onEnterEditMode');
    if (this.options.externalControl)
      this.options.externalControl.hide();
    this.element.hide();
    this.createForm();
    this.element.parentNode.insertBefore(this._form, this.element);
    if (!this.options.loadTextURL)
      this.postProcessEditField();
    if (e) Event.stop(e);
  },
  enterHover: function(e) {
    if (this.options.hoverClassName)
      this.element.addClassName(this.options.hoverClassName);
    if (this._saving) return;
    this.triggerCallback('onEnterHover');
  },
  getText: function() {
    return this.element.innerHTML.unescapeHTML();
  },
  handleAJAXFailure: function(transport) {
    this.triggerCallback('onFailure', transport);
    if (this._oldInnerHTML) {
      this.element.innerHTML = this._oldInnerHTML;
      this._oldInnerHTML = null;
    }
  },
  handleFormCancellation: function(e) {
    this.wrapUp();
    if (e) Event.stop(e);
  },
  handleFormSubmission: function(e) {
    var form = this._form;
    var value = $F(this._controls.editor);
    this.prepareSubmission();
    var params = this.options.callback(form, value) || '';
    if (Object.isString(params))
      params = params.toQueryParams();
    params.editorId = this.element.id;
    if (this.options.htmlResponse) {
      var options = Object.extend({ evalScripts: true }, this.options.ajaxOptions);
      Object.extend(options, {
        parameters: params,
        onComplete: this._boundWrapperHandler,
        onFailure: this._boundFailureHandler
      });
      new Ajax.Updater({ success: this.element }, this.url, options);
    } else {
      var options = Object.extend({ method: 'get' }, this.options.ajaxOptions);
      Object.extend(options, {
        parameters: params,
        onComplete: this._boundWrapperHandler,
        onFailure: this._boundFailureHandler
      });
      new Ajax.Request(this.url, options);
    }
    if (e) Event.stop(e);
  },
  leaveEditMode: function() {
    this.element.removeClassName(this.options.savingClassName);
    this.removeForm();
    this.leaveHover();
    this.element.style.backgroundColor = this._originalBackground;
    this.element.show();
    if (this.options.externalControl)
      this.options.externalControl.show();
    this._saving = false;
    this._editing = false;
    this._oldInnerHTML = null;
    this.triggerCallback('onLeaveEditMode');
  },
  leaveHover: function(e) {
    if (this.options.hoverClassName)
      this.element.removeClassName(this.options.hoverClassName);
    if (this._saving) return;
    this.triggerCallback('onLeaveHover');
  },
  loadExternalText: function() {
    this._form.addClassName(this.options.loadingClassName);
    this._controls.editor.disabled = true;
    var options = Object.extend({ method: 'get' }, this.options.ajaxOptions);
    Object.extend(options, {
      parameters: 'editorId=' + encodeURIComponent(this.element.id),
      onComplete: Prototype.emptyFunction,
      onSuccess: function(transport) {
        this._form.removeClassName(this.options.loadingClassName);
        var text = transport.responseText;
        if (this.options.stripLoadedTextTags)
          text = text.stripTags();
        this._controls.editor.value = text;
        this._controls.editor.disabled = false;
        this.postProcessEditField();
      }.bind(this),
      onFailure: this._boundFailureHandler
    });
    new Ajax.Request(this.options.loadTextURL, options);
  },
  postProcessEditField: function() {
    var fpc = this.options.fieldPostCreation;
    if (fpc)
      $(this._controls.editor)['focus' == fpc ? 'focus' : 'activate']();
  },
  prepareOptions: function() {
    this.options = Object.clone(Ajax.InPlaceEditor.DefaultOptions);
    Object.extend(this.options, Ajax.InPlaceEditor.DefaultCallbacks);
    [this._extraDefaultOptions].flatten().compact().each(function(defs) {
      Object.extend(this.options, defs);
    }.bind(this));
  },
  prepareSubmission: function() {
    this._saving = true;
    this.removeForm();
    this.leaveHover();
    this.showSaving();
  },
  registerListeners: function() {
    this._listeners = { };
    var listener;
    $H(Ajax.InPlaceEditor.Listeners).each(function(pair) {
      listener = this[pair.value].bind(this);
      this._listeners[pair.key] = listener;
      if (!this.options.externalControlOnly)
        this.element.observe(pair.key, listener);
      if (this.options.externalControl)
        this.options.externalControl.observe(pair.key, listener);
    }.bind(this));
  },
  removeForm: function() {
    if (!this._form) return;
    this._form.remove();
    this._form = null;
    this._controls = { };
  },
  showSaving: function() {
    this._oldInnerHTML = this.element.innerHTML;
    this.element.innerHTML = this.options.savingText;
    this.element.addClassName(this.options.savingClassName);
    this.element.style.backgroundColor = this._originalBackground;
    this.element.show();
  },
  triggerCallback: function(cbName, arg) {
    if ('function' == typeof this.options[cbName]) {
      this.options[cbName](this, arg);
    }
  },
  unregisterListeners: function() {
    $H(this._listeners).each(function(pair) {
      if (!this.options.externalControlOnly)
        this.element.stopObserving(pair.key, pair.value);
      if (this.options.externalControl)
        this.options.externalControl.stopObserving(pair.key, pair.value);
    }.bind(this));
  },
  wrapUp: function(transport) {
    this.leaveEditMode();
    // Can't use triggerCallback due to backward compatibility: requires
    // binding + direct element
    this._boundComplete(transport, this.element);
  }
});

Object.extend(Ajax.InPlaceEditor.prototype, {
  dispose: Ajax.InPlaceEditor.prototype.destroy
});

Ajax.InPlaceCollectionEditor = Class.create(Ajax.InPlaceEditor, {
  initialize: function($super, element, url, options) {
    this._extraDefaultOptions = Ajax.InPlaceCollectionEditor.DefaultOptions;
    $super(element, url, options);
  },

  createEditField: function() {
    var list = document.createElement('select');
    list.name = this.options.paramName;
    list.size = 1;
    this._controls.editor = list;
    this._collection = this.options.collection || [];
    if (this.options.loadCollectionURL)
      this.loadCollection();
    else
      this.checkForExternalText();
    this._form.appendChild(this._controls.editor);
  },

  loadCollection: function() {
    this._form.addClassName(this.options.loadingClassName);
    this.showLoadingText(this.options.loadingCollectionText);
    var options = Object.extend({ method: 'get' }, this.options.ajaxOptions);
    Object.extend(options, {
      parameters: 'editorId=' + encodeURIComponent(this.element.id),
      onComplete: Prototype.emptyFunction,
      onSuccess: function(transport) {
        var js = transport.responseText.strip();
        if (!/^\[.*\]$/.test(js)) // TODO: improve sanity check
          throw('Server returned an invalid collection representation.');
        this._collection = eval(js);
        this.checkForExternalText();
      }.bind(this),
      onFailure: this.onFailure
    });
    new Ajax.Request(this.options.loadCollectionURL, options);
  },

  showLoadingText: function(text) {
    this._controls.editor.disabled = true;
    var tempOption = this._controls.editor.firstChild;
    if (!tempOption) {
      tempOption = document.createElement('option');
      tempOption.value = '';
      this._controls.editor.appendChild(tempOption);
      tempOption.selected = true;
    }
    tempOption.update((text || '').stripScripts().stripTags());
  },

  checkForExternalText: function() {
    this._text = this.getText();
    if (this.options.loadTextURL)
      this.loadExternalText();
    else
      this.buildOptionList();
  },

  loadExternalText: function() {
    this.showLoadingText(this.options.loadingText);
    var options = Object.extend({ method: 'get' }, this.options.ajaxOptions);
    Object.extend(options, {
      parameters: 'editorId=' + encodeURIComponent(this.element.id),
      onComplete: Prototype.emptyFunction,
      onSuccess: function(transport) {
        this._text = transport.responseText.strip();
        this.buildOptionList();
      }.bind(this),
      onFailure: this.onFailure
    });
    new Ajax.Request(this.options.loadTextURL, options);
  },

  buildOptionList: function() {
    this._form.removeClassName(this.options.loadingClassName);
    this._collection = this._collection.map(function(entry) {
      return 2 === entry.length ? entry : [entry, entry].flatten();
    });
    var marker = ('value' in this.options) ? this.options.value : this._text;
    var textFound = this._collection.any(function(entry) {
      return entry[0] == marker;
    }.bind(this));
    this._controls.editor.update('');
    var option;
    this._collection.each(function(entry, index) {
      option = document.createElement('option');
      option.value = entry[0];
      option.selected = textFound ? entry[0] == marker : 0 == index;
      option.appendChild(document.createTextNode(entry[1]));
      this._controls.editor.appendChild(option);
    }.bind(this));
    this._controls.editor.disabled = false;
    Field.scrollFreeActivate(this._controls.editor);
  }
});

//**** DEPRECATION LAYER FOR InPlace[Collection]Editor! ****
//**** This only  exists for a while,  in order to  let ****
//**** users adapt to  the new API.  Read up on the new ****
//**** API and convert your code to it ASAP!            ****

Ajax.InPlaceEditor.prototype.initialize.dealWithDeprecatedOptions = function(options) {
  if (!options) return;
  function fallback(name, expr) {
    if (name in options || expr === undefined) return;
    options[name] = expr;
  };
  fallback('cancelControl', (options.cancelLink ? 'link' : (options.cancelButton ? 'button' :
    options.cancelLink == options.cancelButton == false ? false : undefined)));
  fallback('okControl', (options.okLink ? 'link' : (options.okButton ? 'button' :
    options.okLink == options.okButton == false ? false : undefined)));
  fallback('highlightColor', options.highlightcolor);
  fallback('highlightEndColor', options.highlightendcolor);
};

Object.extend(Ajax.InPlaceEditor, {
  DefaultOptions: {
    ajaxOptions: { },
    autoRows: 3,                                // Use when multi-line w/ rows == 1
    cancelControl: 'link',                      // 'link'|'button'|false
    cancelText: 'cancel',
    clickToEditText: 'Click to edit',
    externalControl: null,                      // id|elt
    externalControlOnly: false,
    fieldPostCreation: 'activate',              // 'activate'|'focus'|false
    formClassName: 'inplaceeditor-form',
    formId: null,                               // id|elt
    highlightColor: '#ffff99',
    highlightEndColor: '#ffffff',
    hoverClassName: '',
    htmlResponse: true,
    loadingClassName: 'inplaceeditor-loading',
    loadingText: 'Loading...',
    okControl: 'button',                        // 'link'|'button'|false
    okText: 'ok',
    paramName: 'value',
    rows: 1,                                    // If 1 and multi-line, uses autoRows
    savingClassName: 'inplaceeditor-saving',
    savingText: 'Saving...',
    size: 0,
    stripLoadedTextTags: false,
    submitOnBlur: false,
    textAfterControls: '',
    textBeforeControls: '',
    textBetweenControls: ''
  },
  DefaultCallbacks: {
    callback: function(form) {
      return Form.serialize(form);
    },
    onComplete: function(transport, element) {
      // For backward compatibility, this one is bound to the IPE, and passes
      // the element directly.  It was too often customized, so we don't break it.
      new Effect.Highlight(element, {
        startcolor: this.options.highlightColor, keepBackgroundImage: true });
    },
    onEnterEditMode: null,
    onEnterHover: function(ipe) {
      ipe.element.style.backgroundColor = ipe.options.highlightColor;
      if (ipe._effect)
        ipe._effect.cancel();
    },
    onFailure: function(transport, ipe) {
      alert('Error communication with the server: ' + transport.responseText.stripTags());
    },
    onFormCustomization: null, // Takes the IPE and its generated form, after editor, before controls.
    onLeaveEditMode: null,
    onLeaveHover: function(ipe) {
      ipe._effect = new Effect.Highlight(ipe.element, {
        startcolor: ipe.options.highlightColor, endcolor: ipe.options.highlightEndColor,
        restorecolor: ipe._originalBackground, keepBackgroundImage: true
      });
    }
  },
  Listeners: {
    click: 'enterEditMode',
    keydown: 'checkForEscapeOrReturn',
    mouseover: 'enterHover',
    mouseout: 'leaveHover'
  }
});

Ajax.InPlaceCollectionEditor.DefaultOptions = {
  loadingCollectionText: 'Loading options...'
};

// Delayed observer, like Form.Element.Observer,
// but waits for delay after last key input
// Ideal for live-search fields

Form.Element.DelayedObserver = Class.create({
  initialize: function(element, delay, callback) {
    this.delay     = delay || 0.5;
    this.element   = $(element);
    this.callback  = callback;
    this.timer     = null;
    this.lastValue = $F(this.element);
    Event.observe(this.element,'keyup',this.delayedListener.bindAsEventListener(this));
  },
  delayedListener: function(event) {
    if(this.lastValue == $F(this.element)) return;
    if(this.timer) clearTimeout(this.timer);
    this.timer = setTimeout(this.onTimerEvent.bind(this), this.delay * 1000);
    this.lastValue = $F(this.element);
  },
  onTimerEvent: function() {
    this.timer = null;
    this.callback(this.element, $F(this.element));
  }
});/* 
 * flowplayer.js 3.2.6. The Flowplayer API
 * 
 * Copyright 2009-2011 Flowplayer Oy
 * 
 * This file is part of Flowplayer.
 * 
 * Flowplayer is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * Flowplayer is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with Flowplayer.  If not, see <http://www.gnu.org/licenses/>.
 * 
 * Date: 2011-02-04 05:45:28 -0500 (Fri, 04 Feb 2011)
 * Revision: 614 
 */
(function(){function g(o){console.log("$f.fireEvent",[].slice.call(o))}function k(q){if(!q||typeof q!="object"){return q}var o=new q.constructor();for(var p in q){if(q.hasOwnProperty(p)){o[p]=k(q[p])}}return o}function m(t,q){if(!t){return}var o,p=0,r=t.length;if(r===undefined){for(o in t){if(q.call(t[o],o,t[o])===false){break}}}else{for(var s=t[0];p<r&&q.call(s,p,s)!==false;s=t[++p]){}}return t}function c(o){return document.getElementById(o)}function i(q,p,o){if(typeof p!="object"){return q}if(q&&p){m(p,function(r,s){if(!o||typeof s!="function"){q[r]=s}})}return q}function n(s){var q=s.indexOf(".");if(q!=-1){var p=s.slice(0,q)||"*";var o=s.slice(q+1,s.length);var r=[];m(document.getElementsByTagName(p),function(){if(this.className&&this.className.indexOf(o)!=-1){r.push(this)}});return r}}function f(o){o=o||window.event;if(o.preventDefault){o.stopPropagation();o.preventDefault()}else{o.returnValue=false;o.cancelBubble=true}return false}function j(q,o,p){q[o]=q[o]||[];q[o].push(p)}function e(){return"_"+(""+Math.random()).slice(2,10)}var h=function(t,r,s){var q=this,p={},u={};q.index=r;if(typeof t=="string"){t={url:t}}i(this,t,true);m(("Begin*,Start,Pause*,Resume*,Seek*,Stop*,Finish*,LastSecond,Update,BufferFull,BufferEmpty,BufferStop").split(","),function(){var v="on"+this;if(v.indexOf("*")!=-1){v=v.slice(0,v.length-1);var w="onBefore"+v.slice(2);q[w]=function(x){j(u,w,x);return q}}q[v]=function(x){j(u,v,x);return q};if(r==-1){if(q[w]){s[w]=q[w]}if(q[v]){s[v]=q[v]}}});i(this,{onCuepoint:function(x,w){if(arguments.length==1){p.embedded=[null,x];return q}if(typeof x=="number"){x=[x]}var v=e();p[v]=[x,w];if(s.isLoaded()){s._api().fp_addCuepoints(x,r,v)}return q},update:function(w){i(q,w);if(s.isLoaded()){s._api().fp_updateClip(w,r)}var v=s.getConfig();var x=(r==-1)?v.clip:v.playlist[r];i(x,w,true)},_fireEvent:function(v,y,w,A){if(v=="onLoad"){m(p,function(B,C){if(C[0]){s._api().fp_addCuepoints(C[0],r,B)}});return false}A=A||q;if(v=="onCuepoint"){var z=p[y];if(z){return z[1].call(s,A,w)}}if(y&&"onBeforeBegin,onMetaData,onStart,onUpdate,onResume".indexOf(v)!=-1){i(A,y);if(y.metaData){if(!A.duration){A.duration=y.metaData.duration}else{A.fullDuration=y.metaData.duration}}}var x=true;m(u[v],function(){x=this.call(s,A,y,w)});return x}});if(t.onCuepoint){var o=t.onCuepoint;q.onCuepoint.apply(q,typeof o=="function"?[o]:o);delete t.onCuepoint}m(t,function(v,w){if(typeof w=="function"){j(u,v,w);delete t[v]}});if(r==-1){s.onCuepoint=this.onCuepoint}};var l=function(p,r,q,t){var o=this,s={},u=false;if(t){i(s,t)}m(r,function(v,w){if(typeof w=="function"){s[v]=w;delete r[v]}});i(this,{animate:function(y,z,x){if(!y){return o}if(typeof z=="function"){x=z;z=500}if(typeof y=="string"){var w=y;y={};y[w]=z;z=500}if(x){var v=e();s[v]=x}if(z===undefined){z=500}r=q._api().fp_animate(p,y,z,v);return o},css:function(w,x){if(x!==undefined){var v={};v[w]=x;w=v}r=q._api().fp_css(p,w);i(o,r);return o},show:function(){this.display="block";q._api().fp_showPlugin(p);return o},hide:function(){this.display="none";q._api().fp_hidePlugin(p);return o},toggle:function(){this.display=q._api().fp_togglePlugin(p);return o},fadeTo:function(y,x,w){if(typeof x=="function"){w=x;x=500}if(w){var v=e();s[v]=w}this.display=q._api().fp_fadeTo(p,y,x,v);this.opacity=y;return o},fadeIn:function(w,v){return o.fadeTo(1,w,v)},fadeOut:function(w,v){return o.fadeTo(0,w,v)},getName:function(){return p},getPlayer:function(){return q},_fireEvent:function(w,v,x){if(w=="onUpdate"){var z=q._api().fp_getPlugin(p);if(!z){return}i(o,z);delete o.methods;if(!u){m(z.methods,function(){var B=""+this;o[B]=function(){var C=[].slice.call(arguments);var D=q._api().fp_invoke(p,B,C);return D==="undefined"||D===undefined?o:D}});u=true}}var A=s[w];if(A){var y=A.apply(o,v);if(w.slice(0,1)=="_"){delete s[w]}return y}return o}})};function b(q,G,t){var w=this,v=null,D=false,u,s,F=[],y={},x={},E,r,p,C,o,A;i(w,{id:function(){return E},isLoaded:function(){return(v!==null&&v.fp_play!==undefined&&!D)},getParent:function(){return q},hide:function(H){if(H){q.style.height="0px"}if(w.isLoaded()){v.style.height="0px"}return w},show:function(){q.style.height=A+"px";if(w.isLoaded()){v.style.height=o+"px"}return w},isHidden:function(){return w.isLoaded()&&parseInt(v.style.height,10)===0},load:function(J){if(!w.isLoaded()&&w._fireEvent("onBeforeLoad")!==false){var H=function(){u=q.innerHTML;if(u&&!flashembed.isSupported(G.version)){q.innerHTML=""}if(J){J.cached=true;j(x,"onLoad",J)}flashembed(q,G,{config:t})};var I=0;m(a,function(){this.unload(function(K){if(++I==a.length){H()}})})}return w},unload:function(J){if(this.isFullscreen()&&/WebKit/i.test(navigator.userAgent)){if(J){J(false)}return w}if(u.replace(/\s/g,"")!==""){if(w._fireEvent("onBeforeUnload")===false){if(J){J(false)}return w}D=true;try{if(v){v.fp_close();w._fireEvent("onUnload")}}catch(H){}var I=function(){v=null;q.innerHTML=u;D=false;if(J){J(true)}};setTimeout(I,50)}else{if(J){J(false)}}return w},getClip:function(H){if(H===undefined){H=C}return F[H]},getCommonClip:function(){return s},getPlaylist:function(){return F},getPlugin:function(H){var J=y[H];if(!J&&w.isLoaded()){var I=w._api().fp_getPlugin(H);if(I){J=new l(H,I,w);y[H]=J}}return J},getScreen:function(){return w.getPlugin("screen")},getControls:function(){return w.getPlugin("controls")._fireEvent("onUpdate")},getLogo:function(){try{return w.getPlugin("logo")._fireEvent("onUpdate")}catch(H){}},getPlay:function(){return w.getPlugin("play")._fireEvent("onUpdate")},getConfig:function(H){return H?k(t):t},getFlashParams:function(){return G},loadPlugin:function(K,J,M,L){if(typeof M=="function"){L=M;M={}}var I=L?e():"_";w._api().fp_loadPlugin(K,J,M,I);var H={};H[I]=L;var N=new l(K,null,w,H);y[K]=N;return N},getState:function(){return w.isLoaded()?v.fp_getState():-1},play:function(I,H){var J=function(){if(I!==undefined){w._api().fp_play(I,H)}else{w._api().fp_play()}};if(w.isLoaded()){J()}else{if(D){setTimeout(function(){w.play(I,H)},50)}else{w.load(function(){J()})}}return w},getVersion:function(){var I="flowplayer.js 3.2.6";if(w.isLoaded()){var H=v.fp_getVersion();H.push(I);return H}return I},_api:function(){if(!w.isLoaded()){throw"Flowplayer "+w.id()+" not loaded when calling an API method"}return v},setClip:function(H){w.setPlaylist([H]);return w},getIndex:function(){return p},_swfHeight:function(){return v.clientHeight}});m(("Click*,Load*,Unload*,Keypress*,Volume*,Mute*,Unmute*,PlaylistReplace,ClipAdd,Fullscreen*,FullscreenExit,Error,MouseOver,MouseOut").split(","),function(){var H="on"+this;if(H.indexOf("*")!=-1){H=H.slice(0,H.length-1);var I="onBefore"+H.slice(2);w[I]=function(J){j(x,I,J);return w}}w[H]=function(J){j(x,H,J);return w}});m(("pause,resume,mute,unmute,stop,toggle,seek,getStatus,getVolume,setVolume,getTime,isPaused,isPlaying,startBuffering,stopBuffering,isFullscreen,toggleFullscreen,reset,close,setPlaylist,addClip,playFeed,setKeyboardShortcutsEnabled,isKeyboardShortcutsEnabled").split(","),function(){var H=this;w[H]=function(J,I){if(!w.isLoaded()){return w}var K=null;if(J!==undefined&&I!==undefined){K=v["fp_"+H](J,I)}else{K=(J===undefined)?v["fp_"+H]():v["fp_"+H](J)}return K==="undefined"||K===undefined?w:K}});w._fireEvent=function(Q){if(typeof Q=="string"){Q=[Q]}var R=Q[0],O=Q[1],M=Q[2],L=Q[3],K=0;if(t.debug){g(Q)}if(!w.isLoaded()&&R=="onLoad"&&O=="player"){v=v||c(r);o=w._swfHeight();m(F,function(){this._fireEvent("onLoad")});m(y,function(S,T){T._fireEvent("onUpdate")});s._fireEvent("onLoad")}if(R=="onLoad"&&O!="player"){return}if(R=="onError"){if(typeof O=="string"||(typeof O=="number"&&typeof M=="number")){O=M;M=L}}if(R=="onContextMenu"){m(t.contextMenu[O],function(S,T){T.call(w)});return}if(R=="onPluginEvent"||R=="onBeforePluginEvent"){var H=O.name||O;var I=y[H];if(I){I._fireEvent("onUpdate",O);return I._fireEvent(M,Q.slice(3))}return}if(R=="onPlaylistReplace"){F=[];var N=0;m(O,function(){F.push(new h(this,N++,w))})}if(R=="onClipAdd"){if(O.isInStream){return}O=new h(O,M,w);F.splice(M,0,O);for(K=M+1;K<F.length;K++){F[K].index++}}var P=true;if(typeof O=="number"&&O<F.length){C=O;var J=F[O];if(J){P=J._fireEvent(R,M,L)}if(!J||P!==false){P=s._fireEvent(R,M,L,J)}}m(x[R],function(){P=this.call(w,O,M);if(this.cached){x[R].splice(K,1)}if(P===false){return false}K++});return P};function B(){if($f(q)){$f(q).getParent().innerHTML="";p=$f(q).getIndex();a[p]=w}else{a.push(w);p=a.length-1}A=parseInt(q.style.height,10)||q.clientHeight;E=q.id||"fp"+e();r=G.id||E+"_api";G.id=r;t.playerId=E;if(typeof t=="string"){t={clip:{url:t}}}if(typeof t.clip=="string"){t.clip={url:t.clip}}t.clip=t.clip||{};if(q.getAttribute("href",2)&&!t.clip.url){t.clip.url=q.getAttribute("href",2)}s=new h(t.clip,-1,w);t.playlist=t.playlist||[t.clip];var I=0;m(t.playlist,function(){var K=this;if(typeof K=="object"&&K.length){K={url:""+K}}m(t.clip,function(L,M){if(M!==undefined&&K[L]===undefined&&typeof M!="function"){K[L]=M}});t.playlist[I]=K;K=new h(K,I,w);F.push(K);I++});m(t,function(K,L){if(typeof L=="function"){if(s[K]){s[K](L)}else{j(x,K,L)}delete t[K]}});m(t.plugins,function(K,L){if(L){y[K]=new l(K,L,w)}});if(!t.plugins||t.plugins.controls===undefined){y.controls=new l("controls",null,w)}y.canvas=new l("canvas",null,w);u=q.innerHTML;function J(L){var K=w.hasiPadSupport&&w.hasiPadSupport();if(/iPad|iPhone|iPod/i.test(navigator.userAgent)&&!/.flv$/i.test(F[0].url)&&!K){return true}if(!w.isLoaded()&&w._fireEvent("onBeforeClick")!==false){w.load()}return f(L)}function H(){if(u.replace(/\s/g,"")!==""){if(q.addEventListener){q.addEventListener("click",J,false)}else{if(q.attachEvent){q.attachEvent("onclick",J)}}}else{if(q.addEventListener){q.addEventListener("click",f,false)}w.load()}}setTimeout(H,0)}if(typeof q=="string"){var z=c(q);if(!z){throw"Flowplayer cannot access element: "+q}q=z;B()}else{B()}}var a=[];function d(o){this.length=o.length;this.each=function(p){m(o,p)};this.size=function(){return o.length}}window.flowplayer=window.$f=function(){var p=null;var o=arguments[0];if(!arguments.length){m(a,function(){if(this.isLoaded()){p=this;return false}});return p||a[0]}if(arguments.length==1){if(typeof o=="number"){return a[o]}else{if(o=="*"){return new d(a)}m(a,function(){if(this.id()==o.id||this.id()==o||this.getParent()==o){p=this;return false}});return p}}if(arguments.length>1){var t=arguments[1],q=(arguments.length==3)?arguments[2]:{};if(typeof t=="string"){t={src:t}}t=i({bgcolor:"#000000",version:[9,0],expressInstall:"http://static.flowplayer.org/swf/expressinstall.swf",cachebusting:false},t);if(typeof o=="string"){if(o.indexOf(".")!=-1){var s=[];m(n(o),function(){s.push(new b(this,k(t),k(q)))});return new d(s)}else{var r=c(o);return new b(r!==null?r:o,t,q)}}else{if(o){return new b(o,t,q)}}}return null};i(window.$f,{fireEvent:function(){var o=[].slice.call(arguments);var q=$f(o[0]);return q?q._fireEvent(o.slice(1)):null},addPlugin:function(o,p){b.prototype[o]=p;return $f},each:m,extend:i});if(typeof jQuery=="function"){jQuery.fn.flowplayer=function(q,p){if(!arguments.length||typeof arguments[0]=="number"){var o=[];this.each(function(){var r=$f(this);if(r){o.push(r)}});return arguments.length?o[arguments[0]]:new d(o)}return this.each(function(){$f(this,k(q),p?k(p):{})})}}})();(function(){var e=typeof jQuery=="function";var i={width:"100%",height:"100%",allowfullscreen:true,allowscriptaccess:"always",quality:"high",version:null,onFail:null,expressInstall:null,w3c:false,cachebusting:false};if(e){jQuery.tools=jQuery.tools||{};jQuery.tools.flashembed={version:"1.0.4",conf:i}}function j(){if(c.done){return false}var l=document;if(l&&l.getElementsByTagName&&l.getElementById&&l.body){clearInterval(c.timer);c.timer=null;for(var k=0;k<c.ready.length;k++){c.ready[k].call()}c.ready=null;c.done=true}}var c=e?jQuery:function(k){if(c.done){return k()}if(c.timer){c.ready.push(k)}else{c.ready=[k];c.timer=setInterval(j,13)}};function f(l,k){if(k){for(key in k){if(k.hasOwnProperty(key)){l[key]=k[key]}}}return l}function g(k){switch(h(k)){case"string":k=k.replace(new RegExp('(["\\\\])',"g"),"\\$1");k=k.replace(/^\s?(\d+)%/,"$1pct");return'"'+k+'"';case"array":return"["+b(k,function(n){return g(n)}).join(",")+"]";case"function":return'"function()"';case"object":var l=[];for(var m in k){if(k.hasOwnProperty(m)){l.push('"'+m+'":'+g(k[m]))}}return"{"+l.join(",")+"}"}return String(k).replace(/\s/g," ").replace(/\'/g,'"')}function h(l){if(l===null||l===undefined){return false}var k=typeof l;return(k=="object"&&l.push)?"array":k}if(window.attachEvent){window.attachEvent("onbeforeunload",function(){__flash_unloadHandler=function(){};__flash_savedUnloadHandler=function(){}})}function b(k,n){var m=[];for(var l in k){if(k.hasOwnProperty(l)){m[l]=n(k[l])}}return m}function a(r,t){var q=f({},r);var s=document.all;var n='<object width="'+q.width+'" height="'+q.height+'"';if(s&&!q.id){q.id="_"+(""+Math.random()).substring(9)}if(q.id){n+=' id="'+q.id+'"'}if(q.cachebusting){q.src+=((q.src.indexOf("?")!=-1?"&":"?")+Math.random())}if(q.w3c||!s){n+=' data="'+q.src+'" type="application/x-shockwave-flash"'}else{n+=' classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"'}n+=">";if(q.w3c||s){n+='<param name="movie" value="'+q.src+'" />'}q.width=q.height=q.id=q.w3c=q.src=null;for(var l in q){if(q[l]!==null){n+='<param name="'+l+'" value="'+q[l]+'" />'}}var o="";if(t){for(var m in t){if(t[m]!==null){o+=m+"="+(typeof t[m]=="object"?g(t[m]):t[m])+"&"}}o=o.substring(0,o.length-1);n+='<param name="flashvars" value=\''+o+"' />"}n+="</object>";return n}function d(m,p,l){var k=flashembed.getVersion();f(this,{getContainer:function(){return m},getConf:function(){return p},getVersion:function(){return k},getFlashvars:function(){return l},getApi:function(){return m.firstChild},getHTML:function(){return a(p,l)}});var q=p.version;var r=p.expressInstall;var o=!q||flashembed.isSupported(q);if(o){p.onFail=p.version=p.expressInstall=null;m.innerHTML=a(p,l)}else{if(q&&r&&flashembed.isSupported([6,65])){f(p,{src:r});l={MMredirectURL:location.href,MMplayerType:"PlugIn",MMdoctitle:document.title};m.innerHTML=a(p,l)}else{if(m.innerHTML.replace(/\s/g,"")!==""){}else{m.innerHTML="<h2>Flash version "+q+" or greater is required</h2><h3>"+(k[0]>0?"Your version is "+k:"You have no flash plugin installed")+"</h3>"+(m.tagName=="A"?"<p>Click here to download latest version</p>":"<p>Download latest version from <a href='http://www.adobe.com/go/getflashplayer'>here</a></p>");if(m.tagName=="A"){m.onclick=function(){location.href="http://www.adobe.com/go/getflashplayer"}}}}}if(!o&&p.onFail){var n=p.onFail.call(this);if(typeof n=="string"){m.innerHTML=n}}if(document.all){window[p.id]=document.getElementById(p.id)}}window.flashembed=function(l,m,k){if(typeof l=="string"){var n=document.getElementById(l);if(n){l=n}else{c(function(){flashembed(l,m,k)});return}}if(!l){return}if(typeof m=="string"){m={src:m}}var o=f({},i);f(o,m);return new d(l,o,k)};f(window.flashembed,{getVersion:function(){var m=[0,0];if(navigator.plugins&&typeof navigator.plugins["Shockwave Flash"]=="object"){var l=navigator.plugins["Shockwave Flash"].description;if(typeof l!="undefined"){l=l.replace(/^.*\s+(\S+\s+\S+$)/,"$1");var n=parseInt(l.replace(/^(.*)\..*$/,"$1"),10);var r=/r/.test(l)?parseInt(l.replace(/^.*r(.*)$/,"$1"),10):0;m=[n,r]}}else{if(window.ActiveXObject){try{var p=new ActiveXObject("ShockwaveFlash.ShockwaveFlash.7")}catch(q){try{p=new ActiveXObject("ShockwaveFlash.ShockwaveFlash.6");m=[6,0];p.AllowScriptAccess="always"}catch(k){if(m[0]==6){return m}}try{p=new ActiveXObject("ShockwaveFlash.ShockwaveFlash")}catch(o){}}if(typeof p=="object"){l=p.GetVariable("$version");if(typeof l!="undefined"){l=l.replace(/^\S+\s+(.*)$/,"$1").split(",");m=[parseInt(l[0],10),parseInt(l[2],10)]}}}}return m},isSupported:function(k){var m=flashembed.getVersion();var l=(m[0]>k[0])||(m[0]==k[0]&&m[1]>=k[1]);return l},domReady:c,asString:g,getHTML:a});if(e){jQuery.fn.flashembed=function(l,k){var m=null;this.each(function(){m=flashembed(this,l,k)});return l.api===false?this:m}}})();/*	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}}}}();var flview1_map_cont = 'flview1_cont';
var flview1_map = '';
var flview1_movie_store = new Array();
var flview1_zoom_slider;
var flview1_current_zoom_level = 8;

var flview1_gevent;
var flview1_markers;
var flview1_markers_html;
var flview1_bouble_height;
var flview1_title;
var flview1_tooltip;

var flview1_default_bounds = undefined;
var flview1_default_zoom = undefined;

var flview1_duplicate_movies = new Array();

var flview1_is_hidding = false;
function flview1() {
	var self = this;
	self.container_id = '';
	flview1_markers = new Array();
}

function set_width_to_300_px(img_id) {
	setTimeout("set_width_to_300_px_delay(\'" + img_id + "\');" , 200);
}

function set_width_to_300_px_delay(img_id) {
	if ($(img_id)) {
		if ($(img_id).width == 151 || $(img_id).width == 150) {
			$(img_id).setStyle({'width' : '150px' , 'left' : '0px' , 'display' : 'block'});
			$(img_id).addClassName('doooof');
		} else {
			$(img_id).setStyle({'width' : '300px' , 'left' : '0px' , 'display' : 'block'});
			$(img_id).addClassName('doooof');
		}
	} else {
		setTimeout("set_width_to_300_px_delay(\'" + img_id + "\');" , 200);
	}
}

function flview1_reset_map_buttons() {
	$('button_G_NORMAL_MAP_img').setAttribute('src' , 'img/map/karte-trans.png');
	$('button_G_SATELLITE_MAP_img').setAttribute('src' , 'img/map/stat-trans.png');
	$('button_G_HYBRID_MAP_img').setAttribute('src' , 'img/map/hybrid-trans.png');
	$('button_G_PHYSICAL_MAP_img').setAttribute('src' , 'img/map/terain-trans.png');
	button_G_NORMAL_MAP_selected = false;
	button_G_SATELLITE_MAP_selected = false;
	button_G_HYBRID_MAP_selected = false;
	button_G_PHYSICAL_MAP_selected = false;
}

var button_G_NORMAL_MAP_selected = false;
var button_G_SATELLITE_MAP_selected = false;
var button_G_HYBRID_MAP_selected = false;
var button_G_PHYSICAL_MAP_selected = true;

flview1.prototype.get_about_this_view_object = function() {
	var self = this;
	var ret_obj = {
		'author': {
			'name' : 'Micha Surber - futureLAB AG',
			'url' : 'http://www.futurelab.ch'
		},
		'design' : {
			'name' : 'Stephen England',
			'url' : null
		},
		'idea' : {
			'name' : 'NZZ - SwissMade TV',
			'url' : null
		}
	}
	return ret_obj;
}

flview1.prototype.toolbar_size_changed = function(render_in) {
	var self = this;
	/* if the toolbar size changed the view is notified here, and could get the new size using: slider.get_bottom_coordinate() */
	var new_top = slider.get_bottom_coordinate() + 10;

	if (true) {
		$('button_container').setStyle({'top' : new_top + 'px'});
		$('flview1_slider_container').setStyle({'top': new_top + 'px'});
	} else {
		new Effect.Morph('button_container' , {
			style: 'top:' + new_top + 'px;', // CSS Properties
			duration: 0.5 // Core Effect properties
		});
		/*$('button_container').setStyle({'top' : new_top + 'px'});*/
		new Effect.Morph('flview1_slider_container' , {
			style: 'top:' + new_top + 'px;', // CSS Properties
			duration: 0.5 // Core Effect properties
		});
		/*$('flview1_slider_container').setStyle({'top' : new_top + 'px'});*/
	}
}

flview1.prototype.load = function(render_in) {
	var self = this;
	self.container_id = render_in;
	
	var dimensions = getWindowSize();
	var ws = dimensions.width;
	var hs = dimensions.height;
	
	//var map_container = new Element('div' , {'class' : 'map_container' , 'id' : flview1_map_cont , 'style' : 'position:absolute;left:0px;top:0px;width:' + ws + 'px;height:' + hs + 'px;display:block;' });
	var map_container = new Element('div' , {'class' : 'map_container' , 'id' : flview1_map_cont , 'style' : 'position:absolute;left:0px;top:0px;width:100%;height:100%;display:block;background-color:#000000;' });
 	$(render_in).appendChild(map_container);

	/* setup the google map in the background */ 
	/* this is just a prove of concept until now*/
	if (GBrowserIsCompatible()) {
		flview1_map = new GMap2(document.getElementById(flview1_map_cont));
		
		flview1_map.setCenter(new GLatLng(47.136439,8.50354), (17 - flview1_current_zoom_level));
		/*flview1_map.addControl(new GSmallZoomControl());*/
		flview1_map.setMapType(G_PHYSICAL_MAP);
		
		var right_position = ($(self.container_id).getWidth() - 920)/2;
		
		var button_container = new Element('div' , {'class' : 'button_container' , 'id' : 'button_container' , 'style' :'position:absolute;left:' + (right_position + 37.0) + 'px;'});
		$(render_in).appendChild(button_container);

		var button_1 = new Element('div' , {'class' : 'flview1_button' , 'id' : 'button_G_NORMAL_MAP'});
		var dummy1 = new Element('img' , {'class' : 'button_nor_img' , 'id' : 'button_G_NORMAL_MAP_img' , 'src' : 'img/map/karte-trans.png' , 'width' : '67' , 'height' : '30'});
		button_1.appendChild(dummy1);
		button_container.appendChild(button_1);
		$('button_G_NORMAL_MAP').observe('click', function() {flview1_reset_map_buttons();button_G_NORMAL_MAP_selected = true;$('button_G_NORMAL_MAP_img').setAttribute('src' , 'img/map/karte_ac-trans.png');flview1_map.setMapType(G_NORMAL_MAP);});
		$('button_G_NORMAL_MAP').observe('mouseover', function() {
			if (!(button_G_NORMAL_MAP_selected)) {
				$('button_G_NORMAL_MAP_img').setAttribute('src' , 'img/map/karte_ho-trans.png');
			}
		});
		$('button_G_NORMAL_MAP').observe('mouseout', function() {
			if (!(button_G_NORMAL_MAP_selected)) {
				$('button_G_NORMAL_MAP_img').setAttribute('src' , 'img/map/karte-trans.png');
			}
		});
		var button_2 = new Element('div' , {'class' : 'flview1_button' , 'id' : 'button_G_SATELLITE_MAP'});
		var dummy2 = new Element('img' , {'class' : 'button_sat_img' , 'id' : 'button_G_SATELLITE_MAP_img' , 'src' : 'img/map/stat-trans.png' , 'width' : '67' , 'height' : '26'});
		button_2.appendChild(dummy2);
		button_container.appendChild(button_2);
		$('button_G_SATELLITE_MAP').observe('click' , function() {flview1_reset_map_buttons();button_G_SATELLITE_MAP_selected = true;$('button_G_SATELLITE_MAP_img').setAttribute('src' , 'img/map/sat_ac-trans.png');flview1_map.setMapType(G_SATELLITE_MAP);});
		$('button_G_SATELLITE_MAP').observe('mouseover', function() {
			if (!(button_G_SATELLITE_MAP_selected)) {
				$('button_G_SATELLITE_MAP_img').setAttribute('src' , 'img/map/sat_ho-trans.png');
			}
		});
		$('button_G_SATELLITE_MAP').observe('mouseout', function() {
			if (!(button_G_SATELLITE_MAP_selected)) {
				$('button_G_SATELLITE_MAP_img').setAttribute('src' , 'img/map/stat-trans.png');
			}
		});

		var button_3 = new Element('div' , {'class' : 'flview1_button' , 'id' : 'button_G_HYBRID_MAP'});
		var dummy3 = new Element('img' , {'class' : 'button_hyb_img' , 'id' : 'button_G_HYBRID_MAP_img' , 'src' : 'img/map/hybrid-trans.png' , 'width' : '67' , 'height' : '26'});
		button_3.appendChild(dummy3);
		button_container.appendChild(button_3);
		$('button_G_HYBRID_MAP').observe('click' , function() {flview1_reset_map_buttons();button_G_HYBRID_MAP_selected = true;$('button_G_HYBRID_MAP_img').setAttribute('src' , 'img/map/hybrid_ac-trans.png');flview1_map.setMapType(G_HYBRID_MAP);});
		$('button_G_HYBRID_MAP').observe('mouseover', function() {
			if (!(button_G_HYBRID_MAP_selected)) {
				$('button_G_HYBRID_MAP_img').setAttribute('src' , 'img/map/hybrid_ho-trans.png');
			}
		});
		$('button_G_HYBRID_MAP').observe('mouseout', function() {
			if (!(button_G_HYBRID_MAP_selected)) {
				$('button_G_HYBRID_MAP_img').setAttribute('src' , 'img/map/hybrid-trans.png');
			}
		});
	
		var button_4 = new Element('div' , {'class' : 'flview1_button' , 'id' : 'button_G_PHYSICAL_MAP'});
		var dummy4 = new Element('img' , {'class' : 'button_ter_img' , 'id' : 'button_G_PHYSICAL_MAP_img' , 'src' : 'img/map/terain_ac-trans.png' , 'width' : '67' , 'height' : '26'});
		button_4.appendChild(dummy4);
		button_container.appendChild(button_4);
		$('button_G_PHYSICAL_MAP').observe('click' , function() {flview1_reset_map_buttons();button_G_PHYSICAL_MAP_selected = true;$('button_G_PHYSICAL_MAP_img').setAttribute('src' , 'img/map/terain_ac-trans.png');flview1_map.setMapType(G_PHYSICAL_MAP);});
		$('button_G_PHYSICAL_MAP').observe('mouseover', function() {
			if (!(button_G_PHYSICAL_MAP_selected)) {
				$('button_G_PHYSICAL_MAP_img').setAttribute('src' , 'img/map/terain_ho-trans.png');
			}
		});
		$('button_G_PHYSICAL_MAP').observe('mouseout', function() {
			if (!(button_G_PHYSICAL_MAP_selected)) {
				$('button_G_PHYSICAL_MAP_img').setAttribute('src' , 'img/map/terain-trans.png');
			}
		});
		
		var button_5 = new Element('div' , {'class' : 'flview1_button_world' , 'id' : 'world_button'});
		var dummy5 = new Element('img' , {'class' : 'button_ter_img_world' , 'id' : 'world_button_img' , 'src' : 'img/map/global-trans.png' , 'width' : '67' , 'height' : '34' , 'style' : 'width:67px;height:34px;'});
		button_5.appendChild(dummy5);
		button_container.appendChild(button_5);
		$('world_button').observe('click' , function() {
			flview1_map.setCenter(new GLatLng(0,8.50354));
			flview1_zoom_slider.setValue(15);
		});
		$('world_button_img').observe('mouseover', function() {
			$('world_button_img').setAttribute('src' , 'img/map/global_ho-trans.png');
		});
		$('world_button_img').observe('mouseout', function() {
			$('world_button_img').setAttribute('src' , 'img/map/global-trans.png');
		});


		/* old implementation with a 'schweiz' button */
		/*
		var button_5 = new Element('div' , {'class' : 'flview1_button_world' , 'id' : 'world_button'});
		var dummy5 = new Element('img' , {'class' : 'button_ter_img_world' , 'id' : 'world_button_img' , 'src' : 'img/map/global2-trans.png' , 'width' : '67' , 'height' : '26'});
		button_5.appendChild(dummy5);
		button_container.appendChild(button_5);
		$('world_button').observe('click' , function() {
			flview1_zoom_slider.setValue(14);
		});
		$('world_button_img').observe('mouseover', function() {
			$('world_button_img').setAttribute('src' , 'img/map/global2_ho-trans.png');
		});
		$('world_button_img').observe('mouseout', function() {
			$('world_button_img').setAttribute('src' , 'img/map/global2-trans.png');
		});

		var button_6 = new Element('div' , {'class' : 'flview1_button_ch' , 'id' : 'ch_button'});
		var dummy6 = new Element('img' , {'class' : 'button_ter_img_ch' , 'id' : 'ch_button_img' , 'src' : 'img/map/ch-trans.png' , 'width' : '67' , 'height' : '38'});
		button_6.appendChild(dummy6);
		button_container.appendChild(button_6);
		$('ch_button').observe('click' , function() {
			flview1_zoom_slider.setValue(8);
			flview1_map.setCenter(new GLatLng(47.136439,8.50354), (17 - flview1_current_zoom_level));
		});
		$('ch_button_img').observe('mouseover', function() {
			$('ch_button_img').setAttribute('src' , 'img/map/ch_ho-trans.png');
		});
		$('ch_button_img').observe('mouseout', function() {
			$('ch_button_img').setAttribute('src' , 'img/map/ch-trans.png');
		});
		*/

		/* build up the zoom slider */
		var flview1_slider_container = new Element('div' , {'class' : 'flview1_slider_container' , 'id' : 'flview1_slider_container' , 'style' :'position:absolute;left:' + right_position + 'px;'});
		$(render_in).appendChild(flview1_slider_container);

		var slider_plus_container = new Element('div' , {'class' : 'slider_plus_container' , 'id' : 'slider_plus_container'});
		flview1_slider_container.appendChild(slider_plus_container);
		var slider_plus_img = new Element('img' , {'class' : 'slider_plus_img' , 'id' : 'slider_plus_img' , 'src' : '/img/slider_plus-trans.png'});
		slider_plus_container.appendChild(slider_plus_img);

		var slider_bar_container_div = new Element('div' , {'class' : 'slider_bar_container' , 'id' : 'slider_bar_container'});
		flview1_slider_container.appendChild(slider_bar_container_div);

		var slider_bar_container2 = new Element('img' , {'class' : 'slider_bar_container_img' , 'id' : 'slider_bar_container_img' , 'src' : '/img/slider_track-trans.png' , 'width' : '27' , 'height' : '134' , 'style' : 'width:27px;height:134px;'});
		slider_bar_container_div.appendChild(slider_bar_container2);
		var slider_bar_container3 = new Element('img' , {'class' : 'slider_handle_container' , 'id' : 'slider_handle_container' , 'src' : '/img/slider_handle-trans.png'});
		slider_bar_container_div.appendChild(slider_bar_container3);

		var slider_minus_container = new Element('div' , {'class' : 'slider_minus_container' , 'id' : 'slider_minus_container'});
		flview1_slider_container.appendChild(slider_minus_container);
		var slider_minus_img = new Element('img' , {'class' : 'slider_minus_img' , 'id' : 'slider_minus_img' , 'src' : '/img/slider_minus-trans.png'});
		slider_minus_container.appendChild(slider_minus_img);
		
		flview1_zoom_slider = new Control.Slider('slider_handle_container', 'slider_bar_container_img', {
		  axis:'vertical',
		  sliderValue: flview1_current_zoom_level,
		  range: $R(0, 15),
		  values: $R(0, 15)
		 /* alignX: -28,
		  alignY: -5,
		  disabled: true, */
		});
		
		$('slider_plus_img').observe('click' , function() {sh.view.zoomin();});
		$('slider_minus_img').observe('click' , function() {sh.view.zoomout();});

		flview1_zoom_slider.options.onChange = function(value) {
			flview1_current_zoom_level = value;
			GEvent.removeListener(flview1_gevent);
			flview1_map.setZoom(17 - flview1_current_zoom_level);
			flview1_gevent = GEvent.addListener(flview1_map,"zoomend", function(oldLevel, newLevel) {
				var tmp_zoom_value;
				if (oldLevel > newLevel) {
					tmp_zoom_value = flview1_current_zoom_level - oldLevel + newLevel;
				} else {
					tmp_zoom_value = flview1_current_zoom_level + oldLevel - newLevel;
				}
				flview1_zoom_slider.setValue(tmp_zoom_value);
			}); 
		};
		
		resize_handler.add_on_resize_handler(function() {
			var right_position = ($(self.container_id).getWidth() - 920)/2;
			if ($('flview1_slider_container')) {
				$('flview1_slider_container').setStyle({'left' : right_position + 'px'});
			}
			if ($('button_container')) {
				$('button_container').setStyle({'left' : (right_position + 37.0) + 'px'});
			}
		});
		
		flview1_gevent = GEvent.addListener(flview1_map,"zoomend", function(oldLevel, newLevel) {
			var tmp_zoom_value;
			if (oldLevel > newLevel) {
				tmp_zoom_value = flview1_current_zoom_level - oldLevel + newLevel;
			} else {
				tmp_zoom_value = flview1_current_zoom_level + oldLevel - newLevel;
			}
			flview1_zoom_slider.setValue(tmp_zoom_value);
		}); 
		
		
		recalc_ie7();
		self.toolbar_size_changed();
	}

/*	new Effect.Appear(flview1_map_cont , { 
			duration : 1.0,
			afterFinish: function() {
				sh.view_did_load();
			}
		});*/
	sh.view_did_load();
}

flview1.prototype.zoomin = function(movies) {
	var self = this;
	flview1_current_zoom_level--;
	/*flview1_map.setZoom(17 - flview1_current_zoom_level);*/
	flview1_zoom_slider.setValue(flview1_current_zoom_level);
}

flview1.prototype.zoomout = function(movies) {
	var self = this;
	flview1_current_zoom_level++;
	/*flview1_map.setZoom(17 - flview1_current_zoom_level);*/
	flview1_zoom_slider.setValue(flview1_current_zoom_level);
}


flview1.prototype.update = function(movies) {
	var self = this;
	
	if (flview1_default_bounds == undefined) {
		flview1_default_bounds = flview1_map.getBounds();
		console.log('did initialize default bounds = ' , flview1_default_bounds);
		flview1_default_zoom = flview1_map.getZoom();
		flview1_map.savePosition();
	}
	
	flview1_movie_store = movies;
	
	flview1_map.clearOverlays();
	/* performance optimization */
	if (Prototype.Browser.IE) {
		if (!Object.isUndefined(self.clusterMarker)) {
			self.clusterMarker.clearMarkers();
		}
	}

	var tinyIcon = new GIcon();
	tinyIcon.image = "http://www.swissmadetv.ch/img/map_icon_ng.png";
	tinyIcon.shadow = "http://www.swissmadetv.ch/img/map_icon_ng_shadow.png";
	tinyIcon.iconSize = new GSize(13, 28);
	tinyIcon.shadowSize = new GSize(24, 28);
	tinyIcon.iconAnchor = new GPoint(6, 28);
	tinyIcon.infoWindowAnchor = new GPoint(6, 28);
	
	var tinyIconRed;
	var number_of_red_markers = 20;
	if ((current_order_type != order_types_random) && (current_order_type != order_types_reset)) {
		tinyIconRed = new GIcon();
		tinyIconRed.image = "http://www.swissmadetv.ch/img/map_icon_red.png";
		tinyIconRed.shadow = "http://www.swissmadetv.ch/img/map_icon_ng_shadow.png";
		tinyIconRed.iconSize = new GSize(13, 28);
		tinyIconRed.shadowSize = new GSize(24, 28);
		tinyIconRed.iconAnchor = new GPoint(6, 28);
		tinyIconRed.infoWindowAnchor = new GPoint(6, 28);
		
		if (movies.length < 50 ) {
			number_of_red_markers = Math.round(movies.length / 4);
		}
	}

	flview1_markers = new Array();
	flview1_markers_html = new Array();
	flview1_bouble_height = new Array();
	flview1_title = new Array();
	
	var a_marker_is_in_range = false;
	var a_marker_is_displayed = false;
	var marker_in_switzerland = false;
	var visible_markers = new Array();
	var dimensions = getWindowSize();
	var ws = dimensions.width;
	var hs = dimensions.height;
	
	var unvisibleMarkers = new Array();
	
	var title_store = new Array();

	/* performance optimization */
	var markers_to_add = new Array();
	for (var i = 0; i < movies.length; i++) {
		var lat = movies[i].latitude;
		var lon = movies[i].longitude;
		if (lat != 0 && lon != 0 && movies[i].files.img_small) {
			a_marker_is_displayed = true;
			var point = new GLatLng(lat,lon);
			
			var pxcord = flview1_map.fromLatLngToContainerPixel(point);

			if (pxcord.x > 0 && pxcord.x < ws && pxcord.y > 0 && pxcord.y < hs) {
				a_marker_is_in_range = true;
				visible_markers.push(point);
			} else {
				unvisibleMarkers.push(point);
			}
			if (!(marker_in_switzerland) && flview1_default_bounds.containsLatLng(point)) {
				marker_in_switzerland = true;
			}
			
			var arr_id = lat/1 + lon/1;
			if (flview1_title[arr_id]) {
				console.log('dublicate movie!! title = ' + movies[i].title);
				/* replace title in tooltip with new tooltip */
				flview1_title[arr_id] = flview1_title[arr_id] + ' \u2022 ' + movies[i].title;
				/* we load the initial bouble size here */
				height = flview1_bouble_height[arr_id];
				
				var tmpString = flview1_markers_html[arr_id];
				var old_title = title_store[arr_id];
				var old_height = flview1_bouble_height[arr_id];

				/* replace title in bouble with new title */
				tmpString = tmpString.replace(old_title, '<table style="margin-top:10px;"><tr><td width="140">' + old_title + '</td><td width="15" style="text-align:center;"></td><td width="140" style="text-align:right;">' + movies[i].title + '</td></tr></table>');
				/* replace height and with of image with new height and with of image */
				var with_of_old_image = 300;
				if (Prototype.Browser.IE) {
					with_of_old_image = 301;
				}
				var with_of_new_image = 150;
				if (Prototype.Browser.IE) {
					with_of_new_image = 151;
				}
				tmpString = tmpString.replace('width:' + with_of_old_image + 'px;height:' + old_height + 'px', 'width:' + with_of_new_image + 'px;height:' + old_height/2 + 'px');
				/* replace position of movie icon with new position of movie icon */
				tmpString = tmpString.replace('left:128px', 'left:53px');
				tmpString = tmpString.replace('top:' + ((old_height - 44)/2) + 'px', 'top:' + (((old_height/2) - 44)/2) + 'px');

				/* finally add the second movie to the bouble */
				tmpString = tmpString.replace('</div></p></td></tr></table></div></div></div>' , '<img style="position:absolute;left:160px;top:0px;width:' + with_of_new_image + 'px;height:' + height/2 + 'px;cursor:pointer;" onclick="screen_handler.show_details_of_movie(flview1_movie_store['+ i + '].id);flview1_map.getInfoWindow().hide();" src="' + movies[i].files.img_small + '" style="cursor:pointer;"/><img style="width:44px;height:44px;cursor:pointer;position:absolute;left:' + (160 + ((150 - 44) /2)) + 'px;top:' + (((height/2) - 44)/2) + 'px;" onclick="screen_handler.show_details_of_movie(flview1_movie_store['+ i + '].id);" src="img/movieplaysmall-trans.png"/></div></p></td></tr></table></div></div></div>');
				
				flview1_markers_html[arr_id] = tmpString;				
			} else {
				flview1_title[arr_id] = movies[i].title;
				if (tinyIconRed && i < number_of_red_markers) {
					flview1_markers[arr_id] = new GMarker(point,tinyIconRed,false);
				} else {
					flview1_markers[arr_id] = new GMarker(point,tinyIcon,false);
				}
				var ar_parts;
				if (movies[i].aspectratio) {
					ar_parts = movies[i].aspectratio.split(':');
				} else {
					ar_parts = [4,3];
				}
				var height = 300 / (ar_parts[0] / ar_parts[1]);
				flview1_bouble_height[arr_id] = height;
	
				var bgimg = 'bouble43-trans.png';
				if (height < 170) {
					/* 16:9 */
					bgimg = 'bouble169-trans.png';
				} 
				title_store[arr_id] = movies[i].title;
				
				
				var negative_left_position = 0;
				if (Prototype.Browser.IE) {
					negative_left_position = 10;
				}
				var with_of_image = 300;
				if (Prototype.Browser.IE) {
					with_of_image = 301;
				}
	
				flview1_markers_html[arr_id] = '<div style="width:300px;height:' + (height + 50/1) + 'px;position:relative;">\
						<div style="position:absolute;left:-16px;top:-15px;width:335px;height:' + (height + 150/1) + 'px;background-image:url(\'/img/' + bgimg + '\');">\
							<div style="position:absolute;left:15px;top:15px;">\
								<table cellpadding="0" cellspacing="0" border="0"><tr><td style="color:#FFFFFF;">' + movies[i].title + '</td><td style="text-align:right;"></td></tr>\
								<tr><td colspan="2">\
									<p><div style="position:relative;">\
										<img onload="set_width_to_300_px(\'fl_view1_img' + i +'\')" id="fl_view1_img' + i + '" style="position:absolute;left:-' + negative_left_position + 'px;top:0px;width:' + with_of_image + 'px;height:' + height + 'px;cursor:pointer;" onclick="screen_handler.show_details_of_movie(flview1_movie_store['+ i + '].id);flview1_map.getInfoWindow().hide();" src="' + movies[i].files.img_small + '" style="cursor:pointer;display:none;"/>\
										<img style="width:44px;height:44px;cursor:pointer;position:absolute;left:' + ((300 - 44) /2) + 'px;top:' + ((height - 44)/2) + 'px;" onclick="screen_handler.show_details_of_movie(flview1_movie_store['+ i + '].id);flview1_map.getInfoWindow().hide();" src="img/movieplaysmall-trans.png"/>\
									</div></p></td></tr></table></div></div></div>';
	
				/* 
				Ich denke sie mgen das icon nicht... (Ich mags auch nicht...) 
				<img src="/img/fullsize.jpg" onclick="screen_handler.show_details_of_movie(flview1_movie_store['+ i + '].id);" style="position:relative;left:6px;top:13px;"/>	
				*/
	
				GEvent.addListener(flview1_markers[arr_id], "mouseover", function(cord) {
					if (!(flview1_is_hidding)) {
						var pxcord = flview1_map.fromLatLngToContainerPixel(cord);
						var arr_id = cord.lat() + cord.lng();
						if (flview1_tooltip) {
							flview1_tooltip.hide_and_remove();
						}
						flview1_tooltip = greate_tooltipp(flview1_title[arr_id] , pxcord.x , pxcord.y - 27);
						/*tooltip.show(flview1_title[arr_id]);*/
					}
				});
	
				GEvent.addListener(flview1_markers[arr_id], "mouseout", function(cord) { 
					var arr_id = cord.lat() + cord.lng(); 
					if (flview1_tooltip) {
						flview1_tooltip.hide_and_remove();
					}
					/*tooltip.hide();*/
				});
	
				GEvent.addListener(flview1_markers[arr_id], "click", function(cord) { 
					var arr_id = cord.lat() + cord.lng(); 
					var theHtml = flview1_markers_html[arr_id];
					var theMarker = flview1_markers[arr_id];
	
					theMarker.openInfoWindowHtml(theHtml);
					
					var theGPoint = flview1_map.fromLatLngToContainerPixel(theMarker.getLatLng()); 
					
					var box_height = flview1_bouble_height[arr_id] + 150;
					var top_coordinate_of_the_box = theGPoint.y - box_height;
					
					var we_need_to_pan = false;
					var pan_by_x = 0;
					var pan_by_y = 0;
					if (top_coordinate_of_the_box < 148) {
						we_need_to_pan = true;
						pan_by_y = 148 - top_coordinate_of_the_box;
						console.log('we need to move the marker down by ' , pan_by_y);
					}
					var left_coordinate_of_the_box = theGPoint.x - 125;
					var width_of_map_view = $(self.container_id).getWidth();
					var right_coordinate_of_map_controls = (width_of_map_view/2)-361;
					
					if (left_coordinate_of_the_box < right_coordinate_of_map_controls) {
						we_need_to_pan = true;
						pan_by_x = right_coordinate_of_map_controls - left_coordinate_of_the_box;
						console.log('we need to move the marker right by ' , pan_by_x);
					}
					
					if (we_need_to_pan) {
						console.log("we need to pan!");
						
						var map_center_coordinate = flview1_map.getCenter();
						var map_center_pixel = flview1_map.fromLatLngToContainerPixel(map_center_coordinate);
						
						map_center_pixel.x = map_center_pixel.x - pan_by_x;
						map_center_pixel.y = map_center_pixel.y - pan_by_y;
						
						var new_center_coordinate = flview1_map.fromContainerPixelToLatLng(map_center_pixel);
						
						/*var size_to_pan = new GSize(pan_by_x, pan_by_y);
						flview1_map.panBy(size_to_pan);*/
						flview1_map.setCenter(new_center_coordinate);
					} else {
						recalc_ie7();
					}
				});
				
				
				/* performance optimization */
				if (Prototype.Browser.IE) {
					markers_to_add.push(flview1_markers[arr_id]);
				} else {
					flview1_map.addOverlay(flview1_markers[arr_id]);
				}

			}
			//flview1_map.addOverlay(new ImageGOverlay(point , 120 -( 7 * (movies.length - i)) , image12));
		}
	}
	/* performance optimization */
	if (Prototype.Browser.IE) {
		self.clusterMarker = new MarkerClusterer(flview1_map , markers_to_add , {gridSize: 30 , styles: [{
			url: '/img/map_icon_2_ng.png',
			height: 26,
			width: 23,
			opt_anchor: [-8, 0],
			opt_textColor : 'black;'
		  },
		  /*{
			url: '/img/map_icon_3_ng.png',
			height: 30,
			width: 23,
			opt_anchor: [10, 0],
			opt_textColor : 'transparent'
		  },*/
		  {
			url: '/img/map_icon_4_ng.png',
			width: 23,
			height: 33,
			opt_anchor: [-12, 0],
			opt_textColor : 'black;'
		  },
		  {
			url: '/img/map_icon_6_ng.png',
			width: 34,
			height: 36,
			opt_anchor: [-15, 0],
			opt_textColor : 'black;'
		  },
		  {
			url: '/img/map_icon_6_ng.png',
			width: 34,
			height: 36,
			opt_anchor: [-15, 0],
			opt_textColor : 'black;'
		  }]
		});
	}

	if (marker_in_switzerland) {
		console.log('marker_in_switzerland : zoom map = ' + flview1_map.getZoom() + ' default zoom = ' , flview1_default_zoom );
	}
	/* wenn es marker in der Schweiz gibt, und wir einen grssere ansicht dargestellt haben, dann zoomen wir auf die schweiz */
	if ((marker_in_switzerland && (flview1_map.getZoom() < flview1_default_zoom)) || 
		/* wenn wir ausserhalb der schweiz sind zoomen wir in die schweiz wenn dort marker gefunden werden. */
		(!flview1_default_bounds.containsLatLng(flview1_map.getCenter()) &&  marker_in_switzerland)) {
		console.log('zooming to default view!')
		flview1_map.setCenter(new GLatLng(47.136439,8.50354));
		flview1_zoom_slider.setValue(8);
	} else {
		if (!(a_marker_is_in_range) && a_marker_is_displayed){
			console.log('no visible marker. but a marker displayed. zooming out. ');
			var currentMapBounds = new GLatLngBounds();
			currentMapBounds.extend(flview1_default_bounds.getSouthWest());
			currentMapBounds.extend(flview1_default_bounds.getNorthEast()); //;//flview1_map.getBounds();
			for (var i = 0 ; i < unvisibleMarkers.length ; i++ ) {
				currentMapBounds.extend(unvisibleMarkers[i]);
			}
			
			flview1_map.setCenter(currentMapBounds.getCenter());
			flview1_zoom_slider.setValue(17 - flview1_map.getBoundsZoomLevel(currentMapBounds));
			/* old code to zoom to world view */
			/*
			flview1_map.setCenter(new GLatLng(0,8.50354));
			flview1_zoom_slider.setValue(15);
			*/
		}
	}
	if (visible_markers.length == 1) {
		/* wir haben nur einen marker. wir behalten die aktuelle Zoomstufe, und zentrieren auf diesen Marker */
		flview1_map.setCenter(visible_markers[0]);
	}
	if (!a_marker_is_displayed) {
		screen_handler.render_alert('Es wurden keine Filme gefunden!');
	}
	/* remove old still existing tooltips */
	if (flview1_tooltip) {
		flview1_tooltip.hide_and_remove();
	}
}

/**
	@description if this function is implemented, a search request will only return the number of images returned by this function 
	@type int
	@return the number of images that can be displayed in this view
*/

/*
var search_types_text = 0;
var search_types_kanal = 1;
var search_types_random = 2;
var search_types_all = 3

var current_search_type = 3;

var order_types_relevance = 0;
var order_types_favorites = 1;
var order_types_age = 2;
var order_types_random = 3
var order_types_reset = 5;

var current_order_type = 3;
*/
flview1.prototype.maximum_movies_displayed = function(current_search_type , current_order_type) {
	var self = this;
	console.log('map view = ' , current_search_type , current_order_type);
	/*
	if (Prototype.Browser.IE) {
		return 50;
	}
	return 0;
	*/
	if (current_search_type == search_types_random) {
		return 0;
	}
	if (current_order_type == order_types_random) {
		return 0;
	}
	if (current_order_type == order_types_reset) {
		return 0;
	}
	return 0;
}


flview1.prototype.unload = function() {
	var self = this;
	flview1_is_hidding = true;
	
	if (flview1_tooltip) {
		flview1_tooltip.hide_and_remove();
	}

	$(flview1_map_cont).remove();
	flview1_is_hidding = false;
	sh.view_did_unload();
}
function flview4() {
	var self = this;
	self.container_id = '';

}

flview4.prototype.toolbar_size_changed = function(render_in) {
	var self = this;
	/* if the toolbar size changed the view is notified here, and could get the new size using: slider.get_bottom_coordinate() */	
	var nov_p = slider.get_bottom_coordinate();
	$('flview4center').setStyle({'top' : nov_p + 'px'});
}

flview4.prototype.load = function(render_in) {
	var self = this;
	self.container_id = render_in;
	
	var full = new Element('div' , {'class' : 'flview4fullsize'});
	$(render_in).appendChild(full);
	
	var center = new Element ('div' , {'class' : 'flview4center' , 'id' : 'flview4center'});
	full.appendChild(center);
	center.innerHTML = '<h2>Haben Sie eine andere Ansicht?</h2>\
		<p>MĂ¶chten Sie die Filme aufgrund ihrer Farbstimmung auswĂ€hlen kĂ¶nnen? Oder Filme finden, die Ă€hnlich sind, wie einer, der Ihnen besonders gefallen hat? Oder einen neuen Film aus den bestehenden zusammenschneiden? Alle diese Funktionen kĂ¶nnten nĂ€chste Ausbauschritte fĂŒr diese Website sein.</p>\
		<p>Vielleicht sind Sie Programmierer und mĂ¶chten selber eine neue Ansicht kreieren? Schicken  Sie einfach eine Mail mit Stichwort âSwissMadeTVâ an  <a href="mailto:tvnzz@nzz.ch">tvnzz@nzz.ch</a>, wir werden Ihnen gerne Informationen geben, wie Sie vorgehen mĂŒssen.</p>';
	/*
	center.innerHTML = '<h2>Gestalten Sie Ihre eigene Ansicht</h2>\
		<p>Programmieren Sie Ihre eigene Ansicht. Sie kĂ¶nnen das Ergebnis sofort mit unseren Filmen testen!</p>\
		<ul><li><a href="/js/docs" target="_blank">hier</a> finden Sie die Schnittstellen Beschreibung</li>\
		<li><a href="/js/views/flview2.js" target="_blank">hier</a> finden Sie eine Beispiel Ansicht</li>\
		<li><a href="/js/views/flview5.js" target="_blank">hier</a> finden Sie eine minimale Javascript Klasse, welche Sie als Basis versenden kĂ¶nnen</li></ul>\
		<p>Um Ihre Ansicht zu testen, rufen Sie die URL dieser Webseite mit follgenden Parametern auf:</p>\
		<p>http://swissmadetv.futurelab.ch/?vjs=vjs&vclass=vclass&vcss=vcss&vicon=vicon\
		<ul><li>vjs = pfad zum javascript file</li>\
		<li>vclass = name der javascript klasse</li>\
		<li>vcss = optionaler pfad zu einem css</li>\
		<li>vicon = optionaler pfad zu einem icon</li></ul>';
	*/	

	var nov_p = slider.get_bottom_coordinate();
	$('flview4center').setStyle({'top' : nov_p + 'px'});	
}

flview4.prototype.unload = function() {
	var self = this;
	sh.view_did_unload();
}


flview4.prototype.update = function(movies) {
	var self = this;
}





/**
    @class an example implementation of a view 
    @author Micha Surber, futureLAB AG
    @constructor
 */
function starfield2() {
	var self = this;
	self.container_id = '';
}

var starfield2_container = '';

/**
	@description if the size of the main menu slider changes (e.g. if a new filter is added or if the main menu slider is hidden) this function is called
*/
starfield2.prototype.toolbar_size_changed = function() {
	var self = this;	
}

/*
var search_types_text = 0;
var search_types_kanal = 1;
var search_types_random = 2;
var search_types_all = 3

var current_search_type = 3;

var order_types_relevance = 0;
var order_types_favorites = 1;
var order_types_age = 2;
var order_types_random = 3

var current_order_type = 3;
*/
/**
	@description if this function is implemented, a search request will only return the number of images returned by this function 
	@type int
	@return the number of images that can be displayed in this view
*/
starfield2.prototype.maximum_movies_displayed = function() {
	var self = this;
	/*
		old version reducing the number of items in view for search_type_random
	*/
	/*
	if (current_search_type == search_types_random) {
		return 10;
	}*/
	if (Prototype.Browser.IE6 || Prototype.Browser.IE7) {
		return 20;
	}
	return 0;
}

/**
	@description in this function the general DOM elements of a view are rendered. After the general environment is built up the view needs to call sh.view_did_load(); to notify the search handler that it accepts search results now. 
	@param render_in the id of the element where the view should be rendered in
*/
starfield2.prototype.load = function(render_in) {
	var self = this;
	self.container_id = render_in;
	starfield2_container = render_in;
	var main_container = new Element('div' , {'id' : 'starfield2cont' , 'style' : 'z-index:0;position:absolute;left:0px;top:0px;width:100%;height:100%;overflow:hidden;background-color:#000000;' });
	$(render_in).appendChild(main_container);

	var main_container2 = new Element('div' , {'name' : 'starfield2' , 'id' : 'starfield2' , 'style' : 'z-index:0;position:absolute;left:0px;top:0px;width:100%;height:100%;overflow:hidden;background-color:#000000;' });
	main_container.appendChild(main_container2);
	
	self.retryload();

	/*recalc_ie7();*/
}

starfield2.prototype.retryload = function() {
	var self = this;

	var dim = $(self.container_id).getDimensions();	
	if (dim.width < 10 || dim.height < 10) {
		setTimeout('sh.view.retryload()' , 200);
	} else {
		swfobject.embedSWF("/views/starfield/starfield_ng.swf", "starfield2", dim.width , dim.height , "9.0.0" , null , {} , {'wmode' : 'opaque' , 'bgcolor' : '#000000' , "allowFullScreen" : "true" , 'play' : 'true'});

		// intialize the scollwheel for mac os x 
		if (!(Prototype.Browser.IE)) {
			pageInit();
		}
	}
}

/**
	@description in this function the DOM elements of a view are removed. When all the components are removed the view needs to call sh.view_did_unload(); to notify the search handler that the next view can be rendered
*/
starfield2.prototype.unload = function() {
	var self = this;
	sh.view_did_unload();
}

starfield2.prototype.setactivate = function() {
	var self = this;
	var flexApp = getFlashObject();
	flexApp.flplay();
}

/**
	@description this is the function called by the search_handler (sh) if new search results need to be displayed. 
	@param movies an array with movie objects. Below you can see an example of such a movie object, with the most important information<br/>
*/
starfield2.prototype.update = function(movies) {
	var self = this;
	var flexApp = getFlashObject();
	flexApp.update(movies);
}

function getFlashObject() {
	return $('starfield2');
}

function MovieWithIdWasClicked(mid) {
	var flexApp = getFlashObject();
	flexApp.flpause();
	screen_handler.show_details_of_movie(mid);
}


function FlashDidInit() {
	var dim = $(starfield2_container).getDimensions();	
	var flexApp = getFlashObject();
	flexApp.setDimensions(dim.width , dim.height);
	sh.view_did_load();
}function listview() {
	var self = this;
	self.container_id = '';
	self.movie_stack = null;
	self.movies_per_page = 10;
}

listview.prototype.get_about_this_view_object = function() {
	var self = this;
	var ret_obj = {
		'author': {
			'name' : 'Micha Surber - futureLAB AG',
			'url' : 'http://www.futurelab.ch'
		},
		'design' : {
			'name' : 'Micha Surber',
			'url' : null
		},
		'idea' : {
			'name' : 'NZZ - SwissMade TV',
			'url' : null
		}
	}
	return ret_obj;
}

listview.prototype.toolbar_size_changed = function(render_in) {
	var self = this;
}

listview.prototype.load = function(render_in) {
	var self = this;
	self.container_id = render_in;
	
	var dimensions = getWindowSize();
	var ws = dimensions.width;
	var hs = dimensions.height;
	
	var main_container = new Element('div' , {'class' : 'list_container' , 'id' : 'list_container' , 'style' : 'width:' + ws + 'px;height:' + hs + 'px;background-color:#000000;'});
	$(render_in).appendChild(main_container);
	var list_container_ie = new Element('div' , {'class' : 'list_container_div_id' , 'id' : 'list_container_div_id' , 'style' : 'position:absolute;width:936px;overflow:auto;height:' + (hs/1 - 143) + 'px;left:' + ((ws/1 - 920 )/2)  + 'px;top:143px;'});
	var list_container  = new Element('div' , {'class' : 'list_container_div' , 'id' : 'list_container_div' , 'style' : 'position:absolute;width:920px;height:465px;left:0px;top:0px;'});
	list_container_ie.appendChild(list_container);
	$(render_in).appendChild(list_container_ie);

	resize_handler.add_on_resize_handler(function() {
		var dimensions = getWindowSize();
		var ws = dimensions.width;
		var hs = dimensions.height;
		if ($('list_container')) {
			$('list_container').setStyle({'width' : ws + 'px' , 'height' : hs + 'px'});
		}
		if ($('list_container_div_id')) {
			$('list_container_div_id').setStyle({'height' : (hs/1 - 143) + 'px' , 'left' : ((ws/1 - 920 )/2) + 'px'});
		}
	});
	
	sh.view_did_load();
}


listview.prototype.update = function(movies) {
	var self = this;
	self.movie_stack = movies;
	self.show_page_number(0);
}

listview.prototype.show_page_number = function(page_id) {
	var self = this;
	
	if ($('list_table')) {
		$('list_table').remove();
	}
	
	var table_ie = new Element('table' , {'class' : 'list_table' , 'id' : 'list_table' , 'cellpadding' : '0' , 'cellspacing' : '0' , 'border' : '0'});
	$('list_container_div').appendChild(table_ie);
	var table = new Element('tbody');
	table_ie.appendChild(table);
	
	table.appendChild(self.get_movie_navigation('first' , page_id));

	var trs = new Array();
	for (var i = this.movies_per_page * page_id ; i < this.movies_per_page * (page_id/1 + 1.0); i ++) {
		if (self.movie_stack[i]) {
			if (i % 2 == 0) {
				trs[i] = new Element('tr' , {'class' : 'list_tr' , 'id' : 'list_tr' + i});
				table.appendChild(trs[i]);
			}
		}
	}
	var itemCounter = 0;
	for (var i = this.movies_per_page * page_id ; i < this.movies_per_page * (page_id/1 + 1.0); i ++) {
		if (self.movie_stack[i]) {
			var main_td1 = new Element('td' , {'class' : 'list_td' , 'id' : 'list_td' + i});
			main_td1.appendChild(self.get_movie_item_dom(i , self.movie_stack[i]));
			trs[i - (i % 2)].appendChild(main_td1);
			self.add_onclick_event_to_image(self.movie_stack[i]);
			itemCounter++;
		}
	}
		
	table.appendChild(self.get_movie_navigation('last' , page_id));
	recalc_ie7();
}


var next_prev_amout_of_links = 3;

listview.prototype.get_movie_navigation = function(id , page_id) {
	var self = this;
	// build up the general table here //
	var last_tr = new Element('tr' , {'class' : 'list_tr_navi' , 'id' : 'list_tr_' + id});
	var main_td1 = new Element('td' , {'class' : 'list_td_navi', 'id' : 'list_td_' + id  , 'colspan' : '2'});
	last_tr.appendChild(main_td1);
	
	var table3_ie = new Element('table' , {'class' : 'list_table_navi_table' , 'id' : 'list_table_navi' + id , 'cellpadding' : '0' , 'cellspacing' : '0' , 'border' : '0'});
	main_td1.appendChild(table3_ie);
	var table3 = new Element('tbody');
	table3_ie.appendChild(table3);
	var tr3 = new Element('tr' , {'class' : 'list_tr_navi_tr' , 'id' : 'list_tr_tr' + id});
	table3.appendChild(tr3);

	// build the 'back' link here 
	var td11 = new Element('td' , {'class' : 'list_td_navi_td list_td_navi_td_left ' + id , 'id' : 'list_td_td1' + id});
	tr3.appendChild(td11);
	if (page_id > 0) {
		a1 = new Element('a' , {'class' : 'nagi_link' , 'id' : 'navi_link_1' + id , 'href' : 'javascript:sh.view.show_page_number(' + (page_id - 1.0) + ')' , 'onclick' : 'sh.view.show_page_number(' + (page_id - 1.0) + ')'});
		td11.appendChild(a1);
		a1.appendChild(document.createTextNode('zurĂŒck'));
	}

	// the centered links of the navigation 
	var td12 = new Element('td' , {'class' : 'list_td_navi_td list_td_navi_td_center ' + id , 'id' : 'list_td_td2' + id});
	tr3.appendChild(td12);

	// if we are on a page more right then 'next_prev_amout_of_links' - 1 we display a link to the first page first
	if (page_id > next_prev_amout_of_links - 1) {
		var first = new Element('a' , {'class' : 'nagi_link' , 'id' : 'navi_link_1_first' , 'href' : 'javascript:sh.view.show_page_number(0)' , 'onclick' : 'sh.view.show_page_number(0)'});
		td12.appendChild(first);
		first.appendChild(document.createTextNode('1'));
	}

	// if we are on a page more right then 
	if (page_id > next_prev_amout_of_links) {
		var spacer_after_first = new Element('span' , {'class' : 'nagi_link'});
		td12.appendChild(spacer_after_first);
		spacer_after_first.appendChild(document.createTextNode('...'));
	}

	// if we have more movies than we can have on a single page we need a navigation
	if (this.movie_stack.length > this.movies_per_page) {
		for (var i = 0; i < Math.ceil(this.movie_stack.length / this.movies_per_page) ; i++) {
			var a1z;
			if (i == page_id) {
				a1z = new Element('a' , {'class' : 'nagi_link_current' , 'id' : 'navi_link_1' + id , 'href' : '#'});
			} else {
				if ((i < page_id + next_prev_amout_of_links) && (i > page_id - next_prev_amout_of_links)) {
					a1z = new Element('a' , {'class' : 'nagi_link' , 'id' : 'navi_link_1' + id , 'href' : 'javascript:sh.view.show_page_number(' + i + ')' , 'onclick' : 'sh.view.show_page_number(' + i + ')'});
				}
			}
			if ((i < page_id + next_prev_amout_of_links) && (i > page_id - next_prev_amout_of_links)) {
				td12.appendChild(a1z);
				a1z.appendChild(document.createTextNode((i/1 + 1.0)));
			}
		}
	}

	if (page_id + next_prev_amout_of_links + 1 < Math.ceil(this.movie_stack.length / this.movies_per_page)) {
		var spacer_after_first = new Element('span' , {'class' : 'nagi_link'});
		td12.appendChild(spacer_after_first);
		spacer_after_first.appendChild(document.createTextNode('...'));
	}
	if (page_id + (next_prev_amout_of_links) < Math.ceil(this.movie_stack.length / this.movies_per_page)) {
		var first = new Element('a' , {'class' : 'nagi_link' , 'id' : 'navi_link_1_first' , 'href' : 'javascript:sh.view.show_page_number(' + (Math.ceil(this.movie_stack.length / this.movies_per_page) - 1) + ')' , 'onclick' : 'sh.view.show_page_number(' + (Math.ceil(this.movie_stack.length / this.movies_per_page) - 1) + ')'});
		td12.appendChild(first);
		first.appendChild(document.createTextNode(Math.ceil(this.movie_stack.length / this.movies_per_page)));
	}

	var td13 = new Element('td' , {'class' : 'list_td_navi_td list_td_navi_td_right ' + id , 'id' : 'list_td_td3' + id});
	tr3.appendChild(td13);
	if (this.movies_per_page * (page_id + 1) < this.movie_stack.length) {
		a3 = new Element('a' , {'class' : 'nagi_link' , 'id' : 'navi_link_3' + id , 'href' : 'javascript:sh.view.show_page_number(' + (page_id + 1.0) + ')' , 'onclick' : 'sh.view.show_page_number(' + (page_id + 1.0) + ')'});
		td13.appendChild(a3);
		a3.appendChild(document.createTextNode('weiter'));
	}
	
	return last_tr;
		
}


listview.prototype.add_onclick_event_to_image = function(movie_obj) {
	var self = this;
	eval('var tmp = function() {screen_handler.show_details_of_movie(\''+ movie_obj.id + '\');}');
	$('list_item_img' + movie_obj.id).observe('click' , tmp);
	$('list_item_img_movie_icon' + movie_obj.id).observe('click' , tmp);
	$('list_item_img' + movie_obj.id).observe('mouseover' , function() {$('list_item_img_movie_icon' + movie_obj.id).src='img/movieplaysmall-trans.png'});
	$('list_item_img' + movie_obj.id).observe('mouseout' , function() {$('list_item_img_movie_icon' + movie_obj.id).src='img/movieplaylightsmall-trans.png'});
	$('list_item_img_movie_icon' + movie_obj.id).observe('mouseover' , function() {$('list_item_img_movie_icon' + movie_obj.id).src='img/movieplaysmall-trans.png'});
	$('list_item_img_movie_icon' + movie_obj.id).observe('mouseout' , function() {$('list_item_img_movie_icon' + movie_obj.id).src='img/movieplaylightsmall-trans.png'});
}

listview.prototype.enhanceMetadataTable = function(table, object, id , type) {
	var self = this;

	var tr = new Element('tr' , {'class' : 'list_item_tr_meta' , 'id' : 'list_item_tr_' + id});
	table.appendChild(tr);
	var td = new Element('td' , { 'id' : 'list_item_td_' + id  , 'class' : 'meta_' + type , 'style' : 'width:85px;height:14px;'});
	tr.appendChild(td);	
	td.appendChild(object);
	
	return table;
}



listview.prototype.get_movie_item_dom = function(position , movie_obj) {
	var self = this; 
	var table2_ie = new Element('table' , {'class' : 'list_item_table' , 'id' : 'list_item_table' + movie_obj.id , 'cellpadding' : '0' , 'cellspacing' : '0' , 'border' : '0'});
	var table2 = new Element('tbody');
	table2_ie.appendChild(table2);
	var tr = new Element('tr' , {'class' : 'list_item_tr' , 'id' : 'list_item_tr' + movie_obj.id});
	table2.appendChild(tr);
	var td0 = new Element('td' , {'class' : 'list_item_td' , 'id' : 'list_item_td0' + movie_obj.id});
	tr.appendChild(td0);
	var number_div = new Element('div' , {'class' : 'list_number' , 'id' : 'list_item_number_' + movie_obj.id});
	td0.appendChild(number_div);
	number_div.appendChild(document.createTextNode((position/1 + 1)));
	var td1 = new Element('td' , {'class' : 'list_item_td' , 'id' : 'list_item_tdl' + movie_obj.id});
	tr.appendChild(td1);

	var ar_parts;
	if (movie_obj.aspectratio) {
		ar_parts = movie_obj.aspectratio.split(':');
	} else {
		ar_parts = [4,3];
	}
	
	var marginleft = 7;
	if ((position+1) < 10) {
		marginleft = 20;
	}
	if ((position+1) < 100 && (position+1)>90) {
		marginleft = 20;
	}
	/*
	var marginleft = 20;
	if (((position + 1) > 9) && ((position + 1) < 91) || ((position + 1) > 99)) {
		marginleft = 7;
	}
	*/

	var height = 107 / ar_parts[0] * ar_parts[1];
	var img_div = new Element('div' , {'class' : 'list_img_div' , 'style' : 'position:relative;'});
	var img = new Element('img' , {'class' : 'list_item_img' , 
									'id' : 'list_item_img' + movie_obj.id , 
									'src' : movie_obj.files.img_small , 
									'width' : '107px' , 
									'border' : '0',
									'height': height + 'px' , 
									'style' : 'margin-top:' + ((84 - height)/2) + 'px;margin-left:' + marginleft + 'px;cursor:pointer;width:107px;height:' + height + 'px;'
									/*'onclick' : 'screen_handler.show_details_of_movie(' + movie_obj.id + ');'*/
						});
	var img2 = new Element('img' , {'class' : 'list_item_img_movie_icon' , 
									'id' : 'list_item_img_movie_icon' + movie_obj.id , 
									'src' : 'img/movieplaylightsmall-trans.png' , 
									'width' : '44px' , 
									'border' : '0',
									'height': '44px' , 
									'style' : 'position:absolute;left:0px;top:0px;margin-top:18px;margin-left:'+ (31 + marginleft/1) +'px;cursor:pointer;width:44px;height:44px;'
									/*'onclick' : 'screen_handler.show_details_of_movie(' + movie_obj.id + ');'*/
						});
	td1.appendChild(img_div);
	img_div.appendChild(img);
	img_div.appendChild(img2);
	var td2 = new Element('td' , {'class' : 'list_item_td' , 'id' : 'list_item_tdr' + movie_obj.id , 'style' : 'vertical-align:top;'});
	tr.appendChild(td2);
	
	var descWidth = 215;
	if ((position + 1) > 90) {
		descWidth = 198;
	}

	var table3_ie = new Element('table' , {'class' : 'list_item_table_meta' , 'id' : 'list_item_table_meta' + movie_obj.id , 'cellpadding' : '0' , 'cellspacing' : '0' , 'border' : '0' , 'style' : 'padding-left:10px;width:' + descWidth + 'px;'});
	var table3 = new Element('tbody');
	table3_ie.appendChild(table3);
	td2.appendChild(table3_ie);
	
	var tr3 = new Element('tr' , {'class' : 'list_item_tr_meta' , 'id' : 'list_item_tr_meta' + movie_obj.id});
	table3.appendChild(tr3);

	var td3 = new Element('td' , { 'id' : 'list_item_td_meta' + movie_obj.id , 'style' : 'width:190px;'});
	td3.addClassName('list_item_td_meta_title');
	tr3.appendChild(td3);
	if (movie_obj.title != undefined) {
		td3.appendChild(document.createTextNode(movie_obj.title));
	}
	var td31 = new Element('td' , {'class' : 'list_item_td_meta_date' , 'id' : 'list_item_td_meta' + movie_obj.id , 'style' : 'text-align:right;width:60px;'});
	tr3.appendChild(td31);

	var tr4 = new Element('tr' , {'class' : 'list_item_tr_meta' , 'id' : 'list_item_tr_meta1' + movie_obj.id});
	table3.appendChild(tr4);
	var td4 = new Element('td' , {'class' : 'list_item_td_meta_description' , 'id' : 'list_item_td_meta1' + movie_obj.id , 'colspan' : '2'});
	tr4.appendChild(td4);
	if (movie_obj.description != undefined) {
		var desc = movie_obj.description;
		if (desc.length > 153) {
			desc = desc.substring(0 , 150) + '...';
		}
		td4.appendChild(document.createTextNode(desc));
	}

	var tr5 = new Element('tr' , {'class' : 'list_item_tr_meta' , 'id' : 'list_item_tr_meta1' + movie_obj.id});
	table3.appendChild(tr5);
	var td5 = new Element('td' , {'class' : 'list_item_td_meta_viewcount' , 'id' : 'list_item_td_meta1' + movie_obj.id , 'colspan' : '2' , 'style' : 'text-align:right;'});
	tr5.appendChild(td5);

	var tda = new Element('td' , {'class' : 'list_item_td' , 'id' : 'list_item_tdra' + movie_obj.id , 'style' : 'vertical-align:top;'});
	tr.appendChild(tda);

	var table3_iea = new Element('table' , {'class' : 'list_item_table_meta' , 'id' : 'list_item_table_meta_new' + movie_obj.id , 'cellpadding' : '0' , 'cellspacing' : '0' , 'border' : '0' , 'style' : 'padding-left:10px;width:85px;'});
	var table3a = new Element('tbody');
	table3_iea.appendChild(table3a);
	tda.appendChild(table3_iea);
	
	/* Aufrufe */
	table3a = self.enhanceMetadataTable(table3a , document.createTextNode('Aufrufe') , movie_obj.id + 'calltitle' , 'title');
	if (!(movie_obj.viewcount)) {
		movie_obj.viewcount = '0';
	}
	table3a = self.enhanceMetadataTable(table3a , document.createTextNode('' + movie_obj.viewcount + '') , movie_obj.id + 'callnumber' , 'value');
	
	table3a = self.enhanceMetadataTable(table3a , document.createTextNode('Bewertung') , movie_obj.id + 'ratingTitle' , 'title');
	var rating = new flrating();
	var ratval = 0;
	if (movie_obj.ratings) {
		ratval = movie_obj.ratings;
	}
	rating.setValue(ratval);
	var ratingDiv = rating.render(movie_obj.id);
	
	table3a = self.enhanceMetadataTable(table3a , ratingDiv , movie_obj.id + 'ratingValue' , 'value');
	
	/* produktion */
	if (movie_obj.date) {
		table3a = self.enhanceMetadataTable(table3a , document.createTextNode('Produktion') , movie_obj.id + 'prodTitle' , 'title');
		table3a = self.enhanceMetadataTable(table3a , document.createTextNode('' + movie_obj.date.substring(0,4) + '') , movie_obj.id + 'prodValue' , 'value');
	}

	return table2_ie;	
}


/**
	@description if this function is implemented, a search request will only return the number of images returned by this function 
	@type int
	@return the number of images that can be displayed in this view
*/

/*
var search_types_text = 0;
var search_types_kanal = 1;
var search_types_random = 2;
var search_types_all = 3

var current_search_type = 3;

var order_types_relevance = 0;
var order_types_favorites = 1;
var order_types_age = 2;
var order_types_random = 3

var current_order_type = 3;
*/
listview.prototype.maximum_movies_displayed = function(current_search_type , current_order_type) {
	var self = this;
	if (current_search_type == search_types_random) {
		return 10;
	}
/*
	if (current_order_type == order_types_random) {
		return 10;
	}
	return 0;
*/
	return 0;
}



listview.prototype.unload = function() {
	var self = this;
	$('list_container').remove();
	sh.view_did_unload();
}



function tvview() {
	var self = this;
	self.container_id = '';
	self.has_flow_player = false;
	self.tvview_movie_store = new Array();
	self.current_movie = null;
	self.next_movie_to_play = 0;
}

tvview.prototype.get_about_this_view_object = function() {
	var self = this;
	var ret_obj = {
		'author': {
			'name' : 'Micha Surber - futureLAB AG',
			'url' : 'http://www.futurelab.ch'
		},
		'design' : {
			'name' : 'Micha Surber',
			'url' : null
		},
		'idea' : {
			'name' : 'NZZ - SwissMade TV',
			'url' : null
		}
	}
	return ret_obj;
}

tvview.prototype.needs_to_update_before_loading = function() {
	var self = this;
	return true;
}

tvview.prototype.toolbar_size_changed = function(render_in) {
	var self = this;
}

tvview.prototype.load = function(render_in) {
	var self = this;
	history_manager_disabled = true;
	self.container_id = render_in;
	
	var dimensions = getWindowSize();
	var ws = dimensions.width;
	var hs = dimensions.height;
	var th = hs; 
	var tw = ws;
	if (th < 679) {
		th = 679;
		if (!(Prototype.Browser.IE)) {
			tw = tw - 15;
		}
	}
	var main_container = new Element('div' , {'class' : 'tv_container' , 'id' : 'tv_container' , 'style' : 'position:relative;overflow:auto;width:' + tw + 'px;height:' + th + 'px;'});
	$(render_in).appendChild(main_container);

	var height = hs;
	if (height > 539) {
		height = 539;
	}
	
	var tv_div_ie = new Element('div' , {'class' : 'tv_div_ie' , 'id' : 'tv_div_ie' , 'style' : 'height:679px;width:100px;'});
	main_container.appendChild(tv_div_ie);
	var tv_div = new Element('div' , {'class' : 'tv_div' , 'id' : 'tv_div' , 'style' : 'height:539px;width:920px;left:' + ((ws/2) - 460) + 'px;top:100px;'});
	main_container.appendChild(tv_div);
	var tv_player_div = new Element('div' , {'class' : 'tvplayer_small' , 'id' : 'tvplayer_small' , 'style' : 'top:184px;'});
	main_container.appendChild(tv_player_div);

	resize_handler.add_on_resize_handler(function() {
		var dimensions = getWindowSize();
		var ws = dimensions.width;
		var hs = dimensions.height;
		console.log('resize handler of tvview: width = ' + ws + ' height = ' + hs);
		var th1 = hs; 
		var tw1 = ws;
		if (th1 < 679) {
			th1 = 679;
			if (!(Prototype.Browser.IE)) {
				tw1 = tw1 - 15;
			}
		}
		if ($('tv_container')) {
			$('tv_container').setStyle({'height' : th1 + 'px' , 'width' : tw1 + 'px'});
		}
		if ($('tv_div')) {
			$('tv_div').setStyle({'height' : '539px' , 'left' : ((ws/2) - 460) + 'px'});
		}
		if ($('tv_hide_controll_div')) {
			$('tv_hide_controll_div').setStyle({'left':  Math.round(((ws/2) - 468)) + 'px'});
		}
	});

	var hide_controll_div = new Element('div' , {'class' : 'hide_controll_div' , 'id' : 'tv_hide_controll_div' , 'style' : 'position:absolute;width:940px;height:40px;left:' + Math.round(((ws/2) - 468)) + 'px;top:105px;background-color:#000000;'});
	$('the_body').appendChild(hide_controll_div);

	sh.view_did_load();
}

tvview.prototype.update = function(movies) {
	var self = this;
	self.movies = movies;
	var plist = new Array();
	var first = true;
	for (var i = 0; i < movies.length ; i++) {
		if (movies[i].aspectratio == '16:9' && movies[i].length && (movies[i].length > 0)) {
			var urlparts = movies[i].files.mov_pal.split('pal');
			var ending = urlparts[urlparts.length - 1];
		
			var fileparts = movies[i].files.mov_pal.split('/movies/');
			var oriclip = fileparts[fileparts.length - 1];
			var url = 'mp4:' + oriclip;
			
			var hackurl = url.replace(new RegExp("pal[^.]*" + ending), "qpal" + ending);
			
			var start_int = 0;
			if (first) {
				first = false;
				start_int = 120 + Math.floor(Math.random()*121);
			}
			while (start_int > movies[i].length) {
				start_int = Math.floor(start_int / 2);
			}
			
			var length_int = movies[i].length / 1000 - start_int;
			
			var plistitem = {
				url      : hackurl,
				provider : 'rtmp',
				scaling  : 'fit',
				loop     : true ,
				start    : start_int,
				duration : length_int
			};
			/*
			if (first) {
				first = false;
				console.log('first movie');
				plistitem.start = 240;
			}
			*/
			/*
			var plistitem = hackurl;
			*/

			/*
			if (movies[i].starttime) {
				plistitem.start = movies[i].starttime / 1000;
			}
			*/
			
			/*
			if (i == 0) {
				plistitem['start'] = 100;
			}
			*/
			/*
			if (movies[i].length > 1000) {
				if (plistitem.start) {
					plistitem.duration = plistitem.start + movies[i].length / 1000;
				} else {
					plistitem.duration = movies[i].length / 1000;
				}
			}
			*/
	
			plist.push(plistitem);
		}
	}
	
	console.log('plist = ' , plist);

	self.currentmovie = self.movies.length - 1;

	if (!(self.has_flow_player)) {
		self.render_flow_player(plist);
		/* scale the div containing the movie player to the right aspectratio */
		console.log('no flashplayer yet. will call update_movie_ar');
		/*self.update_movie_ar(self.movies[self.currentmovie]);*/
		/* increase movie in array count */
		/*$f("tvplayer_small").onBeforeFinish(function() {
			self.currentmovie--;
			self.update_movie_ar(self.movies[self.currentmovie]);
			return true;
		});*/
	} else {
		console.log('plist = ' , plist);
		/*$f("tvplayer_small").setPlaylist(plist);*/
	}
}



tvview.prototype.update_old = function(movies) {
	var self = this;
	self.tvview_movie_store = movies;
	self.next_movie_to_play = 0;

	if (!(self.has_flow_player)) {
		var movie_obj = self.tvview_movie_store[self.next_movie_to_play];
		self.current_movie = movie_obj;
		/* render the movie player */
		self.render_flow_player(movie_obj.files.mov_pal);
		/* scale the div containing the movie player to the right aspectratio */
		self.update_movie_ar(movie_obj);
		/* increase movie in array count */
		self.next_movie_to_play++;
		if (self.next_movie_to_play > (self.tvview_movie_store.lenth - 1)) {
			self.next_movie_to_play = 0;
		}
		/* add onBeforeFinish handler wich will play the next movie */
		$f("tvplayer_small").onBeforeFinish(function() {
			self.play_next_clip();
			return false;
		});
	} else {
		self.play_next_clip();
	}
}

tvview.prototype.update_movie_ar = function(movie_obj) {
	var self = this;
	
	console.log('setting new aspect ratio for movie with title ' + movie_obj.title + ' ar = ' + movie_obj.aspectratio);
	var ar_parts;
	if (movie_obj.aspectratio) {
		ar_parts = [16,9];
		/*ar_parts = movie_obj.aspectratio.split(':');*/
	} else {
		ar_parts = [16,9];
		/*ar_parts = [4,3];*/
	}
	var height = 415;
	var width = (415 / ar_parts[1]) * ar_parts[0];

	$('tvplayer_small').setStyle({'width': width + 'px' , 'marginLeft': (-1 * Math.round(width/2)) + 'px' , 'height' : height + 'px'});
}

tvview.prototype.play_next_clip = function(event) {
	var self = this;
	var movie_obj = self.tvview_movie_store[self.next_movie_to_play];
	self.current_movie = movie_obj;

	$f("tvplayer_small").setClip(movie_obj.files.mov_pal);
	$f("tvplayer_small").play();
	self.next_movie_to_play++;
	if (self.next_movie_to_play > (self.tvview_movie_store.lenth - 1)) {
		self.next_movie_to_play = 0;
	}
}


/**
	@description if this function is implemented, a search request will only return the number of images returned by this function 
	@type int
	@return the number of images that can be displayed in this view
*/

/*
var search_types_text = 0;
var search_types_kanal = 1;
var search_types_random = 2;
var search_types_all = 3

var current_search_type = 3;

var order_types_relevance = 0;
var order_types_favorites = 1;
var order_types_age = 2;
var order_types_random = 3

var current_order_type = 3;
*/
tvview.prototype.maximum_movies_displayed = function(current_search_type , current_order_type) {
	var self = this;
/*
	if (current_search_type == search_types_random) {
		return 10;
	}
	if (current_order_type == order_types_random) {
		return 10;
	}
	return 0;
*/
	return 0;
}



tvview.prototype.unload = function() {
	var self = this;

	$f("tvplayer_small").stop();
	$f("tvplayer_small").close();
	$f("tvplayer_small").unload();

	if ($('tv_container')) {
		$('tv_container').remove();
	}
	if ($('tv_hide_controll_div')) {
		$('tv_hide_controll_div').remove();
	}
	history_manager_disabled = false;
	sh.view_did_unload();
}



tvview.prototype.render_flow_player = function(plist) {
	var self = this;
	
	$f("tvplayer_small", {'src' : "/swf/flowplayer.commercial-3.2.7.swf", wmode: 'opaque'},
		{	
			key:'#$4b5ebe5e5c3146d8626',
			/*clip: { 
				provider: 'rtmp',
				scaling : 'fit'
			}, */
			playlist : plist,
			play: { opacity: 0 },
			canvas: {
				backgroundColor: '#000000',
				backgroundGradient : 'none'
			},
			plugins: { 
				rtmp: {
					url: '/swf/flowplayer.rtmp-3.2.3.swf',
					netConnectionUrl: 'rtmp://46.4.8.119/vod/foo/'
				},
				controls:{
					url:'/swf/flowplayer.controls-3.2.5.swf',
					all:false,
					opacity:0,
					backgroundGradient: 'none',
					backgroundColor: '#000000',
					sliderColor:'#FFFFFF',
					volumeSliderColor:'#000000',
					scrubber:false, 
					volume:false,
					play:false,
					autoHide:'always',
					buttonColor:'#999999', 
					buttonOverColor:'#777777', 
					hideDelay:2000,
					bufferColor:'#BBBBBB',
					progressColor:'#FFFFFF'
				}
		    } 
		}
	);	
}


tvview.prototype.render_flow_player_old = function(movie_url) {
	var self = this;
	
	/*$f("tvplayer_small", {'src' : "/swf/flowplayer-3.0.7.swf", wmode: 'opaque'},*/
	$f("tvplayer_small", {'src' : "flowplayer/flowplayer.commercial-3.1.1.swf", wmode: 'opaque'},
		{	
			/* todo: activate comercial licence */
			key:'#$41ffd77be016480fc7d',
			clip: 
			{
				url:movie_url,
			    provider: 'h264streaming',
				scaling:'scale',
				play:true,
				start:0
			},
			canvas: {
				backgroundGradient: 'none',
				backgroundColor: 'none'
			},
			plugins:{
				h264streaming: {
					url: '/swf/flowplayer.pseudostreaming-3.1.2.swf'
				},
				controls:{
					url:'flowplayer/flowplayer.controls-3.1.1.swf',
					all:false,
					opacity:1.0,
					backgroundGradient: 'none',
					backgroundColor: '#444444',
					sliderColor:'#FFFFFF',
					volumeSliderColor:'#000000',
					scrubber:true, 
					/*height:1*/
					volume:true,
					play:true,
					autoHide:'always',
					buttonColor:'#999999', 
					buttonOverColor:'#777777', 
					hideDelay:2000,
					bufferColor:'#BBBBBB',
					progressColor:'#FFFFFF'
				}
			}
		}
	);
	
	$f("tvplayer_small").onCuepoint(60000,function(){
		if (!(did_count_for_movie_with_id[self.current_movie.id])) {

			var params = {
						'movie':self.current_movie.id
					};
			new Ajax.Request('/data/IncreasePlayCount', { 
				method:'post', 
				parameters : params,
				onSuccess: function(transport){
				}
			});
		
			did_count_for_movie_with_id[self.current_movie.id] = true;
		} else {
		}
	});
}

					/* todo: activate comercial licence */
					/*url:'flowplayer/flowplayer.controls-3.1.1.swf',*/

