/*  Prototype JavaScript framework, version 1.6.1
 *  (c) 2005-2009 Sam Stephenson
 *
 *  Prototype is freely distributable under the terms of an MIT-style license.
 *  For details, see the Prototype web site: http://www.prototypejs.org/
 *
 *--------------------------------------------------------------------------*/

var Prototype = {
  Version: '1.6.1',

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

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

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

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

      div = form = null;

      return isSupported;
    })()
  },

  ScriptFragment: '<script[^>]*>([\\S\\s]*?)<\/script>',
  JSONFilter: /^\/\*-secure-([\s\S]*)\*\/\s*$/,

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

if (Prototype.Browser.MobileSafari)
  Prototype.BrowserFeatures.SpecificElementExtensions = false;


var Abstract = { };


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

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

    return returnValue;
  }
};

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

var Class = (function() {
  function subclass() {};
  function create() {
    var parent = null, properties = $A(arguments);
    if (Object.isFunction(properties[0]))
      parent = properties.shift();

    function klass() {
      this.initialize.apply(this, arguments);
    }

    Object.extend(klass, Class.Methods);
    klass.superclass = parent;
    klass.subclasses = [];

    if (parent) {
      subclass.prototype = parent.prototype;
      klass.prototype = new subclass;
      parent.subclasses.push(klass);
    }

    for (var i = 0; i < properties.length; i++)
      klass.addMethods(properties[i]);

    if (!klass.prototype.initialize)
      klass.prototype.initialize = Prototype.emptyFunction;

    klass.prototype.constructor = klass;
    return klass;
  }

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

    if (!Object.keys({ toString: true }).length) {
      if (source.toString != Object.prototype.toString)
        properties.push("toString");
      if (source.valueOf != Object.prototype.valueOf)
        properties.push("valueOf");
    }

    for (var i = 0, length = properties.length; i < length; i++) {
      var property = properties[i], value = source[property];
      if (ancestor && Object.isFunction(value) &&
          value.argumentNames().first() == "$super") {
        var method = value;
        value = (function(m) {
          return function() { return ancestor[m].apply(this, arguments); };
        })(property).wrap(method);

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

    return this;
  }

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

  var _toString = Object.prototype.toString;

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

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

  function toJSON(object) {
    var type = typeof object;
    switch (type) {
      case 'undefined':
      case 'function':
      case 'unknown': return;
      case 'boolean': return object.toString();
    }

    if (object === null) return 'null';
    if (object.toJSON) return object.toJSON();
    if (isElement(object)) return;

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

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

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

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

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

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

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

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

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


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


Date.prototype.toJSON = function() {
  return '"' + this.getUTCFullYear() + '-' +
    (this.getUTCMonth() + 1).toPaddedString(2) + '-' +
    this.getUTCDate().toPaddedString(2) + 'T' +
    this.getUTCHours().toPaddedString(2) + ':' +
    this.getUTCMinutes().toPaddedString(2) + ':' +
    this.getUTCSeconds().toPaddedString(2) + 'Z"';
};


RegExp.prototype.match = RegExp.prototype.test;

RegExp.escape = function(str) {
  return String(str).replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1');
};
var PeriodicalExecuter = Class.create({
  initialize: function(callback, frequency) {
    this.callback = callback;
    this.frequency = frequency;
    this.currentlyExecuting = false;

    this.registerCallback();
  },

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

  execute: function() {
    this.callback(this);
  },

  stop: function() {
    if (!this.timer) return;
    clearInterval(this.timer);
    this.timer = null;
  },

  onTimerEvent: function() {
    if (!this.currentlyExecuting) {
      try {
        this.currentlyExecuting = true;
        this.execute();
        this.currentlyExecuting = false;
      } catch(e) {
        this.currentlyExecuting = false;
        throw e;
      }
    }
  }
});
Object.extend(String, {
  interpret: function(value) {
    return value == null ? '' : String(value);
  },
  specialChar: {
    '\b': '\\b',
    '\t': '\\t',
    '\n': '\\n',
    '\f': '\\f',
    '\r': '\\r',
    '\\': '\\\\'
  }
});

Object.extend(String.prototype, (function() {

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

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

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

    if (!(pattern.length || pattern.source)) {
      replacement = replacement('');
      return replacement + source.split('').join(replacement) + replacement;
    }

    while (source.length > 0) {
      if (match = source.match(pattern)) {
        result += source.slice(0, match.index);
        result += String.interpret(replacement(match));
        source  = source.slice(match.index + match[0].length);
      } else {
        result += source, source = '';
      }
    }
    return result;
  }

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

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

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

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

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

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

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

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

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

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

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


  function toQueryParams(separator) {
    var match = this.strip().match(/([^?#]*)(#.*)?$/);
    if (!match) return { };

    return match[1].split(separator || '&').inject({ }, function(hash, pair) {
      if ((pair = pair.split('='))[0]) {
        var key = decodeURIComponent(pair.shift());
        var value = pair.length > 1 ? pair.join('=') : pair[0];
        if (value != undefined) value = decodeURIComponent(value);

        if (key in hash) {
          if (!Object.isArray(hash[key])) hash[key] = [hash[key]];
          hash[key].push(value);
        }
        else hash[key] = value;
      }
      return hash;
    });
  }

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

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

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

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

    var camelized = this.charAt(0) == '-'
      ? parts[0].charAt(0).toUpperCase() + parts[0].substring(1)
      : parts[0];

    for (var i = 1; i < len; i++)
      camelized += parts[i].charAt(0).toUpperCase() + parts[i].substring(1);

    return camelized;
  }

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

      var before = match[1] || '';
      if (before == '\\') return match[2];

      var ctx = object, expr = match[3];
      var pattern = /^([^.[]+|\[((?:.*?[^\\])?)\])(\.|\[|$)/;
      match = pattern.exec(expr);
      if (match == null) return before;

      while (match != null) {
        var comp = match[1].startsWith('[') ? match[2].replace(/\\\\]/g, ']') : match[1];
        ctx = ctx[comp];
        if (null == ctx || '' == match[3]) break;
        expr = expr.substring('[' == match[3] ? match[1].length : match[0].length);
        match = pattern.exec(expr);
      }

      return before + String.interpret(ctx);
    });
  }
});
Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/;

var $break = { };

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

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

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

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

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

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

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

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

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

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

  function include(object) {
    if (Object.isFunction(this.indexOf))
      if (this.indexOf(object) != -1) return true;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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









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

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

Array.from = $A;


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

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

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

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

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

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

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

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

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

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

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


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

  function size() {
    return this.length;
  }

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

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

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

  function lastIndexOf(item, i) {
    i = isNaN(i) ? this.length : (i < 0 ? this.length + i : i) + 1;
    var n = this.slice(0, i).reverse().indexOf(item);
    return (n < 0) ? n : i - n - 1;
  }

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

  Object.extend(arrayProto, Enumerable);

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

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

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

  if (CONCAT_ARGUMENTS_BUGGY) arrayProto.concat = concat;

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

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

  function _each(iterator) {
    for (var key in this._object) {
      var value = this._object[key], pair = [key, value];
      pair.key = key;
      pair.value = value;
      iterator(pair);
    }
  }

  function set(key, value) {
    return this._object[key] = value;
  }

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  function succ() {
    return this + 1;
  }

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

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

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

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

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

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

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

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

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

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

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

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

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



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

  activeRequestCount: 0
};

Ajax.Responders = {
  responders: [],

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

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

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

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

Object.extend(Ajax.Responders, Enumerable);

Ajax.Responders.register({
  onCreate:   function() { Ajax.activeRequestCount++ },
  onComplete: function() { Ajax.activeRequestCount-- }
});
Ajax.Base = Class.create({
  initialize: function(options) {
    this.options = {
      method:       'post',
      asynchronous: true,
      contentType:  'application/x-www-form-urlencoded',
      encoding:     'UTF-8',
      parameters:   '',
      evalJSON:     true,
      evalJS:       true
    };
    Object.extend(this.options, options || { });

    this.options.method = this.options.method.toLowerCase();

    if (Object.isString(this.options.parameters))
      this.options.parameters = this.options.parameters.toQueryParams();
    else if (Object.isHash(this.options.parameters))
      this.options.parameters = this.options.parameters.toObject();
  }
});
Ajax.Request = Class.create(Ajax.Base, {
  _complete: false,

  initialize: function($super, url, options) {
    $super(options);
    this.transport = Ajax.getTransport();
    this.request(url);
  },

  request: function(url) {
    this.url = url;
    this.method = this.options.method;
    var params = Object.clone(this.options.parameters);

    if (!['get', 'post'].include(this.method)) {
      params['_method'] = this.method;
      this.method = 'post';
    }

    this.parameters = params;

    if (params = Object.toQueryString(params)) {
      if (this.method == 'get')
        this.url += (this.url.include('?') ? '&' : '?') + params;
      else if (/Konqueror|Safari|KHTML/.test(navigator.userAgent))
        params += '&_=';
    }

    try {
      var response = new Ajax.Response(this);
      if (this.options.onCreate) this.options.onCreate(response);
      Ajax.Responders.dispatch('onCreate', this, response);

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

      if (this.options.asynchronous) this.respondToReadyState.bind(this).defer(1);

      this.transport.onreadystatechange = this.onStateChange.bind(this);
      this.setRequestHeaders();

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

      /* Force Firefox to handle ready state 4 for synchronous requests */
      if (!this.options.asynchronous && this.transport.overrideMimeType)
        this.onStateChange();

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

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

  setRequestHeaders: function() {
    var headers = {
      'X-Requested-With': 'XMLHttpRequest',
      'X-Prototype-Version': Prototype.Version,
      'Accept': 'text/javascript, text/html, application/xml, text/xml, */*'
    };

    if (this.method == 'post') {
      headers['Content-type'] = this.options.contentType +
        (this.options.encoding ? '; charset=' + this.options.encoding : '');

      /* Force "Connection: close" for older Mozilla browsers to work
       * around a bug where XMLHttpRequest sends an incorrect
       * Content-length header. See Mozilla Bugzilla #246651.
       */
      if (this.transport.overrideMimeType &&
          (navigator.userAgent.match(/Gecko\/(\d{4})/) || [0,2005])[1] < 2005)
            headers['Connection'] = 'close';
    }

    if (typeof this.options.requestHeaders == 'object') {
      var extras = this.options.requestHeaders;

      if (Object.isFunction(extras.push))
        for (var i = 0, length = extras.length; i < length; i += 2)
          headers[extras[i]] = extras[i+1];
      else
        $H(extras).each(function(pair) { headers[pair.key] = pair.value });
    }

    for (var name in headers)
      this.transport.setRequestHeader(name, headers[name]);
  },

  success: function() {
    var status = this.getStatus();
    return !status || (status >= 200 && status < 300);
  },

  getStatus: function() {
    try {
      return this.transport.status || 0;
    } catch (e) { return 0 }
  },

  respondToReadyState: function(readyState) {
    var state = Ajax.Request.Events[readyState], response = new Ajax.Response(this);

    if (state == 'Complete') {
      try {
        this._complete = true;
        (this.options['on' + response.status]
         || this.options['on' + (this.success() ? 'Success' : 'Failure')]
         || Prototype.emptyFunction)(response, response.headerJSON);
      } catch (e) {
        this.dispatchException(e);
      }

      var contentType = response.getHeader('Content-type');
      if (this.options.evalJS == 'force'
          || (this.options.evalJS && this.isSameOrigin() && contentType
          && contentType.match(/^\s*(text|application)\/(x-)?(java|ecma)script(;.*)?\s*$/i)))
        this.evalResponse();
    }

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

    if (state == 'Complete') {
      this.transport.onreadystatechange = Prototype.emptyFunction;
    }
  },

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

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

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

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

Ajax.Request.Events =
  ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete'];








Ajax.Response = Class.create({
  initialize: function(request){
    this.request = request;
    var transport  = this.transport  = request.transport,
        readyState = this.readyState = transport.readyState;

    if((readyState > 2 && !Prototype.Browser.IE) || readyState == 4) {
      this.status       = this.getStatus();
      this.statusText   = this.getStatusText();
      this.responseText = String.interpret(transport.responseText);
      this.headerJSON   = this._getHeaderJSON();
    }

    if(readyState == 4) {
      var xml = transport.responseXML;
      this.responseXML  = Object.isUndefined(xml) ? null : xml;
      this.responseJSON = this._getResponseJSON();
    }
  },

  status:      0,

  statusText: '',

  getStatus: Ajax.Request.prototype.getStatus,

  getStatusText: function() {
    try {
      return this.transport.statusText || '';
    } catch (e) { return '' }
  },

  getHeader: Ajax.Request.prototype.getHeader,

  getAllHeaders: function() {
    try {
      return this.getAllResponseHeaders();
    } catch (e) { return null }
  },

  getResponseHeader: function(name) {
    return this.transport.getResponseHeader(name);
  },

  getAllResponseHeaders: function() {
    return this.transport.getAllResponseHeaders();
  },

  _getHeaderJSON: function() {
    var json = this.getHeader('X-JSON');
    if (!json) return null;
    json = decodeURIComponent(escape(json));
    try {
      return json.evalJSON(this.request.options.sanitizeJSON ||
        !this.request.isSameOrigin());
    } catch (e) {
      this.request.dispatchException(e);
    }
  },

  _getResponseJSON: function() {
    var options = this.request.options;
    if (!options.evalJSON || (options.evalJSON != 'force' &&
      !(this.getHeader('Content-type') || '').include('application/json')) ||
        this.responseText.blank())
          return null;
    try {
      return this.responseText.evalJSON(options.sanitizeJSON ||
        !this.request.isSameOrigin());
    } catch (e) {
      this.request.dispatchException(e);
    }
  }
});

Ajax.Updater = Class.create(Ajax.Request, {
  initialize: function($super, container, url, options) {
    this.container = {
      success: (container.success || container),
      failure: (container.failure || (container.success ? null : container))
    };

    options = Object.clone(options);
    var onComplete = options.onComplete;
    options.onComplete = (function(response, json) {
      this.updateContent(response.responseText);
      if (Object.isFunction(onComplete)) onComplete(response, json);
    }).bind(this);

    $super(url, options);
  },

  updateContent: function(responseText) {
    var receiver = this.container[this.success() ? 'success' : 'failure'],
        options = this.options;

    if (!options.evalScripts) responseText = responseText.stripScripts();

    if (receiver = $(receiver)) {
      if (options.insertion) {
        if (Object.isString(options.insertion)) {
          var insertion = { }; insertion[options.insertion] = responseText;
          receiver.insert(insertion);
        }
        else options.insertion(receiver, responseText);
      }
      else receiver.update(responseText);
    }
  }
});

Ajax.PeriodicalUpdater = Class.create(Ajax.Base, {
  initialize: function($super, container, url, options) {
    $super(options);
    this.onComplete = this.options.onComplete;

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

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

    this.start();
  },

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

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

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

      this.lastText = response.responseText;
    }
    this.timer = this.onTimerEvent.bind(this).delay(this.decay * this.frequency);
  },

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



function $(element) {
  if (arguments.length > 1) {
    for (var i = 0, elements = [], length = arguments.length; i < length; i++)
      elements.push($(arguments[i]));
    return elements;
  }
  if (Object.isString(element))
    element = document.getElementById(element);
  return Element.extend(element);
}

if (Prototype.BrowserFeatures.XPath) {
  document._getElementsByXPath = function(expression, parentElement) {
    var results = [];
    var query = document.evaluate(expression, $(parentElement) || document,
      null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
    for (var i = 0, length = query.snapshotLength; i < length; i++)
      results.push(Element.extend(query.snapshotItem(i)));
    return results;
  };
}

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

if (!window.Node) var Node = { };

if (!Node.ELEMENT_NODE) {
  Object.extend(Node, {
    ELEMENT_NODE: 1,
    ATTRIBUTE_NODE: 2,
    TEXT_NODE: 3,
    CDATA_SECTION_NODE: 4,
    ENTITY_REFERENCE_NODE: 5,
    ENTITY_NODE: 6,
    PROCESSING_INSTRUCTION_NODE: 7,
    COMMENT_NODE: 8,
    DOCUMENT_NODE: 9,
    DOCUMENT_TYPE_NODE: 10,
    DOCUMENT_FRAGMENT_NODE: 11,
    NOTATION_NODE: 12
  });
}


(function(global) {

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

  var element = global.Element;
  global.Element = function(tagName, attributes) {
    attributes = attributes || { };
    tagName = tagName.toLowerCase();
    var cache = Element.cache;
    if (SETATTRIBUTE_IGNORES_NAME && attributes.name) {
      tagName = '<' + tagName + ' name="' + attributes.name + '">';
      delete attributes.name;
      return Element.writeAttribute(document.createElement(tagName), attributes);
    }
    if (!cache[tagName]) cache[tagName] = Element.extend(document.createElement(tagName));
    return Element.writeAttribute(cache[tagName].cloneNode(false), attributes);
  };
  Object.extend(global.Element, element || { });
  if (element) global.Element.prototype = element.prototype;
})(this);

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

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

  toggle: function(element) {
    element = $(element);
    Element[Element.visible(element) ? 'hide' : 'show'](element);
    return element;
  },


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

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

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

  update: (function(){

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

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

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

    function update(element, content) {
      element = $(element);

      if (content && content.toElement)
        content = content.toElement();

      if (Object.isElement(content))
        return element.update().insert(content);

      content = Object.toHTML(content);

      var tagName = element.tagName.toUpperCase();

      if (tagName === 'SCRIPT' && SCRIPT_ELEMENT_REJECTS_TEXTNODE_APPENDING) {
        element.text = content;
        return element;
      }

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

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

    return update;
  })(),

  replace: function(element, content) {
    element = $(element);
    if (content && content.toElement) content = content.toElement();
    else if (!Object.isElement(content)) {
      content = Object.toHTML(content);
      var range = element.ownerDocument.createRange();
      range.selectNode(element);
      content.evalScripts.bind(content).defer();
      content = range.createContextualFragment(content.stripScripts());
    }
    element.parentNode.replaceChild(content, element);
    return element;
  },

  insert: function(element, insertions) {
    element = $(element);

    if (Object.isString(insertions) || Object.isNumber(insertions) ||
        Object.isElement(insertions) || (insertions && (insertions.toElement || insertions.toHTML)))
          insertions = {bottom:insertions};

    var content, insert, tagName, childNodes;

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

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

      content = Object.toHTML(content);

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

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

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

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

    return element;
  },

  wrap: function(element, wrapper, attributes) {
    element = $(element);
    if (Object.isElement(wrapper))
      $(wrapper).writeAttribute(attributes || { });
    else if (Object.isString(wrapper)) wrapper = new Element(wrapper, attributes);
    else wrapper = new Element('div', wrapper);
    if (element.parentNode)
      element.parentNode.replaceChild(wrapper, element);
    wrapper.appendChild(element);
    return wrapper;
  },

  inspect: function(element) {
    element = $(element);
    var result = '<' + element.tagName.toLowerCase();
    $H({'id': 'id', 'className': 'class'}).each(function(pair) {
      var property = pair.first(), attribute = pair.last();
      var value = (element[property] || '').toString();
      if (value) result += ' ' + attribute + '=' + value.inspect(true);
    });
    return result + '>';
  },

  recursivelyCollect: function(element, property) {
    element = $(element);
    var elements = [];
    while (element = element[property])
      if (element.nodeType == 1)
        elements.push(Element.extend(element));
    return elements;
  },

  ancestors: function(element) {
    return Element.recursivelyCollect(element, 'parentNode');
  },

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

  firstDescendant: function(element) {
    element = $(element).firstChild;
    while (element && element.nodeType != 1) element = element.nextSibling;
    return $(element);
  },

  immediateDescendants: function(element) {
    if (!(element = $(element).firstChild)) return [];
    while (element && element.nodeType != 1) element = element.nextSibling;
    if (element) return [element].concat($(element).nextSiblings());
    return [];
  },

  previousSiblings: function(element) {
    return Element.recursivelyCollect(element, 'previousSibling');
  },

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

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

  match: function(element, selector) {
    if (Object.isString(selector))
      selector = new Selector(selector);
    return selector.match($(element));
  },

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

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

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

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


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

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

  identify: function(element) {
    element = $(element);
    var id = Element.readAttribute(element, 'id');
    if (id) return id;
    do { id = 'anonymous_element_' + Element.idCounter++ } while ($(id));
    Element.writeAttribute(element, 'id', id);
    return id;
  },

  readAttribute: function(element, name) {
    element = $(element);
    if (Prototype.Browser.IE) {
      var t = Element._attributeTranslations.read;
      if (t.values[name]) return t.values[name](element, name);
      if (t.names[name]) name = t.names[name];
      if (name.include(':')) {
        return (!element.attributes || !element.attributes[name]) ? null :
         element.attributes[name].value;
      }
    }
    return element.getAttribute(name);
  },

  writeAttribute: function(element, name, value) {
    element = $(element);
    var attributes = { }, t = Element._attributeTranslations.write;

    if (typeof name == 'object') attributes = name;
    else attributes[name] = Object.isUndefined(value) ? true : value;

    for (var attr in attributes) {
      name = t.names[attr] || attr;
      value = attributes[attr];
      if (t.values[attr]) name = t.values[attr](element, value);
      if (value === false || value === null)
        element.removeAttribute(name);
      else if (value === true)
        element.setAttribute(name, name);
      else element.setAttribute(name, value);
    }
    return element;
  },

  getHeight: function(element) {
    return Element.getDimensions(element).height;
  },

  getWidth: function(element) {
    return Element.getDimensions(element).width;
  },

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

  hasClassName: function(element, className) {
    if (!(element = $(element))) return;
    var elementClassName = element.className;
    return (elementClassName.length > 0 && (elementClassName == className ||
      new RegExp("(^|\\s)" + className + "(\\s|$)").test(elementClassName)));
  },

  addClassName: function(element, className) {
    if (!(element = $(element))) return;
    if (!Element.hasClassName(element, className))
      element.className += (element.className ? ' ' : '') + className;
    return element;
  },

  removeClassName: function(element, className) {
    if (!(element = $(element))) return;
    element.className = element.className.replace(
      new RegExp("(^|\\s+)" + className + "(\\s+|$)"), ' ').strip();
    return element;
  },

  toggleClassName: function(element, className) {
    if (!(element = $(element))) return;
    return Element[Element.hasClassName(element, className) ?
      'removeClassName' : 'addClassName'](element, className);
  },

  cleanWhitespace: function(element) {
    element = $(element);
    var node = element.firstChild;
    while (node) {
      var nextNode = node.nextSibling;
      if (node.nodeType == 3 && !/\S/.test(node.nodeValue))
        element.removeChild(node);
      node = nextNode;
    }
    return element;
  },

  empty: function(element) {
    return $(element).innerHTML.blank();
  },

  descendantOf: function(element, ancestor) {
    element = $(element), ancestor = $(ancestor);

    if (element.compareDocumentPosition)
      return (element.compareDocumentPosition(ancestor) & 8) === 8;

    if (ancestor.contains)
      return ancestor.contains(element) && ancestor !== element;

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

    return false;
  },

  scrollTo: function(element) {
    element = $(element);
    var pos = Element.cumulativeOffset(element);
    window.scrollTo(pos[0], pos[1]);
    return element;
  },

  getStyle: function(element, style) {
    element = $(element);
    style = style == 'float' ? 'cssFloat' : style.camelize();
    var value = element.style[style];
    if (!value || value == 'auto') {
      var css = document.defaultView.getComputedStyle(element, null);
      value = css ? css[style] : null;
    }
    if (style == 'opacity') return value ? parseFloat(value) : 1.0;
    return value == 'auto' ? null : value;
  },

  getOpacity: function(element) {
    return $(element).getStyle('opacity');
  },

  setStyle: function(element, styles) {
    element = $(element);
    var elementStyle = element.style, match;
    if (Object.isString(styles)) {
      element.style.cssText += ';' + styles;
      return styles.include('opacity') ?
        element.setOpacity(styles.match(/opacity:\s*(\d?\.?\d*)/)[1]) : element;
    }
    for (var property in styles)
      if (property == 'opacity') element.setOpacity(styles[property]);
      else
        elementStyle[(property == 'float' || property == 'cssFloat') ?
          (Object.isUndefined(elementStyle.styleFloat) ? 'cssFloat' : 'styleFloat') :
            property] = styles[property];

    return element;
  },

  setOpacity: function(element, value) {
    element = $(element);
    element.style.opacity = (value == 1 || value === '') ? '' :
      (value < 0.00001) ? 0 : value;
    return element;
  },

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

    var els = element.style;
    var originalVisibility = els.visibility;
    var originalPosition = els.position;
    var originalDisplay = els.display;
    els.visibility = 'hidden';
    if (originalPosition != 'fixed') // Switching fixed to absolute causes issues in Safari
      els.position = 'absolute';
    els.display = 'block';
    var originalWidth = element.clientWidth;
    var originalHeight = element.clientHeight;
    els.display = originalDisplay;
    els.position = originalPosition;
    els.visibility = originalVisibility;
    return {width: originalWidth, height: originalHeight};
  },

  makePositioned: function(element) {
    element = $(element);
    var pos = Element.getStyle(element, 'position');
    if (pos == 'static' || !pos) {
      element._madePositioned = true;
      element.style.position = 'relative';
      if (Prototype.Browser.Opera) {
        element.style.top = 0;
        element.style.left = 0;
      }
    }
    return element;
  },

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

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

  undoClipping: function(element) {
    element = $(element);
    if (!element._overflow) return element;
    element.style.overflow = element._overflow == 'auto' ? '' : element._overflow;
    element._overflow = null;
    return element;
  },

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

  positionedOffset: function(element) {
    var valueT = 0, valueL = 0;
    do {
      valueT += element.offsetTop  || 0;
      valueL += element.offsetLeft || 0;
      element = element.offsetParent;
      if (element) {
        if (element.tagName.toUpperCase() == 'BODY') break;
        var p = Element.getStyle(element, 'position');
        if (p !== 'static') break;
      }
    } while (element);
    return Element._returnOffset(valueL, valueT);
  },

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

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

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

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

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

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

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

  cumulativeScrollOffset: function(element) {
    var valueT = 0, valueL = 0;
    do {
      valueT += element.scrollTop  || 0;
      valueL += element.scrollLeft || 0;
      element = element.parentNode;
    } while (element);
    return Element._returnOffset(valueL, valueT);
  },

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

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

    return $(document.body);
  },

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

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

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

    } while (element = element.offsetParent);

    element = forElement;
    do {
      if (!Prototype.Browser.Opera || (element.tagName && (element.tagName.toUpperCase() == 'BODY'))) {
        valueT -= element.scrollTop  || 0;
        valueL -= element.scrollLeft || 0;
      }
    } while (element = element.parentNode);

    return Element._returnOffset(valueL, valueT);
  },

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

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

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

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

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

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

  childElements: Element.Methods.immediateDescendants
});

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

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

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

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

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

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

else if (Prototype.Browser.IE) {
  Element.Methods.getOffsetParent = Element.Methods.getOffsetParent.wrap(
    function(proceed, element) {
      element = $(element);
      try { element.offsetParent }
      catch(e) { return $(document.body) }
      var position = element.getStyle('position');
      if (position !== 'static') return proceed(element);
      element.setStyle({ position: 'relative' });
      var value = proceed(element);
      element.setStyle({ position: position });
      return value;
    }
  );

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

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

  Element.Methods.getStyle = function(element, style) {
    element = $(element);
    style = (style == 'float' || style == 'cssFloat') ? 'styleFloat' : style.camelize();
    var value = element.style[style];
    if (!value && element.currentStyle) value = element.currentStyle[style];

    if (style == 'opacity') {
      if (value = (element.getStyle('filter') || '').match(/alpha\(opacity=(.*)\)/))
        if (value[1]) return parseFloat(value[1]) / 100;
      return 1.0;
    }

    if (value == 'auto') {
      if ((style == 'width' || style == 'height') && (element.getStyle('display') != 'none'))
        return element['offset' + style.capitalize()] + 'px';
      return null;
    }
    return value;
  };

  Element.Methods.setOpacity = function(element, value) {
    function stripAlpha(filter){
      return filter.replace(/alpha\([^\)]*\)/gi,'');
    }
    element = $(element);
    var currentStyle = element.currentStyle;
    if ((currentStyle && !currentStyle.hasLayout) ||
      (!currentStyle && element.style.zoom == 'normal'))
        element.style.zoom = 1;

    var filter = element.getStyle('filter'), style = element.style;
    if (value == 1 || value === '') {
      (filter = stripAlpha(filter)) ?
        style.filter = filter : style.removeAttribute('filter');
      return element;
    } else if (value < 0.00001) value = 0;
    style.filter = stripAlpha(filter) +
      'alpha(opacity=' + (value * 100) + ')';
    return element;
  };

  Element._attributeTranslations = (function(){

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

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

    el.setAttribute(classProp, 'x');

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

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

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

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

            if (String(value).indexOf('{') > -1) {
              f = function(element, attribute) {
                attribute = element.getAttribute(attribute);
                if (!attribute) return null;
                attribute = attribute.toString();
                attribute = attribute.split('{')[1];
                attribute = attribute.split('}')[0];
                return attribute.strip();
              };
            }
            else if (value === '') {
              f = function(element, attribute) {
                attribute = element.getAttribute(attribute);
                if (!attribute) return null;
                return attribute.strip();
              };
            }
            el = null;
            return f;
          })(),
          _flag: function(element, attribute) {
            return $(element).hasAttribute(attribute) ? attribute : null;
          },
          style: function(element) {
            return element.style.cssText.toLowerCase();
          },
          title: function(element) {
            return element.title;
          }
        }
      }
    }
  })();

  Element._attributeTranslations.write = {
    names: Object.extend({
      cellpadding: 'cellPadding',
      cellspacing: 'cellSpacing'
    }, Element._attributeTranslations.read.names),
    values: {
      checked: function(element, value) {
        element.checked = !!value;
      },

      style: function(element, value) {
        element.style.cssText = value ? value : '';
      }
    }
  };

  Element._attributeTranslations.has = {};

  $w('colSpan rowSpan vAlign dateTime accessKey tabIndex ' +
      'encType maxLength readOnly longDesc frameBorder').each(function(attr) {
    Element._attributeTranslations.write.names[attr.toLowerCase()] = attr;
    Element._attributeTranslations.has[attr.toLowerCase()] = attr;
  });

  (function(v) {
    Object.extend(v, {
      href:        v._getAttr2,
      src:         v._getAttr2,
      type:        v._getAttr,
      action:      v._getAttrNode,
      disabled:    v._flag,
      checked:     v._flag,
      readonly:    v._flag,
      multiple:    v._flag,
      onload:      v._getEv,
      onunload:    v._getEv,
      onclick:     v._getEv,
      ondblclick:  v._getEv,
      onmousedown: v._getEv,
      onmouseup:   v._getEv,
      onmouseover: v._getEv,
      onmousemove: v._getEv,
      onmouseout:  v._getEv,
      onfocus:     v._getEv,
      onblur:      v._getEv,
      onkeypress:  v._getEv,
      onkeydown:   v._getEv,
      onkeyup:     v._getEv,
      onsubmit:    v._getEv,
      onreset:     v._getEv,
      onselect:    v._getEv,
      onchange:    v._getEv
    });
  })(Element._attributeTranslations.read.values);

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

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

}

else if (Prototype.Browser.Gecko && /rv:1\.8\.0/.test(navigator.userAgent)) {
  Element.Methods.setOpacity = function(element, value) {
    element = $(element);
    element.style.opacity = (value == 1) ? 0.999999 :
      (value === '') ? '' : (value < 0.00001) ? 0 : value;
    return element;
  };
}

else if (Prototype.Browser.WebKit) {
  Element.Methods.setOpacity = function(element, value) {
    element = $(element);
    element.style.opacity = (value == 1 || value === '') ? '' :
      (value < 0.00001) ? 0 : value;

    if (value == 1)
      if(element.tagName.toUpperCase() == 'IMG' && element.width) {
        element.width++; element.width--;
      } else try {
        var n = document.createTextNode(' ');
        element.appendChild(n);
        element.removeChild(n);
      } catch (e) { }

    return element;
  };

  Element.Methods.cumulativeOffset = function(element) {
    var valueT = 0, valueL = 0;
    do {
      valueT += element.offsetTop  || 0;
      valueL += element.offsetLeft || 0;
      if (element.offsetParent == document.body)
        if (Element.getStyle(element, 'position') == 'absolute') break;

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

    return Element._returnOffset(valueL, valueT);
  };
}

if ('outerHTML' in document.documentElement) {
  Element.Methods.replace = function(element, content) {
    element = $(element);

    if (content && content.toElement) content = content.toElement();
    if (Object.isElement(content)) {
      element.parentNode.replaceChild(content, element);
      return element;
    }

    content = Object.toHTML(content);
    var parent = element.parentNode, tagName = parent.tagName.toUpperCase();

    if (Element._insertionTranslations.tags[tagName]) {
      var nextSibling = element.next();
      var fragments = Element._getContentFromAnonymousElement(tagName, content.stripScripts());
      parent.removeChild(element);
      if (nextSibling)
        fragments.each(function(node) { parent.insertBefore(node, nextSibling) });
      else
        fragments.each(function(node) { parent.appendChild(node) });
    }
    else element.outerHTML = content.stripScripts();

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

Element._returnOffset = function(l, t) {
  var result = [l, t];
  result.left = l;
  result.top = t;
  return result;
};

Element._getContentFromAnonymousElement = function(tagName, html) {
  var div = new Element('div'), t = Element._insertionTranslations.tags[tagName];
  if (t) {
    div.innerHTML = t[0] + html + t[1];
    t[2].times(function() { div = div.firstChild });
  } else div.innerHTML = html;
  return $A(div.childNodes);
};

Element._insertionTranslations = {
  before: function(element, node) {
    element.parentNode.insertBefore(node, element);
  },
  top: function(element, node) {
    element.insertBefore(node, element.firstChild);
  },
  bottom: function(element, node) {
    element.appendChild(node);
  },
  after: function(element, node) {
    element.parentNode.insertBefore(node, element.nextSibling);
  },
  tags: {
    TABLE:  ['<table>',                '</table>',                   1],
    TBODY:  ['<table><tbody>',         '</tbody></table>',           2],
    TR:     ['<table><tbody><tr>',     '</tr></tbody></table>',      3],
    TD:     ['<table><tbody><tr><td>', '</td></tr></tbody></table>', 4],
    SELECT: ['<select>',               '</select>',                  1]
  }
};

(function() {
  var tags = Element._insertionTranslations.tags;
  Object.extend(tags, {
    THEAD: tags.TBODY,
    TFOOT: tags.TBODY,
    TH:    tags.TD
  });
})();

Element.Methods.Simulated = {
  hasAttribute: function(element, attribute) {
    attribute = Element._attributeTranslations.has[attribute] || attribute;
    var node = $(element).getAttributeNode(attribute);
    return !!(node && node.specified);
  }
};

Element.Methods.ByTag = { };

Object.extend(Element, Element.Methods);

(function(div) {

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

  div = null;

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

Element.extend = (function() {

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

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

  var HTMLOBJECTELEMENT_PROTOTYPE_BUGGY = checkDeficiency('object');

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

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

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

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

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

    extendElementWith(element, methods);

    element._extendedByPrototype = Prototype.emptyFunction;
    return element;

  }, {
    refresh: function() {
      if (!Prototype.BrowserFeatures.ElementExtensions) {
        Object.extend(Methods, Element.Methods);
        Object.extend(Methods, Element.Methods.Simulated);
      }
    }
  });

  extend.refresh();
  return extend;
})();

Element.hasAttribute = function(element, attribute) {
  if (element.hasAttribute) return element.hasAttribute(attribute);
  return Element.Methods.Simulated.hasAttribute(element, attribute);
};

Element.addMethods = function(methods) {
  var F = Prototype.BrowserFeatures, T = Element.Methods.ByTag;

  if (!methods) {
    Object.extend(Form, Form.Methods);
    Object.extend(Form.Element, Form.Element.Methods);
    Object.extend(Element.Methods.ByTag, {
      "FORM":     Object.clone(Form.Methods),
      "INPUT":    Object.clone(Form.Element.Methods),
      "SELECT":   Object.clone(Form.Element.Methods),
      "TEXTAREA": Object.clone(Form.Element.Methods)
    });
  }

  if (arguments.length == 2) {
    var tagName = methods;
    methods = arguments[1];
  }

  if (!tagName) Object.extend(Element.Methods, methods || { });
  else {
    if (Object.isArray(tagName)) tagName.each(extend);
    else extend(tagName);
  }

  function extend(tagName) {
    tagName = tagName.toUpperCase();
    if (!Element.Methods.ByTag[tagName])
      Element.Methods.ByTag[tagName] = { };
    Object.extend(Element.Methods.ByTag[tagName], methods);
  }

  function copy(methods, destination, onlyIfAbsent) {
    onlyIfAbsent = onlyIfAbsent || false;
    for (var property in methods) {
      var value = methods[property];
      if (!Object.isFunction(value)) continue;
      if (!onlyIfAbsent || !(property in destination))
        destination[property] = value.methodize();
    }
  }

  function findDOMClass(tagName) {
    var klass;
    var trans = {
      "OPTGROUP": "OptGroup", "TEXTAREA": "TextArea", "P": "Paragraph",
      "FIELDSET": "FieldSet", "UL": "UList", "OL": "OList", "DL": "DList",
      "DIR": "Directory", "H1": "Heading", "H2": "Heading", "H3": "Heading",
      "H4": "Heading", "H5": "Heading", "H6": "Heading", "Q": "Quote",
      "INS": "Mod", "DEL": "Mod", "A": "Anchor", "IMG": "Image", "CAPTION":
      "TableCaption", "COL": "TableCol", "COLGROUP": "TableCol", "THEAD":
      "TableSection", "TFOOT": "TableSection", "TBODY": "TableSection", "TR":
      "TableRow", "TH": "TableCell", "TD": "TableCell", "FRAMESET":
      "FrameSet", "IFRAME": "IFrame"
    };
    if (trans[tagName]) klass = 'HTML' + trans[tagName] + 'Element';
    if (window[klass]) return window[klass];
    klass = 'HTML' + tagName + 'Element';
    if (window[klass]) return window[klass];
    klass = 'HTML' + tagName.capitalize() + 'Element';
    if (window[klass]) return window[klass];

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

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

  if (F.ElementExtensions) {
    copy(Element.Methods, elementPrototype);
    copy(Element.Methods.Simulated, elementPrototype, true);
  }

  if (F.SpecificElementExtensions) {
    for (var tag in Element.Methods.ByTag) {
      var klass = findDOMClass(tag);
      if (Object.isUndefined(klass)) continue;
      copy(T[tag], klass.prototype);
    }
  }

  Object.extend(Element, Element.Methods);
  delete Element.ByTag;

  if (Element.extend.refresh) Element.extend.refresh();
  Element.cache = { };
};


document.viewport = {

  getDimensions: function() {
    return { width: this.getWidth(), height: this.getHeight() };
  },

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

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

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

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

    return document.documentElement;
  }

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

    property[D] = 'client' + D;

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

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

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


Element.Storage = {
  UID: 1
};

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

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

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

    return Element.Storage[uid];
  },

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

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

    return element;
  },

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

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

    return value;
  },

  clone: function(element, deep) {
    if (!(element = $(element))) return;
    var clone = element.cloneNode(deep);
    clone._prototypeUID = void 0;
    if (deep) {
      var descendants = Element.select(clone, '*'),
          i = descendants.length;
      while (i--) {
        descendants[i]._prototypeUID = void 0;
      }
    }
    return Element.extend(clone);
  }
});
/* Portions of the Selector class are derived from Jack Slocum's DomQuery,
 * part of YUI-Ext version 0.40, distributed under the terms of an MIT-style
 * license.  Please see http://www.yui-ext.com/ for more information. */

var Selector = Class.create({
  initialize: function(expression) {
    this.expression = expression.strip();

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

  },

  shouldUseXPath: (function() {

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

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

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

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

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

      var e = this.expression;

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

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

      if (IS_DESCENDANT_SELECTOR_BUGGY) return false;

      return true;
    }

  })(),

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

    if (Selector.CASE_INSENSITIVE_CLASS_NAMES) return false;

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

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

    return true;
  },

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

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

    this.matcher = ["this.matcher = function(root) {",
                    "var r = root, h = Selector.handlers, c = false, n;"];

    while (e && le != e && (/\S/).test(e)) {
      le = e;
      for (var i = 0; i<len; i++) {
        p = ps[i].re;
        name = ps[i].name;
        if (m = e.match(p)) {
          this.matcher.push(Object.isFunction(c[name]) ? c[name](m) :
            new Template(c[name]).evaluate(m));
          e = e.replace(m[0], '');
          break;
        }
      }
    }

    this.matcher.push("return h.unique(n);\n}");
    eval(this.matcher.join('\n'));
    Selector._cache[this.expression] = this.matcher;
  },

  compileXPathMatcher: function() {
    var e = this.expression, ps = Selector.patterns,
        x = Selector.xpath, le, m, len = ps.length, name;

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

    this.matcher = ['.//*'];
    while (e && le != e && (/\S/).test(e)) {
      le = e;
      for (var i = 0; i<len; i++) {
        name = ps[i].name;
        if (m = e.match(ps[i].re)) {
          this.matcher.push(Object.isFunction(x[name]) ? x[name](m) :
            new Template(x[name]).evaluate(m));
          e = e.replace(m[0], '');
          break;
        }
      }
    }

    this.xpath = this.matcher.join('');
    Selector._cache[this.expression] = this.xpath;
  },

  findElements: function(root) {
    root = root || document;
    var e = this.expression, results;

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

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

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

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

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

    while (e && le !== e && (/\S/).test(e)) {
      le = e;
      for (var i = 0; i<len; i++) {
        p = ps[i].re;
        name = ps[i].name;
        if (m = e.match(p)) {
          if (as[name]) {
            this.tokens.push([name, Object.clone(m)]);
            e = e.replace(m[0], '');
          } else {
            return this.findElements(document).include(element);
          }
        }
      }
    }

    var match = true, name, matches;
    for (var i = 0, token; token = this.tokens[i]; i++) {
      name = token[0], matches = token[1];
      if (!Selector.assertions[name](element, matches)) {
        match = false; break;
      }
    }

    return match;
  },

  toString: function() {
    return this.expression;
  },

  inspect: function() {
    return "#<Selector:" + this.expression.inspect() + ">";
  }
});

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

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

Object.extend(Selector, {
  _cache: { },

  xpath: {
    descendant:   "//*",
    child:        "/*",
    adjacent:     "/following-sibling::*[1]",
    laterSibling: '/following-sibling::*',
    tagName:      function(m) {
      if (m[1] == '*') return '';
      return "[local-name()='" + m[1].toLowerCase() +
             "' or local-name()='" + m[1].toUpperCase() + "']";
    },
    className:    "[contains(concat(' ', @class, ' '), ' #{1} ')]",
    id:           "[@id='#{1}']",
    attrPresence: function(m) {
      m[1] = m[1].toLowerCase();
      return new Template("[@#{1}]").evaluate(m);
    },
    attr: function(m) {
      m[1] = m[1].toLowerCase();
      m[3] = m[5] || m[6];
      return new Template(Selector.xpath.operators[m[2]]).evaluate(m);
    },
    pseudo: function(m) {
      var h = Selector.xpath.pseudos[m[1]];
      if (!h) return '';
      if (Object.isFunction(h)) return h(m);
      return new Template(Selector.xpath.pseudos[m[1]]).evaluate(m);
    },
    operators: {
      '=':  "[@#{1}='#{3}']",
      '!=': "[@#{1}!='#{3}']",
      '^=': "[starts-with(@#{1}, '#{3}')]",
      '$=': "[substring(@#{1}, (string-length(@#{1}) - string-length('#{3}') + 1))='#{3}']",
      '*=': "[contains(@#{1}, '#{3}')]",
      '~=': "[contains(concat(' ', @#{1}, ' '), ' #{3} ')]",
      '|=': "[contains(concat('-', @#{1}, '-'), '-#{3}-')]"
    },
    pseudos: {
      'first-child': '[not(preceding-sibling::*)]',
      'last-child':  '[not(following-sibling::*)]',
      'only-child':  '[not(preceding-sibling::* or following-sibling::*)]',
      'empty':       "[count(*) = 0 and (count(text()) = 0)]",
      'checked':     "[@checked]",
      'disabled':    "[(@disabled) and (@type!='hidden')]",
      'enabled':     "[not(@disabled) and (@type!='hidden')]",
      'not': function(m) {
        var e = m[6], p = Selector.patterns,
            x = Selector.xpath, le, v, len = p.length, name;

        var exclusion = [];
        while (e && le != e && (/\S/).test(e)) {
          le = e;
          for (var i = 0; i<len; i++) {
            name = p[i].name
            if (m = e.match(p[i].re)) {
              v = Object.isFunction(x[name]) ? x[name](m) : new Template(x[name]).evaluate(m);
              exclusion.push("(" + v.substring(1, v.length - 1) + ")");
              e = e.replace(m[0], '');
              break;
            }
          }
        }
        return "[not(" + exclusion.join(" and ") + ")]";
      },
      'nth-child':      function(m) {
        return Selector.xpath.pseudos.nth("(count(./preceding-sibling::*) + 1) ", m);
      },
      'nth-last-child': function(m) {
        return Selector.xpath.pseudos.nth("(count(./following-sibling::*) + 1) ", m);
      },
      'nth-of-type':    function(m) {
        return Selector.xpath.pseudos.nth("position() ", m);
      },
      'nth-last-of-type': function(m) {
        return Selector.xpath.pseudos.nth("(last() + 1 - position()) ", m);
      },
      'first-of-type':  function(m) {
        m[6] = "1"; return Selector.xpath.pseudos['nth-of-type'](m);
      },
      'last-of-type':   function(m) {
        m[6] = "1"; return Selector.xpath.pseudos['nth-last-of-type'](m);
      },
      'only-of-type':   function(m) {
        var p = Selector.xpath.pseudos; return p['first-of-type'](m) + p['last-of-type'](m);
      },
      nth: function(fragment, m) {
        var mm, formula = m[6], predicate;
        if (formula == 'even') formula = '2n+0';
        if (formula == 'odd')  formula = '2n+1';
        if (mm = formula.match(/^(\d+)$/)) // digit only
          return '[' + fragment + "= " + mm[1] + ']';
        if (mm = formula.match(/^(-?\d*)?n(([+-])(\d+))?/)) { // an+b
          if (mm[1] == "-") mm[1] = -1;
          var a = mm[1] ? Number(mm[1]) : 1;
          var b = mm[2] ? Number(mm[2]) : 0;
          predicate = "[((#{fragment} - #{b}) mod #{a} = 0) and " +
          "((#{fragment} - #{b}) div #{a} >= 0)]";
          return new Template(predicate).evaluate({
            fragment: fragment, a: a, b: b });
        }
      }
    }
  },

  criteria: {
    tagName:      'n = h.tagName(n, r, "#{1}", c);      c = false;',
    className:    'n = h.className(n, r, "#{1}", c);    c = false;',
    id:           'n = h.id(n, r, "#{1}", c);           c = false;',
    attrPresence: 'n = h.attrPresence(n, r, "#{1}", c); c = false;',
    attr: function(m) {
      m[3] = (m[5] || m[6]);
      return new Template('n = h.attr(n, r, "#{1}", "#{3}", "#{2}", c); c = false;').evaluate(m);
    },
    pseudo: function(m) {
      if (m[6]) m[6] = m[6].replace(/"/g, '\\"');
      return new Template('n = h.pseudo(n, "#{1}", "#{6}", r, c); c = false;').evaluate(m);
    },
    descendant:   'c = "descendant";',
    child:        'c = "child";',
    adjacent:     'c = "adjacent";',
    laterSibling: 'c = "laterSibling";'
  },

  patterns: [
    { name: 'laterSibling', re: /^\s*~\s*/ },
    { name: 'child',        re: /^\s*>\s*/ },
    { name: 'adjacent',     re: /^\s*\+\s*/ },
    { name: 'descendant',   re: /^\s/ },

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

  assertions: {
    tagName: function(element, matches) {
      return matches[1].toUpperCase() == element.tagName.toUpperCase();
    },

    className: function(element, matches) {
      return Element.hasClassName(element, matches[1]);
    },

    id: function(element, matches) {
      return element.id === matches[1];
    },

    attrPresence: function(element, matches) {
      return Element.hasAttribute(element, matches[1]);
    },

    attr: function(element, matches) {
      var nodeValue = Element.readAttribute(element, matches[1]);
      return nodeValue && Selector.operators[matches[2]](nodeValue, matches[5] || matches[6]);
    }
  },

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

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

    unmark: (function(){

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

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

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

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

    descendant: function(nodes) {
      var h = Selector.handlers;
      for (var i = 0, results = [], node; node = nodes[i]; i++)
        h.concat(results, node.getElementsByTagName('*'));
      return results;
    },

    child: function(nodes) {
      var h = Selector.handlers;
      for (var i = 0, results = [], node; node = nodes[i]; i++) {
        for (var j = 0, child; child = node.childNodes[j]; j++)
          if (child.nodeType == 1 && child.tagName != '!') results.push(child);
      }
      return results;
    },

    adjacent: function(nodes) {
      for (var i = 0, results = [], node; node = nodes[i]; i++) {
        var next = this.nextElementSibling(node);
        if (next) results.push(next);
      }
      return results;
    },

    laterSibling: function(nodes) {
      var h = Selector.handlers;
      for (var i = 0, results = [], node; node = nodes[i]; i++)
        h.concat(results, Element.nextSiblings(node));
      return results;
    },

    nextElementSibling: function(node) {
      while (node = node.nextSibling)
        if (node.nodeType == 1) return node;
      return null;
    },

    previousElementSibling: function(node) {
      while (node = node.previousSibling)
        if (node.nodeType == 1) return node;
      return null;
    },

    tagName: function(nodes, root, tagName, combinator) {
      var uTagName = tagName.toUpperCase();
      var results = [], h = Selector.handlers;
      if (nodes) {
        if (combinator) {
          if (combinator == "descendant") {
            for (var i = 0, node; node = nodes[i]; i++)
              h.concat(results, node.getElementsByTagName(tagName));
            return results;
          } else nodes = this[combinator](nodes);
          if (tagName == "*") return nodes;
        }
        for (var i = 0, node; node = nodes[i]; i++)
          if (node.tagName.toUpperCase() === uTagName) results.push(node);
        return results;
      } else return root.getElementsByTagName(tagName);
    },

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

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

      if (nodes) {
        if (combinator) {
          if (combinator == 'child') {
            for (var i = 0, node; node = nodes[i]; i++)
              if (targetNode.parentNode == node) return [targetNode];
          } else if (combinator == 'descendant') {
            for (var i = 0, node; node = nodes[i]; i++)
              if (Element.descendantOf(targetNode, node)) return [targetNode];
          } else if (combinator == 'adjacent') {
            for (var i = 0, node; node = nodes[i]; i++)
              if (Selector.handlers.previousElementSibling(targetNode) == node)
                return [targetNode];
          } else nodes = h[combinator](nodes);
        }
        for (var i = 0, node; node = nodes[i]; i++)
          if (node == targetNode) return [targetNode];
        return [];
      }
      return (targetNode && Element.descendantOf(targetNode, root)) ? [targetNode] : [];
    },

    className: function(nodes, root, className, combinator) {
      if (nodes && combinator) nodes = this[combinator](nodes);
      return Selector.handlers.byClassName(nodes, root, className);
    },

    byClassName: function(nodes, root, className) {
      if (!nodes) nodes = Selector.handlers.descendant([root]);
      var needle = ' ' + className + ' ';
      for (var i = 0, results = [], node, nodeClassName; node = nodes[i]; i++) {
        nodeClassName = node.className;
        if (nodeClassName.length == 0) continue;
        if (nodeClassName == className || (' ' + nodeClassName + ' ').include(needle))
          results.push(node);
      }
      return results;
    },

    attrPresence: function(nodes, root, attr, combinator) {
      if (!nodes) nodes = root.getElementsByTagName("*");
      if (nodes && combinator) nodes = this[combinator](nodes);
      var results = [];
      for (var i = 0, node; node = nodes[i]; i++)
        if (Element.hasAttribute(node, attr)) results.push(node);
      return results;
    },

    attr: function(nodes, root, attr, value, operator, combinator) {
      if (!nodes) nodes = root.getElementsByTagName("*");
      if (nodes && combinator) nodes = this[combinator](nodes);
      var handler = Selector.operators[operator], results = [];
      for (var i = 0, node; node = nodes[i]; i++) {
        var nodeValue = Element.readAttribute(node, attr);
        if (nodeValue === null) continue;
        if (handler(nodeValue, value)) results.push(node);
      }
      return results;
    },

    pseudo: function(nodes, name, value, root, combinator) {
      if (nodes && combinator) nodes = this[combinator](nodes);
      if (!nodes) nodes = root.getElementsByTagName("*");
      return Selector.pseudos[name](nodes, value, root);
    }
  },

  pseudos: {
    'first-child': function(nodes, value, root) {
      for (var i = 0, results = [], node; node = nodes[i]; i++) {
        if (Selector.handlers.previousElementSibling(node)) continue;
          results.push(node);
      }
      return results;
    },
    'last-child': function(nodes, value, root) {
      for (var i = 0, results = [], node; node = nodes[i]; i++) {
        if (Selector.handlers.nextElementSibling(node)) continue;
          results.push(node);
      }
      return results;
    },
    'only-child': function(nodes, value, root) {
      var h = Selector.handlers;
      for (var i = 0, results = [], node; node = nodes[i]; i++)
        if (!h.previousElementSibling(node) && !h.nextElementSibling(node))
          results.push(node);
      return results;
    },
    'nth-child':        function(nodes, formula, root) {
      return Selector.pseudos.nth(nodes, formula, root);
    },
    'nth-last-child':   function(nodes, formula, root) {
      return Selector.pseudos.nth(nodes, formula, root, true);
    },
    'nth-of-type':      function(nodes, formula, root) {
      return Selector.pseudos.nth(nodes, formula, root, false, true);
    },
    'nth-last-of-type': function(nodes, formula, root) {
      return Selector.pseudos.nth(nodes, formula, root, true, true);
    },
    'first-of-type':    function(nodes, formula, root) {
      return Selector.pseudos.nth(nodes, "1", root, false, true);
    },
    'last-of-type':     function(nodes, formula, root) {
      return Selector.pseudos.nth(nodes, "1", root, true, true);
    },
    'only-of-type':     function(nodes, formula, root) {
      var p = Selector.pseudos;
      return p['last-of-type'](p['first-of-type'](nodes, formula, root), formula, root);
    },

    getIndices: function(a, b, total) {
      if (a == 0) return b > 0 ? [b] : [];
      return $R(1, total).inject([], function(memo, i) {
        if (0 == (i - b) % a && (i - b) / a >= 0) memo.push(i);
        return memo;
      });
    },

    nth: function(nodes, formula, root, reverse, ofType) {
      if (nodes.length == 0) return [];
      if (formula == 'even') formula = '2n+0';
      if (formula == 'odd')  formula = '2n+1';
      var h = Selector.handlers, results = [], indexed = [], m;
      h.mark(nodes);
      for (var i = 0, node; node = nodes[i]; i++) {
        if (!node.parentNode._countedByPrototype) {
          h.index(node.parentNode, reverse, ofType);
          indexed.push(node.parentNode);
        }
      }
      if (formula.match(/^\d+$/)) { // just a number
        formula = Number(formula);
        for (var i = 0, node; node = nodes[i]; i++)
          if (node.nodeIndex == formula) results.push(node);
      } else if (m = formula.match(/^(-?\d*)?n(([+-])(\d+))?/)) { // an+b
        if (m[1] == "-") m[1] = -1;
        var a = m[1] ? Number(m[1]) : 1;
        var b = m[2] ? Number(m[2]) : 0;
        var indices = Selector.pseudos.getIndices(a, b, nodes.length);
        for (var i = 0, node, l = indices.length; node = nodes[i]; i++) {
          for (var j = 0; j < l; j++)
            if (node.nodeIndex == indices[j]) results.push(node);
        }
      }
      h.unmark(nodes);
      h.unmark(indexed);
      return results;
    },

    'empty': function(nodes, value, root) {
      for (var i = 0, results = [], node; node = nodes[i]; i++) {
        if (node.tagName == '!' || node.firstChild) continue;
        results.push(node);
      }
      return results;
    },

    'not': function(nodes, selector, root) {
      var h = Selector.handlers, selectorType, m;
      var exclusions = new Selector(selector).findElements(root);
      h.mark(exclusions);
      for (var i = 0, results = [], node; node = nodes[i]; i++)
        if (!node._countedByPrototype) results.push(node);
      h.unmark(exclusions);
      return results;
    },

    'enabled': function(nodes, value, root) {
      for (var i = 0, results = [], node; node = nodes[i]; i++)
        if (!node.disabled && (!node.type || node.type !== 'hidden'))
          results.push(node);
      return results;
    },

    'disabled': function(nodes, value, root) {
      for (var i = 0, results = [], node; node = nodes[i]; i++)
        if (node.disabled) results.push(node);
      return results;
    },

    'checked': function(nodes, value, root) {
      for (var i = 0, results = [], node; node = nodes[i]; i++)
        if (node.checked) results.push(node);
      return results;
    }
  },

  operators: {
    '=':  function(nv, v) { return nv == v; },
    '!=': function(nv, v) { return nv != v; },
    '^=': function(nv, v) { return nv == v || nv && nv.startsWith(v); },
    '$=': function(nv, v) { return nv == v || nv && nv.endsWith(v); },
    '*=': function(nv, v) { return nv == v || nv && nv.include(v); },
    '~=': function(nv, v) { return (' ' + nv + ' ').include(' ' + v + ' '); },
    '|=': function(nv, v) { return ('-' + (nv || "").toUpperCase() +
     '-').include('-' + (v || "").toUpperCase() + '-'); }
  },

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

  matchElements: function(elements, expression) {
    var matches = $$(expression), h = Selector.handlers;
    h.mark(matches);
    for (var i = 0, results = [], element; element = elements[i]; i++)
      if (element._countedByPrototype) results.push(element);
    h.unmark(matches);
    return results;
  },

  findElement: function(elements, expression, index) {
    if (Object.isNumber(expression)) {
      index = expression; expression = false;
    }
    return Selector.matchElements(elements, expression || '*')[index || 0];
  },

  findChildElements: function(element, expressions) {
    expressions = Selector.split(expressions.join(','));
    var results = [], h = Selector.handlers;
    for (var i = 0, l = expressions.length, selector; i < l; i++) {
      selector = new Selector(expressions[i].strip());
      h.concat(results, selector.findElements(element));
    }
    return (l > 1) ? h.unique(results) : results;
  }
});

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

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

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

  serializeElements: function(elements, options) {
    if (typeof options != 'object') options = { hash: !!options };
    else if (Object.isUndefined(options.hash)) options.hash = true;
    var key, value, submitted = false, submit = options.submit;

    var data = elements.inject({ }, function(result, element) {
      if (!element.disabled && element.name) {
        key = element.name; value = $(element).getValue();
        if (value != null && element.type != 'file' && (element.type != 'submit' || (!submitted &&
            submit !== false && (!submit || key == submit) && (submitted = true)))) {
          if (key in result) {
            if (!Object.isArray(result[key])) result[key] = [result[key]];
            result[key].push(value);
          }
          else result[key] = value;
        }
      }
      return result;
    });

    return options.hash ? data : Object.toQueryString(data);
  }
};

Form.Methods = {
  serialize: function(form, options) {
    return Form.serializeElements(Form.getElements(form), options);
  },

  getElements: function(form) {
    var elements = $(form).getElementsByTagName('*'),
        element,
        arr = [ ],
        serializers = Form.Element.Serializers;
    for (var i = 0; element = elements[i]; i++) {
      arr.push(element);
    }
    return arr.inject([], function(elements, child) {
      if (serializers[child.tagName.toLowerCase()])
        elements.push(Element.extend(child));
      return elements;
    })
  },

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

    if (!typeName && !name) return $A(inputs).map(Element.extend);

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

    return matchingInputs;
  },

  disable: function(form) {
    form = $(form);
    Form.getElements(form).invoke('disable');
    return form;
  },

  enable: function(form) {
    form = $(form);
    Form.getElements(form).invoke('enable');
    return form;
  },

  findFirstElement: function(form) {
    var elements = $(form).getElements().findAll(function(element) {
      return 'hidden' != element.type && !element.disabled;
    });
    var firstByIndex = elements.findAll(function(element) {
      return element.hasAttribute('tabIndex') && element.tabIndex >= 0;
    }).sortBy(function(element) { return element.tabIndex }).first();

    return firstByIndex ? firstByIndex : elements.find(function(element) {
      return /^(?:input|select|textarea)$/i.test(element.tagName);
    });
  },

  focusFirstElement: function(form) {
    form = $(form);
    form.findFirstElement().activate();
    return form;
  },

  request: function(form, options) {
    form = $(form), options = Object.clone(options || { });

    var params = options.parameters, action = form.readAttribute('action') || '';
    if (action.blank()) action = window.location.href;
    options.parameters = form.serialize(true);

    if (params) {
      if (Object.isString(params)) params = params.toQueryParams();
      Object.extend(options.parameters, params);
    }

    if (form.hasAttribute('method') && !options.method)
      options.method = form.method;

    return new Ajax.Request(action, options);
  }
};

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


Form.Element = {
  focus: function(element) {
    $(element).focus();
    return element;
  },

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

Form.Element.Methods = {

  serialize: function(element) {
    element = $(element);
    if (!element.disabled && element.name) {
      var value = element.getValue();
      if (value != undefined) {
        var pair = { };
        pair[element.name] = value;
        return Object.toQueryString(pair);
      }
    }
    return '';
  },

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

  setValue: function(element, value) {
    element = $(element);
    var method = element.tagName.toLowerCase();
    Form.Element.Serializers[method](element, value);
    return element;
  },

  clear: function(element) {
    $(element).value = '';
    return element;
  },

  present: function(element) {
    return $(element).value != '';
  },

  activate: function(element) {
    element = $(element);
    try {
      element.focus();
      if (element.select && (element.tagName.toLowerCase() != 'input' ||
          !(/^(?:button|reset|submit)$/i.test(element.type))))
        element.select();
    } catch (e) { }
    return element;
  },

  disable: function(element) {
    element = $(element);
    element.disabled = true;
    return element;
  },

  enable: function(element) {
    element = $(element);
    element.disabled = false;
    return element;
  }
};

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

var Field = Form.Element;

var $F = Form.Element.Methods.getValue;

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

Form.Element.Serializers = {
  input: function(element, value) {
    switch (element.type.toLowerCase()) {
      case 'checkbox':
      case 'radio':
        return Form.Element.Serializers.inputSelector(element, value);
      default:
        return Form.Element.Serializers.textarea(element, value);
    }
  },

  inputSelector: function(element, value) {
    if (Object.isUndefined(value)) return element.checked ? element.value : null;
    else element.checked = !!value;
  },

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

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

  selectOne: function(element) {
    var index = element.selectedIndex;
    return index >= 0 ? this.optionValue(element.options[index]) : null;
  },

  selectMany: function(element) {
    var values, length = element.length;
    if (!length) return null;

    for (var i = 0, values = []; i < length; i++) {
      var opt = element.options[i];
      if (opt.selected) values.push(this.optionValue(opt));
    }
    return values;
  },

  optionValue: function(opt) {
    return Element.extend(opt).hasAttribute('value') ? opt.value : opt.text;
  }
};

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


Abstract.TimedObserver = Class.create(PeriodicalExecuter, {
  initialize: function($super, element, frequency, callback) {
    $super(callback, frequency);
    this.element   = $(element);
    this.lastValue = this.getValue();
  },

  execute: function() {
    var value = this.getValue();
    if (Object.isString(this.lastValue) && Object.isString(value) ?
        this.lastValue != value : String(this.lastValue) != String(value)) {
      this.callback(this.element, value);
      this.lastValue = value;
    }
  }
});

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

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

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

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

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

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

  registerFormCallbacks: function() {
    Form.getElements(this.element).each(this.registerCallback, this);
  },

  registerCallback: function(element) {
    if (element.type) {
      switch (element.type.toLowerCase()) {
        case 'checkbox':
        case 'radio':
          Event.observe(element, 'click', this.onElementEvent.bind(this));
          break;
        default:
          Event.observe(element, 'change', this.onElementEvent.bind(this));
          break;
      }
    }
  }
});

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

Form.EventObserver = Class.create(Abstract.EventObserver, {
  getValue: function() {
    return Form.serialize(this.element);
  }
});
(function() {

  var Event = {
    KEY_BACKSPACE: 8,
    KEY_TAB:       9,
    KEY_RETURN:   13,
    KEY_ESC:      27,
    KEY_LEFT:     37,
    KEY_UP:       38,
    KEY_RIGHT:    39,
    KEY_DOWN:     40,
    KEY_DELETE:   46,
    KEY_HOME:     36,
    KEY_END:      35,
    KEY_PAGEUP:   33,
    KEY_PAGEDOWN: 34,
    KEY_INSERT:   45,

    cache: {}
  };

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

  var _isButton;
  if (Prototype.Browser.IE) {
    var buttonMap = { 0: 1, 1: 4, 2: 2 };
    _isButton = function(event, code) {
      return event.button === buttonMap[code];
    };
  } else if (Prototype.Browser.WebKit) {
    _isButton = function(event, code) {
      switch (code) {
        case 0: return event.which == 1 && !event.metaKey;
        case 1: return event.which == 1 && event.metaKey;
        default: return false;
      }
    };
  } else {
    _isButton = function(event, code) {
      return event.which ? (event.which === code + 1) : (event.button === code);
    };
  }

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

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

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

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

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

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

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

    return Element.extend(node);
  }

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

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

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

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

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

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


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

    event.stopped = true;
  }

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

    element: element,
    findElement: findElement,

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

    stop: stop
  };


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

  if (Prototype.Browser.IE) {
    function _relatedTarget(event) {
      var element;
      switch (event.type) {
        case 'mouseover': element = event.fromElement; break;
        case 'mouseout':  element = event.toElement;   break;
        default: return null;
      }
      return Element.extend(element);
    }

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

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

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

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

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

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

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

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

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

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

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

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

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

            if (parent === element) return;

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

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

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

  var CACHE = [];

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

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


  var _getDOMEventName = Prototype.K;

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

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

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

    if (!responder) return element;

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

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

    return element;
  }

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

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

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

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

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

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

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

    var responders = registry.get(eventName);

    if (!responders) return;

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

    var actualEventName = _getDOMEventName(eventName);

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

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

    return element;
  }

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

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

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

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

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

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

    return Event.extend(event);
  }


  Object.extend(Event, Event.Methods);

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

  Element.addMethods({
    fire:          fire,

    observe:       observe,

    stopObserving: stopObserving
  });

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

    observe:       observe.methodize(),

    stopObserving: stopObserving.methodize(),

    loaded:        false
  });

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

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

  var timer;

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

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

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

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

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

Element.addMethods();

/*------------------------------- DEPRECATED -------------------------------*/

Hash.toQueryString = Object.toQueryString;

var Toggle = { display: Element.toggle };

Element.Methods.childOf = Element.Methods.descendantOf;

var Insertion = {
  Before: function(element, content) {
    return Element.insert(element, {before:content});
  },

  Top: function(element, content) {
    return Element.insert(element, {top:content});
  },

  Bottom: function(element, content) {
    return Element.insert(element, {bottom:content});
  },

  After: function(element, content) {
    return Element.insert(element, {after:content});
  }
};

var $continue = new Error('"throw $continue" is deprecated, use "return" instead');

var Position = {
  includeScrollOffsets: false,

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

  within: function(element, x, y) {
    if (this.includeScrollOffsets)
      return this.withinIncludingScrolloffsets(element, x, y);
    this.xcomp = x;
    this.ycomp = y;
    this.offset = Element.cumulativeOffset(element);

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

  withinIncludingScrolloffsets: function(element, x, y) {
    var offsetcache = Element.cumulativeScrollOffset(element);

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

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

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


  cumulativeOffset: Element.Methods.cumulativeOffset,

  positionedOffset: Element.Methods.positionedOffset,

  absolutize: function(element) {
    Position.prepare();
    return Element.absolutize(element);
  },

  relativize: function(element) {
    Position.prepare();
    return Element.relativize(element);
  },

  realOffset: Element.Methods.cumulativeScrollOffset,

  offsetParent: Element.Methods.getOffsetParent,

  page: Element.Methods.viewportOffset,

  clone: function(source, target, options) {
    options = options || { };
    return Element.clonePosition(target, source, options);
  }
};

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

if (!document.getElementsByClassName) document.getElementsByClassName = function(instanceMethods){
  function iter(name) {
    return name.blank() ? null : "[contains(concat(' ', @class, ' '), ' " + name + " ')]";
  }

  instanceMethods.getElementsByClassName = Prototype.BrowserFeatures.XPath ?
  function(element, className) {
    className = className.toString().strip();
    var cond = /\s/.test(className) ? $w(className).map(iter).join('') : iter(className);
    return cond ? document._getElementsByXPath('.//*' + cond, element) : [];
  } : function(element, className) {
    className = className.toString().strip();
    var elements = [], classNames = (/\s/.test(className) ? $w(className) : null);
    if (!classNames && !className) return elements;

    var nodes = $(element).getElementsByTagName('*');
    className = ' ' + className + ' ';

    for (var i = 0, child, cn; child = nodes[i]; i++) {
      if (child.className && (cn = ' ' + child.className + ' ') && (cn.include(className) ||
          (classNames && classNames.all(function(name) {
            return !name.toString().blank() && cn.include(' ' + name + ' ');
          }))))
        elements.push(Element.extend(child));
    }
    return elements;
  };

  return function(className, parentElement) {
    return $(parentElement || document.body).getElementsByClassName(className);
  };
}(Element.Methods);

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

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

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

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

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

  remove: function(classNameToRemove) {
    if (!this.include(classNameToRemove)) return;
    this.set($A(this).without(classNameToRemove).join(' '));
  },

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

Object.extend(Element.ClassNames.prototype, Enumerable);

/*--------------------------------------------------------------------------*/
// script.aculo.us scriptaculous.js v1.8.2, Tue Nov 18 18:30:58 +0100 2008

// Copyright (c) 2005-2008 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
// For details, see the script.aculo.us web site: http://script.aculo.us/

var Scriptaculous = {
  Version: '1.8.2',
  REQUIRED_PROTOTYPE: '1.6.0.3',
  load: function() {
    function convertVersionString(versionString) {
      var v = versionString.replace(/_.*|\./g, '');
      v = parseInt(v + '0'.times(4-v.length));
      return versionString.indexOf('_') > -1 ? v-1 : v;
    }

    if((typeof Prototype=='undefined') ||
       (typeof Element == 'undefined') ||
       (typeof Element.Methods=='undefined') ||
       (convertVersionString(Prototype.Version) <
        convertVersionString(Scriptaculous.REQUIRED_PROTOTYPE)))
       throw("script.aculo.us requires the Prototype JavaScript framework >= " +
        Scriptaculous.REQUIRED_PROTOTYPE);
  }
};

Scriptaculous.load();
// script.aculo.us builder.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)
//
// script.aculo.us is freely distributable under the terms of an MIT-style license.
// For details, see the script.aculo.us web site: http://script.aculo.us/

var Builder = {
  NODEMAP: {
    AREA: 'map',
    CAPTION: 'table',
    COL: 'table',
    COLGROUP: 'table',
    LEGEND: 'fieldset',
    OPTGROUP: 'select',
    OPTION: 'select',
    PARAM: 'object',
    TBODY: 'table',
    TD: 'table',
    TFOOT: 'table',
    TH: 'table',
    THEAD: 'table',
    TR: 'table'
  },
  // note: For Firefox < 1.5, OPTION and OPTGROUP tags are currently broken,
  //       due to a Firefox bug
  node: function(elementName) {
    elementName = elementName.toUpperCase();

    // try innerHTML approach
    var parentTag = this.NODEMAP[elementName] || 'div';
    var parentElement = document.createElement(parentTag);
    try { // prevent IE "feature": http://dev.rubyonrails.org/ticket/2707
      parentElement.innerHTML = "<" + elementName + "></" + elementName + ">";
    } catch(e) {}
    var element = parentElement.firstChild || null;

    // see if browser added wrapping tags
    if(element && (element.tagName.toUpperCase() != elementName))
      element = element.getElementsByTagName(elementName)[0];

    // fallback to createElement approach
    if(!element) element = document.createElement(elementName);

    // abort if nothing could be created
    if(!element) return;

    // attributes (or text)
    if(arguments[1])
      if(this._isStringOrNumber(arguments[1]) ||
        (arguments[1] instanceof Array) ||
        arguments[1].tagName) {
          this._children(element, arguments[1]);
        } else {
          var attrs = this._attributes(arguments[1]);
          if(attrs.length) {
            try { // prevent IE "feature": http://dev.rubyonrails.org/ticket/2707
              parentElement.innerHTML = "<" +elementName + " " +
                attrs + "></" + elementName + ">";
            } catch(e) {}
            element = parentElement.firstChild || null;
            // workaround firefox 1.0.X bug
            if(!element) {
              element = document.createElement(elementName);
              for(attr in arguments[1])
                element[attr == 'class' ? 'className' : attr] = arguments[1][attr];
            }
            if(element.tagName.toUpperCase() != elementName)
              element = parentElement.getElementsByTagName(elementName)[0];
          }
        }

    // text, or array of children
    if(arguments[2])
      this._children(element, arguments[2]);

     return $(element);
  },
  _text: function(text) {
     return document.createTextNode(text);
  },

  ATTR_MAP: {
    'className': 'class',
    'htmlFor': 'for'
  },

  _attributes: function(attributes) {
    var attrs = [];
    for(attribute in attributes)
      attrs.push((attribute in this.ATTR_MAP ? this.ATTR_MAP[attribute] : attribute) +
          '="' + attributes[attribute].toString().escapeHTML().gsub(/"/,'&quot;') + '"');
    return attrs.join(" ");
  },
  _children: function(element, children) {
    if(children.tagName) {
      element.appendChild(children);
      return;
    }
    if(typeof children=='object') { // array can hold nodes and text
      children.flatten().each( function(e) {
        if(typeof e=='object')
          element.appendChild(e);
        else
          if(Builder._isStringOrNumber(e))
            element.appendChild(Builder._text(e));
      });
    } else
      if(Builder._isStringOrNumber(children))
        element.appendChild(Builder._text(children));
  },
  _isStringOrNumber: function(param) {
    return(typeof param=='string' || typeof param=='number');
  },
  build: function(html) {
    var element = this.node('div');
    $(element).update(html.strip());
    return element.down();
  },
  dump: function(scope) {
    if(typeof scope != 'object' && typeof scope != 'function') scope = window; //global scope

    var tags = ("A ABBR ACRONYM ADDRESS APPLET AREA B BASE BASEFONT BDO BIG BLOCKQUOTE BODY " +
      "BR BUTTON CAPTION CENTER CITE CODE COL COLGROUP DD DEL DFN DIR DIV DL DT EM FIELDSET " +
      "FONT FORM FRAME FRAMESET H1 H2 H3 H4 H5 H6 HEAD HR HTML I IFRAME IMG INPUT INS ISINDEX "+
      "KBD LABEL LEGEND LI LINK MAP MENU META NOFRAMES NOSCRIPT OBJECT OL OPTGROUP OPTION P "+
      "PARAM PRE Q S SAMP SCRIPT SELECT SMALL SPAN STRIKE STRONG STYLE SUB SUP TABLE TBODY TD "+
      "TEXTAREA TFOOT TH THEAD TITLE TR TT U UL VAR").split(/\s+/);

    tags.each( function(tag){
      scope[tag] = function() {
        return Builder.node.apply(Builder, [tag].concat($A(arguments)));
      };
    });
  }
};// 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 dragdrop.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 Sammi Williams (http://www.oriontransfer.co.nz, sammi@oriontransfer.co.nz)
//
// script.aculo.us is freely distributable under the terms of an MIT-style license.
// For details, see the script.aculo.us web site: http://script.aculo.us/

if(Object.isUndefined(Effect))
  throw("dragdrop.js requires including script.aculo.us' effects.js library");

var Droppables = {
  drops: [],

  remove: function(element) {
    this.drops = this.drops.reject(function(d) { return d.element==$(element) });
  },

  add: function(element) {
    element = $(element);
    var options = Object.extend({
      greedy:     true,
      hoverclass: null,
      tree:       false
    }, arguments[1] || { });

    // cache containers
    if(options.containment) {
      options._containers = [];
      var containment = options.containment;
      if(Object.isArray(containment)) {
        containment.each( function(c) { options._containers.push($(c)) });
      } else {
        options._containers.push($(containment));
      }
    }

    if(options.accept) options.accept = [options.accept].flatten();

    Element.makePositioned(element); // fix IE
    options.element = element;

    this.drops.push(options);
  },

  findDeepestChild: function(drops) {
    deepest = drops[0];

    for (i = 1; i < drops.length; ++i)
      if (Element.isParent(drops[i].element, deepest.element))
        deepest = drops[i];

    return deepest;
  },

  isContained: function(element, drop) {
    var containmentNode;
    if(drop.tree) {
      containmentNode = element.treeNode;
    } else {
      containmentNode = element.parentNode;
    }
    return drop._containers.detect(function(c) { return containmentNode == c });
  },

  isAffected: function(point, element, drop) {
    return (
      (drop.element!=element) &&
      ((!drop._containers) ||
        this.isContained(element, drop)) &&
      ((!drop.accept) ||
        (Element.classNames(element).detect(
          function(v) { return drop.accept.include(v) } ) )) &&
      Position.within(drop.element, point[0], point[1]) );
  },

  deactivate: function(drop) {
    if(drop.hoverclass)
      Element.removeClassName(drop.element, drop.hoverclass);
    this.last_active = null;
  },

  activate: function(drop) {
    if(drop.hoverclass)
      Element.addClassName(drop.element, drop.hoverclass);
    this.last_active = drop;
  },

  show: function(point, element) {
    if(!this.drops.length) return;
    var drop, affected = [];

    this.drops.each( function(drop) {
      if(Droppables.isAffected(point, element, drop))
        affected.push(drop);
    });

    if(affected.length>0)
      drop = Droppables.findDeepestChild(affected);

    if(this.last_active && this.last_active != drop) this.deactivate(this.last_active);
    if (drop) {
      Position.within(drop.element, point[0], point[1]);
      if(drop.onHover)
        drop.onHover(element, drop.element, Position.overlap(drop.overlap, drop.element));

      if (drop != this.last_active) Droppables.activate(drop);
    }
  },

  fire: function(event, element) {
    if(!this.last_active) return;
    Position.prepare();

    if (this.isAffected([Event.pointerX(event), Event.pointerY(event)], element, this.last_active))
      if (this.last_active.onDrop) {
        this.last_active.onDrop(element, this.last_active.element, event);
        return true;
      }
  },

  reset: function() {
    if(this.last_active)
      this.deactivate(this.last_active);
  }
};

var Draggables = {
  drags: [],
  observers: [],

  register: function(draggable) {
    if(this.drags.length == 0) {
      this.eventMouseUp   = this.endDrag.bindAsEventListener(this);
      this.eventMouseMove = this.updateDrag.bindAsEventListener(this);
      this.eventKeypress  = this.keyPress.bindAsEventListener(this);

      Event.observe(document, "mouseup", this.eventMouseUp);
      Event.observe(document, "mousemove", this.eventMouseMove);
      Event.observe(document, "keypress", this.eventKeypress);
    }
    this.drags.push(draggable);
  },

  unregister: function(draggable) {
    this.drags = this.drags.reject(function(d) { return d==draggable });
    if(this.drags.length == 0) {
      Event.stopObserving(document, "mouseup", this.eventMouseUp);
      Event.stopObserving(document, "mousemove", this.eventMouseMove);
      Event.stopObserving(document, "keypress", this.eventKeypress);
    }
  },

  activate: function(draggable) {
    if(draggable.options.delay) {
      this._timeout = setTimeout(function() {
        Draggables._timeout = null;
        window.focus();
        Draggables.activeDraggable = draggable;
      }.bind(this), draggable.options.delay);
    } else {
      window.focus(); // allows keypress events if window isn't currently focused, fails for Safari
      this.activeDraggable = draggable;
    }
  },

  deactivate: function() {
    this.activeDraggable = null;
  },

  updateDrag: function(event) {
    if(!this.activeDraggable) return;
    var pointer = [Event.pointerX(event), Event.pointerY(event)];
    // Mozilla-based browsers fire successive mousemove events with
    // the same coordinates, prevent needless redrawing (moz bug?)
    if(this._lastPointer && (this._lastPointer.inspect() == pointer.inspect())) return;
    this._lastPointer = pointer;

    this.activeDraggable.updateDrag(event, pointer);
  },

  endDrag: function(event) {
    if(this._timeout) {
      clearTimeout(this._timeout);
      this._timeout = null;
    }
    if(!this.activeDraggable) return;
    this._lastPointer = null;
    this.activeDraggable.endDrag(event);
    this.activeDraggable = null;
  },

  keyPress: function(event) {
    if(this.activeDraggable)
      this.activeDraggable.keyPress(event);
  },

  addObserver: function(observer) {
    this.observers.push(observer);
    this._cacheObserverCallbacks();
  },

  removeObserver: function(element) {  // element instead of observer fixes mem leaks
    this.observers = this.observers.reject( function(o) { return o.element==element });
    this._cacheObserverCallbacks();
  },

  notify: function(eventName, draggable, event) {  // 'onStart', 'onEnd', 'onDrag'
    if(this[eventName+'Count'] > 0)
      this.observers.each( function(o) {
        if(o[eventName]) o[eventName](eventName, draggable, event);
      });
    if(draggable.options[eventName]) draggable.options[eventName](draggable, event);
  },

  _cacheObserverCallbacks: function() {
    ['onStart','onEnd','onDrag'].each( function(eventName) {
      Draggables[eventName+'Count'] = Draggables.observers.select(
        function(o) { return o[eventName]; }
      ).length;
    });
  }
};

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

var Draggable = Class.create({
  initialize: function(element) {
    var defaults = {
      handle: false,
      reverteffect: function(element, top_offset, left_offset) {
        var dur = Math.sqrt(Math.abs(top_offset^2)+Math.abs(left_offset^2))*0.02;
        new Effect.Move(element, { x: -left_offset, y: -top_offset, duration: dur,
          queue: {scope:'_draggable', position:'end'}
        });
      },
      endeffect: function(element) {
        var toOpacity = Object.isNumber(element._opacity) ? element._opacity : 1.0;
        new Effect.Opacity(element, {duration:0.2, from:0.7, to:toOpacity,
          queue: {scope:'_draggable', position:'end'},
          afterFinish: function(){
            Draggable._dragging[element] = false
          }
        });
      },
      zindex: 1000,
      revert: false,
      quiet: false,
      scroll: false,
      scrollSensitivity: 20,
      scrollSpeed: 15,
      snap: false,  // false, or xy or [x,y] or function(x,y){ return [x,y] }
      delay: 0
    };

    if(!arguments[1] || Object.isUndefined(arguments[1].endeffect))
      Object.extend(defaults, {
        starteffect: function(element) {
          element._opacity = Element.getOpacity(element);
          Draggable._dragging[element] = true;
          new Effect.Opacity(element, {duration:0.2, from:element._opacity, to:0.7});
        }
      });

    var options = Object.extend(defaults, arguments[1] || { });

    this.element = $(element);

    if(options.handle && Object.isString(options.handle))
      this.handle = this.element.down('.'+options.handle, 0);

    if(!this.handle) this.handle = $(options.handle);
    if(!this.handle) this.handle = this.element;

    if(options.scroll && !options.scroll.scrollTo && !options.scroll.outerHTML) {
      options.scroll = $(options.scroll);
      this._isScrollChild = Element.childOf(this.element, options.scroll);
    }

    Element.makePositioned(this.element); // fix IE

    this.options  = options;
    this.dragging = false;

    this.eventMouseDown = this.initDrag.bindAsEventListener(this);
    Event.observe(this.handle, "mousedown", this.eventMouseDown);

    Draggables.register(this);
  },

  destroy: function() {
    Event.stopObserving(this.handle, "mousedown", this.eventMouseDown);
    Draggables.unregister(this);
  },

  currentDelta: function() {
    return([
      parseInt(Element.getStyle(this.element,'left') || '0'),
      parseInt(Element.getStyle(this.element,'top') || '0')]);
  },

  initDrag: function(event) {
    if(!Object.isUndefined(Draggable._dragging[this.element]) &&
      Draggable._dragging[this.element]) return;
    if(Event.isLeftClick(event)) {
      // abort on form elements, fixes a Firefox issue
      var src = Event.element(event);
      if((tag_name = src.tagName.toUpperCase()) && (
        tag_name=='INPUT' ||
        tag_name=='SELECT' ||
        tag_name=='OPTION' ||
        tag_name=='BUTTON' ||
        tag_name=='TEXTAREA')) return;

      var pointer = [Event.pointerX(event), Event.pointerY(event)];
      var pos     = Position.cumulativeOffset(this.element);
      this.offset = [0,1].map( function(i) { return (pointer[i] - pos[i]) });

      Draggables.activate(this);
      Event.stop(event);
    }
  },

  startDrag: function(event) {
    this.dragging = true;
    if(!this.delta)
      this.delta = this.currentDelta();

    if(this.options.zindex) {
      this.originalZ = parseInt(Element.getStyle(this.element,'z-index') || 0);
      this.element.style.zIndex = this.options.zindex;
    }

    if(this.options.ghosting) {
      this._clone = this.element.cloneNode(true);
      this._originallyAbsolute = (this.element.getStyle('position') == 'absolute');
      if (!this._originallyAbsolute)
        Position.absolutize(this.element);
      this.element.parentNode.insertBefore(this._clone, this.element);
    }

    if(this.options.scroll) {
      if (this.options.scroll == window) {
        var where = this._getWindowScroll(this.options.scroll);
        this.originalScrollLeft = where.left;
        this.originalScrollTop = where.top;
      } else {
        this.originalScrollLeft = this.options.scroll.scrollLeft;
        this.originalScrollTop = this.options.scroll.scrollTop;
      }
    }

    Draggables.notify('onStart', this, event);

    if(this.options.starteffect) this.options.starteffect(this.element);
  },

  updateDrag: function(event, pointer) {
    if(!this.dragging) this.startDrag(event);

    if(!this.options.quiet){
      Position.prepare();
      Droppables.show(pointer, this.element);
    }

    Draggables.notify('onDrag', this, event);

    this.draw(pointer);
    if(this.options.change) this.options.change(this);

    if(this.options.scroll) {
      this.stopScrolling();

      var p;
      if (this.options.scroll == window) {
        with(this._getWindowScroll(this.options.scroll)) { p = [ left, top, left+width, top+height ]; }
      } else {
        p = Position.page(this.options.scroll);
        p[0] += this.options.scroll.scrollLeft + Position.deltaX;
        p[1] += this.options.scroll.scrollTop + Position.deltaY;
        p.push(p[0]+this.options.scroll.offsetWidth);
        p.push(p[1]+this.options.scroll.offsetHeight);
      }
      var speed = [0,0];
      if(pointer[0] < (p[0]+this.options.scrollSensitivity)) speed[0] = pointer[0]-(p[0]+this.options.scrollSensitivity);
      if(pointer[1] < (p[1]+this.options.scrollSensitivity)) speed[1] = pointer[1]-(p[1]+this.options.scrollSensitivity);
      if(pointer[0] > (p[2]-this.options.scrollSensitivity)) speed[0] = pointer[0]-(p[2]-this.options.scrollSensitivity);
      if(pointer[1] > (p[3]-this.options.scrollSensitivity)) speed[1] = pointer[1]-(p[3]-this.options.scrollSensitivity);
      this.startScrolling(speed);
    }

    // fix AppleWebKit rendering
    if(Prototype.Browser.WebKit) window.scrollBy(0,0);

    Event.stop(event);
  },

  finishDrag: function(event, success) {
    this.dragging = false;

    if(this.options.quiet){
      Position.prepare();
      var pointer = [Event.pointerX(event), Event.pointerY(event)];
      Droppables.show(pointer, this.element);
    }

    if(this.options.ghosting) {
      if (!this._originallyAbsolute)
        Position.relativize(this.element);
      delete this._originallyAbsolute;
      Element.remove(this._clone);
      this._clone = null;
    }

    var dropped = false;
    if(success) {
      dropped = Droppables.fire(event, this.element);
      if (!dropped) dropped = false;
    }
    if(dropped && this.options.onDropped) this.options.onDropped(this.element);
    Draggables.notify('onEnd', this, event);

    var revert = this.options.revert;
    if(revert && Object.isFunction(revert)) revert = revert(this.element);

    var d = this.currentDelta();
    if(revert && this.options.reverteffect) {
      if (dropped == 0 || revert != 'failure')
        this.options.reverteffect(this.element,
          d[1]-this.delta[1], d[0]-this.delta[0]);
    } else {
      this.delta = d;
    }

    if(this.options.zindex)
      this.element.style.zIndex = this.originalZ;

    if(this.options.endeffect)
      this.options.endeffect(this.element);

    Draggables.deactivate(this);
    Droppables.reset();
  },

  keyPress: function(event) {
    if(event.keyCode!=Event.KEY_ESC) return;
    this.finishDrag(event, false);
    Event.stop(event);
  },

  endDrag: function(event) {
    if(!this.dragging) return;
    this.stopScrolling();
    this.finishDrag(event, true);
    Event.stop(event);
  },

  draw: function(point) {
    var pos = Position.cumulativeOffset(this.element);
    if(this.options.ghosting) {
      var r   = Position.realOffset(this.element);
      pos[0] += r[0] - Position.deltaX; pos[1] += r[1] - Position.deltaY;
    }

    var d = this.currentDelta();
    pos[0] -= d[0]; pos[1] -= d[1];

    if(this.options.scroll && (this.options.scroll != window && this._isScrollChild)) {
      pos[0] -= this.options.scroll.scrollLeft-this.originalScrollLeft;
      pos[1] -= this.options.scroll.scrollTop-this.originalScrollTop;
    }

    var p = [0,1].map(function(i){
      return (point[i]-pos[i]-this.offset[i])
    }.bind(this));

    if(this.options.snap) {
      if(Object.isFunction(this.options.snap)) {
        p = this.options.snap(p[0],p[1],this);
      } else {
      if(Object.isArray(this.options.snap)) {
        p = p.map( function(v, i) {
          return (v/this.options.snap[i]).round()*this.options.snap[i] }.bind(this));
      } else {
        p = p.map( function(v) {
          return (v/this.options.snap).round()*this.options.snap }.bind(this));
      }
    }}

    var style = this.element.style;
    if((!this.options.constraint) || (this.options.constraint=='horizontal'))
      style.left = p[0] + "px";
    if((!this.options.constraint) || (this.options.constraint=='vertical'))
      style.top  = p[1] + "px";

    if(style.visibility=="hidden") style.visibility = ""; // fix gecko rendering
  },

  stopScrolling: function() {
    if(this.scrollInterval) {
      clearInterval(this.scrollInterval);
      this.scrollInterval = null;
      Draggables._lastScrollPointer = null;
    }
  },

  startScrolling: function(speed) {
    if(!(speed[0] || speed[1])) return;
    this.scrollSpeed = [speed[0]*this.options.scrollSpeed,speed[1]*this.options.scrollSpeed];
    this.lastScrolled = new Date();
    this.scrollInterval = setInterval(this.scroll.bind(this), 10);
  },

  scroll: function() {
    var current = new Date();
    var delta = current - this.lastScrolled;
    this.lastScrolled = current;
    if(this.options.scroll == window) {
      with (this._getWindowScroll(this.options.scroll)) {
        if (this.scrollSpeed[0] || this.scrollSpeed[1]) {
          var d = delta / 1000;
          this.options.scroll.scrollTo( left + d*this.scrollSpeed[0], top + d*this.scrollSpeed[1] );
        }
      }
    } else {
      this.options.scroll.scrollLeft += this.scrollSpeed[0] * delta / 1000;
      this.options.scroll.scrollTop  += this.scrollSpeed[1] * delta / 1000;
    }

    Position.prepare();
    Droppables.show(Draggables._lastPointer, this.element);
    Draggables.notify('onDrag', this);
    if (this._isScrollChild) {
      Draggables._lastScrollPointer = Draggables._lastScrollPointer || $A(Draggables._lastPointer);
      Draggables._lastScrollPointer[0] += this.scrollSpeed[0] * delta / 1000;
      Draggables._lastScrollPointer[1] += this.scrollSpeed[1] * delta / 1000;
      if (Draggables._lastScrollPointer[0] < 0)
        Draggables._lastScrollPointer[0] = 0;
      if (Draggables._lastScrollPointer[1] < 0)
        Draggables._lastScrollPointer[1] = 0;
      this.draw(Draggables._lastScrollPointer);
    }

    if(this.options.change) this.options.change(this);
  },

  _getWindowScroll: function(w) {
    var T, L, W, H;
    with (w.document) {
      if (w.document.documentElement && documentElement.scrollTop) {
        T = documentElement.scrollTop;
        L = documentElement.scrollLeft;
      } else if (w.document.body) {
        T = body.scrollTop;
        L = body.scrollLeft;
      }
      if (w.innerWidth) {
        W = w.innerWidth;
        H = w.innerHeight;
      } else if (w.document.documentElement && documentElement.clientWidth) {
        W = documentElement.clientWidth;
        H = documentElement.clientHeight;
      } else {
        W = body.offsetWidth;
        H = body.offsetHeight;
      }
    }
    return { top: T, left: L, width: W, height: H };
  }
});

Draggable._dragging = { };

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

var SortableObserver = Class.create({
  initialize: function(element, observer) {
    this.element   = $(element);
    this.observer  = observer;
    this.lastValue = Sortable.serialize(this.element);
  },

  onStart: function() {
    this.lastValue = Sortable.serialize(this.element);
  },

  onEnd: function() {
    Sortable.unmark();
    if(this.lastValue != Sortable.serialize(this.element))
      this.observer(this.element)
  }
});

var Sortable = {
  SERIALIZE_RULE: /^[^_\-](?:[A-Za-z0-9\-\_]*)[_](.*)$/,

  sortables: { },

  _findRootElement: function(element) {
    while (element.tagName.toUpperCase() != "BODY") {
      if(element.id && Sortable.sortables[element.id]) return element;
      element = element.parentNode;
    }
  },

  options: function(element) {
    element = Sortable._findRootElement($(element));
    if(!element) return;
    return Sortable.sortables[element.id];
  },

  destroy: function(element){
    element = $(element);
    var s = Sortable.sortables[element.id];

    if(s) {
      Draggables.removeObserver(s.element);
      s.droppables.each(function(d){ Droppables.remove(d) });
      s.draggables.invoke('destroy');

      delete Sortable.sortables[s.element.id];
    }
  },

  create: function(element) {
    element = $(element);
    var options = Object.extend({
      element:     element,
      tag:         'li',       // assumes li children, override with tag: 'tagname'
      dropOnEmpty: false,
      tree:        false,
      treeTag:     'ul',
      overlap:     'vertical', // one of 'vertical', 'horizontal'
      constraint:  'vertical', // one of 'vertical', 'horizontal', false
      containment: element,    // also takes array of elements (or id's); or false
      handle:      false,      // or a CSS class
      only:        false,
      delay:       0,
      hoverclass:  null,
      ghosting:    false,
      quiet:       false,
      scroll:      false,
      scrollSensitivity: 20,
      scrollSpeed: 15,
      format:      this.SERIALIZE_RULE,

      // these take arrays of elements or ids and can be
      // used for better initialization performance
      elements:    false,
      handles:     false,

      onChange:    Prototype.emptyFunction,
      onUpdate:    Prototype.emptyFunction
    }, arguments[1] || { });

    // clear any old sortable with same element
    this.destroy(element);

    // build options for the draggables
    var options_for_draggable = {
      revert:      true,
      quiet:       options.quiet,
      scroll:      options.scroll,
      scrollSpeed: options.scrollSpeed,
      scrollSensitivity: options.scrollSensitivity,
      delay:       options.delay,
      ghosting:    options.ghosting,
      constraint:  options.constraint,
      handle:      options.handle };

    if(options.starteffect)
      options_for_draggable.starteffect = options.starteffect;

    if(options.reverteffect)
      options_for_draggable.reverteffect = options.reverteffect;
    else
      if(options.ghosting) options_for_draggable.reverteffect = function(element) {
        element.style.top  = 0;
        element.style.left = 0;
      };

    if(options.endeffect)
      options_for_draggable.endeffect = options.endeffect;

    if(options.zindex)
      options_for_draggable.zindex = options.zindex;

    // build options for the droppables
    var options_for_droppable = {
      overlap:     options.overlap,
      containment: options.containment,
      tree:        options.tree,
      hoverclass:  options.hoverclass,
      onHover:     Sortable.onHover
    };

    var options_for_tree = {
      onHover:      Sortable.onEmptyHover,
      overlap:      options.overlap,
      containment:  options.containment,
      hoverclass:   options.hoverclass
    };

    // fix for gecko engine
    Element.cleanWhitespace(element);

    options.draggables = [];
    options.droppables = [];

    // drop on empty handling
    if(options.dropOnEmpty || options.tree) {
      Droppables.add(element, options_for_tree);
      options.droppables.push(element);
    }

    (options.elements || this.findElements(element, options) || []).each( function(e,i) {
      var handle = options.handles ? $(options.handles[i]) :
        (options.handle ? $(e).select('.' + options.handle)[0] : e);
      options.draggables.push(
        new Draggable(e, Object.extend(options_for_draggable, { handle: handle })));
      Droppables.add(e, options_for_droppable);
      if(options.tree) e.treeNode = element;
      options.droppables.push(e);
    });

    if(options.tree) {
      (Sortable.findTreeElements(element, options) || []).each( function(e) {
        Droppables.add(e, options_for_tree);
        e.treeNode = element;
        options.droppables.push(e);
      });
    }

    // keep reference
    this.sortables[element.id] = options;

    // for onupdate
    Draggables.addObserver(new SortableObserver(element, options.onUpdate));

  },

  // return all suitable-for-sortable elements in a guaranteed order
  findElements: function(element, options) {
    return Element.findChildren(
      element, options.only, options.tree ? true : false, options.tag);
  },

  findTreeElements: function(element, options) {
    return Element.findChildren(
      element, options.only, options.tree ? true : false, options.treeTag);
  },

  onHover: function(element, dropon, overlap) {
    if(Element.isParent(dropon, element)) return;

    if(overlap > .33 && overlap < .66 && Sortable.options(dropon).tree) {
      return;
    } else if(overlap>0.5) {
      Sortable.mark(dropon, 'before');
      if(dropon.previousSibling != element) {
        var oldParentNode = element.parentNode;
        element.style.visibility = "hidden"; // fix gecko rendering
        dropon.parentNode.insertBefore(element, dropon);
        if(dropon.parentNode!=oldParentNode)
          Sortable.options(oldParentNode).onChange(element);
        Sortable.options(dropon.parentNode).onChange(element);
      }
    } else {
      Sortable.mark(dropon, 'after');
      var nextElement = dropon.nextSibling || null;
      if(nextElement != element) {
        var oldParentNode = element.parentNode;
        element.style.visibility = "hidden"; // fix gecko rendering
        dropon.parentNode.insertBefore(element, nextElement);
        if(dropon.parentNode!=oldParentNode)
          Sortable.options(oldParentNode).onChange(element);
        Sortable.options(dropon.parentNode).onChange(element);
      }
    }
  },

  onEmptyHover: function(element, dropon, overlap) {
    var oldParentNode = element.parentNode;
    var droponOptions = Sortable.options(dropon);

    if(!Element.isParent(dropon, element)) {
      var index;

      var children = Sortable.findElements(dropon, {tag: droponOptions.tag, only: droponOptions.only});
      var child = null;

      if(children) {
        var offset = Element.offsetSize(dropon, droponOptions.overlap) * (1.0 - overlap);

        for (index = 0; index < children.length; index += 1) {
          if (offset - Element.offsetSize (children[index], droponOptions.overlap) >= 0) {
            offset -= Element.offsetSize (children[index], droponOptions.overlap);
          } else if (offset - (Element.offsetSize (children[index], droponOptions.overlap) / 2) >= 0) {
            child = index + 1 < children.length ? children[index + 1] : null;
            break;
          } else {
            child = children[index];
            break;
          }
        }
      }

      dropon.insertBefore(element, child);

      Sortable.options(oldParentNode).onChange(element);
      droponOptions.onChange(element);
    }
  },

  unmark: function() {
    if(Sortable._marker) Sortable._marker.hide();
  },

  mark: function(dropon, position) {
    // mark on ghosting only
    var sortable = Sortable.options(dropon.parentNode);
    if(sortable && !sortable.ghosting) return;

    if(!Sortable._marker) {
      Sortable._marker =
        ($('dropmarker') || Element.extend(document.createElement('DIV'))).
          hide().addClassName('dropmarker').setStyle({position:'absolute'});
      document.getElementsByTagName("body").item(0).appendChild(Sortable._marker);
    }
    var offsets = Position.cumulativeOffset(dropon);
    Sortable._marker.setStyle({left: offsets[0]+'px', top: offsets[1] + 'px'});

    if(position=='after')
      if(sortable.overlap == 'horizontal')
        Sortable._marker.setStyle({left: (offsets[0]+dropon.clientWidth) + 'px'});
      else
        Sortable._marker.setStyle({top: (offsets[1]+dropon.clientHeight) + 'px'});

    Sortable._marker.show();
  },

  _tree: function(element, options, parent) {
    var children = Sortable.findElements(element, options) || [];

    for (var i = 0; i < children.length; ++i) {
      var match = children[i].id.match(options.format);

      if (!match) continue;

      var child = {
        id: encodeURIComponent(match ? match[1] : null),
        element: element,
        parent: parent,
        children: [],
        position: parent.children.length,
        container: $(children[i]).down(options.treeTag)
      };

      /* Get the element containing the children and recurse over it */
      if (child.container)
        this._tree(child.container, options, child);

      parent.children.push (child);
    }

    return parent;
  },

  tree: function(element) {
    element = $(element);
    var sortableOptions = this.options(element);
    var options = Object.extend({
      tag: sortableOptions.tag,
      treeTag: sortableOptions.treeTag,
      only: sortableOptions.only,
      name: element.id,
      format: sortableOptions.format
    }, arguments[1] || { });

    var root = {
      id: null,
      parent: null,
      children: [],
      container: element,
      position: 0
    };

    return Sortable._tree(element, options, root);
  },

  /* Construct a [i] index for a particular node */
  _constructIndex: function(node) {
    var index = '';
    do {
      if (node.id) index = '[' + node.position + ']' + index;
    } while ((node = node.parent) != null);
    return index;
  },

  sequence: function(element) {
    element = $(element);
    var options = Object.extend(this.options(element), arguments[1] || { });

    return $(this.findElements(element, options) || []).map( function(item) {
      return item.id.match(options.format) ? item.id.match(options.format)[1] : '';
    });
  },

  setSequence: function(element, new_sequence) {
    element = $(element);
    var options = Object.extend(this.options(element), arguments[2] || { });

    var nodeMap = { };
    this.findElements(element, options).each( function(n) {
        if (n.id.match(options.format))
            nodeMap[n.id.match(options.format)[1]] = [n, n.parentNode];
        n.parentNode.removeChild(n);
    });

    new_sequence.each(function(ident) {
      var n = nodeMap[ident];
      if (n) {
        n[1].appendChild(n[0]);
        delete nodeMap[ident];
      }
    });
  },

  serialize: function(element) {
    element = $(element);
    var options = Object.extend(Sortable.options(element), arguments[1] || { });
    var name = encodeURIComponent(
      (arguments[1] && arguments[1].name) ? arguments[1].name : element.id);

    if (options.tree) {
      return Sortable.tree(element, arguments[1]).children.map( function (item) {
        return [name + Sortable._constructIndex(item) + "[id]=" +
                encodeURIComponent(item.id)].concat(item.children.map(arguments.callee));
      }).flatten().join('&');
    } else {
      return Sortable.sequence(element, arguments[1]).map( function(item) {
        return name + "[]=" + encodeURIComponent(item);
      }).join('&');
    }
  }
};

// Returns true if child is contained within element
Element.isParent = function(child, element) {
  if (!child.parentNode || child == element) return false;
  if (child.parentNode == element) return true;
  return Element.isParent(child.parentNode, element);
};

Element.findChildren = function(element, only, recursive, tagName) {
  if(!element.hasChildNodes()) return null;
  tagName = tagName.toUpperCase();
  if(only) only = [only].flatten();
  var elements = [];
  $A(element.childNodes).each( function(e) {
    if(e.tagName && e.tagName.toUpperCase()==tagName &&
      (!only || (Element.classNames(e).detect(function(v) { return only.include(v) }))))
        elements.push(e);
    if(recursive) {
      var grandchildren = Element.findChildren(e, only, recursive, tagName);
      if(grandchildren) elements.push(grandchildren);
    }
  });

  return (elements.length>0 ? elements.flatten() : []);
};

Element.offsetSize = function (element, type) {
  return element['offset' + ((type=='vertical' || type=='height') ? 'Height' : 'Width')];
};// 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));
  }
});

/*
Copyright (c) 2009 Victor Stanciu - http://www.victorstanciu.ro

Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
*/

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

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

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

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

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

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

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

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

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

		this.deactivateControls();

		event.stop();
    },

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

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

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

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

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

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

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

		return false;
	},

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


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

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

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

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

	update: function (position) {
		this.element.scrollLeft = this.options.x * position + this.originalLeft;
		this.element.scrollTop  = this.options.y * position + this.originalTop;
    }
});
try {if (top.location.hostname != self.location.hostname) throw 1;} catch (e) {top.location.href = self.location.href;}

function deleteChildNodes(element) {
	var children = element.childNodes, i, num;
	for (i = 0, num = children.length; i < num; ++i) {
		element.removeChild(children[i]);
	}
}

// cook the cookies [+]
var Cookies = {
    init: function () {
        var allCookies = document.cookie.split('; ');
        for (var i=0;i<allCookies.length;i++) {
            var cookiePair = allCookies[i].split('=');
            this[cookiePair[0]] = cookiePair[1];
        }
    },

    read:  function (name) {
        var nameEQ = name + "=";
        var ca = document.cookie.split(';');
        for(var i=0; i<ca.length; i++) {
            var c = ca[i];
            while (c.charAt(0)==' ') c = c.substring(1,c.length);
            if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
        }
        return null;
    },

    create: function (name,value,days) {
        if (days) {
            var date = new Date();
            date.setTime(date.getTime()+(days*86400000));
            var expires = "; expires="+date.toGMTString();
        }
        else var expires = "";
        document.cookie = name+"="+value+expires+"; path=" + (window._cookiesPath ? window._cookiesPath : '/') + "; domain=" + (window._cookiesDomain ? window._cookiesDomain : '220.ro');
        this[name] = value;
    },

    erase: function (name) {
        this.create(name,'',-1);
        this[name] = undefined;
    }
};
Cookies.init();
// cook the cookies [-]


/* current view [+]*/
var current_view="";

switchView=function(event){
    className=Event.element(event).readAttribute('title').toLowerCase();
    if(className=='tabel'){
        $$('.container_filme').each(function(dv) {
            dv.removeClassName('view_lista');
            dv.addClassName('view_tabel');
        });
    }
    else {
        $$('.container_filme').each(function(dv) {
            dv.removeClassName('view_tabel');
            dv.addClassName('view_lista');
        });
    }
    current_view=className;
    $('current_view').update(current_view)
}


document.observe("dom:loaded", function() {
    current_view=$('current_view') ? $('current_view').innerHTML : "";

    $$('a.view-switcher').each(function(avs){

        Event.observe(avs,'mouseover', function(event){
            c_elem=Event.element(event);
            $('current_view').update(c_elem.readAttribute('title').toLowerCase())
        })

        Event.observe(avs,'mouseout', function(event){
            c_elem=Event.element(event);
            $('current_view').update(current_view)
        })
        Event.observe(avs,'click', switchView);

    })

});
/* current view [-]*/

document.observe("dom:loaded", function() {
if($('expand-switcher')){
        Event.observe('expand-switcher','click', switchExpand);
    }
});

switchExpand=function(event){
    var elm = $('expand-switcher');
    var elm1 = $('new_box');
    className = elm1.hasClassName('expand');
    if(className){
        if(elm.childNodes[0]){
            elm.removeChild(elm.childNodes[0]);
        }
        var image = Builder.node('img',{src: WEB_BASE+"img/plus.jpg", alt:"+"});
        elm.appendChild(image);
        elm.title = 'unexpand';
        elm1.removeClassName('expand');
        elm1.addClassName('unexpand');
        Cookies.create('fze','unexpand',0);
    }
    else {
        elm1.removeClassName('unexpand');
        elm1.addClassName('expand');
        if(elm.childNodes[0]){
            elm.removeChild(elm.childNodes[0]);
        }
        var image = Builder.node('img',{src: WEB_BASE+"img/minus.jpg", alt:"-"});
        elm.appendChild(image);
        elm.title = 'expand';
        Cookies.create('fze','expand',0);
    }

}

/*[+] filmele zilei exapand*/

/*[-] filmele zilei exapand*/

/* Functie care initializeaza ajax autocompleter pt useri*/
getUserId = function(text, li) {
    $(text.id+'_id').value=li.id;
}

acSuccess=function(req){
    if(req.responseText.strip()=='not found'){
        $(req.request.options.indicator).hide();
    }
}

document.observe("dom:loaded", function() {
    if($$('.autocomplete-user') != undefined)
    {
        ac_users=$$('.autocomplete-user').each(function(ac){
            new Ajax.Autocompleter(ac, ac.id+"_options", SITE_BASE + "ajax.php?module=mesagerie&action=getUsers", {
                paramName: "value",
                minChars: 2,
                indicator: ac.id+'_indicator',
                //afterUpdateElement:getUserId,
                onSuccess:acSuccess
            });
        })
    }
});

/*START  - verifica containerul boom daca are content [vezi lista]*/
/*
document.observe('dom:loaded', function() {
    $$('.boom_container').each(function(item) {
        var hasChildren = item.select('div','table','object','img','a').length > 0;
        if(!hasChildren) {
            try {
                $$('.'+item.id).each(function(related_items) {related_items.hide();});
            }
            catch(e) {;}
        };
    });
});
*/
/*END  - verifica containerul boom daca are content*/

/* Check - Uncheck trigger*/

var CheckUncheckTrigger=Class.create({
    initialize:function(cu_trigger){
        this.cu_trigger=cu_trigger
        this.observeTrigger();
    },

    observeTrigger:function(){
        Event.observe(this.cu_trigger, 'click', this.checkUncheck.bindAsEventListener(this))
    },

    checkUncheck:function(event){
        i=0;
        while($(this.cu_trigger.id+'-'+i)!=undefined){
            ckb=$(this.cu_trigger.id+'-'+i);
            ckb.checked=this.cu_trigger.checked;
            // verific daca e intr-un tabel cu select row
            srt=ckb.up('table.select-row-table');
            if(srt!=undefined){
                ckb_row=ckb.up('tr');
                if(ckb_row!=undefined && ckb.checked)
                ckb_row.addClassName('row-selected');
                else
                ckb_row.removeClassName('row-selected');
            }

            i++;
        }
    }
})

document.observe("dom:loaded", function() {
    $$('.check-uncheck-trigger').each(function(cu_trigger){
        new CheckUncheckTrigger(cu_trigger)
    })
})

/* Checkbox-uri care ingalbenesc linia curenta*/
selectRow=function(event){
    elem=Event.element(event);
    if(elem.tagName != "A" && event.findElement('a')==undefined){
        cb_row=elem.up('tr');
        cb=cb_row.down('input');
        if(!cb.hasClassName('check-uncheck-trigger')){
            if(cb != elem)
            cb.checked=!cb.checked;
            if(cb_row != undefined && cb.checked==true)
            cb_row.addClassName('row-selected');
            else
            cb_row.removeClassName('row-selected');
        }
    }
}

rowOverAndOut=function(event){
    Event.stop(event);
    t_row=event.findElement('tr');
    tabel=event.findElement('table');
    $A(tabel.getElementsByTagName('tr')).invoke('removeClassName','row-over');
    t_row.addClassName('row-over');
}

document.observe("dom:loaded", function() {
    $$('.select-row-table').each(function(s_table){
        Event.observe(s_table, 'click', selectRow);
        Event.observe(s_table, 'mousemove', rowOverAndOut);
        Event.observe(s_table, 'mouseout', function(event){
            Event.stop(event);
            tabel=event.findElement('table');
            $A(tabel.getElementsByTagName('tr')).invoke('removeClassName','row-over');
        });
    })
})

/* Linkuri pentru form submit*/

document.observe("dom:loaded", function() {
    $$('.submit-button').each(function(f_submit){
        Event.observe(f_submit,'click', function(event){
            submit_button=Event.element(event);
            Event.stop(event);
            if($(submit_button.id.gsub('submit_',''))!=undefined)
            $(submit_button.id.gsub('submit_','')).submit();
        })

    })
})


/* Auto-resizing Textarea*/

document.observe("dom:loaded", function() {
    $$('textarea.auto-resize').each(function(ta){
        Event.observe(ta,'keyup', function(event){
            txt_area=Event.element(event);
            ta_st=txt_area.scrollTop
            if(ta_st >0){
                new_height=txt_area.getHeight()+ta_st
                new Effect.Morph(txt_area,{style:{height:new_height+'px'}, duration:0.5});
            }
        })
    })

})

/* AJAX Links*/
doAjax=function(event){
    elem=event.findElement('.ajax-updater');
    ax_url=elem.href;
    ax_container = $(elem.id+'_container');

    if(ax_container != undefined){
        new Ajax.Updater(ax_container, ax_url);
        ax_container.show();
    }
    Event.stop(event);
}

document.observe("dom:loaded", function() {
    $$('.ajax-updater').each(function(axlink){
        Event.observe(axlink, 'click', doAjax);
    })

})

/* Friend list*/
var FriendList={
    currTrigger:"cucu",

    selectFriend:function(event){
        fl=event.findElement('a.friends-list-link');
        up_field=FriendList.currTrigger.id.gsub('update_','');
        if($(up_field)!=undefined && fl != undefined){
            $(up_field).value=fl.innerHTML;
            $('friends-list-container').hide();
        }
    },

    openList:function(event){
        fl_trigger=event.findElement('.friends-list-trigger');
        if($('friends-list-container')!=undefined){
            if($('friends-list-container').getHeight()>250)
            $('friends-list-container').setStyle({height:'250px'});

            fl_trigger_pos=fl_trigger.positionedOffset();
            fl_x=fl_trigger_pos.left-$('friends-list-container').getWidth();
            fl_y=fl_trigger_pos.top-($('friends-list-container').getHeight()/2);

            $('friends-list-container').setStyle({position:'absolute', top:fl_y+'px', left:fl_x+'px'})
            new Effect.toggle('friends-list-container','appear',{duration:0.5})
            FriendList.currTrigger=fl_trigger;
        }
    },

    closeList:function(){
        new Effect.toggle('friends-list-container','appear',{duration:0.5})
    },
    selectAllFriends:function(event){
        up_field=FriendList.currTrigger.id.gsub('update_','');
        if($(up_field)!=undefined && all_friends != undefined){
            $(up_field).value = all_friends;
            $('friends-list-container').hide();
        }
    }

}

document.observe("dom:loaded", function() {
    $$('.friends-list-trigger').each(function(flt){
        Event.observe(flt,'click', FriendList.openList);
    })

    $$('a.friends-list-link').each(function(fl){
        Event.observe(fl, 'click', FriendList.selectFriend.bindAsEventListener(FriendList))
    })

    $$('a.friends-list-all').each(function(fl){
        Event.observe(fl, 'click', FriendList.selectAllFriends);
    })

    if($('friends-list-container')!=undefined){
        new Draggable($('friends-list-container'),{handle:$('friends-list-container').down('h2')})
    }

    $$('.close-button').each(function(close_btn){
        Event.observe(close_btn, 'click', function(event){
            cbtn=event.findElement('.close-button');
            elem_close=$(cbtn.id.gsub('close-',''));
            if(elem_close!=undefined)
            new Effect.toggle(elem_close,'appear',{duration:0.5});
        })
    })
})

toggleColorPicker=function(event, id, act){
    var button = Event.element(event)
    var XY = Element.cumulativeOffset(button);
    var posX = XY[0] + 'px', posY =  XY[1] + 'px', margX = XY[0]-230 + 'px', margY =  XY[1]-20 + 'px';
    Event.stop(event);
    CPicker.loadPicker(posX,posY,act,id);
}

//color_picker_container

document.observe("dom:loaded", function(){
    $$('.color_picker_close').each(function(dv) {
        Event.observe(dv,'click',function(event) {
            var id = (/[^0-9]*([0-9]+)/.exec(dv.id))[1];
            toggleColorPicker(event, id, 'hide');
        });
    });
    $$('.color_picker_show').each(function(dv) {
        Event.observe(dv,'click', function(event) {
            var id = (/[^0-9]*([0-9]+)/.exec(dv.id))[1];
            toggleColorPicker(event, id, 'show');
        });
    });

})


function use_embed_settings(cid) {
    if($A($$('#embeded .titlu_upl')).size() > 0) {
        Effect.Appear('embeded',{duration: 0.4});
    } else if(cid) {
        params = {content_id: cid};
        sn_updateByAjax('get_embed_settings', params,'embeded', {onComplete: embed_code_options});
    }
}

function embed_code_options() {
    if ($('form_embed')) {
        $('form_embed').getElements().each(function(el){
            if (el.type == 'radio') Event.observe(el, 'click', make_embed_code);
            else Event.observe(el, 'change', make_embed_code);
        });
    }
    $$('.color_picker_close').each(function(dv) {
        Event.observe(dv,'click',function(event) {
            var id = (/[^0-9]*([0-9]+)/.exec(dv.id))[1];
            toggleColorPicker(event, id, 'hide');
        });
    });
    $$('.color_picker_show').each(function(dv) {
        Event.observe(dv,'click', function(event) {
            var id = (/[^0-9]*([0-9]+)/.exec(dv.id))[1];
            toggleColorPicker(event, id, 'show');
        });
    });
    Effect.Appear('embeded',{duration: 0.4});
}

function remove_embed(){
    Effect.Fade('embeded',{duration: 0.4});
}

function addIFrame(node) {//deasupra selecturilor in IE6
    $$('iframe:not([id~="my_frame"])').each(function(el){Element.remove(el);});
    var iframe = document.createElement('iframe');
    with (iframe.style) {
        position = 'absolute';
        height = 300;
        width = node.style.width;
        top = -node.style.height;
        border = '0';
        zIndex='-1';
        opacity='0';
    }
   node.appendChild(iframe);
}

function bookmarksite(title,url) {
    if (window.sidebar) { // firefox
        window.sidebar.addPanel(title, url,"");
    } else if (window.opera && window.print){ // opera
        var elem = document.createElement('a');
        elem.setAttribute('href',url);
        elem.setAttribute('title',title);
        elem.setAttribute('rel','sidebar');
        elem.click();
    }
    else if(document.all) { // ie
        window.external.AddFavorite(url, title);
    } else {
        alert("Ne pare rau, browserul dvs nu e suportat \nPentru Safari apsati Ctrl/Cmd + D \nPentru Konqueror apsati Ctrl + B");
    }
}



var mplaylist = {
    add: function(id) {
        params = {mplaylist_id: id, action: 1}
        sn_updateByAjax('mplaylist', params, '');
    },

    del: function(id) {
        params = {mplaylist_id: id, action: 0};
        sn_updateByAjax('mplaylist', params, '');
    }
};




function openLoginBox(option_id) {
    if (typeof(age_minor_deny) != 'undefined' && age_minor_deny == 1 && option_id != 0) return;
    var orig = $('form_login_suplimentar');
    var holder = $('adaugalogin_' + option_id);
    if(!orig || !holder) return;
    orig.remove();
    holder.appendChild(orig);
    form = $('formslogin');
    form.show();
    orig.show();
}

function toggleStar(elementID) {
    var mumu = document.getElementById(elementID)

    if ( typeof c_activ_opt != 'undefined' ) {
        document.getElementById(c_activ_opt).style.display = 'none';
    }

    if (mumu.style.display == 'none') {
        mumu.style.display = 'block'
        openLoginBox(elementID);
    } else {
        mumu.style.display = 'none'
    }
}


function my_toggle(elementID) {
    try {
        if($(elementID).visible())  blind($(elementID));
        else blindDown($(elementID));
    }
    catch(e) {;}
}
// functie pentru development.. printare obiecte, array-uri javascript
function print_array(arr, include_objects)
{
    var sfx = '';
    var include_obj = (typeof(include_objects) == 'undefined' || include_objects == true) ? true : false;
    var lev = (typeof(arguments[2]) != 'undefined') ? arguments[2] : 0;
    for (var i=0; i <= lev; i++) sfx += "\t";
    var ret = typeof(arr) + " :\n" + sfx + "(\n";

    if(typeof(arr) == 'array' || (include_obj ? typeof(arr) == 'object' : false)) {
        for(var i in arr) {
            //alert(i);
            if(typeof(arr[i]) == 'array' || (include_obj ? (typeof(arr[i]) == 'object' && arr[i] != null) : false)) {
                ret += sfx + ' [ ' +  i + '] => ' + print_array(arr[i], include_obj, lev + 1);
            }
            else {
                ret += sfx + '[' + i + '] => ' + arr[i] + "\n";
            }
        }
        ret += sfx + ")\n";
    }
    else {
        ret += arr + "\n)\n";
    }
    if (lev > 0)    return ret;
    else alert(ret);
}

// [+] Zona ajax posts ----------------------------------------------------
function stripLink(text){
    var replacer = '[a #{1}href=#{2}]#{3}[/a]';
    replacer = "";
    //text = text.gsub(/\"/ , '\"');
    //text = text.gsub(/\'/ , "\'");
    var aux = true;
    //--------varianta cu prototype
    while(aux){
        var t2 = text;
        var t = text.gsub(/(.*?)<a class=\"?owner\"? (.*?)href=(.*?)>([^<>]*?)<\/a>/i , replacer);
        if(t == t2) aux= false;
        text = t;
    }
    return t;
}
function unstripLink(text){
    var replacer = '<a #{1}href=#{2}>#{3}</a>';
    //text = text.gsub(/\\"/ , '"');
    var aux = true;
    //--------varianta cu prototype
    while(aux){
        var t2 = text;
        var t = text.gsub(/\[a (.*?)href=(.*?)\]([^\[\]]*?)\[\/a\]/i , replacer);
        if(t == t2) aux= false;
        text = t;
    }
    return t;

}
function stripDiv(text,parent_id,username){
    var replacer = "[citat]#{1}[/citat]";
    if(parent_id != 0) replacer = "";
    var aux = true;

    //text = stripLink(text);
    //--------varianta cu prototype
    //while(aux){
       // var t2 = text;
     //alert(text);
      var index = text.indexOf("</DIV>");

      if(index == -1){
          index = text.indexOf("</div>");
      }
      if(index != -1){
          t = text.substr(index+6);
      }else{
          t = text;
      }
     //text = ' Quote: <a class ="owner" title="bursuculu"  \n href=http://developer.activesoft.ro/~dragos/220v2/bursuculu/>bursuculu</a> a spus: <div class="citat"> asdasd </div> comment';
      //text = text.escapeHTML();
      //var t = text.gsub(/<div class=\"?citat\"?>(.*?)<\/div>/gim , replacer);
       //alert(t);
       //var re = new RegExp( "(.*?)<div class=\"?citat\"?>(.*?)<\/div>","gim" );
       //t = text.replace(re ,replacer);


//      /var re = new RegExp( "(.*?)\n","gim" );
      //if(re.test(t))t = t.replace(re ,replacer);

        //if(t == t2) aux= false;
       // text = t;
    //}

    /*varianta fara ....IE SUCKS
    while(aux)
    {
        var re = new RegExp( "<div class=\"?citat\"?>([^<>]*?)<\/div>","gi" );
        text = text.replace(re ,replacer);
        re = new RegExp( "<div class=\"?citat\"?>([^<>]*?)<\/div>","gi" );
        aux = re.test(text);

    }
    */

    if(parent_id != 0) {

        if(trim(t) != "") {

            t = '[citat|'+username+']'+trim(t)+'[/citat]';
        }else{
            t = trim(t);
        }
    }

    //t = unstripLink(t);
    //alert(t);

    return t;
}

function trim(text){
    return text.replace(/^\s+/, "").replace(/\s+$/, "") ;

}

function setCursor(el,st,end) {
    if(el.setSelectionRange) {
        el.focus();
        el.setSelectionRange(st,end);
    }
    else {
        if(el.createTextRange) {
            range = el.createTextRange();
            range.collapse(true);
            range.moveEnd('character',end);
            range.moveStart('character',st);
            range.select();
        }
    }
}

function insertText(tArea, str){
    var isIE = (document.all)? true : false;
    var poss = tArea.value.length;

    if(isIE){
        tArea.focus();
        var pr_txt = tArea.value;
        var curSelect = document.selection.createRange();
        curSelect.text = str + curSelect.text;
        var cur_txt = tArea.value;
        for(i=0; i<cur_txt.length; i++) {
            if(cur_txt.charAt(i) != pr_txt.charAt(i)) {
                poss = i + str.length;
                break;
            }
        }
    }
    else if(!isIE && typeof tArea.selectionStart != "undefined"){
        var selStart = tArea.value.substr(0, tArea.selectionStart);
        var selEnd = tArea.value.substr(tArea.selectionEnd, tArea.value.length);
        var curSelection = tArea.value.replace(selStart, '').replace(selEnd, '');

        poss = tArea.selectionStart + str.length;
        tArea.value = selStart + str + curSelection + selEnd;
    }
    else {
        tArea.value += str;
    }
    pose = poss;
    tArea.focus();
    setCursor(tArea, poss, pose);
}

function citatToDiv(text,parent_id){
    var replacer = "<div class=\"citat\">#{1}<\/div>";
    if(parent_id == 0 ){
        replacer = "#{1}";
    }
    var auxil = true;
    //--------varianta cu prototype
    //while(auxil){
        var t2 = text;
        var t = text.gsub( /\[citat\]([^\[\]]*?)\[\/citat\]/i , replacer);
        if(t == t2) auxil = false;
        text = t;
    //}

    /*varianta fara ....IE SUCKS
    while(auxil)
    {
        var reg = new RegExp( /\[citat\]([^\[\]]*?)\[\/citat\]/gi );
        text = text.replace(reg,replacer);
        reg = new RegExp( /\[citat\]([^\[\]]*?)\[\/citat\]/gi );
        auxil = reg.test(text);
    }
    */
    return text;
}

function comenteaza(id,parent_id,username){
    blind('add_response');
    blind('add_form');
    blind('post_'+id)
    update(id,parent_id,username);

    //$('post_'+id).style.display = "none";
    //var post_id = "text_post_"+id;
    //blind(post_id);
    //setTimeout("update('"+id+"')",510);
    //setTimeout("blindDown('"+post_id+"')",520);
}

function delete_post(id,replys){
    id_u = $('user_id').value;
    id_d = $('disc_id').value;
    id_g = $('group_id').value;
    params = {user_id:id_u ,disc_id :id_d,post_id:id,group_id:id_g};
    if(replys != 0){
        if(confirm("Acest post are "+replys+" raspunsuri")){
            sn_getAjax("delete_post",params);
        }
    }else{
        sn_getAjax("delete_post",params);
    }
}
function sn_deletePostHandler(result, resultElementName, userData){
    if(result.code == 1002)
    {
    $('completare').update(result.text.showPosts);
    window.ajaxPagination.returnCall(result.text.numPosts);
    }
    else document.location = SITE_BASE + "index.php?module=login&err=no_auth_up";
}
function update(id,parent_id,username){
    var comment_id = "post_comment_"+id;
    var post_id = "post_"+id;
    var link_id = "linker_"+id;
    var post_text = $(post_id).innerHTML;
    post_text = stripDiv(post_text,parent_id,username);
   // post_text.unes_cape_AVIRA_SUCKS_HTML();
    //var text_update = "<div id=\"citat_"+post_id+"\">"+post_text+"</div>"+"<textarea rows=10 cols=60 name=\"text_"+post_id +" \" ";
    if(parent_id == '0'){
        if(post_text != ""){
            post_text = " [citat|"+username+"]"+trim(post_text)+"[/citat]";
        }
    }

    if(post_text)
    {
        var text_update = "<textarea rows=10 cols=57 name=\"text_"+post_id +" \" ";
        text_update += " id=\"text_"+post_id+"\" >"+trim(post_text)+"</textarea><br/>";
        text_update += "<div style='padding:0 0 30px 0' id=\"links_"+id+"\"><a class='replay content btn_albastru btn_albastru_20 b-r-3 right m-h-10' style='margin-right: 35px;' href=\"javascript:void(0)\" onclick=\"raspunde_post('"+id+"','"+parent_id+"')\">trimite</a>";
        text_update += "<a href=\"javascript:void(0)\"  class='replay content btn_albastru btn_albastru_20 b-r-3 right m-h-10' onclick=\"inchide_post('"+id+"','"+parent_id+"')\">inchide</a></div>";
        $(comment_id).update(text_update);
        setCursor($("text_"+post_id),post_text.length,post_text.length);
        $(link_id).style.display = "none";

    }else{
        var text_update = "<textarea rows=10 cols=60 name=\"text_"+post_id +" \" ";
        text_update += " id=\"text_"+post_id+"\" >Acest post nu contine text ce poate fi comentat!</textarea><br/>";
        text_update += "<div id=\"links_"+id+"\"><a href=\"javascript:void(0)\"  class='replay' onclick=\"inchide_post('"+id+"','"+parent_id+"')\">Inchide</a></div>";
        $(comment_id).update(text_update);
        $(link_id).style.display = "none";
    }
}
function inchide_post(id,parent_id){
    var links_id = "links_"+id;
    var post_id =  "post_"+id;
    var text_id = "text_post_"+id;
    var link_id = "linker_"+id;

    $(text_id).remove();
    blindDown(post_id);
    $(links_id).remove();
    $(link_id).style.display = "block";
}
function removeCitat(text){
    var aux =  text.substr(7);
    var stop = aux.length - 8;
    aux = aux.substr(0,stop);
    return aux;
}

function raspunde_post(id,parent_id){//raspunde la un post existent
    id_d = $('disc_id').value;
    var post_id = "text_post_"+id;
    var citat_id = "citat_post_"+id;
    var user_link =  document.getElementById("link_user").innerHTML;
    var post_text = $(post_id).value;
    //var citat_text = stripDiv($(post_id).innerHTML);
    //post_text = "Quote: [citat] "+citat_text+"[/citat]"+user_link+"a scris: "+"<div>"+post_text+"</div>";
    if( post_text != ""){

        post_text = '<strong>Quote:</strong>' + post_text;
        params = {post_description:post_text ,disc_id :id_d, post_id:id};
        sn_getAjax("adauga_post_form",params);

    }
    setTimeout('location.reload(true);', 2000);
}

function add_post(event){//raspunde la o discutie fara a cita
    Event.stop(event);
    id_u = $('user_id').value;
    id_g = $('group_id').value;
    id_d = $('disc_id').value;
    my_form = Event.element(event);
    customParams = my_form.serialize().parseQuery();
    if(customParams.post_description != "") {

        var user_link =  document.getElementById("link_user").innerHTML;
       // customParams.post_description = user_link +" a scris:  "+"<div >"+customParams.post_description+"</div>";
       customParams.post_description = customParams.post_description;
       sn_getAjax('adauga_post_form', customParams);

    }else{

        if($('adauga_response_msg')){
             Effect.Appear($('adauga_response_msg'), { duration: 0.0 });
             $('adauga_response_msg').innerHTML  = "Trebuie sa contina text!";
             Effect.Fade( $('adauga_response_msg'), {transition: Effect.Transitions.linear, duration: 2.0});
        }

    }
}

function sn_adaugaPostFormHandler(result, resultElementName, userData){
    if(result.code == 1005) {
        alert(result.text);
        return;
    }
    else if(result.code == 999) {
        $('completare').update(result.text.showPosts);
        $('events').update(result.text.events);
        $('add_response').style.display = "none";
        $('add_form').style.display = "none";

        var page = Math.round(result.text.numPosts/result.text.posts_per_page) ;

        if(page == 0 ){
            page = 1;
        }

        window.ajaxPagination.gotoPage(page);

        window.ajaxPagination.returnCall(result.text.numPosts);
        window.ajaxPagination2.returnCall(result.text.num_events);
    }
    else document.location = SITE_BASE + "index.php?module=login&err=no_auth_up";
}

document.observe("dom:loaded",function(){
    if($('add_post_form')!=undefined){
        Event.observe('add_post_form','submit',add_post)
    }
})

function fetchPosts(limit, offset,userData) {

    if (discId) {
        div = $('completare');
        while (div.childNodes.length > 0) {
            div.removeChild(div.childNodes[0]);
        }

        params = {limit: limit, offset: offset, disc_id: discId};

        sn_getAjax('fetch_disc_posts', params, 'completare',userData);
    }
}

function sn_fetchDiscPostsHandler(result, resultElementName, userData) {

    if (result.code == 667) {
        result = result.text.evalJSON();
        $(resultElementName).update( result.posts);
        window.ajaxPagination.returnCall(result.num_posts);
    }
    if(userData){
        var locatio = "" + document.location;
        locatio = locatio.replace(/#.+/i, '');
        document.location = locatio + '#' + "an_" + userData;
    }
}
// [-] Zona ajax posts ----------------------------------------------------

// [+] Zona ajax events ----------------------------------------------------
function fetchEvents(limit, offset) {
    if (groupId) {
        div = $('events');
        params = {limit: limit, offset: offset, group_id: groupId};
        sn_getAjax('fetch_events', params, 'events');
    }
}

function sn_fetchEventsHandler(result, resultElementName, userData) {
    if (result.code == 66) {
        result = result.text.evalJSON();
        $(resultElementName).update(result.events);
        window.ajaxPagination2.returnCall(result.num_events);
    }

}
// [-] Zona ajax events ----------------------------------------------------

// [+] Zona ajax members ----------------------------------------------------
function fetchMembers(limit, offset) {
    if (groupId) {
        div = $('events');
        params = {limit: limit, offset: offset, group_id: groupId};
        sn_getAjax('fetch_members', params, 'members');
    }
}

function sn_fetchMembersHandler(result, resultElementName, userData) {
    if (result.code == 66) {
        result = result.text.evalJSON()
        $(resultElementName).update(result.users);
        window.ajaxPagination3.returnCall(result.num_members);
    }
}
function deleteMembers(limit, offset) {
    if (groupId) {
        params = {limit: limit, offset: offset, group_id: groupId};
        sn_getAjax('delete_members', params, 'members');
    }
}

function sn_deleteMembersHandler(result, resultElementName, userData) {
    if (result.code == 66) {
        result = result.text.evalJSON()
        $(resultElementName).update(result.users);
        window.ajaxPagination3.returnCall(result.num_members);
    }
}
// [-] Zona ajax members ----------------------------------------------------

// [+] Zona ajax discussions ----------------------------------------------------
function fetchDisscusions(limit, offset) {
    if (groupId) {
        div = $('completare');
        params = {limit: limit, offset: offset, group_id: groupId};
        sn_getAjax('fetch_disc', params, 'completare');
    }
}

function sn_fetchDiscHandler(result, resultElementName, userData) {

    if (result.code == 668) {
        result = result.text.evalJSON();
        $(resultElementName).update( result.disscusions);
        window.ajaxPagination.returnCall(result.num_disscusions);
    }
}




function del_discussion(event){
  Event.stop(event);
  var  params = {disc_id:discId};
  if(confirm("Sunteti siguri ca vreti sa stergeti aceasta discutie ?")) sn_getAjax('delete_discussion',params);
}


function sn_deleteDiscussionHandler(result, resultElementName, userData){

    if(result.code == 670){
        result = result.text.evalJSON();
        var group_id = result.groupId;
        document.location = result.my_link;
    }else document.location = SITE_BASE + "err/no_rights_to_delete_discussions";
}

document.observe("dom:loaded",function(){
    if($('del_disc')!=undefined){
        Event.observe('del_disc','click',del_discussion)
    }
})
// [-] Zona ajax discussions ----------------------------------------------------

function blind(element)
{
 element = $(element);
 new Effect.BlindUp(element,  {duration : 0.5});


}
function blindDown(element)
{
 element = $(element);
 new Effect.BlindDown(element, {duration : 0.5});

}


//----------------------------------functii pentru grup-----------------------------------
function disable_notification()
{

    id_u = $('user_id').value;
    id_g = $('group_id').value;
    params = {uid: id_u, gid: id_g};
    sn_getAjax('disable_notification',params);

}
function sn_disableNotificationHandler(result, resultElementName, userData)
{
    if(result.code = 666)
    {
        if($('notif').value == "0")
        {
            $('disable_notifications').update("dezactiveaza notificarile");
            $('notif').value = "1";
        }
        else if($('notif').value == "1")
        {
            $('disable_notifications').update("activeaza notificarile");
            $('notif').value = "0";
        }
    }
    if(result.code == 667) document.location = SITE_BASE + "index.php?module=login&err=no_auth_up";
}

document.observe("dom:loaded", function(){
        if($('disable_notifications')!=undefined){
            Event.observe('disable_notifications','click', disable_notification);
        }
    })

function join_group()
{
    id_u = $('user_id').value;
    id_g = $('group_id').value;
    params = {uid: id_u, gid: id_g};
    sn_getAjax('join_group',params);
}

function sn_joinGroupHandler(result, resultElementName, userData)
{
    $('join_group').update(result.text);
    if ($('join_group') != null)
    {
     setTimeout("$('join_group').update('')", 1500);
     id_g = $('group_id').value;
     if(result.code == 0) document.location = SITE_BASE + "index.php?module=sectiune&s=comunitate&id="+id_g;
    }
}
function adauga_discutie(event)
 {

     Event.stop(event);
     my_form = Event.element(event);
     customParams = my_form.serialize().parseQuery();
     if(customParams.title != "") sn_getAjax('adauga_discutie', customParams);
     else{
          if($('adauga_discutie_msg')){
             Effect.Appear($('adauga_discutie_msg'), { duration: 0.0 });
             $('adauga_discutie_msg').innerHTML  = "Discutia trebuie sa contina un titlu!";
             Effect.Fade( $('adauga_discutie_msg'), {transition: Effect.Transitions.linear, duration: 2.0});
        }
     }
 }

 function sn_adaugaDiscutieHandler(result, resultElementName, userData){

    if(result.code == 555) document.location = SITE_BASE + "index.php?module=login&err=no_auth_up";

    if(result.code == 0)
    {
        $('completare').update(result.text.showDisscusions);
        $('events').update(result.text.events);
        $('num1').update(result.text.numDisscusions);
        if($('add_response')){
            $('add_response').style.display = "none";
        }
        if($('add_form')){
            $('add_form').style.display = "none";
        }
        if($('meniu_disc')){
            $('meniu_disc').style.display = "none";
        }
        if($('adauga_discutie_form')){
            $('adauga_discutie_form').reset();
        }
        if($('adauga_discutie_msg')){
             Effect.Appear($('adauga_discutie_msg'), { duration: 0.0 });
             $('adauga_discutie_msg').innerHTML  = "Ati adaugat cu succes discutia!";
             Effect.Fade( $('adauga_discutie_msg'), {transition: Effect.Transitions.linear, duration: 2.0});
        }

        window.ajaxPagination.returnCall(result.text.numDisscusions);
        window.ajaxPagination2.returnCall(result.text.num_events);
    }
 }

document.observe("dom:loaded",function(){
    if($('adauga_discutie_form')!=undefined){
        Event.observe('adauga_discutie_form','submit',adauga_discutie)
    }
})

document.observe("dom:loaded",function(){
    if($('sterge_membri_form')!=undefined){
        Event.observe('sterge_membri_form','submit',sterge_membri)
    }
})
function sterge_membri(event){
    Event.stop(event);
    my_form = Event.element(event);
    customParams = my_form.serialize().parseQuery();
    id_u = $('user_id').value;
    id_g = $('group_id').value;
    customParams['uid'] = id_u;
    customParams['gid'] = id_g;
    if(confirm("Sunteti siguri sa stergeti membri?")) sn_getAjax('sterge_membri',customParams);
}

function sn_stergeMembriHandler(result, resultElementName, userData){
      if(result.code == 1) document.location.reload();
}

document.observe("dom:loaded",function(){
    if($('group_file_add')!=undefined){
        Event.observe('group_file_add','submit',group_file_add)
    }
})

function group_file_add(event){
    Event.stop(event);
    my_form = Event.element(event);
    customParams = my_form.serialize().parseQuery();
    sn_getAjax('add_to_group',customParams)
}

function paraseste_grup(event)
{
    Event.stop(event);
    id_u = $('user_id').value;
    id_g = $('group_id').value;
    params={ uid:id_u , gid:id_g };
    if(confirm("Sunteti siguri ca vreti sa parasiti grupul?")) sn_getAjax('paraseste_grup',params);

}
function sn_parasesteGrupHandler(result, resultElementName, userData){
    if(result.code == 0) {
        id_g = $('group_id').value;
        if( $('num_members')) $('num_members').update(result.text.numMembers);
        document.location.reload();
    } else if (result.code == 1) {
        document.location = SITE_BASE + "index.php?module=login&err=no_auth_up"
    } else {
        var pop =  new MessageBox('response', 'Eroare', result.text, {ok:['Inchide', function(){void(0);}]});
    }
}

document.observe("dom:loaded",function(){
        if($('paraseste_grup_link')!=undefined){
            Event.observe('paraseste_grup_link','click',paraseste_grup)
        }
    })

function sterge_grup(event)
{
    Event.stop(event);
    id_u = $('user_id').value;
    id_g = $('group_id').value;
    params={ uid:id_u , gid:id_g };
    if(confirm("Sunteti siguri ca vreti sa stergeti acest grup?")){
        sn_getAjax('sterge_grup',params);
    }
}

function sn_stergeGrupHandler(result, resultElementName, userData){
 if(result.code == 889){
     document.location = SITE_BASE + "index.php?module=login&err=no_auth_up";
 }
 if(result.code == 888){
     document.location = SITE_BASE + "comunitate/";
 }
}


function sterge_gcontent(caid)
{
    id_u = $('user_id').value;
    id_g = $('group_id').value;
    params={ uid:id_u , gid:id_g , cid:caid };
    if(confirm("Sunteti siguri ca vreti sa stergeti acest fisier?")) sn_getAjax('sterge_gcontent',params);
}

function sn_stergeGcontentHandler(result, resultElementName, userData){
 id_g = $('group_id').value;
 if(result.code == 1) document.location = SITE_BASE + "index.php?module=sectiune&s=comunitate&id="+id_g;
 else{
     alert(result.text);
 }
}

function grup_favorit(aid){
    id_u = $('user_id').value;
    id_g = $('group_id').value;
    id_c = aid;
    params={ uid:id_u , gid:id_g , cid:id_c};
    if(confirm("Sunteti siguri ca vreti sa promovati acest fisier?")) sn_getAjax('favorit_grup',params);

}

function sn_favoritGrupHandler(result, resultElementName, userData){
 id_g = $('group_id').value;
 if(result.code == 1) document.location = SITE_BASE + "index.php?module=sectiune&s=comunitate&id="+id_g;
 else{
     alert(result.text);
 }
}
document.observe("dom:loaded",function(){
    if($('sterge_grup_link')!=undefined){
        Event.observe('sterge_grup_link','click',sterge_grup)
    }
})

function scoate_din_playlist(content_id, pid)
{
    if(content_id != '')
    {
        params = {content_id: content_id, pid: pid};
    }
    sn_getAjax('scoate_din_playlist',params);
}

function sn_scoateDinPlaylistHandler(result, resultElementName, userData)
{
    if(result.code == 0)
    {
        $('playlist_content').update(result.text.playlistContent);
        Sortable.destroy('playlist_content');
        init_sortable_playlist();
    }
}

function seteaza_icon(content_id, pid)
{
    params = {content_id: content_id, pid: pid};
    sn_getAjax('seteaza_icon', params, null, {'content_id': content_id});
}

function sn_seteazaIconHandler(result, resultElementName, userData)
{
    if(result.code == 0)
    {
        $('playlists').update(result.text.playlists);
        var id_msg = 'pmsg_' + userData['content_id'];
        Effect.Appear(id_msg, { duration: 2.0 });
        $(id_msg).update("Continutul a fost setat ca icon principal");
        Effect.Fade(id_msg, {transition: Effect.Transitions.linear, duration: 2.0});
    }
}


document.observe("dom:loaded",function(){
    if($('bkg_form')!=undefined){
        Event.observe('bkg_form','submit',preview_imagine)
    }
})


function preview_imagine(){
sn_getAjax('preview_imagine');
}

function sn_previewImagineHandler(result, resultElementName, userData)
{
    var image = document.getElementById( 'img_preview' );
    image.src = "";
    image.src = result.text;

}
var UserChannel = {
    image_temp_url:"",
    image_url :"",
    setOriginalImage :function(img){
        UserChannel.image_url = img;
    },
    textSize : function(size){
        if($('u_boxText'))  $('u_boxText').style.fontSize = " " + size;
    },
    textFont : function(font){
        if($('u_boxText')){
                    $('u_boxText').style.fontFamily = font;
        }
    },
    textStil : function(stil,check){
        if($('u_boxText')){
                    switch(stil)
                    {
                     case 'bold':
                        $('u_boxText').style.fontWeight =(check)?stil:"normal";
                        break;
                     case 'italic':
                        $('u_boxText').style.fontStyle =(check)?stil:"normal";
                        break;
                     case 'underline':
                        $('u_boxText').style.textDecoration =(check)?stil:"none";
                        break;
                     default:
                        break;
                    }

        }
    },
    textColor : function(){
        $$('.id_cp2').each(function(inp){
                    if(inp.value && $('u_boxText')) $('u_boxText').style.color ="#"+inp.value ;
               });
    },
   linkSize : function(size){
        if($('text_link'))  $('text_link').style.fontSize = " "+size;
   },
   linkFont : function(font){
        if($('text_link')){
                    $('text_link').style.fontFamily = font;
        }
    },
    linkStil : function(stil,check){
        if($('text_link')){
                    switch(stil)
                    {
                     case 'bold':
                        $('text_link').style.fontWeight =(check)?stil:"normal";
                        break;
                     case 'italic':
                        $('text_link').style.fontStyle =(check)?stil:"normal";
                        break;
                     case 'underline':
                        $('text_link').style.textDecoration =(check)?stil:"none";
                        break;
                     default:
                        break;
                    }
        }
    },
   linkColor : function(){
               $$('.id_cp3').each(function(inp){
                    if(inp.value && $('text_link')) $('text_link').style.color ="#"+inp.value ;
               });
   },
   headerSize : function(size){
        if($$('.user_box h5'))  $$('.user_box h5').each(function(inp){
            inp.style.fontSize = size;
        })
    },
   headerFont : function(font){
        if($('text_link')){
                     if($$('.user_box h5'))  $$('.user_box h5').each(function(inp){
                            inp.style.fontFamily = font;
                        })
        }
    },
    headerStil : function(stil,check){
        if($('text_link')){
                       if($$('.user_box h5'))  $$('.user_box h5').each(function(inp){
                            switch(stil)
                            {
                             case 'bold':
                                inp.style.fontWeight =(check)?stil:"normal";
                                break;
                             case 'italic':
                                inp.style.fontStyle =(check)?stil:"normal";
                                break;
                             case 'underline':
                                inp.style.textDecoration =(check)?stil:"none";
                                break;
                             default:
                                break;
                            }

                        })
        }
    },
    headerColor : function(){
                $$('.id_cp4').each(function(inp)
               {
                    if(inp.value && $$('.user_box h5'))  $$('.user_box h5').each(function(inp2){
                                        inp2.style.color ="#" + inp.value;
                                    })
               });
   },
    borderSize : function(size){
        if($$('.user_box'))  $$('.user_box').each(function(inp){
                            switch($('border_position').value){
                                case 'border':
                                inp.style.borderWidth = size;
                                break;
                                case 'border-left':
                                inp.style.borderLeftWidth =  size;
                                break;
                                case 'border-right':
                                inp.style.borderRightWidth =  size;
                                break;
                                case 'border-bottom':
                                inp.style.borderBottomWidth =  size;
                                break;
                                case 'border-top':
                                inp.style.borderTopWidth =  size;
                                default:
                                break;
                            }
                        })

    },
    borderStil :function(stil){
        if($$('.user_box'))  $$('.user_box').each(function(inp){
                                UserChannel.borderSize($('border_size').value);
                                inp.style.borderStyle = stil;
                        })
    },
    borderPosition :function(position){
        if($$('.user_box'))  $$('.user_box').each(function(inp){
                            UserChannel.borderColor();
                            UserChannel.borderStil($('border_stil').value);
                            inp.style.borderWidth = 0 + "px";
                            switch(position){
                                case 'border':
                                inp.style.borderWidth = $('border_size').value;
                                break;
                                case 'border-left':
                                inp.style.borderLeftWidth =  $('border_size').value;
                                break;
                                case 'border-right':
                                inp.style.borderRightWidth =  $('border_size').value;
                                break;
                                case 'border-bottom':
                                inp.style.borderBottomWidth =  $('border_size').value;
                                break;
                                case 'border-top':
                                inp.style.borderTopWidth =  $('border_size').value;
                                default:
                                break;
                            }
                        })

    },
    borderColor :function(){
        $$('.id_cp5').each(function(inp)
               {
                    if(inp.value && $$('.user_box'))  $$('.user_box').each(function(inp2){
                                        inp2.style.borderColor ="#" + inp.value;
                                    })
               });
    },
    headerBkgColor : function(){
          $$('.id_cp6').each(function(inp)
               {
                    if(inp.value && $$('.user_box h5'))  $$('.user_box h5').each(function(inp2){
                                        inp2.style.backgroundColor ="#" + inp.value;
                                    })
               });
    },
    boxBkgColor : function(){
           $$('.id_cp7').each(function(inp)
               {
                    if(inp.value && $$('.user_box'))  $$('.user_box').each(function(inp2){
                                        inp2.style.backgroundColor ="#" + inp.value;
                                    })
               });
    },
    changeImage : function(){
        if($('picture_status')){
            if(!$('picture_status').checked){
                $('immagine').style.display = "none";
                $('immagine_default').style.display = "block";
            }
            else {
                $('immagine').style.display = "block";
                $('immagine_default').style.display = "none";
            }
        }
    },
    imageBackground : function(elem,my_url){
        $(elem).style.backgroundImage = "url('"+my_url+"')";
        $(elem).style.backgroundPosition = "center center";
        $(elem).style.backgroundRepeat = "no-repeat";
        UserChannel.image_temp_url = my_url;
    },
    imagePosition :function(elem,position){
        $(elem).style.backgroundPosition = position;
    },
    imageRepeat :function(elem,repeat){
        $(elem).style.backgroundRepeat = repeat;
    },
    imageAtasament :function(elem,repeat){
        $(elem).style.backgroundAttachment = repeat;
    },
    resetImage : function(elem,checked){
        var url = (checked)?UserChannel.image_temp_url:UserChannel.image_url;
        if($('background_status').checked) url = "";
        if(url != "") $(elem).style.backgroundImage ="url('"+url+"')";
    },
    clearToBackground : function(elem,checked){
        var url = UserChannel.image_url;
        if($('preview_cfg_image').style.backgroundImage != "none" &&  UserChannel.image_url =="" && !$('picture_status').checked){
            UserChannel.image_url = $('preview_cfg_image').style.backgroundImage;
            url =  UserChannel.image_url;
        }else if(UserChannel.image_temp_url != "" && $('picture_status').checked){
            url = UserChannel.image_temp_url;
        }
        if(url) url = "url('"+url+"')";
        $(elem).style.backgroundImage =(checked)?"none":url;

    },
    backgroundColor: function(){
             $$('.id_cp1').each(function(inp){
                    if(inp.value && $('preview_cfg_image')) $('preview_cfg_image').style.backgroundColor ="#"+inp.value ;
               });
    },
    box_resolution : function(element){
        try
        {

       var ratio = 35;

        if(Math.round(screen.width/screen.height) > 1){
            ratio -= (Math.round(screen.width/screen.height)-1)*5;
        };

        $(element).style.width = Math.round((screen.width*ratio)/100)+"px";
        $(element).style.height = Math.round((screen.height*ratio)/100)+"px";
        }catch(err){alert(err);}
    },
    saveAll : function(){
        try{
        if($('bkg_form')) $('bkg_form').submit();
        if( $('general_text')) $('general_text').submit();
        if($('link_text_design')) $('link_text_design').submit();
        if($('header_text_design')) $('header_text_design').submit();
        if($('box_design')) $('box_design').submit();
        }catch(err){
            alert(err);
        }
    },
    resetAll : function(){
        try{
        if($('bkg_form')) $('bkg_form').reset();
        UserChannel.resetBackground();
        if( $('general_text')) $('general_text').reset();
        UserChannel.resetText();
        if($('link_text_design')) $('link_text_design').reset();
        UserChannel.resetLink();
        if($('header_text_design')) $('header_text_design').reset();
        UserChannel.resetHeader();
        if($('box_design')) $('box_design').reset();
        UserChannel.resetBox();
        }catch(err){
            alert(err);
        }
    },
    resetLink : function(){
        UserChannel.linkSize($('link_size').value);
        UserChannel.linkFont($('link_font').value);
        UserChannel.linkStil($('linkStilBold').value,$('linkStilBold').checked);
        UserChannel.linkStil($('linkStilItalic').value,$('linkStilItalic').checked);
        UserChannel.linkStil($('linkStilUnderline').value,$('linkStilUnderline').checked);
        UserChannel.linkColor();

    },
    resetText : function(){
        UserChannel.textSize($('text_size').value);
        UserChannel.textFont($('text_font').value);
        UserChannel.textStil($('textStilBold').value,$('textStilBold').checked);
        UserChannel.textStil($('textStilItalic').value,$('textStilItalic').checked);
        UserChannel.textStil($('textStilUnderline').value,$('textStilUnderline').checked);
        UserChannel.textColor();

    },
    resetHeader : function(){
        UserChannel.headerSize($('header_size').value);
        UserChannel.headerFont($('header_font').value);
        UserChannel.headerStil($('headerStilBold').value,$('headerStilBold').checked);
        UserChannel.headerStil($('headerStilItalic').value,$('headerStilItalic').checked);
        UserChannel.headerStil($('headerStilUnderline').value,$('headerStilUnderline').checked);
        UserChannel.headerColor();

    },
    resetBox : function(){
        UserChannel.borderSize($('border_size').value);
        UserChannel.borderStil($('border_stil').value);
        UserChannel.borderPosition($('border_position').value);
        UserChannel.borderColor();
        UserChannel.headerBkgColor();
        UserChannel.boxBkgColor();

    },
    resetBackground : function(){
     UserChannel.resetImage('preview_cfg_image',$('picture_status').checked);
     UserChannel.imageRepeat('preview_cfg_image',$('repeta_imagine').value);
     UserChannel.backgroundColor();
    },
    rgb:function(a){

        var o=a.toLowerCase();
        return [parseInt(o.slice(0,2),16),parseInt(o.slice(2,4),16),parseInt(o.slice(4),16)];
    },
    shade:function(a,b){
        var v=[],i;
        for(i=0;i<3;i++){
            v[i]=Math.round(a[i]*b);
            if(v[i]>255)v[i] = 255;
            if(v[i]<0)v[i] = 0;
        }
        return v;
    },
    hex:function(a){
        var f=UserChannel._hex;
        return f(a[0])+f(a[1])+f(a[2]);
    },
    _hex:function(a){
        return ('0'+a.toString(16)).slice(-2);
    },
    getShades : function(my_color)
    {
        var cc,v=[],n,dark,lite ;
        cc = my_color;
        if(cc.length<6){
            alert('Value must be a 6 character hex value.');
            return;
        }
        n = m.rgb(cc);
        dark = m.hex(m.shade(n,0.8));
        v.push(dark);
        v.push(cc);
        lite = m.hex(m.shade(n,1.2));
        v.push(lite);
    return v;
    }
}



function copy_playlist(event)
{
    Event.stop(event);
    my_form = Event.element(event);
    customParams = my_form.serialize().parseQuery();
    sn_getAjax('copy_playlist', customParams);
}

function sn_copyPlaylistHandler(result, resultElementName, userData)
{

    if (result.code == 0)
    {
        $(result.text.form).style.display = 'none';
        id_msg = 'pl_err_msg';
        Effect.Appear(id_msg, { duration: 2.0 });
        $(id_msg).innerHTML = "Ai salvat cu succes playlist-ul "+userData['playlist_name']+".Il poti asculta in pagina ta, in zona `Playlist-uri`.";
        $(id_msg).className =  "errorMsgDefault";
        Effect.Fade(id_msg, {transition: Effect.Transitions.linear, duration: 5.0});
    }else{
        id_msg = 'pl_err_msg';
        Effect.Appear(id_msg, { duration: 2.0 });
        $(id_msg).innerHTML = "NU s-a putut efectua salvarea!";
        $(id_msg).className =  "errorMsgDefault";
        Effect.Fade(id_msg, {transition: Effect.Transitions.linear, duration: 5.0});
    }
}

function openNameBox(aid)
{
    $('nume_playlist_form_' + aid).style.display='block';
}

submitForm=function(event){
    my_form=Event.element(event);
    Event.stop(event);
    customParams = my_form.serialize().parseQuery();
    userData = my_form.serialize(true);
    sn_getAjax('copy_playlist', customParams, null, userData);
}


function sn_salveazaContentHandler(result, resultElementName, userData)
{
    if(result.code == 0)
    {
        $(result.text.form).style.display = 'none';
    }
}

submitContentForm=function(event){
    my_form=Event.element(event);
    Event.stop(event);
    customParams = my_form.serialize().parseQuery();
    sn_getAjax('salveaza_content', customParams);
}

function sterge_content(aid)
{
    if(confirm("Sigur  vreti sa stergeti materialul?"))
    {
        customParams = {aid: aid};
        sn_getAjax('sterge_content', customParams);
    }
}

function sn_stergeContentHandler(result, resultElementName, userData)
{
    if(result.code == 0)
    {
       result = result.text.evalJSON();
       document.location = result.my_link;
    }
}

function seteaza_content_principal(aid)
{
    params = {aid: aid}
    if(confirm("Sigur  vrei sa promovezi fisierul pe pagina principala?")){
        sn_getAjax('seteaza_content_principal', params,'',params);
    }
}
function sn_seteazaContentPrincipalHandler(result, resultElementName, userData){
 document.location.reload();
}
function input_radio_uncheck(el) {
    if (el.length == 0) el.checked = false;
    for (i = 0; i < el.length; i++) {
        el[i].checked = false;
    }
}

function input_radio_value(el)
{
    if (el.length == 0 && el.checked) return el.value;
    for (i = 0; i < el.length; i++) {
        if (el[i].checked) return el[i].value
    }
    return null;
}

function make_embed_code(e) {
    var el = null, sz = null, sizes, s, tmp, cid, aplay, w, h;
    var asp_ratio = 3/4, b = 28;

    if(typeof(e) != 'undefined') {
        el = Event.element(e);
    }
    var f = $('form_embed');
    if(el && el.name == 'player_embed') return true;
    cid = f.content_id.value;
    //sizes = [[], [320,240], [450,370], [250,130]];
    //sizes = [450, 400, 300];

    var aplay = f.aplay && f.aplay.checked ? '&aplay=true'  : '';
    var color_player = f.color_player && f.color_player.value ? '&rgb=' + f.color_player.value : ''
    var from = (f.from.value != '') ? '&from=' + f.from.value : '';
    if((!el || el && el.name == 'width_custom') && (f.width_custom && /[\d]+/.test(f.width_custom.value))) {
        w = parseInt(f.width_custom.value)
        input_radio_uncheck(f.width_player);
    } else if(f.width_player && input_radio_value(f.width_player) != null) {
        w = parseInt(input_radio_value(f.width_player));
        if (el && el.name != 'width_custom') {
            f.width_custom.value = '';
        }
    } else {
        w = 450;
    }
    if (!(w >= 300 && w <= 450)) {
        f.width_player[0].checked = true;
        f.width_custom.value = '';
        w = 450;
    }

    if (f.ctype.value != '2') {
        h =  Math.round((w * asp_ratio) + b);
    } else {
        h = 106;
    }
    sz = [w, h];

    s = '<embed width="' + sz[0] + '" height="' + sz[1] + '" src="' + SITE_BASE + 'emb/' + cid + color_player + aplay + from + '" ';
    s += 'allowfullscreen="true" allowscriptaccess="always" ';
    s += 'type="application/x-shockwave-flash" ';
    s += '></embed><br><small>Vezi mai multe din <a href="' + f.categ_link.value + '" target="_blank">' + f.categ_name.value + '</a> pe <a href="http://www.220.ro" target="_blank">220.ro</a></small>';

    script = '<script type="text/javascript" src="' + SITE_BASE + 'embjs?id=' + cid + '&width=' + sz[0] + '&height=' + sz[1] + color_player + aplay + from + '"></script>' +
    '<noscript>Vezi <a href="' + f.content_link.value + '" target="_blank">' + f.content_title.value + '</a> pe <a href="http://www.220.ro" target="_blank">220.ro</a></noscript>';

    f.player_embed.value = s;
    f.player_embed2.value = script;
    return true;
}

document.observe("dom:loaded", function() {
        if ($('form_embed')) {
            $('form_embed').getElements().each(function(el){
                if (el.type == 'radio') Event.observe(el, 'click', make_embed_code);
                else Event.observe(el, 'change', make_embed_code);
            });
        }
});


function add_to_group(instance){

    my_form = $('add_to_group_form_' + instance);
    userData = my_form.serialize(true);
    userData['form_id'] = my_form.id;
    userData['instance'] = instance;
    if(userData['group'] == '0') {
        var l = SITE_BASE + 'index.php?module=create_grup&content_id=' + userData['content_id'];

        if(typeof(window.opener) == 'undefined' || window.opener == null) {
            document.location = l;
        } else {
            window.opener.document.location = l;
            window.opener.focus();
        }

        return;
    }
    customParams=my_form.serialize().parseQuery();
    sn_getAjax('add_to_group', customParams, null, userData);
    return;
}

function sn_addToGroupHandler(result, resultElementName, userData)
{
    if(!$('grup_form_msg'))
    {
        var id_msg = 'add_group_msg_' + userData['instance'];
        Effect.Appear(id_msg, { duration: 0.0 });
        $(id_msg).innerHTML = result.text;
        Effect.Fade(id_msg, {transition: Effect.Transitions.linear, duration: 2.0});
    }else{
        Effect.Appear('grup_form_msg', { duration: 0.0 });
        $('grup_form_msg').innerHTML = result.text;
        Effect.Fade('grup_form_msg', {transition: Effect.Transitions.linear, duration: 4.0});
        if(result.code == 2) setTimeout("reload()",900);
    }
}

function dezaboneaza_subscribe(username){
    params = {uname: username};
    if(confirm("Sunteti siguri ca vreti sa va dezabonati ?"))
        sn_getAjax('dezaboneaza_subscribe',params);
}

function sn_dezaboneazaSubscribeHandler(result, resultElementName, userData)
{

    if(result.code == 1)
    {
        if (window.pageVersion == 3) {
            $('aboneaza_te').toggle();
            $('dezaboneaza_te').toggle();
            var p = $('user').positionedOffset()
            new smallNotif(result.text, {x: p.left + 380, y: p.top - 15}, 'msg_box');
            return;
        }
        var id_msg = 'user_msg' ;
        if($(id_msg)){
            Effect.Appear(id_msg, { duration: 4.0 });
            $(id_msg).innerHTML = result.text;
            $(id_msg).className =  "errorMsgDefault";
            Effect.Fade(id_msg, {transition: Effect.Transitions.linear, duration: 2.0});
        }

        if(!$('is_not_subscribed') ){
            setTimeout("reload()",1500);
        }else{
            $('is_not_subscribed').style.display ="inline";
        }

        if($('is_subscribed')){
            $('is_subscribed').style.display ="none";
        }

    }
}

function reload(){
    document.location.reload();
}

function remove_subscriber(username){
    params = {uname:username};
    if(confirm("Sunteti siguri ca vreti sa stergeti din lista abonatul ?"))
        sn_getAjax('remove_subscriber',params);
}

function sn_removeSubscriberHandler(result, resultElementName, userData)
{
    if(result.code == 1)
    {
        var id_msg = 'user_msg' ;
        Effect.Appear(id_msg, { duration: 4.0 });
        $(id_msg).innerHTML = result.text;
        $(id_msg).className = "errorMsgDefault";
        Effect.Fade(id_msg, {transition: Effect.Transitions.linear, duration: 2.0});
        setTimeout("reload()",900);
    }
}

function remove_favorite(aid){
    params = {aid:aid};
    if(confirm("Sunteti siguri ca vreti sa stergeti filmul din lista de favorite ?"))
        sn_getAjax('remove_favorite',params);
}

function sn_removeFavoriteHandler(result, resultElementName, userData)
{ // nu se face redirect !!!!
    if(result.code == 0)
    {
        var id_msg = 'remove_favorite_msg' ;
        Effect.Appear(id_msg, { duration: 4.0 });
        $(id_msg).innerHTML = result.text;
        $(id_msg).className = "errorMsgDefault";
        Effect.Fade(id_msg, {transition: Effect.Transitions.linear, duration: 2.0});
        setTimeout("reload()",900);
    }
}


function remove_friend(username){
    params = {uname:username};
    if(confirm("Sunteti siguri ca vreti sa il stergeti din lista de prieteni ?"))
        sn_getAjax('remove_friend',params);
}


function remove_request(username){
    params = {uname:username};
    if(confirm("Sunteti siguri ca vreti sa stergeti requestul ?"))
        sn_getAjax('remove_request',params);
}

function sn_removeFriendHandler(result, resultElementName, userData) {
	removeRequestAction(result, resultElementName, userData);
}

function sn_removeRequestHandler(result, resultElementName, userData) {
  removeRequestAction(result, resultElementName, userData);
}

function removeRequestAction(result, resultElementName, userData) {
	var id_msg = 'dezaboneaza_msg' ;
	try {
	    if(result.code == 1) {
	        if (window.pageVersion == 3) {
	            $('stege_prieten').toggle();
	            $('adauga_prieten').toggle();
	            var p = $('user').positionedOffset()
	            new smallNotif(result.text, {x: p.left + 380, y: p.top - 15}, 'msg_box');
	            return;
	        }
	        Effect.Appear(id_msg, { duration: 4.0 });
	        $(id_msg).innerHTML = result.text;
	        $(id_msg).className = "errorMsgDefault";
	        Effect.Fade(id_msg, {transition: Effect.Transitions.linear, duration: 2.0});
	        if(!$('is_not_friend')) setTimeout("reload()",900);
	    }
	}
	catch(e) {
		if(result) alert(result.text);
			setTimeout("reload()",900);
	}
}

function submitFormWithMyAction(form_id,action) {
	try {
		$(form_id).action = (String.interpret(action));
		$(form_id).submit();
	}
	catch(e) {alert("ERROR HANDLING FORM "+e);}

}


function friendshipRequest(username){
    params = {uname:username};
    sn_getAjax('friendship_request',params);
}

function sn_friendshipRequestHandler(result, resultElementName, userData)
{

    if(result.code == 1 || result.code == 0)
    {
        if (window.pageVersion == 3) {
            if (result.code == 0) {
            } else {
                $('stege_prieten').toggle();
                $('adauga_prieten').toggle();
            }
            var p = $('user').positionedOffset()
            new smallNotif(result.text, {x: p.left + 380, y: p.top - 15}, 'msg_box');
            return;
        }


        var id_msg = 'user_msg' ;
        Effect.Appear(id_msg, { duration: 4.0 });
        $(id_msg).innerHTML = result.text;
        $(id_msg).className ="errorMsgDefault";
        Effect.Fade(id_msg, {transition: Effect.Transitions.linear, duration: 2.0});
    }
}

function subscribeToUser(username){
    params = {uname:username};
    sn_getAjax('subscribe_request',params);
}

function sn_subscribeRequestHandler(result, resultElementName, userData)
{
    if(result.code == 1 || result.code == 0)
    {
        if (window.pageVersion == 3) {
            var p = $('user').positionedOffset()
            new smallNotif(result.text, {x: p.left + 380, y: p.top - 15}, 'msg_box');
            if (result.code == 0) {
            } else {
                $('aboneaza_te').toggle();
                $('dezaboneaza_te').toggle();
            }
            return;
        }

        var id_msg = 'user_msg' ;
        Effect.Appear(id_msg, { duration: 4.0 });
        $(id_msg).innerHTML = result.text;
        $(id_msg).className ="errorMsgDefault";
        Effect.Fade(id_msg, {transition: Effect.Transitions.linear, duration: 2.0});
        if($('is_not_subscribed')) $('is_not_subscribed').style.display ="none";
        if($('is_subscribed')) $('is_subscribed').style.display ="inline";
    }
}

// [+] Stars votes
var starsHint = {
    marks: {
        one:    'naspa',
        two:    'slabut',
        tree:   'hai ca merge',
        four:   'misto',
        five:   'genial'
    },
    hint: function(event, act){
        if(act == 1) {
            if(window.isLogged) {
                var el = Event.element(event);
                var ind = (el.classNames() + '').substr(6)
                $('starsMsg').update(window.starsHint.marks[ind]);
                $('starsMsg').show();
            } else {
                $('starsMsg').hide();
                $('starsLog').show();
            }
            $('nr_voturi').hide();
        } else {
            $('starsLog').hide();
            $('starsMsg').update(' voturi').show();
            $('nr_voturi').show();
        }
    }
};
document.observe("dom:loaded", function() {
    if(window.contentId) {
        if(window.isLogged) {
            $$('.stars-holder1 LI A').each(function(a){
                Event.observe(a, 'mouseover', starsHint.hint.bindAsEventListener(a, 1));
                Event.observe(a, 'mouseout', starsHint.hint.bindAsEventListener(a, 0));
            });
        } else {
            $$('.n_rating1').each(function(dv){
                Event.observe(dv, 'mouseover', starsHint.hint.bindAsEventListener(dv, 1));
                Event.observe(dv, 'mouseout', starsHint.hint.bindAsEventListener(dv, 0));
            });
        }
    }
});
// [-] Stars votes

//[+] Zona ajax comentarii pagina profil--------------------
function fetchComments(limit, offset) {
    if (userId) {
        div = $('ajax_comments');
        params = {limit: limit, offset: offset, user_id: userId};
        sn_getAjax('fetch_comments', params, 'ajax_comments');
    }
}

function sn_fetchCommentsHandler(result, resultElementName, userData) {

    if (result.code == 1) {
        result = result.text.evalJSON();
        $(resultElementName).update(result.comments);
        window.ajaxPagination.returnCall(result.nr_messages);
    }
}
//[-] Zona ajax comentarii pagina profil--------------------

function makeSearch(section, q) {
    if (typeof q != 'string' || q.length < 2) {
        alert('Fraza e prea scurta!');
        return;
    }
    var p =  null;
    if (
    section == 'video' ||
    section == 'audio' ||
    section == 'image' ||
    section == 'playlist' ||
    section == 'user'
    ) {
        p = '/' + section;
    }
    if(p != null) {
        window.location.href = SITE_BASE + 'cauta' + '/' + encodeURIComponent(q) + p;
    } else {
        alert('Eroare la cautare');
    }
};

function deblocheaza_user(username){
    params = {uname:username};
    sn_getAjax('deblocheaza_user',params);
}

function sn_deblocheazaUserHandler(result, resultElementName, userData)
{
    if(result.code == 0)
    {
        var id_msg = 'deblocheaza_msg' ;
        if ($(id_msg)) {
            Effect.Appear(id_msg, { duration: 4.0 });
            $(id_msg).innerHTML = result.text;
            $(id_msg).className = "errorMsgDefault";
            Effect.Fade(id_msg, {transition: Effect.Transitions.linear, duration: 2.0});
            setTimeout("reload()",900);
        }
   		var btn1 = $('btnBlockUnbolck');
        if (btn1) {
   		    var a = $$('#btnBlockUnbolck a')[0];
   		    var user = /.*\([\'\"](.+)[\'\"]\).*/.exec(a.readAttribute('onclick'))[1];
            $('btnBlockUnbolck').update('<a class="bNone user_link10" href="javascript:void(0)" onclick="block_user(\'' + user + '\')" rel="nofollow" title="Blocheaza utilizator">Blocheaza utilizator</a>')
   		    new MessageBox('msgBlockUnbolck', 'Deblocheaza utilizator', result.text);
        }
    }
}

function titleForUrl(title) {
    title = title.replace(/^\s+|\s+$/gm, '');
	title = title.replace(/[^\w]+/gm, ' ');
	title = title.replace(/^(.)|\s(.)/gm, function ($1) {return $1.toUpperCase();});
	return title.replace(/\s/gm, '-');
}

function gea_mobile(username){
    params={username:username}
    sn_getAjax('gea_mobile',params);
}

function sn_geaMobileHandler(result, resultElementName, userData){
    if(result.code == 1){
        $('email_addres').update(result.text);
    }
}

function sterge_comment(comment_id)
{

    params={ cid:comment_id };
    if(confirm("Sunteti siguri ca vreti sa stergeti acest comment?")){
        sn_getAjax('sterge_comment',params, 'ajax_comments');
    }
}

function sn_stergeCommentHandler(result, resultElementName, userData){

    if(result.code == 1)
    {

        result = result.text.evalJSON();
        $(resultElementName).update(result.comments);
        window.ajaxPagination.returnCall(result.nr_messages);
    }
}

var ptimeUpd = {
    states: [],
    send : function(id, s) {
        if (typeof window['sn_pltimeUpdHandler'] == 'undefined') {
            window['sn_pltimeUpdHandler'] = function (){}
        }
        if (this.states[id] != 1 && /^[a-zA-Z0-9]{10,10}$/.test(id) && s > 0) {
            ptimeUpd.states[id] = 1;
            sn_getAjax('pltime_upd', {'aid': id, 'dur': s}, null, {'id': id});
        }
    }
}

var Smilies = {
    enabled: 1,
    selfDo: 0,
    imgPath: SITE_BASE + '_templates/_default/img/sml/',
    classApply: 'emoticable',
    smilies: {":-":"7", ":)":"1", ":-)":"1", "(-:":"1", "(:)":"1", ":(":"2", ":-(":"2", ":(":"2", ";)":"3", ";-)":"3", ":D":"4", ";-D":"4", ";;)":"5", ";;-)":"5", "<:D>":"6", ":-/":"7", ":S":"7", ":X":"8", ":-X":"8", "(L)":"8", ":\">":"9", ":$":"9", ":-P":"10", ":P":"10", ":-*":"11", ":*":"11", "(K)":"11", "=((":"12", "(U)":"12", ":-O":"13", ":O":"13", "X-(":"14", "X(":"14", ":@":"14", ":->":"15", ":>":"15", "B-)":"16", "(H)":"16", ":-S":"17", "#:-S":"18", ">:)":"19", "(6)":"19", ":((":"20", ":-((":"20", ":'(":"20", ":))":"21", ":-))":"21", ":|":"22", ":-|":"22", "/:)":"23", "/:-)":"23", "^O)":"23", "=))":"24", "O:-)":"25", "0:-)":"25", "O:)":"25", "0:)":"25", "(A)":"25", ":-B":"26", ":B":"26", "=;":"27", "I-)":"28", "|-)":"28", "8-|":"29", "8-)":"29", "L-)":"30", ":-&":"31", "+O(":"31", ":-$":"32", ":-#":"32", "[-(":"33", ":O)":"34", ":0":"34", "<@:)":"34", "8-}":"35", "<:-P":"36", "<:O)":"36", "(:|":"37", "(:}":"37", "=P~":"38", ":-?":"39", "*-)":"39", "#-O":"40", "=D>":"41", ":-SS":"42", "@-)":"43", ":^O":"44", ":-W":"45", ";-<":"46", ">:P":"47", "<):)":"48", ":@)":"49", "3:-O":"50", ":(|)":"51", "~:>":"52", "@};-":"53", "%%-":"54", "**==":"55", "(~~)":"56", "~O)":"57", "*-:)":"58", "8-X":"59", "=:)":"60", "=:-)":"60", ">-)":"61", ":-L":"62", "[-O<":"63", "$-)":"64", ":-\"":"65", "B-(":"66", ":)>-":"67", "[-X":"68", ":D/":"69", ">:/":"70", ";))":"71", "O->":"72", "O=>":"73", "O-+":"74", "(%)":"75", ":-@":"76", "^:)^":"77", ":-J":"78", "(*)":"79", ":)]":"100", ":-C":"101", "~X(":"102", ":-H":"103", ":-T":"104", "8->":"105", ":-??":"106", "%-(":"107", ":O3":"108", "X_X":"109", ":!!":"110", "\M/":"111", ":-Q":"112", ":-BD":"113", "^#(^":"114", ":BZ":"115"},
    sml4Pad: {':))':'21', '=))':'24', ';)':'3', ':D':'4', ';;)':'5', '=D>':'41', ';))':'71', '8->':'105', ':$':'9', ':P':'10', ':*':'11', ':X':'8', ':-O':'13', '<:D>':'6', ':>':'15', 'B-)':'16', '(*)':'79', ':-BD':'113', '^:)^':'77', ':-H':'103', ':)':'1', '/:)':'23', '<):)':'48', 'O:)':'25', ':B':'26', '=;':'27', 'I-)':'28', '8-)':'29', ':)>-':'67', ':-SS':'42', ':-$':'32', 'M/':'111', '$-)':'64', '8-}':'35', '<:-P':'36', ':D/':'69', '=P~':'38', '*-)':'39', '#-O':'40', ':-/':'7', ':-J':'78', '@-)':'43', ':^O':'44', '[-(':'33', ':O)':'34', ':-S':'17', '#:-S':'18', ':@)':'49', '3:-O':'50', ':(|)':'51', '~:>':'52', '@};-':'53', '%%-':'54', '**==':'55', '(~~)':'56', '~O)':'57', '*-:)':'58', '8-X':'59', '=:)':'60', '>-)':'61', ':-L':'62', '[-O<':'63', ';-<':'46', 'B-(':'66', ':-W':'45', '[-X':'68', ':((':'20', '>:/':'70', '>:P':'47', 'O->':'72', 'O=>':'73', 'O-+':'74', '(%)':'75', ':-@':'76', ':-&':'31', '=((':'12', ':(':'2', ':)]':'100', ':-C':'101', '~X(':'102', 'L-)':'30', ':-T':'104', ':-??':'106', ':O3':'108', 'X_X':'109', ':!!':'110', 'X(':'14', ':-Q':'112', '(:|':'37', '^#(^':'114', ':BZ':'115', '%-(':'107', ':|':'22',  ':-"': '65'},
    smlPrep: {},
    smlRev: {},
    sChars: {"<":"&LT;", ">":"&GT;", "&": "&AMP;"},
    ptr: null,
    init: function(){
        if (!this.enabled) return;
        if (this.ptr == null) {
            this.ptr = '';
            for (var i in this.smilies) {
                this.ptr = (i.replace(/([\W])/g, "\\$1")) + "|" + this.ptr;
                this.smlPrep[i.replace(/<|>|&/g, function($m) {return Smilies.sChars[$m]})] = this.smilies[i];
            }
            for (var i in this.sml4Pad) {
                this.smlRev[this.sml4Pad[i]] = i;
            }
            this.ptr = this.ptr.substr(0, this.ptr.length-1);
            this.ptr = this.ptr.replace(/<|>|&/g, function($m) {return Smilies.sChars[$m]});
        }
        if (this.selfDo) {
            document.observe("dom:loaded", function() {
                Smilies.replace();
            });
        }
    },
    _replace: function(text) {
        if (!this.enabled) return;
        var re = new RegExp (this.ptr, "gmi");
        text = (' ' + text + ' ').replace(re, function ($m) {return '<img class="sml_img" src="' + Smilies.imgPath + Smilies.smlPrep[$m.toUpperCase()] + '.gif">'});
        return text.substr(1, text.length - 2);
    },
    replace: function(addSel){
        if (!this.enabled) return;
        var selector = (typeof(addSel) != 'undefined') ? addSel :  Smilies.classApply;
        $$(selector).each(function(dv) {
            if (typeof (dv.innerHTML) != 'undefined') dv.update(Smilies._replace(dv.innerHTML));
        });
    },
    _reverseReplace: function(text) {
        if (!this.enabled) return;
        text = (' ' + text + ' ').replace(/<img\s+class="?sml_img"?\s+src\=".*?\/([0-9]+)\.gif">/gmi, function ($f, $m) {return Smilies.smlRev[$m] != undefined ? Smilies.smlRev[$m] : '';});
        return text.substr(1, text.length - 2);
    },
    reverseReplace: function(addSel){
        if (!this.enabled) return;
        $$(addSel).each(function(dv) {
            if (typeof (dv.innerHTML) != 'undefined') dv.update(Smilies._reverseReplace(dv.innerHTML));
        });
    },
    sPad: null,
    pTarget: null,
    pTargetList: [],
    showPad: function(trEv, target){
        if (!this.enabled) return;
        if(this.sPad && this.sPad.visible()) {this.hidePad();return;}
        if(!this.sPad) {

            var text = '<div id="smilePadCont" class="sCont">';
            var j = 0;
            for (var i in this.sml4Pad) {
                if (i.indexOf('"') != -1) continue;
                if(j++ == 50) {
                    text += '</div><div class="sCont" id="smilePadExt" style="display: none;">';
                }
                text += '<div><img src="' + Smilies.imgPath + Smilies.smilies[i] + '.gif" onclick="Smilies.insertEmo(\'' + i +'\'); return false;"></div>'
            }
            text += '</div><div id="btns"><a href="#" onclick="Smilies.hidePad(); return false;" title="Close">X</a><br>'
            + '<a href="#" onclick="Smilies.padExtend(); return false;" id="smilePadTglBtn" title="Extend">&gt;</a></div>';
            this.sPad = new Element('div', {'id': 'smiliesPad'});
            document.body.appendChild(this.sPad.update(text));
        }
        else {
            this.sPad.show();
        }
        this.pTarget = target;
        if(this.pTargetList[this.pTarget] !== 1) {
            Event.observe($(this.pTarget), 'click', Smilies.hidePad.bindAsEventListener());
            this.pTargetList[this.pTarget] = 1;
        }
        var XY = Element.cumulativeOffset(Event.element(trEv));
        var posX = XY[0] + 'px', posY =  XY[1]-245 + 'px';
        this.sPad.setStyle({'left': posX, 'top': posY});
    },
    hidePad: function() {
        if(Smilies.sPad) {
            Smilies.sPad.hide();
            if($(this.pTarget)) $(this.pTarget).focus();
        }
    },
    padExtend: function(){
        if(Smilies.sPad) {
            $('smilePadExt').toggle();
            if($('smilePadExt').visible()) {
                $('smilePadTglBtn').update('&lt;');
                $('smiliesPad').setStyle({'width': '390px'});
            }
            else {
                $('smilePadTglBtn').update('&gt;');
                $('smiliesPad').setStyle({'width': '205px'});
            }
        }
    },
    insertEmo: function(e) {
        if (!this.enabled) return;
        insertText($(this.pTarget), e);
        this.hidePad();
    }
}
Smilies.init();

document.observe("dom:loaded", function() {
    window.domLoaded = true;
});


function resizePreview(size){
  if($('previewer')){
      var my_size = parseInt($('previewer').height) + size;
      $('previewer').height = my_size;
  }
   if($('div_previewer')){
      var my_size = parseInt($('div_previewer').style.height) + size;
      $('div_previewer').style.height = my_size+'px';
  }
}

function colorPickerScripts() {

    cpc = new Element('div', {'id': 'color_picker_container_1' , 'class':'colorPick_box','style' : 'display:none'});
    document.body.appendChild(cpc);
    var jss = ["js/colorpicker/colormethods.js", "js/colorpicker/colorvaluepicker.js", "js/colorpicker/slider.js", "js/colorpicker/colorpicker.js"];
    var x, hd = document.getElementsByTagName('head')[0];
    /*
    new Ajax.Request(WEB_BASE + jss[0], {method: 'get', onSuccess: function(t){CPicker.loadPickerPhase2();
    new Ajax.Request(WEB_BASE + jss[1], {method: 'get', onSuccess: function(t){CPicker.loadPickerPhase2();
    new Ajax.Request(WEB_BASE + jss[2], {method: 'get', onSuccess: function(t){CPicker.loadPickerPhase2();
    new Ajax.Request(WEB_BASE + jss[3], {method: 'get', onSuccess: function(t){CPicker.loadPickerPhase2();
    }}); }}); }}); }});
    */
    $A(jss).each(function(i){
        x = document.createElement('script');
        x.src = WEB_BASE + i;
        hd.appendChild(x);
    });
    sn_getAjax('load_picker',{},'color_picker_container_1', CPicker.userData);
}

var CPicker = {
    fetch_js : 1,
    picker_loaded : false,
    picker_loadedPhase2 : 0,
    loadPicker : function(posX,posY,act,id){
        if (!this.picker_loaded) {
            this.picker_loaded = true;
            params={}
            CPicker.userData ={posX:posX,posY:posY,act:act,id:id};
            if(this.fetch_js){//----------------add the javascript for the color picker-----------------
                this.fetch_js = 0;
                colorPickerScripts();
            }
        }else{
             this.togglePicker(posX,posY,act,id);
        }

    },
    loadPickerPhase2: function(){
      if (++this.picker_loadedPhase2 != 4) return;

      sn_getAjax('load_picker',{},'color_picker_container_1', CPicker.userData);
    },
    togglePicker:function(posX,posY,act,id){
        var cont = 'color_picker_container_1';

        if (act == 'show') {
            if ($('cp1_Hex')) $('cp1_Hex').setAttribute('id', 'id_temp');
            $$('.id_cp' + id).each(function(inp) {
                inp.setAttribute('id', 'cp1_Hex');
            });
        }

        Element.absolutize(cont);
        if(act != 'hide'){
        $(cont).setStyle({'left': posX, 'top': posY});
        }
        color_picker = null;
        $('cp1_ColorMap').update('');
        $('cp1_ColorBar').update('');
        $$('.color_picker_arrow').each(function(el){Element.remove(el);});

        if($(cont)){
            if($(cont).visible()){
                $(cont).hide();
                $$('img.color_picker_arrow').invoke('hide');
            }
            else{
                $(cont).show();
                $$('img.color_picker_arrow').invoke('show');

                color_picker = new Refresh.Web.ColorPicker('cp1', {startHex: 'b9121b', startMode:'s'});
            }
        }
       if(act == 'hide'){
           if($('form_embed')) make_embed_code();
           if($('form_vchannel')) make_embed_wm();
           try
           {
                   UserChannel.backgroundColor();
                   UserChannel.linkColor();
                   UserChannel.headerColor();
                   UserChannel.textColor();
                   UserChannel.borderColor();
                   UserChannel.headerBkgColor();
                   UserChannel.boxBkgColor();

           }catch(err){}
        }
    }
}

function sn_loadPickerHandler(result, resultElementName, userData){
    $(resultElementName).update(result);
    CPicker.togglePicker(userData['posX'],userData['posY'],userData['act'],userData['id']).defer();
}

function sterge_raspuns_video(content_response_to, id){
    if(confirm('Sunteti sigur ca vreti sa stergeti acest raspuns video ?')) {
        params = {content_response_to: content_response_to,content_id: id};
        sn_getAjax('sterge_raspuns_video', params);
    }
    return;
}

function sn_stergeRaspunsVideoHandler(result, resultElementName, userData){
    var id_msg = 'mesaj_ok' ;
    Effect.Appear(id_msg, { duration: 4.0 });
    $(id_msg).update(result.text);
    Effect.Fade(id_msg, {transition: Effect.Transitions.linear, duration: 2.0});
    setTimeout("reload()",900);
}

var minFPVer =  "9.0.115";
var recomFPVer =  "10.0.0";
var SNotices = {
	close: function(id,place) {
		if ($(place)) Effect.SlideUp(place, {duration: 0.3});
		Cookies.create(id, '1', 2)
	}
}


function abonare_show(aid, status) {
    params = {aid: aid, status: status}
    sn_getAjax('abonare_show', params);
}

function sn_abonareShowHandler(result, resultElementName, userData){
    if(result.code == 0){
        var inner = (result.text.status)?"Dezaboneaza-te":"Aboneaza-te";
        var text = (result.text.status )?"Te-ai abonat cu succes!":"Te-ai dezabonat cu succes!";
        var status = (result.text.status )?0:1;
        var a = Builder.node('a', {className:'abshow', onclick:'abonare_show(\''+result.text.show_id+'\',\''+status+'\');', href:'javascript:void(0);'}, [inner]);
        $('abonare_show').innerHTML ="";
        $('abonare_show').appendChild(a);
        $('abonare_mesaj').style.display = "block";
        $('abonare_mesaj').update(text);
        setTimeout(function(){$('abonare_mesaj').update('');$('abonare_mesaj').style.display = "none";},4000);
    }
}

/*widget provari*/
function fetchPromovariShows(limit, offset,userData ) {
    if(limit != 0 && window.ajaxPagination.interval){
           window.ajaxPagination.interval.stop();
           window.ajaxPagination.offset = offset;
           window.ajaxPagination.interval = null;
           if(window.ajaxPagination.timeout){
               clearTimeout(window.ajaxPagination.timeout);
           }
           if(num_promo > 1){
            window.ajaxPagination.timeout = setTimeout(function(){new PeriodicalExecuter(promo_widget_interval,4);},10000);
           }
    }else{
         var cur_pag = offset + 1;
         window.ajaxPagination.startPage = cur_pag;
    }

     $$('.promo_show').each(function(el){
         if(el.style.display == 'block'){
             el.style.display = 'none';
         }
     });
    try{
        $('promo_show_'+offset).style.display = 'block';
        window.ajaxPagination.returnCall(num_promo);
    }catch(e){}
}

function promo_widget_interval(pe){
    if(!window.ajaxPagination.interval){
        window.ajaxPagination.interval = pe;
    }
    window.ajaxPagination.offset += 1;
    if(window.ajaxPagination.offset >= num_promo){
        window.ajaxPagination.offset = 0;
    }
    fetchPromovariShows(0,window.ajaxPagination.offset,null);//limit 0 because is an automatic call
    return;
}

function toggleShowDescription(){
	try{
		if($('desriere_show').style.display != "none"){
		 	$('desriere_show').style.display = 'none';
		 	$('desriere_show_big').style.display = 'block';
		 	$('desc_show').style.width = "940px";
		}else{
			$('desriere_show').style.display = 'block';
		 	$('desriere_show_big').style.display = 'none';
		 	$('desc_show').style.width = "310px";
		}
	}catch(e){}
}


var getPageDimensions = function() {
	var xScroll, yScroll, windowWidth, windowHeight, pageDimensions = {};
	if (window.innerHeight && window.scrollMaxY) {
		xScroll = document.body.scrollWidth;
		yScroll = window.innerHeight + window.scrollMaxY;
	} else if (document.body.scrollHeight > document.body.offsetHeight){
		xScroll = document.body.scrollWidth;
		yScroll = document.body.scrollHeight;
	} else {
		xScroll = document.body.offsetWidth;
		yScroll = document.body.offsetHeight;
	}
	if (self.innerHeight) {
		windowWidth = self.innerWidth;
		windowHeight = self.innerHeight;
	} else if (document.documentElement && document.documentElement.clientHeight) {
		windowWidth = document.documentElement.clientWidth;
		windowHeight = document.documentElement.clientHeight;
	} else if (document.body) {
		windowWidth = document.body.clientWidth;
		windowHeight = document.body.clientHeight;
	}
	if(yScroll < windowHeight){
		pageDimensions.height = windowHeight;
	} else {
		pageDimensions.height = yScroll;
	}
	if(xScroll < windowWidth){
		pageDimensions.width = windowWidth;
	} else {
		pageDimensions.width = xScroll;
	}
	return pageDimensions;
}

var MessageBox =  Class.create({
	// callbacks {'ok': 'name of function callback', 'cancel': 'name of function callback'}
	open: function(){
		var nd;
		if (typeof message == "object") message = message.join('<br>');
		if (!$(this.id)) nd = new Element('DIV', {'id': this.id});
		nd.update('\
		<div class="msg_box_cont" style="height:' + getPageDimensions().height + 'px;" onclick="window[\'' + this.id +'\'].blink();"></div>\
		<table cellspacing="0" cellpadding="0" border="0" class="box_msg">\
        <tr>\
            <td class="top-left"></td>\
            <td class="top"></td>\
            <td class="top-right"></td>\
        </tr>\
        <tr>\
            <td class="left"></td>\
            <td class="boxy-inner">\
                <div class="title-bar" style="-moz-user-select: none;">\
                    <h5 class="h5_msg_box">' + this.title + '' + (this.callback['x'] ? '<a class="content inchide" style="float:right;margin-top: 4px;" href="javascript:void(0);" onclick="window[\'' + this.id +'\'].callback.x();" id="bXMB' + this.id +'">' + this.callbackLabels['x'] + '</a>' : '') +'</h2>\
                </div>\
                <div style="display: block;" class="boxy-content">\
                	<div class="msg_box_desc">' + this.message +'</div>\
                    ' + (this.callback['ok'] ? '<a class="close_nsg_box" href="javascript:void(0);" onclick="window[\'' + this.id +'\'].callback.ok();" id="bOkMB' + this.id +'">' + this.callbackLabels['ok'] + '</a>' : '') +'\
                    ' + (this.callback['cancel'] ? '<a class="close_nsg_box" href="javascript:void(0);" onclick="window[\'' + this.id +'\'].callback.cancel();" id="bClsMB' + this.id +'">' + this.callbackLabels['cancel'] + '</a>' : '') +'\
                </div>\
            </td>\
            <td class="right"></td>\
        </tr>\
        <tr>\
            <td class="bottom-left"></td>\
            <td class="bottom"></td>\
            <td class="bottom-right"></td>\
        </tr>\
</table>\
		');
		document.body.appendChild(nd);
		this.positionCenter();
		if ($('bOkMB' + this.id)) $('bOkMB' + this.id).focus();
        if ($('bClsMB' + this.id)) $('bClsMB' + this.id).focus()
	},
	close: function(callbacks){
	    Event.stopObserving(document, 'keyup', this.keyUpBinder);
	    if (callbacks) {//dirty way
	        if (this.callback['cancel']) this.callback['cancel']();
	        else if ((this.callback['x'])) this.callback['x']();
	    }
	    if($(this.id)) $(this.id).remove();
		window[this.id] = null;
	},
	blink: function() {
	    var b = $$('#' + this.id + ' .boxy-content')[0];
	    if (!b) return;
	    b.setStyle({'backgroundColor': '#F1EF36'});
	    setTimeout(function(){b.setStyle({'backgroundColor': '#FFFFFF'});}, 200);
	},
	positionCenter: function(){
		if (!$(this.id)) return;
		var boxDim = {x: 420, y: 120}
		var new_pos_x =  Math.round(document.viewport.getScrollOffsets()[0] + (document.viewport.getDimensions()['width'] * 0.5) - (boxDim.x/2));
		var new_pos_y =  Math.round(document.viewport.getScrollOffsets()[1] + (document.viewport.getDimensions()['height'] * 0.4) - (boxDim.y/2));
		$$('#' + this.id + ' table')[0].setStyle({'top': 200 + 'px', left: new_pos_x  + 'px'});
	},
	onKeyUp: function(e) {
	    e = e || window.event;
	    var code = e.keyCode || e.charCode || e.which;
	    if (code == 27) this.close(1);
	},
	//init
	initialize: function(id, title, message, callbacks) {

	    if (arguments.length == 1) {
   	        message = arguments[0];
	        id = 'mb_' + Math.floor(Math.random() * 10000000000);
 	        title = 'Notificare';
	    }

	    this.id = id;
		this.title = title;
		this.message = message
		var self = this;
		this.callback = {};
		this.callbackLabels = {ok: 'ok', cancel: 'close'};
		if (callbacks)  {
		    if (callbacks['ok']) {
		        this.callback['ok'] = function() {
		            callbacks['ok'][1]();
		            if(!callbacks['ok']['dontClose']) self.close();
		        };
		        this.callbackLabels['ok'] = callbacks['ok'][0];
		    }
		    if (callbacks['cancel'])  {
		        this.callback['cancel'] = function() {
		            callbacks['cancel'][1]();
		            if(!callbacks['cancel']['dontClose']) self.close();
		        };
		        this.callbackLabels['cancel'] = callbacks['cancel'][0];
		    }
		    if (callbacks['x']) {
		        this.callback['x'] = function() {
		            callbacks['x'][1]();
		            if(!callbacks['x']['dontClose']) self.close();
		        };
		        this.callbackLabels['x'] = callbacks['x'][0];
		    }
		}
		if (!this.callback['ok'] && !this.callback['cancel'] && !this.callback['x']) {
		    this.callback['ok'] = function() {self.close()};
		}
		//Event.observe(window, 'scroll', function(){self.positionCenter();});

		window[this.id] = this;
		this.open();
		this.keyUpBinder = this.onKeyUp.bindAsEventListener(this);
		Event.observe(document, 'keyup', this.keyUpBinder);
	}
});


function block_user(username){
	var params = {username: username};
	var userData = {'fromComment': arguments[1]};
	sn_getAjax('block_user', params, null, userData);
}

function sn_blockUserHandler(result, resultElementName, userData){
	if(result.code == 0){
	    if ($('content')) {
	        $('content').update(result.text);
	        setTimeout("$('report').remove()",1500);
	    }

		var btn1 = $('btnBlockUnbolck');
		if (btn1) {
		    var a = $$('#btnBlockUnbolck a')[0];
		    var user = /.*\([\'\"](.+)[\'\"]\).*/.exec(a.readAttribute('onclick'))[1];
		    $('btnBlockUnbolck').update('<a class="bNone user_link9" href="javascript:void(0)" onclick="deblocheaza_user(\'' + user + '\')" rel="nofollow" title="Deblocheaza utilizator">Deblocheaza utilizator</a>')
		    new MessageBox('msgBlockUnbolck', 'Blocheaza utilizator', result.text);
		}

		if(userData.fromComment && $(userData.fromComment)) {
		    $(userData.fromComment).remove();
		    new MessageBox('msgBlockComment', 'Blocheaza utilizator', result.text);
		}
	} else {
		    new MessageBox('msgBlockComment', 'Blocheaza utilizator', result.text);
	}

}

function addFriends() {
   try {
       var ids = [];
       $$('INPUT[type="checkbox"]:checked ').each(function(el){
            ids.push(el.value);
        });
        if (!(ids.length > 0)) {
        	new MessageBox('adauga_prieteni', 'Eroare', 'Nu ati selectat niciun user');
        	return;
        }
       	addFriendsIds(ids);
   } catch(e) {
       //alert(e);
   }
}

function addFriendsIds(ids){
    if (typeof ids == 'object') {
		ids =  ids.join(',');
	}
	var params = {users_names:ids};
	sn_getAjax('add_friends_msg',params);
}

function sn_addFriendsMsgHandler(result, resultElementName, userData){
	if(result.code == 1){
		new MessageBox('raportare_spam', 'Eroare', result.text);
		return;
	}else if(result.code == 0){
        window.location = SITE_BASE + "index.php?module=mesagerie&folder=inbox";
	}

}

function add_avatar(){
    var url=SITE_BASE+"index.php?module=profile&action=edit&what=2";
    var loader=SITE_BASE+"_templates/_default/img/upload_loader.gif";
    var str='<body><p id="f1_upload_process" style="display:none">Loading...<br/><img src="'+loader+'" /></p><p id="result" class="errUpl red"></p><div id="form"><form action="'+url+'" method="post" enctype="multipart/form-data" target="upload_target" onsubmit="startUpload();" >File: <input name="myfile" id="myfile" type="file" /><input type="submit" name="submitBtn" value="Upload" /></form></div><iframe id="upload_target" name="upload_target" src="#" style="width:0;height:0;border:0px solid #fff;"></iframe></body>';
    new MessageBox('uploadAvatar', 'Adaugare avatar', str, {ok: ['OK', reloadComments]});
}

function startUpload(){
    if ($('myfile').value.length < 3) {
        $('result').update('Trebuie sa selectati o imagine !')
        return false;
    } else {
        $('f1_upload_process').show();
        $('form').hide();
    }
    return true;
}

function reloadComments() {
    window.ajaxPagination.gotoPage(window.ajaxPagination.startPage);
}

function stopUpload(success){
    var result = '';
    if (success == 1) {
        $('result').innerHTML =
        '<span class="msg">Avatarul a fost adaugat !<\/span><br/><br/>';
        //setTimeout("$('schimbaAvatarC').remove()",1500);
    } else {
        $('result').innerHTML = '<span class="emsg">A aparut o problema la upload !<\/span><br/><br/>';
    }
    $('f1_upload_process').style.visibility = 'hidden';
    return true;

}

var trackSource = {
    cName: 'trSrc',
    checkerAdd: function(tr) {// tr must be of form: {check:function(){}}
        if (typeof tr == 'object' && typeof tr.check == 'function') {
            var v = tr.check();
            if (v !== false) {
                trackSource.set(v);
            }
        }
    },
    set: function(v) {
        Cookies.create(this.cName, v);
    },
    get: function() {
        return Cookies.read(this.cName);
    }
}

var addLolzTrCheck = {
    nls: ['2946', '2974', '2980', '3112', '3174', '3175', '3176', '3212'],
    check: function() {
        prm = document.location.href.toQueryParams();
        if(prm) {
            if (prm.utm_campaign && prm.utm_campaign.substr(11) == '1756' && this.nls.indexOf(prm.nl_id) != -1) {
                return 'nl' + prm.nl_id;
            }
            else if (prm.utm_campaign && this.nls.indexOf(prm.utm_campaign.substr(11)) != -1) {
                return 'nl' + prm.utm_campaign.substr(11);
            }
        }
        return false;
    }
}
//trackSource.checkerAdd(addLolzTrCheck);

document.observe("dom:loaded", function() {
(function(){//lolz banner
    if(!window.ctPlDet || window.ctPlDet.ctype != 1) return;
    var el = $$('DIV.content_det')[0];
    if (!el) return;
    var a = $$('#user_stats a')[0];
    if (a && /\/CronicaCarcotasilor\//.test(a.href)) {
        //el.insert({bottom: new Element('div', {'id': 'promovare_carca'}).update('<a href="http://cronica.primatv.ro/tv/din-15-septembrie-un-nou-sezon-de-cronica-la-prima-tv.html?play=1" id="promovare_carca_bann" target="_blank"></a>')});
        return;
    } else if (a && /\/DaKINO\//.test(a.href)) {
        el.insert({bottom: new Element('div', {'id': 'promovare_dakino'}).update('<a href="http://iff.dakino.ro/" id="promovare_dakino_bann" target="_blank">&nbsp;</a>')});
        return;
    }
    var cook = Cookies.read('dp_lolz');
    if (cook) return;
    el.insert({bottom: new Element('div', {'id': 'promovare_lolz'}).update('<a href="' + SITE_BASE + 'index.php?module=alert_special&action=configure" id="lolz">&nbsp;</a><a href="javascript:void(0)" onclick="Cookies.create(\'dp_lolz\', \'1\', 7);$(\'promovare_lolz\').remove()" id="inchide_lolz">&nbsp;</a>')});
})();
});

var RoundBox = function(text) {
    var tpl = '\
    <div class="rounded-box">\
    <div class="rb-top-left-corner"><div class="rb-top-left-inside">&bull;</div></div>\
    <div class="rb-bottom-left-corner"><div class="rb-bottom-left-inside">&bull;</div></div>\
    <div class="rb-top-right-corner"><div class="rb-top-right-inside">&bull;</div></div>\
    <div class="rb-bottom-right-corner"><div class="rb-bottom-right-inside">&bull;</div></div>\
    <div class="rb-box-contents">[boxcontent]</div>\
    </div>'
    return tpl.replace(/\[boxcontent\]/, text);
};

var ATTip = {
    show: function(el, text) {
        if (arguments.length == 3) {
            el = arguments[1];
            text = arguments[2];
        }
        if (! $(el)) return;
        if (! $(el.attId) && text == '') return;
        if (! el.attId) {
            el.attId = 'ttid_' + (new Date()).getTime() + Math.floor(Math.random() * 3);
            if (el.title) el.title = '';
            if (el.alt) el.alt = '';
            var dv = new Element('div', {'id': el.attId, style: 'border-radius: 5px; -webkit-border-radius: 5px; -moz-border-radius:5px; box-shadow: 1px 1px 2px #666666, 0 0 5px #000000 inset; -webkit-box-shadow: 1px 1px 2px #666666, 0 0 5px #000000 inset; -moz-box-shadow: 1px 1px 2px #666666, 0 0 5px #000000 inset; background:#B9121A; border:2px solid #fff; color:#fff; display:block; font-size:11px; filter:alpha(opacity=85); -moz-opacity:0.85; -webkit-opacity: 0.85; opacity: 0.85; padding: 3px 7px 3px 7px; overflow-x: hidden; text-align:center; width: 100px; position: absolute; z-index: 1002; top:' + (parseInt(el.positionedOffset().top) - 30) + 'px; left:' + el.positionedOffset().left + 'px;'});

            document.body.appendChild(dv.update(text));
            dv.setStyle({top: (parseInt(el.positionedOffset().top) + el.getHeight()) + 'px'});
            Event.observe(el.attId, 'mouseover', this.show.bindAsEventListener(null, el, null));
            Event.observe(el.attId, 'mouseout', this.hide.bindAsEventListener(null, el, null));
            Event.observe(el, 'mouseout', this.hide.bindAsEventListener(null, el, null));
        }
        $(el.attId).show();
    },
    hide: function(e, el) {
        if (! el.attId) return;
        $(el.attId).hide();
    }
};


Ajax.CachedAutocompleter = Class.create();
Object.extend(Object.extend(Ajax.CachedAutocompleter.prototype, Autocompleter.Base.prototype), (function (){
    var auto_complete_cache = {};

    return {
        initialize: function(element, update, url, options) {
            if (!Prototype.Browser.IE) Event.observe(element, 'keydown', this.onKeyPress2.bindAsEventListener(this));
            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;
            this.options.workSpace = this.options.workSpace || (this.element.id || this.element.name);
            if (auto_complete_cache[this.options.workSpace] === undefined) {
                auto_complete_cache[this.options.workSpace] = {};
            } else if (Object.values(auto_complete_cache[this.options.workSpace]).length >= 5000) {
                auto_complete_cache[this.options.workSpace] = {};
            }
            if (Prototype.Browser.IE) Event.observe(element, 'keydown', this.onKeyPress2.bindAsEventListener(this));
        },

        onKeyPress2: function(event) {
            switch(event.keyCode) {
                case Event.KEY_RETURN:
                this.active = false;
                return;
            }
        },

        getUpdatedChoices: function() {
            this.startIndicator();
            var t = this.getToken();
            if(auto_complete_cache[this.options.workSpace][t]) {
                this.updateChoices(auto_complete_cache[this.options.workSpace][t]);
            } else {
                entry = encodeURIComponent(this.options.paramName) + '=' +
                encodeURIComponent(t);

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

                if(this.options.defaultParams)
                this.options.parameters += '&' + (typeof this.options.defaultParams == 'string' ? this.options.defaultParams : Object.toQueryString(this.options.defaultParams));
                new Ajax.Request(this.url, this.options);
            }
        },
        onComplete: function(request) {
            var rsp = request.responseJSON, txt = '';
            txt = '<ul><li>' + rsp[1].join('</li><li>') + '</li></ul>';
            this.updateChoices(auto_complete_cache[this.options.workSpace][this.getToken()] = txt);
        }
    }
}()));

if ($('input_cautare_top')) {
	var input_cautare_top_sugg = new Ajax.CachedAutocompleter('input_cautare_top', 'input_cautare_top_sugg', SITE_BASE + '?module=opensuggest&format=json&add_info=link', {autoSelect: false, paramName: 'q', minChars: 3, method: 'GET', frequency: 0.6, afterUpdateElement: function(t, el) {makeSearch('video', t.value);}});
}

document.observe("dom:loaded", function() {
    $$('.disabled_js_div').each(function(d) {
        var ins = new Element('div');
        d.insert({after: ins});
        ins.setStyle('background-color: #000000; position: absolute; filter: alpha(opacity=05); opacity: .05; color: #FFFFFF; z-index:' + (d.style.zIndex + 1) + ';top: ' + d.cumulativeOffset().top + 'px; left:' +  d.cumulativeOffset().left + 'px; height:' + d.getHeight() + 'px; width:' + d.getWidth() + 'px;');
    });
});

//deprecated
var menuTopSections = {
    timeoutDelay: 1000,
    timeoutFn: [],
    menuStats: [],
    init: function() {
        var els = new Hash({'video': 'toate filmele', 'muzica': 'toata muzica', 'comunitate': 'toate grupurile'});
        var ptr = new RegExp (SITE_BASE.replace(/([\W])/g, "\\$1") + '([a-z]+)\/?.*', 'i');
        var section, el, tmp, size, i;
        $$('div#meniu>a').each(function(a){
            section = ptr.exec(a.href);
            if (section == null) return;
            section = section[1];
            if(els.keys().indexOf(section) == -1) return;
            if ($('footer_categ_' + section) == null) return;
            el = new Element('div', {'id': 'topMenu_' + section, 'style' : 'position: absolute; z-index: 77000; width: 390px;display: none; left: ' + (parseInt(a.positionedOffset().left)) + 'px;'});
            $(document.body).insert({top: el});
            size = $$('#footer_categ_' + section + ' A').length;
            if (! (size > 0)) return;
            i = 0;
            tmp = '<div class="droptitle">\
                <div class="droptitle-inside">\
                        <a href="' + a.href +'" title="' + els.get(section) +'">' + els.get(section) +'</a>\
                </div>\
        </div>\
        <div class="divider">\
                <div class="divider-inside"></div>\
        </div>\
        <div class="content">\
                <div class="content-inside">\
                        <div class="col-l">';
            $$('#footer_categ_' + section + ' A').each(function(a) {
                tmp += '<a href="' + a.href + '" title="' + a.innerHTML + '">' + a.innerHTML + '</a>';
                if (Math.ceil(size/2) == ++i) tmp +='</div><div class="col-r">';
            });
            tmp += '</div>\
                </div>\
                </div>\
                <div class="cbl"></div>\
                <div class="bb"></div>\
                <div class="cbr"></div>';
            el.update(tmp);
            Event.observe(a, 'mouseover', menuTopSections.show.bindAsEventListener(null, section));
            Event.observe(a, 'mouseout', menuTopSections.hide.bindAsEventListener(null, section));
            Event.observe('topMenu_' + section, 'mouseover', menuTopSections.show.bindAsEventListener(null, section));
            Event.observe('topMenu_' + section, 'mouseout', menuTopSections.hide.bindAsEventListener(null, section));
        });
    },
    show: function(e, section, from_timeout) {
        $('topMenu_' + section).setStyle({top: (parseInt(menuTopSections.firstTab.positionedOffset().top) + menuTopSections.firstTab.getHeight()-1) + 'px'});
        $('topMenu_' + section).show();
    },
    hide: function(e, section, from_timeout) {
        $('topMenu_' + section).hide();
    },
    firstTab: $$('#meniu A')[0]
}
//menuTopSections.init();

LoginPop = {
    message: '',
    tpl: '<div id="msg_login_box_pp">{MSG}</div><form id="frm_login" class="pop_login fl_left" onsubmit="LoginPop.login();return false;"><label>Utilizator:</label><input class="log_inp" type="text" maxlength="500" name="username"><label>Parola:</label><input class="log_inp" type="password" name="password"><div class="clearAll"></div><span id="pop_tine_minte"><label for="autologin">Tine-ma minte</label><input id="autologin" type="checkbox" value="" checked="checked" name="autologin"/></span><input type="hidden" value="usr_auth" name="f"><input type="submit" value="Login" id="pop_login"><div id="pop_optiuni_cont"><a title="Cont nou" href="'+ SITE_BASE +'inregistrare">cont nou</a><a title="Am uitat parola" href="' + SITE_BASE + 'recuperare-parola" style="border: none!important;">am uitat parola</a></div></form><div class="pop_login fl_right"><label>Autentificare prin Facebook</label><p>Acum te poti conecta la 220.ro si prin contul tau de Facebook! Fa click pe butonul de mai jos si introdu datele tale:</p><a href="javascript:void(0)" onclick="FbConnect.loginFB()" id="facebook">&nbsp;</a></div><div class="clearAll"></div>',
    show: function(message) {
        if (message == undefined) message = 'Autentificare';
        FbConnect.init()
        new MessageBox('dvLoginBox', '<span>Autentificare</span>', this.tpl.replace(/\{MSG\}/, message), {x: ['x', function(){}]});
        $('frm_login').username.focus();
    },
    login: function() {
        var f = $('frm_login');
        if (typeof window.sn_usrAuthHandler != 'function') {
            window.sn_usrAuthHandler = function(result, resultElementName, userData) {
                if (result.code == 0) {
                    window.location.href = window.location.href;
                } else {
                    $('msg_login_box_pp').update(result.text);
                }
            }
        }
        sn_getAjax('usr_auth', f.serialize(true), '');
        $('msg_login_box_pp').update('');
    }
}

function urlDecode(str){
    if (!str) return str;
    return unescape(str.replace(new RegExp('\\+','g'), ' '));
}

QLSearch = {
    search: function(query) {
        if (trim(query) == '' || query.substr(0, 4) == 'Ex: ') {
            new MessageBox('QLSearchB', 'Playlist audio', 'Nu ati introdus un termen de cautare');
            return;
        }
        var params = {query: query};
        sn_getAjax('ql_search_audio', params);
        if (typeof window.sn_qlSearchAudioHandler != 'function') {
            window.sn_qlSearchAudioHandler = function(result, resultElementName, userData) {
                if(result.code == 0) {
                    var resJS = result.text.evalJSON();
                    window.location.href = SITE_BASE + 'muzica-online/' + resJS.tk.substr(0, (resJS.tk.length - 32)) + '/';
                } else if(result.code == 1) {
                    new MessageBox('QLSearchB', 'Playlist audio', 'Ne pare rau, nu am gasit muzica conform termenilor introdusi');
                } else {
                    new MessageBox('QLSearchB', 'Playlist audio', 'A aparut o eroare la cautare');
                }
            }
        }
    },
    store: function(val) {
        Cookies.create('QLSearch', val);
    },
    del: function(id) {
        var ql = QLSearch.getData();
        var i = ql.ct.indexOf(id);
        if (i == -1) return false;
        delete ql.ct[i];
        ql.ct = ql.ct.without(null, undefined).compact();
        QLSearch.store(Object.toJSON(ql));
        return true;
    },
    getData: function() {
        var cook = Cookies.read('QLSearch');
        if (!cook) return {};
        return urlDecode(Cookies.read('QLSearch')).evalJSON();
    },
    shuffle: function() {
        var ql_tmp = QLSearch.getData().ct, sh_tmp = [];
        if (! ql_tmp) return;
        while (ql_tmp.length > 0) {
            i = Math.floor(Math.random() * 1000000) % ql_tmp.length;
            sh_tmp.push(ql_tmp[i]);
            ql_tmp.splice(i, 1);
        }
        QLSearch.storeItems(sh_tmp);
    },
    storeItems: function(ct) {
        var cook = QLSearch.getData();
        cook.ct = ct;
        QLSearch.store(Object.toJSON(cook));
    }
}

function clone_playlist(pid) {
    sn_getAjax('clone_playlist', {'pid': pid});
}

function sn_clonePlaylistHandler(result, resultElementName, userData) {
    new MessageBox('dv_clone_playlist', 'Salveaza playlist', result.text);
}

function delete_playlist(aid){
    sn_getAjax('delete_playlist', {'aid': aid});
}

function sn_deletePlaylistHandler(result, resultElementName, userData){
    if(result.code == 0)
    {
        document.location = SITE_BASE + "index.php?module=profile&action=playlists";
    }
}

function conf_delete_playlist(aid) {
    new MessageBox ('del_playlist', 'Stergere Playlist', 'Esti sigur ca vrei sa stergi acest Playlist?', {ok: ['Ok', function(){delete_playlist(aid)}], cancel: ['Cancel', function(){}]});
}

function setSelect(el, value) {
    if (typeof el == 'string') el = document.getElementById(el);
    if (!el || !el.type || el.type != 'select-one') return false;
    for (var i = 0; i < el.options.length; i++) {
        if (el.options[i].value == value) {
            el.options.selectedIndex = i;
            return true;
        }
    }
}

function setSelectSearchHead(){
    if (!$('searchBoxHead')) return;
    var section = document.location.href.replace(/^https?\:\/\/.*?\//, '/'), search_section;
    var prm = $.string(document.location.href).toQueryParams();
    if (typeof ctPlDet != 'undefined' && ctPlDet.ctype) {
        section = [null, 'video', 'audio', 'image', 'video'][ctPlDet.ctype];
    } else if (/\/cauta\//.test(section)) {
        search_section = /.*?\/(video|audio|image|playlist|user)(?:\/[0-9]+)?$/.exec(section)[1];
    } else if(/\/(muzica|dj)\//.test(section) || prm['module'] == 'quicklist') {
        search_section = 'audio';
    } else if(/\/user\//.test(section)) {
        search_section = 'user';
    }
    if (search_section) setSelect('searchBoxHead', search_section);
}
setSelectSearchHead();

(function(){
    if ($('input_cautare_top') && $('input_cautare_top').visible()) $('input_cautare_top').focus();
})();

HeadNotif = function(id, message, style) {
    this.id = id;
    if (Cookies.read('HeadNotif' + this.id)) return;
    this.message = message;
    var h = $$('div#header')[0];
    if (! h) return;
    h.insert({before: new Element('div', {'id': 'HeadNotif' + this.id, 'class': 'not_220_top', 'style': style}).update('<a class="not_220_inchide" href="javascript:void(0)" title="Inchide" onclick="HeadNotif' + this.id + '.close(); return false;"><img src="' + WEB_BASE + 'img/close_info.png" alt="Inchide" width="15" height="15"></a><center><p>' + this.message + '</p></center>')});
    this.close = function() {
        var el = $('HeadNotif' + this.id);
        if (! el) return;
        Effect.SlideUp(el, {duration: 0.3});
		Cookies.create('HeadNotif' + this.id, '1', 7);
		window['HeadNotif' + this.id] = null;
    }
    window['HeadNotif' + this.id] = this;
};

var player220Control = {
    getPlayer: function() {
	return $$('#player220' + ((Prototype.Browser.Gecko) ? ' OBJECT' : ''))[0];
    },
    aplay: 0,
    trackPrerollView: function(id) {
        if (typeof _gaq != 'undefined') _gaq.push(['_trackEvent', 'Internal prerolls', id]);
        sn_getAjax('track_preroll_view', {id: id});
    },
    nextLink: null,
    PlayNext: function() {
        this.finishedPlay = true;
        if (!this.aplay){
            var o =  player220Control.getPlayer();
            if (o && typeof o.toggleRelatedMovies == 'function') o.toggleRelatedMovies();
            return;
        }
        if (this.nextLink != null) document.location = this.nextLink;
        return;
    },
    finishedPlay: false,
    setTextAdProvider: function(type) {
	player220Control.getPlayer().setAdType(type); // tradeads | google
    },
    incrementSessCookie: function(name) {
        var count = Cookies.read(name);
        if (!count) {
            count = 0;
        }
        count++;
        Cookies.create(name, count, 0);
    },
    getCountSessCookie: function(name) {
        return Cookies.read(name);
    }
}
document.observe("dom:loaded", function() {
    var pl = player220Control.getPlayer();
    if (!window.contentId || !pl) return;
    if (window.userData && userData.adfree) return;

    if (typeof getTradeAdsParams == 'undefined' || getTradeAdsParams() == '') {
    	//pl.setAdType('google');
    } else {
    }
});
var smallNotif = function(message, ev, classes) {

    if (!ev) return false;
    if (ev.clientX) {
        var pos = {x: ev.clientX +  document.viewport.getScrollOffsets().left, y: ev.clientY + document.viewport.getScrollOffsets().top};
        try {Event.stop(ev)} catch(e){};
    } else if (ev.nodeType && ev.nodeType == 1) {
        var pos = {x: parseInt(ev.cumulativeOffset()[0] + ev.getWidth()/2), y: parseInt(ev.cumulativeOffset()[1] + ev.getHeight()/2)};
    } else if (ev.x && ev.y) {
        var pos = ev;
    } else {
        return false;
    }
    var id_not = 'smn_' + Math.floor(Math.random() * 10000000000);

    var propr = {id: id_not, className: classes ? classes : 'msg_box', style: 'position: absolute; z-index: 1002; top:' + pos.y + 'px; left:' + pos.x + 'px;'};
    if (classes === undefined) {
        propr.style = propr.style + 'border-radius: 5px; -webkit-border-radius: 5px; -moz-border-radius:5px; box-shadow: 1px 1px 2px #666666, 0 0 5px #000000 inset; -webkit-box-shadow: 1px 1px 2px #666666, 0 0 5px #000000 inset; -moz-box-shadow: 1px 1px 2px #666666, 0 0 5px #000000 inset; background:#333; border:2px solid #fff; color:#fff; display:block; font-size:11px; filter:alpha(opacity=70); -moz-opacity:0.7; -webkit-opacity: 0.7; opacity: 0.7; padding:3px 7px 3px 7px; text-align:center; max-width:200px;';
    }
    var dv = new Element('div', propr);
    message = '<a style="close_smn" style="color: #fff; font-weight: bold;" onclick="$(\'' + id_not +  '\').remove()" href="javascript:void(0)"></a><span>' + message + '</span>';
    dv.innerHTML = message;
    document.body.appendChild(dv);
    setTimeout(function() {if ($(id_not)) $(id_not).remove()}, 2000);
};

var sn_getPlaylistContentHandler = function(result, resultElementName, userData) {
    if(result.code == 0) {
        var cont =  result.text.evalJSON();
        if (userData.PlayIt) {
            window.location.href = cont.link + '?play_from=playlist&playlist_id=' + userData.id;
        }
    } else {
        new MessageBox(result.text);
    }
}

var play_playlist = function(id) {sn_getAjax('get_playlist_content', {id: id, position: 1}, null, {PlayIt: true, id: id})};

function contest_vote(content, contest, votePlace, ev) {
    sn_getAjax('contest_vote', {content: content, contest: contest}, null, {ev: {clientX: ev.clientX, clientY: ev.clientY}, votePlace: votePlace});
    try{Event.stop(ev)} catch(e) {};
}

function sn_contestVoteHandler(result, resultElementName, userData) {
    if (result.code == 0) {
        new smallNotif('Vot inregistrat!', userData.ev);
        userData.votePlace.update(parseInt(userData.votePlace.innerHTML) + 1);
    } else {
        new smallNotif(result.text, userData.ev);
    }
}

function soft_delete_comment(id, status, ev) {
    sn_getAjax('soft_delete_comment', {id: id, status: status}, null, {id: id, ev: ev});
}
function sn_softDeleteCommentHandler(result, resultElementName, userData) {
    if (result.code == 0) {
        $$('.contentBody#ccomm_' + userData.id)[0].remove();
    }
    new smallNotif(result.text, userData.ev);
}

function prop_delete_user(u, ev) {
    sn_getAjax('prop_delete_user', {u: u}, null, {ev: ev});
}
function sn_propDeleteUserHandler(result, resultElementName, userData) {
    new smallNotif(result.text, userData.ev);
}
var NQL = {
    enabled: false,
    type: null,
    status: null,
    min: null,
    aplay: null,
    playingItem: null,
    listFetched: false,
    items: [],
    customData: {},
    getIdFromLink: function(lnk) {
        return /.*\/([0-9a-zA-Z]){10,10}\/[^\/]*/.exec(lnk)[1];
    },
    getCookieSettings: function() {
        var cookie_settings = urlDecode(Cookies.read('NQL'));
        cookie_settings = cookie_settings ? cookie_settings.evalJSON() : {};
        return cookie_settings;
    },
    setCookieSettings: function(name, value) {
        var cookie_settings = NQL.getCookieSettings();
        cookie_settings[name] = value;
        Cookies.create('NQL', Object.toJSON(cookie_settings));
    },
    getCurPlayIndex: function() {
        if(NQL.items.length < 1) return false;
        var cur_id = NQL.getCurrPlayItem();
        for (var i = NQL.items.length - 1; i >= 0; i--) {
            if (NQL.items[i].id == cur_id) return i;
        }
        return false;
    },
    play: function(i) {
        NQL.disablePopulate = true;
        if(NQL.items[i]) {
            document.location = NQL.prepareLink(NQL.items[i].link);
        } else if (! NQL.listFetched) {
            NQL.fetchList({callbackFn: function() {NQL.play(i)}});
        }
    },
    playPrev: function() {
        var  cur_idx = NQL.getCurPlayIndex();
        if (cur_idx == 0) return false;
        NQL.play(cur_idx - 1);
    },
    playNext: function() {
        var  cur_idx = NQL.getCurPlayIndex();
        if (cur_idx == (NQL.items.length - 1)) return false;
        NQL.play(cur_idx + 1);
    },
    typeMap: {'fz' : 'Filmele zilei', 'ql': 'Quicklist', 'playlist': 'Playlist', 'uhist': 'Istoric'},
    init: function() {
        var q_param = document.location.href.toQueryParams();
        var type = q_param.play_from || 'fz';
        var cookie_settings = NQL.getCookieSettings();
        //if (!NQL.typeMap[type]) return;
        if (! $('newQL')) return;
        this.enabled = true;
        this.type = type;
        if (cookie_settings.type != NQL.type) {
            NQL.setCookieSettings('type', NQL.type);
        }

        if (NQL.type == 'playlist') {
            NQL.customData.playlist_id = document.location.href.toQueryParams()['playlist_id'];
        }

        try {
            var cur_index = NQL.getCurPlayIndex();
        } catch (e) {};

        if (cookie_settings.aplay || (cur_index == 0 && (type == 'ql' || type == 'playlist'))) {
            if (document.location.href.toQueryParams()['play_from'] == NQL.type) NQL.toggleAplay(null, true);
        }
        $('nql_lista_optiune').update(NQL.typeMap[type]);

        if (NQL.type == 'ql'){
            $('nql_shuffle').show();
        }
        if (NQL.type != 'playlist'){
            $$('#nql_submeniu button')[2].hide();
        }
        NQL.bindButtonsActions();
        if (!NQL.listFetched) NQL.fetchList();
        NQL.bindInfoTools();
        //if (true || NQL.getCookieSettings().min) {
        //    setTimeout(function() {NQL.toggleBox(undefined, true)}, 1500);
        //}
    },
    bindButtonsActions: function() {
        $('nql_prev').onmouseover = function(){$('nql_i_prev').show()};
        $('nql_prev').onmouseout = function(){$('nql_i_prev').hide()};
        $('nql_next').onmouseover = function(){$('nql_i_next').show()};
        $('nql_next').onmouseout = function(){$('nql_i_next').hide()};
        Event.observe($('nql_min'), 'mouseover', function(){$('nql_i_toggle').show()});
        Event.observe($('nql_min'), 'mouseout', function(){$('nql_i_toggle').hide()});

        Event.observe($('nql_min'), 'click', this.toggleBox.bindAsEventListener());
        Event.observe($('nql_shuffle'), 'click', this.toggleShuffle.bindAsEventListener());
        Event.observe($('nql_autoplay'), 'click', this.toggleAplay.bindAsEventListener());
        Event.observe($('nql_prev'), 'click', this.playPrev.bindAsEventListener());
        Event.observe($('nql_next'), 'click', this.playNext.bindAsEventListener());
        Event.observe($('nql_lista'), 'click', this.togglePlTypeMenu.bindAsEventListener());
        Event.observe($$('#nql_submeniu button')[0], 'click', this.changeType.bindAsEventListener(null, 'fz'));
        Event.observe($$('#nql_submeniu button')[1], 'click', this.changeType.bindAsEventListener(null, 'ql'));
        Event.observe($$('#nql_submeniu button')[2], 'click', this.changeType.bindAsEventListener(null, 'playlist'));
    },
    bindInfoTools: function() {
        var cur_index = NQL.getCurPlayIndex();
        if (!cur_index) {
            $('nql_prev').onmouseover = $('nql_prev').onmouseout = function() {};
        } else {
            $$('#nql_i_prev .nql_text')[0].update('Anterior: ' + NQL.items[cur_index - 1].title);
        }
        if (NQL.items.length == 0 || cur_index == (NQL.items.length - 1)) {
            $('nql_next').onmouseover = $('nql_next').onmouseout = function() {};
        } else {
            $$('#nql_i_next .nql_text')[0].update('Urmeaza: ' + NQL.items[cur_index + 1].title);
        }
    },
    getCurrPlayItem: function() {
        return window.contentId;
    },
    isExpanded: function() {
        return $('NQLmain').hasClassName('nql_minimize') == false;
    },
    getItemsIds: function() {
        var ids = [];
        NQL.items.each(function(itm) {ids.push(itm.id);});
        return ids;
    },
    addOneItem: function(id) {
        if (NQL.listFetched) {
            NQL.fetchOneItem(id);
            return;
        } else {
            var itm = NQL.getCookieSettings()['items'];
            if (itm == undefined) {
                itm = id;
            } else {
                itm.push(id);
            }
        }
    },
    deleteOneItem: function(id) {
        var idx = NQL.getItemsIds().indexOf(id);
        if (idx === -1) return;
        NQL.items.splice(idx, 1);
        $$('#nql_lista_filme ul')[idx].remove();
    },
    fetchOneItem: function(id) {
        if (NQL.getItemsIds().indexOf(id) != -1) return;

        sn_getAjax('get_item_4mix', {c: id});
        if (window.sn_getItem4mixHandler === undefined) {
            window.sn_getItem4mixHandler = function(result, resultElementName, userData) {
                var els, items;
                if (result.code != 0) return;
                el = result.text.evalJSON();
                items = NQL.items;
                items.push(el);
                NQL.populateList(items);
            }
        }
    },
    fetchList: function(prm) {
        var params = {type: NQL.type, c: NQL.getCurrPlayItem()};
        if (NQL.type == 'playlist') {
            params['playlist'] = NQL.customData.playlist_id;
        }
        if (NQL.type == 'fz' && document.location.href.toQueryParams()['play_from'] == null) {
            params['force_new'] = 1;
        }
        sn_getAjax('get_mixlist', params, null, prm);

        if (window.sn_getMixlistHandler === undefined) {
            window.sn_getMixlistHandler = function(result, resultElementName, userData) {
                var els, index, ids = [];
                if(result.code == 0) {
                    NQL.populateList(result.text.evalJSON());
                    if (typeof userData.callbackFn == 'function') userData.callbackFn.call(null);
                    NQL.setCookieSettings('type', NQL.type);
                    NQL.positionPlayingItem();
                } else {
                    //new MessageBox(result.text);
                }
            }
        }
    },
    populateList: function(els) {
        NQL.listFetched = true;
        NQL.items = [];
        var index = 0, items = [], ids = [], cont = $$('#nql_lista_filme ul')[0];
        if (! NQL.disablePopulate) cont.update('');
        els.each(function(el) {
            index++;
            if (!NQL.disablePopulate) cont.insert({bottom: new Element('li').update(
            '<a title="' + el.title + '" class="nql_film' + (el.id == NQL.getCurrPlayItem() ? ' nql_activ' : '') + '" href="' + NQL.prepareLink(el.link) + '"><img src="' + el.tb100 + '">' +
			'<span class="nql_durata">' + (el.duration ? el.duration : '') + '</span><button class="nql_play">&nbsp;</button>' +
			'<span class="nql_titlu">' + el.title + '</span>' +
			(NQL.type == 'ql' ? '<button class="nql_inchide" onclick="quicklist.del(\'' + el.id + '\');return false">&nbsp;</button>' : '') + '</a>'
            )});

            items.push(el);
            ids.push(el.id);
        });
        NQL.items = items;
        NQL.positionPlayingItem();
    },
    setPopulateListOnToggle: function(els) {
        if (!(els.length > 0)) return false;
        NQL.listFetched = true;
        NQL.items = els;
        NQL.populateOnToggle = true;
    },
    setPlayNext: function(set) {
        var prev = false;
        if (set) {
            NQL.playNextLink = set;
            if (NQL.aplay) {
                player220Control.nextLink = NQL.playNextLink;
            }
            return;
        }

        if (NQL.items.length > 0) {
            for (var i = 0; i < NQL.items.length; i++) {
                if (prev.id == NQL.getCurrPlayItem()) {
                    NQL.playNextLink = NQL.prepareLink(NQL.items[i].link);
                    break;
                }
                prev = NQL.items[i];
            }
        } else {
            $$('#nql_lista_filme a.nql_film').each(function(a) {
                if (prev && prev.id === NQL.getCurrPlayItem()) {
                    NQL.playNextLink = NQL.prepareLink(prev.link);
                    return;
                }
                prev = {id: NQL.getIdFromLink(a.href), link: a.href};
            });
            if (! NQL.playNextLink && prev.link) NQL.playNextLink = NQL.prepareLink(prev.link);
        }
        if (NQL.aplay) {
            player220Control.nextLink = NQL.playNextLink;
        }
    },
    toggleBox: function(e, hide) {
        if (!NQL.enabled) return;
        try {Event.stop(e)} catch(e) {}

        if(! NQL.listFetched) {
            NQL.fetchList();
        }
        var next_state = $('nql_lista_filme').visible();
        if (hide == undefined) {
            hide = next_state;
        }
        if (hide) {
            Effect.SlideUp('nql_lista_filme', {duration: 0.1});
            $('nql_min').addClassName('nql_minimize');
            $$('#nql_i_toggle .nql_text')[0].update('Afiseaza lista filme');
        } else {
            if (NQL.populateOnToggle) {
                NQL.populateOnToggle = false;
                NQL.populateList(NQL.items);
            }
            Effect.SlideDown('nql_lista_filme', {duration: 0.1});
            $('nql_min').removeClassName('nql_minimize');
            $$('#nql_i_toggle .nql_text')[0].update('Ascunde lista filme');
        }
        NQL.min = hide ? 1 : 0;
        if (NQL.getCookieSettings().min != NQL.min) {
            NQL.setCookieSettings('min', NQL.min ? 1 : 0);
        }
        NQL.positionPlayingItem();
        //$('newQL').toggleClassName('nql_minimize');
    },
    togglePlTypeMenu: function(e, hide) {
        try {Event.stop(e)} catch(e) {}
        if (!NQL.enabled) return;
        if (hide === undefined) {
            hide = $('nql_submeniu').hasClassName('nql_submeniu');
        }
        if (hide) {
            $('nql_submeniu').removeClassName('nql_submeniu');
        } else {
            $('nql_submeniu').addClassName('nql_submeniu');
            setTimeout(function() {NQL.togglePlTypeMenu(undefined, true);}, 2000)
        }
    },
    toggleAplay: function(e, set) {
        try {Event.stop(e);} catch(e){};
        if (!NQL.enabled) return;
        if (set === undefined) {
            set = !NQL.aplay;
        } else {
            set = (set == true);
        }
        player220Control.aplay = NQL.aplay = set;
        if (NQL.aplay) {
            $('nql_autoplay').update('Autoplay (on)').addClassName('on');
            if (NQL.items == undefined || NQL.items.length == 0){
                //if ($('nql_lista_filme').hasClassName('minified')) NQL.disablePopulate = true;
                NQL.fetchList({callbackFn: function() {NQL.setPlayNext();NQL.disablePopulate = false;}});
                return;
                //NQL.fetchList();
            }
            NQL.setPlayNext();
            if (player220Control.finishedPlay) player220Control.PlayNext();
        } else {
            $('nql_autoplay').update('Autoplay (off)').removeClassName('on');
        }
        //if (e && e.button !== undefined) NQL.setCookieSettings('aplay', NQL.aplay ? 1 : 0);
        if (NQL.getCookieSettings().aplay != NQL.aplay) {
            NQL.setCookieSettings('aplay', NQL.aplay ? 1 : 0);
        }
    },
    toggleShuffle: function(e) {
        try {Event.stop(e)} catch(e) {};
        if (!NQL.enabled) return;
        if (NQL.type != 'ql') return;
        if (!NQL.listFetched) {
            NQL.fetchList({callbackFn: function() {NQL.toggleShuffle()}});
            return;
        }
        if(arguments[1] === undefined) {
            if (NQL.shuffleing == 1) return;
            NQL.shuffleing = 1;
            $('nql_shuffle').addClassName('on');
            setTimeout(function() {NQL.toggleShuffle(null, 1)}, 300);
            return;
        }
        var l = NQL.items.length, items = NQL.items, i, sh_items = [],  ids = [];
        if (!(l > 0)) return;
        if (['ql'].indexOf(NQL.type) === -1) return;

        if (NQL.type == 'ql') {
            quicklist.shuffle();
            var ql_tmp = getQLItems().keys();
            var map_ids = {};
            items.each(function(v, i) {map_ids[v.id] = i});
            ql_tmp.each(function(id) {
                sh_items.push(items[map_ids[id]]);
            });
        }
        NQL.populateList(sh_items);
        $('nql_shuffle').removeClassName('on');
        NQL.shuffleing = false;
        //NQL.setCookieSettings('items', ids);
        NQL.positionPlayingItem();
        NQL.setPlayNext();
    },
    changeType: function(e, type) {
        try {Event.stop(e)} catch(e) {}
        NQL.togglePlTypeMenu();
        if (type == NQL.type) return;

        if (type == 'ql' && !(getQLItems().keys().length > 0)
        ) {
            new MessageBox('Nu exista iteme in aceasta lista!!');
            return;
        }

        NQL.type = type;
        NQL.listFetched = false;
        NQL.items = [];
        NQL.play(0);
    },
    prepareLink: function(link) {
        //if (!link) return '';
        if (/[\W]play_from\=/.test(link)) return link;
        link = link + (link.indexOf('?') == -1 ? '?' : '&') + 'play_from=' + NQL.type;
        if (NQL.type == 'playlist') {
            link = link + '&playlist_id=' + NQL.customData.playlist_id;
        }
        return link;
    },
    positionPlayingItem: function() {
        var h = 0, finished = false, delta = 0;
        $$('#nql_lista_filme UL A').each(function(el) {
            if (finished || el.hasClassName('nql_activ')) {
                finished = true;
                return;
            }
            h += 120;
            //h += el.getWidth();
        });
        if (finished) $('nql_lista_filme').scrollLeft = h + 0;
    }
};
//document.observe('dom:loaded', function() {NQL.init();});

(function(){
    return;
    if (!Prototype.Browser.IE) return;
    //if (Cookies.read('HeadNotifie6alert') == '1') return;
    var mVer = /.*MSIE ([0-9]{1,}[\.0-9]{0,}).*/.exec(navigator.userAgent)[1];
    mVer = parseFloat(mVer);
    if (mVer >= 7) return;
    new HeadNotif('ie6alert', 'Browserul tau e preistoric, navigheaza cu unul mai acatarii: <a href="http://www.opera.com/browser/" target="_blank">Opera</a>, <a href="http://www.google.com/chrome/" target="_blank">Google Chrome</a>, <a href="http://www.mozilla.com/" target="_blank">Firefox</a>, <a href="http://www.apple.com/safari/" target="_blank">Safari</a> ... ori fa-ti upgrade: <a href="http://www.microsoft.com/windows/internet-explorer/default.aspx" target="_blank">Internet Explorer</a>!');
})();

var FbConnect = {
    init: function(callback) {
        if (FbConnect.inited) return false;
        if (!window.FACEBOOK_APPID) return false;
        if (window.FB && window.FB.init) {
            clearInterval(FbConnect.intLoad);
            FB.init({appId: window.FACEBOOK_APPID, status: true, cookie: true, xfbml: false});
            FbConnect.inited = true;
            if (typeof callback == 'function') {
                callback.call();
            }
        } else if(!$('fb-root')) {
            var newEl = new Element('script', {'src': 'http://connect.facebook.net/en_US/all.js', type: 'text/javascript', async: 'async'});
            document.getElementsByTagName('head')[0].appendChild(newEl);
            newEl = new Element('div', {'id': 'fb-root'});
            document.body.appendChild(newEl);
            if (!FbConnect.intLoad) FbConnect.intLoad = setInterval(function(){FbConnect.init(callback);}, 100);
        }
    },
    loginFB: function() {
        if (!FbConnect.inited) {
            FbConnect.init(FbConnect.loginFB);
            return;
        }
        FB.login(function(response) {
            if (response.session) {
                if (response.perms) {
                    FbConnect.login();
                } else {
                    new MessageBox('err_notif', 'Conectare esuata prin Facebook', 'Pentru a va loga este necesar sa dati drepturi de acces pe facebook pentru site-ul 220.ro');
                    // user is logged in, but did not grant any permissions
                }
            } else {
                //new MessageBox('err_notif', 'Conectare prin Facebook', 'Nu te-ai logat');
                //user is not logged in
            }
        }, {perms: 'user_about_me,user_birthday,email'}
        );
    },
    login: function() {
        if (!FbConnect.inited) {
            FbConnect.init(FbConnect.login);
            return;
        }
        sn_getAjax('login_facebook', {});
        if (window.sn_loginFacebookHandler == undefined) {
            window.sn_loginFacebookHandler = function(result, resultElementName, userData) {
                if (result.code == 7) {
                    FbConnect.registerBox();
                } else if (result.code == 0) {
                    window.location.href = SITE_BASE;
                } else {
                    new MessageBox(result.text);
                }
            }
        }
    },
    register: function() {
        if (!FbConnect.inited) {
            FbConnect.init(FbConnect.register);
            return;
        }
        var box_err = $$('#fb_registebox .facebook_error')[0];
        if (!$('frm_fb_register')) return false;
        if (!$('fb_register_terms').checked) {
            box_err.update('Trebuie sa fii de acord cu termenii si conditiile pentru a putea continua').show();
            return false;
        }
        box_err.hide();

        params = $('frm_fb_register').serialize(true);

        sn_getAjax('register_facebook', params);

        if (window.sn_registerFacebookHandler == undefined) {
            window.sn_registerFacebookHandler = function(result, resultElementName, userData) {
                if(result.code == 0) {
                    window.location.href = SITE_BASE;
                } else {
                    box_err.update(result.text).show();
                }
            }
        }
    },
    registerBox: function() {
        if (!FbConnect.inited) {
            FbConnect.init(FbConnect.registerBox);
            return;
        }
        var tpl = '<form id="frm_fb_register"><br>' +
        '<div class="check_div"><input type="checkbox" class="check_btnx" id="fb_register_nl" name="newsletter" value="1" checked="checked"/><label for="fb_register_nl">Dresc sa ma abonez la newsletter zilnic</label></div>' +
        '<div class="check_div"><input type="checkbox" class="check_btnx" id="fb_register_terms" name="terms" value="1" checked="checked"/><label for="fb_register_terms">Am citit si sunt de acord cu </label><a class="facebook" href="' + SITE_BASE + 'index.php?module=rules" target="_blank" title="termenii si conditiile 220.ro">termenii si conditiile</a></div>' +
        '<p class="facebook_error" style="display: none"></p>' +
        '</form>';
        new MessageBox('fb_registebox', 'Te-ai autentificat folosind Facebook', tpl, {ok: {0: 'Inregistrare', 1: FbConnect.register, dontClose: 1}, cancel: ['Cancel', function(){}]});
    }
};
//FbConnect.init();
if($('quicklogin_fb')) $('quicklogin_fb').onmouseover = FbConnect.init;

// colorpicker2
var CPicker2 = {
    reg: [],
    init: function(callback) {
        if (CPicker2.inited) return false;
        if (window.Control && Control.ColorPicker) {
            clearInterval(CPicker2.intLoad);
            CPicker2.inited = true;
            if (typeof callback == 'function') {
                callback.call();
            }
        } else if(!window.Control || !Control.ColorPicker) {
            var css = ['css/colorPicker.css'];
            var jss = ['js/yahoo.color.js', 'js/colorPicker.js'];
            var x, hd = document.getElementsByTagName('head')[0];
            $A(css).each(function(i) {
                x = document.createElement('link');
                x.rel = 'stylesheet';
                x.type = 'text/css';
                x.href = WEB_BASE + i;
                hd.appendChild(x);
            });
            $A(jss).each(function(i) {
                x = document.createElement('script');
                x.src = WEB_BASE + i;
                hd.appendChild(x);
            });
            if (!CPicker2.intLoad) CPicker2.intLoad = setInterval(function(){CPicker2.init(callback);}, 100);
        }
    },
    instance: function(id, options) {
        if (!CPicker2.inited) {
            CPicker2.init(function() {CPicker2.instance(id, options);});
            return;
        }
        if (this.reg[id]) {
            return this.reg[id];
        }
        options = options || {};
        options.IMAGE_BASE = WEB_BASE + 'img/colorpicker2/';
        new Control.ColorPicker(id, options);
        return this.reg[id] = Control.colorPickers[Control.colorPickers.length - 1];
    }
}

var toggle_get_embed = function(open) {

    if (!window.elementCache.exists('get_embed_maker')) {
        sn_updateByAjax('get_embed_maker', {}, 'video_options_container', {
            onComplete: function(t) {
                window.elementCache.save('get_embed_maker', $('video_options_container'));
                window.elementCache.addPostSaveDeploy(function() {CPicker2.instance('emb_picker').close()});
                toggle_get_embed(true);
            }
        });
        return;
    } else if (!$('embed_opt') && window.elementCache.exists('get_embed_maker')) {
        window.elementCache.deploy('get_embed_maker', $('video_options_container'));
        CPicker2.instance('emb_picker').open();
        return;
    }
    CPicker2.inited || CPicker2.init(function() {
        CPicker2.instance('emb_picker',
        {
            getPopUpPosition: function() {
                var p = $('embed_opt').positionedOffset();
                return [p[0] + 10, p[1] + 220];
            },
            onUpdate: function(v) {
                EmbedCode.set('color', v);
            }
        }).open();
    });
    if (open || !$('embed_opt').visible()) {
        $('embed_opt').show();
        !CPicker2.inited || CPicker2.instance('emb_picker').open();
        EmbedCode.make();
    } else {
        $('embed_opt').hide();
        CPicker2.instance('emb_picker').close();
    }
};

EmbedCode = {
    opt: {width: '450'},
    asp_ratio:  3/4,
    bar:  28,
    setWidth: function(width, v) {

        this.opt.width = width;
        if  (!(width >= 300 && width <= 450)) {
            this.opt.width = 450;
            v = 'mare';
        }
        if (window.content.ctype != 2) {
            this.opt.height =  Math.round((this.opt.width * this.asp_ratio) + this.bar);
        } else {
            this.opt.height = 106;
        }
        if (v) {
            $('embed_opt').custom_width.value = this.opt.width;
            $('embed_opt').custom_height.value = this.opt.height;
        }
        $A(['mic', 'mediu', 'mare', 'custom']).each(function(d) {
            $('dim_' + d).removeClassName('activ');
        });
        $('dim_' + v).addClassName('activ');
        this.make();
    },
    set: function(option, v) {
        this.opt[option] = v;
        if (option == 'color' && $('masca_player')) $('masca_player').setStyle({'backgroundColor' : '#' + v});
        this.make();
    },
    make: function(e) {
        var c = window.content;
        //sizes = [[], [320,240], [450,370], [250,130]];
        //sizes = [450, 400, 300];

        var aplay = this.opt.aplay ? '&aplay=true'  : '';
        var color_player = this.opt.color ? '&rgb=' + this.opt.color : '';
        var from = (window.lUser) ? '&from=' + lUser.nameb64 : '';

        if (c.ctype != 2) {
            this.opt.height =  Math.round((this.opt.width * this.asp_ratio) + this.bar);
        } else {
            this.opt.height = 106;
        }

        sz = [this.opt.width, this.opt.height];

        s = '<embed width="' + sz[0] + '" height="' + sz[1] + '" src="' + SITE_BASE + 'emb/' + c.id + color_player + aplay + from + '" ';
        s += 'allowfullscreen="true" allowscriptaccess="always" ';
        s += 'type="application/x-shockwave-flash" ';
        s += '></embed><br><small>Vezi mai multe din <a href="' + c.category + '" target="_blank">' + c.category + '</a> pe <a href="http://www.220.ro" target="_blank">220.ro</a></small>';
        script = '<script type="text/javascript" src="' + SITE_BASE + 'embjs?id=' +  c.id + '&width=' + sz[0] + '&height=' + sz[1] + color_player + aplay + from + '"></script>' +
        '<noscript>Vezi <a href="' +  c.link + '" target="_blank">' + c.title + '</a> pe <a href="http://www.220.ro" target="_blank">220.ro</a></noscript>';
        $('embed_opt').player_embed.value = s;
        $('embed_opt').player_embed2.value = script;
        return true;
    }
}

var gUtilities = {
    isValidUrl: function(url) {
        return /\/(https?\:\/\/)?(www\.)?google\.[^\/]{2,6}(\/.*)/.test(url);
    },
    getSearchTerm: function(url) {
        if (!url) return '';
        if (!this.isValidUrl(url)) return '';
        return /.+[\?&]q\=([^&]{1,}).*/.exec(url)[1] || '';
    }
}

var roDateUtils = {
    months: ['Ianuarie', 'Februarie', 'Martie', 'Aprilie', 'Mai', 'Iunie', 'Iulie', 'August', 'Septembrie', 'Octombrie', 'Noiembrie', 'Decembrie'],
    weekDays: ['Luni', 'Marti', 'Miercuri', 'Joi', 'Vineri', 'Sambata', 'Duminica']
};

(function(){
    /*
    if (isLogged && !Cookies.read('HeadNotifupdPData')) {
        new HeadNotif('updPData', '<a href="javascript:void(0)" onclick="onDemandJsLoader(\'' + WEB_BASE + 'js/rare_r' + JS_SERIAL + '.js\', function() {addUpdateUserDataBox()})">Actualizeaza-ti datele personale si ai sansa sa castigi saptamal un cadou surpiza oferit de BitDefender!</a>');
    } else
    */
    if ((Math.random() * 1000) > 500) {
	//new HeadNotif('votca_camp', '<a href="http://www.220.ro/concursuri/vreau-o-tara-ca-afara/"><img src="http://static.220.ro/_templates/_default/img/notificari/votca_header.png"></a', 'background-color: #000!important;padding: 0');
    } else {
	//new HeadNotif('farsa_vacan', '<a href="http://www.220.ro/concursuri/farsa-pentru-vacanta/"><img src="http://static.220.ro/_templates/_default/img/notificari/farsa_header.jpg"></a', 'background-color: #1b3c5e!important;padding: 0');
    }
})();

document.observe("dom:loaded", function() {
    if (window.isLogged) return false;
    var func_login = function() {if (this.href) this.href = 'javascript:void(0)'; LoginPop.show()};
    if (window.contentId) {//content detail
        toggleStar =
        $('optiune_3').onclick =
        $('optiune_4').onclick =
        $('optiune_5').onclick =
        $('optiune_6').onclick =
        $$('#starsLog a')[0].onclick =
        $('add_comment_f_content_tarea_main').onclick =
        $('posteaza_comentariu').onfocus =
        $('posteaza_comentariu').onclick =
        $$('#is_not_subscribed a')[0].onclick =
        $$('#is_friend a')[0].onclick =
        $$('a[title="Trimite mesaj"]')[0].onclick =
        func_login;
    } else if (window.userId) {//user detail
        $$('a.replay').each(function(i) {i.onclick = func_login;});
        $$('.user_det_menu a')[0].onclick =
        $$('.user_det_menu a')[1].onclick =
        $$('.user_det_menu a')[2].onclick =
        $$('.user_det_menu a')[3].onclick =
        $$('.user_det_menu a')[4].onclick =
        $$('.user_det_menu a')[5].onclick =
        $$('#poz_7 a.replay')[0].onclick =
        $('add_comment_f_content_tarea').onclick =
        func_login;
    }
});

(function(){
    if (true || Cookies.read('qlUseNot')) return;
    var str = '<div class="ql_tt_wrapper">' +
    '<span class="ql_tt_img">&nbsp;</span><span class="ql_tt_continut">' +
    '<span class="ql_tt_titlu">Bifezi si te uiti mai tarziu!</span>' +
    'Ai vazut un filmulet interesant si nu ai timp sa te uiti la el? Quicklist-ul nostru te ajuta sa pui deoparte ce vrei si sa vezi oricand vrei tu.' +
    '<a href="javascript:void(0)" onclick="$(\'ql_tt_video\').toggle()" title="Vezi demonstratia" class="ql_tt_link" id="ql_tt_functionare">vezi cum functioneaza</a>' +
    '</span>' +
    '<div class="clearAll"></div>' +
    '<span id="ql_tt_video" style="display:none">' +
    '<embed width="300" height="253" src="http://www.220.ro/emb/flccAi4vVp&aplay=true" allowfullscreen="true" allowscriptaccess="always" type="application/x-shockwave-flash"></embed>' +
    '</span></div>' +
    '<div class="ql_tt_bottom">&nbsp;</div>';
    $('lgnql').insert({after: new Element('div', {id: 'ql_tooltip_box', 'class': 'ql_tooltip_box'}).update(str)});
    var a = new Element('a', {id: 'ql_tt_inchide','class':'ql_tt_inchide', 'href':'javascript:void(0)', 'title':'Inchide'}).update('&nbsp;');
    a.onclick = function() {Cookies.create('qlUseNot', 1, 7); $('ql_tooltip_box').remove(); $('ql_tt_inchide').remove();};
    $('ql_tooltip_box').insert({before: a});
})();

onDemandJsLoader = function(url, cback) {
    var idName = 'dl_' + url.replace(/[^A-Za-z0-9_\:\.\-]/g, '');
    if (document.getElementById(idName)) {
        if (cback) cback.call();
        return;
    }
    var nE = document.createElement('script');
    nE.src = url;
    nE.id = idName;
    nE.type = 'text/javascript';
    nE.async = 'async';
    nE.defer = 'defer';
    if (cback != undefined) {
        if (Prototype.Browser.IE) {
            nE.onreadystatechange = function() {
                if (!cback) return;
                if (this.readyState == 'complete' || this.readyState == 'loaded') {
                    cback.call();
                    cback = undefined;
                }
            }
        } else {
            nE.onload = cback;
        }
    }
    document.getElementsByTagName('head')[0].appendChild(nE);
}

if (Cookies.read('addUpdateUserData')) {
    //onDemandJsLoader(WEB_BASE + 'js/rare_r' + JS_SERIAL + '.js', function() {addUpdateUserDataBox()});
};

var Content = {
    addV: function(id) {
    }
}

function popBuyAdPlaceBursa(link) {
    if(!$('buyAdspace')) document.body.appendChild(new Element('div', {id: 'buyAdspace'}));
    onDemandJsLoader('http://leads.bursadereclama.ro/Scripts/LeadCollector.js', function(){
	_gaq.push(['_trackEvent', 'buyAdspace', link]);
	return LeadCollector('buyAdspace', link);
    });
    return false;
}

var strReplacer = {
    init: function(){
        var r = '<a href="http://www.220.ro/fara-publicitate/" title="Te-ai saturat de reclama? Nu mai carcoti, fa ceva!" class="no_ads">tpl</a>';
        this.list = {'reclame': r, 'reclamele': r, 'reclama': r, 'publicitate': r, 'publicitatea': r};
        for (var i in this.list) {
            this.ptr = (i.replace(/([\W])/g, "\\$1")) + "|" + this.ptr;
            this.listPrep[i.replace(/<|>|&/g, function($m) {return strReplacer.sChars[$m]}).toUpperCase()] = this.list[i].replace(/tpl/g, i);
        }
        this.ptr = this.ptr.substr(0, this.ptr.length-1);
        this.ptr = this.ptr.replace(/<|>|&/g, function($m) {return strReplacer.sChars[$m]});
    },
    ptr: '',
    sChars: {"<":"&LT;", ">":"&GT;", "&": "&AMP;"},
    list: null,
    listPrep: {},
    replace: function(selector) {
        var re = new RegExp (this.ptr, "gmi");
        $$(selector).each(function(i) {
            var text = i.innerHTML;
            text = (' ' + text + ' ').replace(re, function ($m) {return strReplacer.listPrep[$m.toUpperCase()]});
            i.update(text.substr(1, text.length - 2));
        });
    }
};

strReplacer.init();
strReplacer.replace('#comments .emoticable');

var topMenu = {
	init: function(){
		$$('#meniu>li').each(function(li){
//		    var menu = $(li).findChildElements('div');
//		    console.log(menu);
		    //$(menu).show();
//			if(menu.length){
//			    Event.observe(menu, 'mouseenter', function(){
//			        console.log('enter');
////			        $(menu).addClassName('activ');
//			    });
//			    Event.observe(menu, 'mouseleave', function(){
//    			    console.log('leave');
////			        $(menu).removeClassName('activ');
//			    });
//			}
		});
	}
};

topMenu.init();

$$('.refresh').each(function(r){
    Event.observe(r, 'click', function(e) {
        setTimeout('location.reload(true);', 2000);
//        console.log(e);
    });
});
var HTML_SWITCHER = {
    replace: function() {
        if (typeof HTMLSW == 'undefined' || !HTMLSW.length) return;
        for (var i = 0, l = HTMLSW.length; i < l; i++ ) {
            var e = HTMLSW[i];
            var o = document.getElementById('hsworig_' + e), h = document.getElementById('hswhold_' + e);
            //o.parentNode.replaceChild(h, o); h.style.display = 'block';
            //o.parentNode.insertBefore(h, o);
            o.innerHTML = h.innerHTML; h.parentNode.removeChild(h);
            //o = e = h = null;
        }
    }
};
var jsLoadAsync = function(url, t) {
    setTimeout(function(){onDemandJsLoader(url)}, t);
};

document.observe("dom:loaded", function() {
    HTML_SWITCHER.replace();
});function getQLItems()
{
    var tmp;
    var ql = new Hash();
    try {
        qlString = Cookies.read('ql');
        if (qlString && qlString.length > 0) {
            qlString.split('|').without(0, '').compact().each(function(s){
                if(/.+:.+/.test(s)) {
                    tmp = /(.+)\:(\d+)/.exec(s);
                    ql.set(tmp[1], tmp[2]);
                }
            });
        }

    }
    catch(e) {
    }
    return ql;
}

var quicklist = {
    items : [],

    add : function(content_id, orginator) {
        var ql, ql_index, in_ql, q_param = document.location.href.toQueryParams(), tmp = [], in_qbox;
        ql = getQLItems();

        if (ql.size() >= 30){
            alert('Puteti adauga in Quicklist maxim 30 de materiale!');
            return;
        }
        if(/.+:[\d]+/.test('' + content_id)) {
            tmp = /(.+)\:(\d+)/.exec("" + content_id);
            content_id = tmp[1];
            var ctype = tmp[2];
        }
        if(content_id.indexOf(':') != -1 || content_id.indexOf('|') != -1) return;
        ql_index = ql.keys().indexOf(content_id);
        in_ql = (ql_index != -1);
        in_qbox = (quicklist.items.indexOf(content_id) != -1);

        if (!in_ql){
            ql.set(content_id, ctype);
            Cookies.erase('ql');
            tmp = [];
            ql.each(function(s){tmp.push(s[0] + ':' + s[1]);});
            Cookies.create('ql', tmp.join('|'));

            if (orginator && window.smallNotif) {
                new smallNotif('Adaugat in Quicklist', orginator);
            }

            if (window.NQL && window.NQL.type == 'ql') {
                window.NQL.addOneItem(content_id);
            }
        }
        if (!in_qbox) {
            quicklist.items.push(content_id);
            if ($('rez_quicklist') != null || $('rez_quicklist_2') != null) {
                var fetch_one = 1; //($('quick_container') != null);
                this.statConn = 1;
                params = {
                    content_id: content_id,
                    action: 0,
                    play_from: q_param['play_from'],
                    played_now: q_param['id'],
                    fetch_one: fetch_one};
                    sn_getAjax('adauga_quicklist', params, 'rez_quicklist', {content_id: content_id, fetch_one: fetch_one});
            }
            this.upd_menu(ql.size());
            this.showPromoNotification();
        }
    },

    clearplaylist : function() {
        Cookies.erase('ql');
        this.upd_menu(0);
        //this.items = [];
    },

    del : function(content_id) {

        var ql, ql_index, in_ql, q_param = document.location.href.toQueryParams(), tmp = [];
        ql = getQLItems();
        if(/.+:.+/.test('' + content_id)) {
            var tmp = /(.+)\:(\d+)/.exec("" + content_id);
            content_id = tmp[1];
            var ctype = tmp[2];
        }

        if (window.NQL && window.NQL.type == 'ql') {
            window.NQL.deleteOneItem(content_id);
        }

        ql_index = ql.keys().indexOf(content_id);
        in_ql = (ql_index != -1);

        if (in_ql) {//del
            ql.unset(content_id);
            Cookies.erase('ql');
            ql.each(function(s){tmp[tmp.length] = s[0] + ':' + s[1];})
            Cookies.create('ql', tmp.join('|'));

            this.upd_menu(ql.size());
            this.upd_at_del(content_id);
        }
    },

    upd_menu : function(count) {
        if ($('lgnql')) $('lgnql').update('Quicklist (' + count +')');
    },
    upd_at_del: function(content_id) {

        this.items[this.items.indexOf(content_id)] = null;
        this.items = this.items.compact().without('');
        if($('bql' + content_id) != null) $('bql' + content_id).remove();
        if(!this.items || this.items.length == 0) {
            if($('rez_quicklist')) $('rez_quicklist').hide();
            if($('rez_quicklist_2')) $('rez_quicklist_2').hide();
        }

        var j = 0, cls, q_param = document.location.href.toQueryParams();
        $$('.quick_container > DIV[id]').each(function(dv){
            if (q_param.play_from == 'ql' && ('bql' + q_param.id == dv.id)) { cls = 'quick_list_sel';}
            else if (j % 2 == 0) {cls = 'quick_grey';}
            else {cls = 'quick_white';}
            dv.removeClassName('quick_list_sel').removeClassName('quick_white').removeClassName('quick_grey').addClassName(cls);
        });
    },

    sync: function(){

        if(typeof this.sync.started == 'undefined') {
            this.sync.started = true;
            setInterval('quicklist.sync()', 1000);
        }
        if (this.statConn == 1) return;

        var tmp = getQLItems(), to_add;
        var ql = tmp.keys(), ql_ctype = tmp.values(), items_list = [];
        if (ql.size() >= 30) return;
        if (this.items != null){
            this.items.each(function(o){
                if(ql.indexOf(o) == -1) quicklist.upd_at_del(o);
                else items_list.push(o);
            });
        }

        ql.each(function(id,k){
            to_add = (items_list.indexOf(id) == -1);
            if(to_add) {
                quicklist.add(id + ':' + ql_ctype[k]);
            }
        });

    },

    shuffle: function() {
        var tmp = getQLItems();
        var ql_tmp = tmp.keys(), ctype_tmp = tmp.values(), items_list = [];
        while (ql_tmp.length > 0) {
            i = Math.floor(Math.random() * 1000000) % ql_tmp.length;
            items_list.push(ql_tmp[i] + ':' + ctype_tmp[i]);
            ql_tmp.splice(i, 1);
            ctype_tmp.splice(i, 1);
        }
        quicklist.clearplaylist();
        items_list.each(function(i){
            quicklist.add(i);
        });
    },

    statConn: 0,

    init: function(){
        this.items = getQLItems().keys() ;
        //quicklist.sync();
    },
    getNumItems: function() {
        return getQLItems().size();
    },
    showPromoNotification: function() {
        if (!$('ql_tt_add')) {
            var str =
            '<div class="ql_tt_wrapper">' +
            '<div><a href="javascript:void(0)" onclick="$(\'ql_tt_add\').toggle()" class="ql_tt_inchide" title="Inchide">inchide</a></div>'+
            '<span class="ql_tt_img">&nbsp;</span>' +
            '<span class="ql_tt_continut">' +
            '<span class="ql_tt_titlu">Ai reusit!</span>' +
            'Ai <b id="ql_promo_not_count"></b>&nbsp;filmulete in Quicklist-ul tau! Uita-te la ele oricand vrei!' +
            '<a href="' + SITE_BASE + 'quicklist" title="Vezi quicklist" class="ql_tt_link">vezi quicklist</a>' +
            '</span>' +
            '<div class="clearAll"></div>' +
            '</div>' +
            '<div class="ql_tt_bottom">&nbsp;</div>';
            $('header').insert({after: new Element('div', {id: 'ql_tt_add', 'class': 'ql_added'}).update(str)});
        }
        $('ql_promo_not_count').update(quicklist.getNumItems());
        clearTimeout(this.timeOutNotif);
        this.timeOutNotif = setTimeout(function() {Effect.Fade('ql_tt_add', {duration: 0.5})}, 2200);
        $('ql_tt_add').show();
    }
}
quicklist.init();

function sn_adaugaQuicklistHandler(result, resultElementName, userData) {
    if (result.code == 1) {
        quicklist.del(userData['content_id']);
        return;
    }
    var result = result.text.evalJSON();
    if ($('rez_quicklist') != null || $('rez_quicklist_2') != null) {
        if(quicklist.items.indexOf(userData['content_id']) == -1) {
            if(userData['fetch_one']) {
                if (quicklist.items == null || quicklist.items.length % 2 == 0) {cls = 'quick_grey';}
                else {cls = 'quick_white';}
                $('quick_container').insert({bottom :new Element('div', {'class': 'quick_det ' + cls, 'id': 'bql' + userData['content_id']}).update(result.txt)});
            } else {
                $('rez_quicklist').update(result.txt);
                $('rez_quicklist_2').update(result.txt);
            }
            quicklist.items.push(userData['content_id']);
            quicklist.statConn = 0;
            $('rez_quicklist').show();
        }
    }
    if ($('rez_quicklist_2') != null) {
        $('ql' + result.c_id).remove();
        $('rez_quicklist_2').show();
    }
    if($('add_to_playlist_form1') != undefined) Event.observe('add_to_playlist_form1', 'submit', add_to_playlist)
}


// [+] Music Payer -----------------------------------------------------------------------------------------
function MPlayer(inp)
{
    this.urlPlayer = (typeof (inp.urlPlayer) != 'undefined') ? inp.urlPlayer : SITE_BASE + 'index.php?popup=true&play=ql&module=quicklist';
    this.idWin = (typeof (inp.idWin) != 'undefined') ? inp.idWin : 'musicPlayerWin';
    this.opt_del = (typeof (inp.opt_del) != 'undefined') ? inp.opt_del : 1;
    this.playerId = inp.playerId;
    this.qlSynced = false;
    if (window.mpQlSyncQueue == undefined) window.mpQlSyncQueue = [];
    window.mpQlSyncQueue[this.playerId] = [];
    this.popup_mode = (typeof (inp.popup_mode) != 'undefined' && inp.popup_mode == true) ? true : false;
    this.items = null;
    this.ajax_req = inp.ajax_req;
    this.add = function(id) {
        if (this.has_child_pp() && this.popup_mode) {
            this[this.idWin].pp_PLMusic.add(id);
        }
        else {
            params = {content_id: id, action: 1};
            sn_getAjax(this.ajax_req, params, null, {instance:this, op: 'add', content_id: id});
        }
    };
    this.del = function(id) {
        if (this.opt_del) {
            var to_del = null;
            quicklist.del(id);
            if (this.popup_mode) {
                this[this.idWin].pp_PLMusic.items.each(function(s,k){if (s['id'] == id) {to_del = k;}});
                this[this.idWin].pp_PLMusic.items[to_del] = null;
                this[this.idWin].pp_PLMusic.items = this[this.idWin].pp_PLMusic.items.without(0, '').compact();
                this[this.idWin].document[this[this.idWin].pp_PLMusic.playerId].del(id);
            }
            else {
                this.items.each(function(s,k){if (s['id'] == id) {to_del = k;}});
                this.items[to_del] = null;
                this.items =  this.items.without(0, '').compact();
                document[this.playerId].del(id);
            }
        }
    };
    this.getList = function() {
        if(typeof (inp.getListParams) != 'undefined') {
            params = new Hash({action: 2});
            params = params.merge(inp.getListParams)
        }
        else {
            params = {action: 2};
        }
        sn_getAjax(this.ajax_req, params, null, {instance:this, op: 'get_list'});
    };
    this.save = function(list_name) {
        params = {list_name: list_name, action: 3};
        sn_getAjax(this.ajax_req, params, null, {instance:this});
    };
    this.init = function() {
        this.getList();
    };
    this.openPlayerWin = function() {
        if (!this.has_child_pp()) {
            this[this.idWin] = window.open(this.urlPlayer, this.idWin, 'height=500, width=500, resizable=0, scrollbars=1', 1);
        }
        if (this[this.idWin]) this[this.idWin].focus();
        else delete this[this.idWin];
    };
    this.reloadPL = function(self) {
        if (typeof(self) == 'undefined') self = this;
        if (self.popup_mode) {
            self[self.idWin].document[self[self.idWin].pp_PLMusic.playerId].reloadIt(self[self.idWin].pp_PLMusic.items);
            self[self.idWin].focus();
        }
        else {
            document[self.playerId].reloadIt(self.items);
        }
    };
    this.show = function() {
        if (typeof(this.targetContainer) == 'undefined') return;
        var ret = '';
    };
    this.has_child_pp = function() {
        return (typeof this[this.idWin] != 'undefined' && !this[this.idWin].closed);
    };
    this.getItems = function() {
        var ql_pp;
        try {
            ql_pp = Cookies.read('ql_pp').split('|');
        }
        catch(e) {
            ql_pp = new Array();
        }
        ql_pp = ql_pp.without(0, '').compact();
        return ql_pp;
    };
    this.setId = function() {
        if (typeof(this.id) == 'undefined' || !this.id) {
            this.id = ((new Date()).getTime() + '' + Math.floor(Math.random() *1000000));
        }
    };
    this.flashLoaded = function(){
        var t;
        if (this.popup_mode) {
            t = typeof(this[this.idWin].document[this[this.idWin].pp_PLMusic.playerId].reloadIt);
        }
        else {
            t = typeof(document[this.playerId].reloadIt);
        }
        return (t == 'function');
    };
    this.sync2QL = function(self){
        var tmp = getQLItems();
        var ql = tmp.keys(), ql_ctype = tmp.values(), items_list = [];
        if (self.items != null){
            self.items.each(function(o){
                if(o && ql.indexOf(o['id']) == -1) self.del(o['id']);
                else items_list.push(o['id']);
            });
        }
        ql.each(function(id,k){
            if(ql_ctype[k] == 2) {
                var to_add = (items_list.indexOf(id) == -1 && window.mpQlSyncQueue[self.playerId][id] !== 1);
                if(to_add) {
                    window.mpQlSyncQueue[self.playerId][id] = 1;
                    self.add(id);
                }
            }
        });
    };

    this.setSync2QL = function(mlsec, add_handler){
        this.qlSynced = true;
        var self = this;
        if (typeof (add_handler) != 'function') add_handler = function(){};
        setInterval(function(){
            self.sync2QL(self);
            add_handler(self);
        }, mlsec);
    }

    window['sn_' + this.ajax_req.dasherize().camelize()+ 'Handler'] = function (result, resultElementName, userData)
    {
        var inst = userData.instance;
        if (inst.qlSynced && result.code == 1 && userData.op == 'add') {
            quicklist.del(userData.content_id);
        }
        if (result.code == 0) {
            switch(userData.op) {
                case 'add':
                itm = result.text.evalJSON();
                var itm_added = false;
                if (inst.popup_mode) {
                    if(inst[inst.idWin].pp_PLMusic.items != null)  inst[inst.idWin].pp_PLMusic.items.each(function(one_item){if(one_item['id'] == itm['id']) itm_added = true;});
                    delete window.mpQlSyncQueue[inst.playerId][itm['id']];
                    if (itm_added) return;
                    inst[inst.idWin].pp_PLMusic.items.push(itm);
                    inst[inst.idWin].document[inst[inst.idWin].pp_PLMusic.playerId].reloadIt([itm], 'add');
                }
                else {

                    if(inst.items != null) inst.items.each(function(one_item){if(one_item['id'] == itm['id']) itm_added = true;});
                    delete window.mpQlSyncQueue[inst.playerId][itm['id']];
                    if (itm_added) return;
                    if (inst.items == null) {
                        inst.items = [itm];
                    }
                    else {
                        inst.items.push(itm);
                    }
                    document[inst.playerId].reloadIt([itm], 'add');
                }
                break;
                case 'get_list':
                result = result.text.evalJSON().length > 0 ? result.text.evalJSON() : null;
                if (inst.popup_mode) {
                    inst[inst.idWin].pp_PLMusic.items = result;
                }
                else {
                    inst.items = result;
                }
                inst.reloadPL();
                break;
                case 'del':
                break;
            }
        }
    }
};
// [-] Music Payer -----------------------------------------------------------------------------------------

document.observe('dom:loaded', function(event) {
    $$('.quicklist1, .quicklist_dm').each(function(element) {
        Event.observe(element, 'click', function(event) {
            id = element.id.substr(2, element.id.length);
            quicklist.add(id, event);
            try {element.parentNode.removeChild(element)}catch(e) {}
        });
    });
});
/************************* AJAX WRAPPER MECHANISM *****************************/
function sn_getAjax(formName, customParams, resultElementName, userData) {
		params = new Hash({
        f: formName,
        ajax: 1
    });
    params = params.merge(customParams);
    new Ajax.Request(SITE_BASE  + 'index.php',
    {
        method: 'POST',
        parameters: params,
        onSuccess: function (transport) {
            result = transport.responseText;

            if(result.length > 0) {
                result = result.evalJSON(true);
            } else {
                result = '';
            }

            sn_gotAjax(formName, result, resultElementName, userData);

        },
        onComplete: function(transport) {
            sn_completedAjax(formName, resultElementName, userData);

        },
        onFailure: function(transport) {
            sn_failedAjax(formName, resultElementName, userData);

        }
    });
}

function sn_updateByAjax(formName, customParams, resultElementName, updaterParams) {
    params = new Hash({
        f: formName,
        ajax: 1
    });

    params = params.merge(customParams);

    options = new Hash(
    {
        method: 'POST',
        parameters: params
    });

    options = options.merge(updaterParams).toObject();
    new Ajax.Updater(resultElementName, SITE_BASE + 'index.php', options);
}

function sn_getAjaxByQuery(formName, query, resultElementName, userData) {
    params = new Hash({
        f: formName,
        ajax: 1
    });

    params = params.toQueryString() + '&' + query;

    new Ajax.Request(SITE_BASE + 'index.php',
    {
        method: 'POST',
        parameters: params,
        onSuccess: function (transport) {
            result = transport.responseText;
            if(result.length > 0) {
                result = result.evalJSON(true);
            } else {
                result = '';
            }
            sn_gotAjax(formName, result, resultElementName, userData);
        },
        onFailure: function(transport) {
            sn_failedAjax(formName, resultElementName, userData);
        }
    });
}

function sn_gotAjax(formName, result, resultElementName, userData) {
	funcName = "sn_" + formName.dasherize().camelize() + "Handler";
    if(typeof window[funcName] == 'function') window[funcName](result, resultElementName, userData);
}

function sn_failedAjax(formName, resultElementName, userData) {
    funcName = "sn_" + formName.dasherize().camelize() + "ErrorHandler";
    if(typeof window[funcName] == 'function') window[funcName](result, resultElementName, userData);
}

function sn_completedAjax(formName, resultElementName, userData) {
    funcName = "sn_" + formName.dasherize().camelize() + "CompleteHandler";
    if(typeof window[funcName] == 'function') window[funcName](result, resultElementName, userData);
}
/******************************************************************************/



function ax_submit_form( id )
{
    form = document.getElementById( id );
    customParams = { formId : id }
    for ( i=0; i < form.elements.length; i++ )
    {
        elem = form.elements[i];
        if ( elem.type == "checkbox" )
        {
            customParams[ elem.name ] = elem.checked;
        }else if ( elem.type == "select-one" )
        {
            customParams[ elem.name ] = elem.options[ elem.selectedIndex ].value;
        }else{
            customParams[ elem.name ] = elem.value;
        }
    }

    sn_getAjax( "generic_form_handler", customParams, "", {form_id:id} );
}

function sn_genericFormHandlerHandler( result, resultElementName, userData )
{
    if ( result.code == 0 )
    {
        innerRes = result.text.evalJSON(true);
        if ( innerRes.js )
        {
            eval( innerRes.js );
        }
    }else{
        alert( result.text );
    }
}

function load_children( id )
{
    // get value

    elem = document.getElementById( id );
    formId = elem.form.id;
    if ( elem.type == "select-one" )
    {
        value = elem.options[ elem.selectedIndex ].value;
    }else if ( elem.type == "checkbox" )
    {
        value = elem.checked;
    }else{
        value = elem.value;
    }

    customParams = {id:id}
    customParams[ id ] = value;
    customParams[ "formId" ] = formId;
    sn_getAjax( "load_children", customParams, "", customParams );
}

function sn_loadChildrenHandler( result, resultElementName, userData )
{
    if ( result.code == 0 )
    {
        innerRes = result.text.evalJSON(true);
        elem = document.getElementById( innerRes.id );
        elem.options.length = 0;
        if ( innerRes.children )
        {
            children = innerRes.children;
            for ( i=0; i<children.length; i++ )
            {
                o = new Option( children[i].innerHTML, children[i].value );
                elem.options.add(o);
            }
        }
        elem.style.display = "";
    }
}

function voteaza_film(content_id, nota) {
    customParams = {content_id: content_id, nota: nota};
    sn_getAjax('voteaza_film', customParams);
}

function sn_voteazaFilmHandler(result, resultElementName, userData)
{
    if (result.code == 0) {
        // we're ok
        val = result.text.evalJSON(true);
        $('voted').update('').setStyle({width: val.medie + "%"});
        $('nr_voturi').update(val.nr_voturi);
    } else {
        $('raspuns_vot').update(result.text);
    }
}

function s_add_favorite(content_id)
{
    customParams = {content_id: content_id};
    sn_getAjax('s_add_favorite', customParams);
}

function sn_sAddFavoriteHandler(result, resultElementName, userData)
{
    var code = result.code;
    result = result.text.evalJSON();
    $('add_favorites').update(result.text);
    if (code == 0) $('delete_favorites').update('<br/><input type="submit" onclick="javascript:s_delete_favorite(\'' + result.id + '\');" value="Scoate din favorite">');
}

function s_delete_favorite(content_id)
{
    customParams = {content_id: content_id};
    sn_getAjax('s_delete_favorite', customParams);
}

function sn_sDeleteFavoriteHandler(result, resultElementName, userData)
{
    $('add_favorites').update('');
    $('delete_favorites').update(result.text);
}

function add_to_playlist(instance){
    //Event.stop(event);
    my_form = $('add_to_playlist_form_' + instance);
    userData = my_form.serialize(true);
    userData['form_id'] = my_form.id;
    userData['instance'] = instance;
    if(userData['playlist'] == 0) {
        var l = SITE_BASE + 'index.php?module=playlist&action=new&save_from=' + userData['save_from'] + '&content_id=' + userData['content_id'];
        if(window.name.length > 0 && (typeof(window.opener) == 'undefined' || window.opener == null || window.opener.closed)) {
            var nw = window.open(l, '_blank');
            nw.focus();
        }
        else if (typeof(window.opener) != 'undefined' && window.opener != null &&  !window.opener.closed && window.opener.name.length == 0) {
            window.opener.document.location.href = l;
            window.opener.focus();
        }
        else {
             document.location.href = l;
        }
    }
    else {
        customParams=my_form.serialize().parseQuery();
        sn_getAjax('add_to_playlist', customParams, null, userData);
    }
    return;
}

function sn_addToPlaylistHandler(result, resultElementName, userData)
{
    var id_msg = 'add_playlist_msg_' + userData['instance'];
    Effect.Appear(id_msg, { duration: 0.0 });
    $(id_msg).innerHTML = result.text;
    Effect.Fade(id_msg, {transition: Effect.Transitions.linear, duration: 1.0});
}

function report_motiv(event){
    Event.stop(event);
    my_form =  $(arguments[1]) || Event.element(event);
    customParams=my_form.serialize().parseQuery();
    sn_getAjax('report_motiv', customParams, null, {opt: arguments[1]});
}

document.observe("dom:loaded",function(){
    if($('report_form')!=undefined){
        Event.observe('report_form','submit',report_motiv)
    }
})

function sn_reportMotivHandler(result, resultElementName, userData)
{
    if (userData.opt == 'raporteaza_input') {
        $('video_options_container').innerHTML = '<div class="alert_box">' + result.text + '</div>';
        //Effect.Fade($('video_options_container'), {transition: Effect.Transitions.linear, duration: 2.0});
        return;
    }
    Effect.Appear($('raporteaza'), { duration: 0.0 });
    $('raporteaza').innerHTML = result.text;
    Effect.Fade( $('raporteaza'), {transition: Effect.Transitions.linear, duration: 2.0});
    try {
        Effect.Fade( $('video_options_container'), {transition: Effect.Transitions.linear, duration: 2.0});
    }
    catch(e) {
        Effect.Fade( $('det_optiune_5'), {transition: Effect.Transitions.linear, duration: 2.0});
    }
}


/* [+] Music search */
function fetchmusicIDs(limit, offset, query) {
	if (query) {
		div = $('searchMusicResults');
		while (div.childNodes.length > 0) {
			div.removeChild(div.childNodes[0]);
		}
		$('music_pag_top').update('');
		$('music_pag_bottom').update('');

		params = {limit: limit, offset: offset, query: query};

		sn_getAjax('fetch_musicIDs', params, 'searchMusicResults');
	}
}
function sn_fetchMusicIDsHandler(result, resultElementName, userData) {
    if (result.code == 0) {
        result = result.text.evalJSON();
        element = $(resultElementName);
        if (typeof element != 'undefined') {
            Element.update(element, result.audio_list);
        }

        $('mess_music_search').setStyle({display:'none'});
       	$('mess_music_search').update();

    } else {

    	$('mess_music_search').setStyle({display:'block'});
    	$('mess_music_search').update(result.text);
    	result.total = 0;
    }
    try{
     window.ajaxPagination.returnCall(result.total);
    }catch(e){ }
}
/* [-] Music search */

/* [+] VideoClips search */
function searchVideoClips() {
	var query;

	query = $('cautareMuzica').value.strip();

	if (query.length >= 3) {
	    fetchVideoByQuery(query);
	} else {
		//alert('Cuvantul cautat e cam scurt, manca-ti-as!');
		return false;
	}

	return true;
}
function fetchVideoByQuery(query) {
	if (query) {
		params = {query: query};
		sn_getAjax('fetch_VideoByQuery', params);
	}
}
function sn_fetchVideoByQueryHandler(result, resultElementName, userData) {
    if (result.code == 0) {
        result = result.text.evalJSON();
        element = $(resultElementName);
        if (typeof element != 'undefined') {
            Element.update(element, result.video_list);
        }

//       	$('searchVideoResults').update(result.video_list);
    }
}
/* [-] VideoClips search */


/* Related v3  */
function fetchRelated3(cid, mode) {
    var map_cont = {'sameuser': 'filme_user', 'hotlist': 'hotlist'};
    params = {cid: cid, relatedSource: mode};
    if (!window.fetched3[mode]) {
        sn_getAjax('fetchRelated3', params, null, {mode: mode, map_cont: map_cont});
        $(map_cont[mode]).update('Se incarca ...');
    }
    if (mode == 'sameuser') {
        $('user').toggleClassName('user_activ');
    } else if (mode == 'hotlist') {
        $('filmele_zilei').toggleClassName('activ');
    } else if (mode == 'similare') {
        $('filme_similare').toggleClassName('activ');
    }

    //$(map_cont[mode]).toggleClassName('activ');
}
function sn_fetchRelated3Handler(result, resultElementName, userData) {
    if ( result.code == 0 ) {
        $(userData.map_cont[userData.mode]).update(result.text);
    } else {
        $(map_cont[userData.mode]).update('');
    }
    window.fetched3[userData.mode] = true;
}

function fetchRelated(mode) {
    var cid = window.contentId;
    var arrDivs = ['similare', 'sameuser', 'hotlist'];
    var doSwitch = function(id) {
        for (i = 0; i < arrDivs.length; i++) {
            if (id == arrDivs[i]) {
                //$('tabc_' + arrDivs[i]).show();
                if($('tabc_' + arrDivs[i])){
                    $('tabc_' + arrDivs[i]).style.display = 'block';
                    $('tab_' + arrDivs[i]).addClassName('s_m_sel');
                }
            } else {
                 if($('tabc_' + arrDivs[i])){
                    //$('tabc_' + arrDivs[i]).hide();
                    $('tabc_' + arrDivs[i]).style.display = 'none';
                    $('tab_' + arrDivs[i]).removeClassName('s_m_sel');
                 }
            }
        }
    };

    if($('similare_menux')){
        if(mode == 'similare'){
            $('similare_menux').setStyle({backgroundPosition: "left bottom"});
        }else{
            $('similare_menux').setStyle({backgroundPosition: "left top"});
        }
    }


    params = {cid: cid, relatedSource: mode};
    if (typeof(eval('window.fetched.' + mode)) == "undefined") {
        sn_getAjax('fetchRelated', params, "", mode);
            }
    doSwitch(mode);
}

function sn_fetchRelatedHandler(result, resultElementName, userData) {
    if ( result.code == 0 ) {
        $('tabc_' + userData).update(result.text);
        eval('window.fetched.' + userData + ' = true');
        Cookies.create('relatedSource', userData, 1);
    }
}


document.observe("dom:loaded",function(){
    if($('muta_in_show_form')!=undefined){
        Event.observe('muta_in_show_form','submit',muta_in_show)
    }
});

function muta_in_show(event)
{
    Event.stop(event);
    my_form = Event.element(event);
    customParams = my_form.serialize().parseQuery();
    sn_getAjax('muta_in_show', customParams);
}

function sn_mutaInShowHandler(result, resultElementName, userData)
{
    $('muta_in_show').update(result.text.userContent);
    $('muta_din_show').update(result.text.showContent);
    Sortable.create('muta_din_show',{
        tag:'div',
        overlap:'horizontal',
        constraint:false,
        ghosting:false
    });
}

document.observe("dom:loaded",function(){
    if($('muta_din_show_form')!=undefined){
        Event.observe('muta_din_show_form','submit',muta_din_show)
    }
})

function muta_din_show(event)
{
    Event.stop(event);
    my_form = Event.element(event);
    customParams = my_form.serialize().parseQuery();
    sn_getAjax('muta_din_show', customParams);
}

function sn_mutaDinShowHandler(result, resultElementName, userData)
{
    $('muta_din_show').update(result.text.showContent);
    $('muta_in_show').update(result.text.userContent);
    Sortable.create('muta_din_show',{
        tag:'div',
        overlap:'horizontal',
        constraint:false,
        ghosting:false
    });
}

function initContentNotInShow() {
    loadContentNotInShow(16, 0);
}

function loadContentNotInShow(countPerPage, offset) {
    divEpisoade = $('containerEpisoade');
    divEpisoade.update('<div class="loading"></div>');
    sn_getAjax('content_get_not_in_show', {show_id: showId, limit: countPerPage, offset: offset}, 'containerEpisoade');
}

function sn_contentGetNotInShowHandler(result, resultElementName) {
    var myResult = result.text.evalJSON(true);
    $(resultElementName).update(myResult.content);
    $$('div.container_film_d').each(function(element){Element.extend(element)});
    window.episoadePagination.returnCall(myResult.total);
}

function showAddContent(contentId) {
    sn_getAjax('show_add_content', {content_id: contentId});
}

function sn_showAddContentHandler(result) {
    if (result.code == 0) {
        document.location = SITE_BASE + 'my-show/episoade';
    }
}

function showRemoveContent(contentId, title) {
    if (confirm('Esti sigur ca vrei sa stergi "' + title + '" din show-ul tau?')) {
        sn_getAjax('show_remove_content', {content_id: contentId});
        return true;
    }
    return false;
}

function sn_showRemoveContentHandler(result) {
    if (result.code == 0) {
        document.location.reload();
    }
}

function onShowReorderEpisoade() {
    var re = new RegExp("^c_(.+)$");
    var matches;
    var episoade = $('lista_episoade').getElementsByClassName('container_film_h');
    var len = episoade.length;
    for (var i = 0; i < len - 1; ++i) {
        episoade[i].getElementsByClassName('clearAll')[0].addClassName('punctata');
    }
    episoade[i].getElementsByClassName('clearAll')[0].removeClassName('punctata');


    var orderList = new Array(len);
    for (var i = 0; i < len; i++) {
        matches = re.exec(episoade[i].id);
        if (matches) {
            orderList[i] = matches[1];
        }
    }

    var saver = $('saverPop');
    saver.innerHTML = 'Salvez ordinea';
    saver.style.top = document.viewport.getScrollOffsets()[1] + 'px';
    saver.show();
    Event.observe(window, 'scroll', scrollSaver);

    sn_getAjax('show_save_order', {json_order_list: orderList.toJSON()});
}

function scrollSaver(event) {
    var saver = $('saverPop');
    saver.style.top = document.viewport.getScrollOffsets()[1] + 'px';
}

function fadeSaver() {
    var saver = $('saverPop');

    Effect.Pulsate('saverPop', { duration: 1.0 });
    setTimeout("Effect.Fade('saverPop', { duration: 0.2 })", 1000);
    setTimeout('Event.stopObserving(window, \'scroll\', scrollSaver); $("saverPop").hide();$("saverPop").className="";', 1200);
}

function sn_showSaveOrderHandler(result) {
    var saver = $('saverPop');
    if (result.code != 0) {
        saver.innerHTML = 'Eroare';
    } else {
        saver.innerHTML = 'OK';
        saver.className = 'ok'
    }

    fadeSaver();
}




function modifica_bkg(event){
    Event.stop(event);
    my_form = Event.element(event);
    customParams = my_form.serialize().parseQuery();
    sn_getAjax('modifica_bkg', customParams);
}




function preview_imagine()
{
    customParams = $('bkg_imagine').value;
    sn_getAjax('preview_imagine', customParams);
}

function Updater(element,url,form_id){
    var element = $(element);
    try{
      params = Form.serialize(form_id);
    }catch(e){ params = ''}
    new Ajax.Updater(element,
        url,
          {
            asynchronous: true,
            evalScripts: true,
            parameters: params ,
            onComplete: function(request) {}
          }
    );
}
/*	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}}}}();function AjaxPagination(countPerPage, shownPages, totalResults, callbackFunction, paginationDivs, className, anchor) {
	this.setCountPerPage(countPerPage);
	this.setShownPages(shownPages);
	this.setTotalResults(totalResults);
	this.setCallbackFunction(callbackFunction);

	this.currentClassName = 'current';
	this.disabledClassName = 'disabled';

	this.currentPage = 0;

	if (typeof className == 'object') {
	    this.className = className.className;
	    if (className.currentPage) {
	        this.currentClassName = className.currentPage;
	    }
	    if (className.disabledPage) {
	        this.disabledClassName = className.disabledPage;
	    }
	} else {
	   this.className = className;
	}
	this.anchor = anchor;

	if (typeof paginationDivs == 'object') {
		this.paginationDivs = paginationDivs;
	}

	this.showButtonsIfInactive = true;

	this.buttons = {
	    firstPage: '<<<',
	    prevSection: '<<',
	    prevPage: '<',
	    nextPage: '>',
	    nextSection: '>>',
	    lastPage: '>>>'
	};
	this.currentClassName = 'current';
	this.startPage = 1;
}

AjaxPagination.prototype.setShowButtonsIfInactive = function(f)
    {
        if (f) this.showButtonsIfInactive = true;
        else this.showButtonsIfInactive = false;
    };

AjaxPagination.prototype.setCountPerPage = function(countPerPage)
	{
		switch (typeof countPerPage) {
			case 'string':
				this.countPerPage = countPerPage.parseInt();
				break;
			case 'number':
				this.countPerPage = Math.floor(countPerPage);
				break;
			default:
				throw "Invalid countPerPage type";
		}
	};

AjaxPagination.prototype.setShownPages = function(shownPages)
	{
		switch (typeof shownPages) {
			case 'string':
				this.shownPages = shownPages.parseInt();
				break;
			case 'number':
				this.shownPages = Math.floor(shownPages);
				break;
			default:
				throw "Invalid ShownPages type";
		}
	};


AjaxPagination.prototype.setTotalResults = function(totalResults)
	{
		switch (typeof totalResults) {
			case 'string':
				this.totalResults = totalResults.parseInt();
				break;
			case 'number':
				this.totalResults = Math.floor(totalResults);
				break;
			default:
				throw "Invalid countPerPage type";
		}
	};

AjaxPagination.prototype.setCallbackFunction = function(callbackFunction)
	{
		this.callbackFunction = callbackFunction;
	};


AjaxPagination.prototype.show = function(flag) {
	var div;
	var i;
	for (var i = 0, len = this.paginationDivs.length; i < len; ++i) {
		div = $(this.paginationDivs[i]);
		if (div) {
		    if (flag) {
		        div.show();
		    } else {
		        div.hide();
		    }
		}
	}
}
AjaxPagination.prototype.paginate = function(userData) {
	var pag = this.startPage;
	var totalPages;
	var firstShownPage = 0;
	var lastShownPage = 0;
	var delta = 0;
	var pagString = '';
	var element;

	this.delDivContents();

	totalPages = Math.ceil(this.totalResults / this.countPerPage);

    this.show(false);

	if (totalPages <= 1) {
		return;
	}


	if (totalPages <= this.shownPages) {
		firstShownPage = 1;
		lastShownPage = totalPages;
	} else {
		firstShownPage = Math.round(pag - (this.shownPages / 2));
		lastShownPage = Math.round(pag + (this.shownPages / 2)) - 1;

		if (firstShownPage < 1) {
			delta = 1 - firstShownPage;
		}

		if (lastShownPage > totalPages) {
			delta = totalPages - lastShownPage;
		}

		firstShownPage += delta;
		lastShownPage += delta;

		if (lastShownPage > totalPages) {
			lastShownPage = totalPages;
		}

		if (firstShownPage < 1) {
			firstShownPage = 1;
		}
	}

	if (this.buttons.firstPage) {
    	if (pag > 1) {
    		this.addPageButton(this.buttons.firstPage, true, 1);
    	} else if (this.showButtonsIfInactive) {
    		this.addPageButton(this.buttons.firstPage, false);
    	}
	}

	if (this.buttons.prevSection) {
    	if (pag - this.shownPages <= firstShownPage && pag - this.shownPages >= 1) {
    		this.addPageButton(this.buttons.prevSection, true, pag - this.shownPages);
    	} else if (this.showButtonsIfInactive) {
    		this.addPageButton(this.buttons.prevSection, false);
    	}
	}

    if (this.buttons.prevPage) {
    	if (pag > 1) {
    		this.addPageButton(this.buttons.prevPage, true, pag - 1);
    	} else if (this.showButtonsIfInactive) {
    		this.addPageButton(this.buttons.prevPage, false);
    	}
    }

	for (i = firstShownPage; i <= lastShownPage; ++i) {
		if (i != pag) {
			this.addPageButton(i.toString(), true, i);
		} else {
			this.addPageButton(i.toString(), false, null, true);
		}
	}

	if (this.buttons.nextPage) {
    	if (pag < totalPages) {
    		this.addPageButton(this.buttons.nextPage, true, pag + 1);
    	} else if (this.showButtonsIfInactive) {
    		this.addPageButton(this.buttons.nextPage, false);
    	}
	}


	if (this.buttons.nextSection) {
    	if (pag + this.shownPages >= lastShownPage && pag + this.shownPages <= totalPages) {
    		this.addPageButton(this.buttons.nextSection, true, pag + this.shownPages);
    	} else if (this.showButtonsIfInactive) {
    		this.addPageButton(this.buttons.nextSection, false);
    	}
	}

    if (this.buttons.lastPage) {
    	if (pag < totalPages) {
    		this.addPageButton(this.buttons.lastPage, true, totalPages);
    	} else if (this.showButtonsIfInactive) {
    		this.addPageButton(this.buttons.lastPage, false);
    	}
    }

    this.show(true);
};

AjaxPagination.prototype.start = function(userData) {
	this.gotoPage(1, userData);
	this.userData = userData;
};

AjaxPagination.prototype.returnCall = function(totalResults, userData) {
	var numTotalResults;
	switch (typeof totalResults) {
		case 'string':
			numTotalResults = parseInt(totalResults);
			break;
		case 'number':
			numTotalResults = Math.floor(totalResults);
			break;
		default:
			numTotalResults = 0;
	}
	if (numTotalResults >= 0) {
		this.totalResults = numTotalResults;
	}

	this.paginate();
}

AjaxPagination.prototype.gotoPage = function(pageNum, userData) {
	var limit;
	var offset;
	var numResults;

	offset = (pageNum - 1) * this.countPerPage;
	this.startPage = pageNum;
	eval(this.callbackFunction + '(' + this.countPerPage + ', ' + offset + ', userData)');
};

AjaxPagination.prototype.delDivContents = function() {
	var div;
	var i;
	for (var i = 0, len = this.paginationDivs.length; i < len; ++i) {
		div = $(this.paginationDivs[i]);
		if (div) {
			while(div.childNodes.length > 0) {
				div.removeChild(div.childNodes[0]);
			}
		}
	}
};

AjaxPagination.prototype.addDivElement = function(element) {
	var div;
	var divName;
	var i;
	for (var i = 0, len = this.paginationDivs.length; i < len; ++i) {
		divName = this.paginationDivs[i];
		div = $(divName);
		if (div) {
			div.appendChild(element);
		}
	}
};


AjaxPagination.prototype.onClick = function(event) {
	var element;
	element = Event.findElement(event, 'a');
	if (element) {
		element.ajaxPagination.gotoPage(element.page, element.ajaxPagination.userData);
		if (element.ajaxPagination.anchor) {
		    a = $(element.ajaxPagination.anchor);
		    a.scrollTo();
//			window.location.hash = '#' + element.ajaxPagination.anchor;
		}
	}
}

AjaxPagination.prototype.getNewElement = function(displayText, enabled, pageNum, current) {
	var element, className, text;

    if (typeof displayText == 'object') {
        className = this.className + ' ' + displayText.className;
        text = (displayText.text?displayText.text:'');
    } else {
        className = this.className;
        text = displayText;
    }
	element = Builder.node('a', {href: 'javascript: void(0);', className: className}, text);

	if (enabled) {
		element.page = pageNum;
		element.ajaxPagination = this;
		Event.observe(element, 'click', this.onClick);
	} else {
	    if (current) {
	        element.addClassName(this.currentClassName);
	    } else {
	        element.addClassName(this.disabledClassName);
		}
	}

	return element;
}

AjaxPagination.prototype.addPageButton = function(displayText, enabled, pageNum, current) {
    var element, div, divName, i, len, image;
	for (i = 0, len = this.paginationDivs.length; i < len; ++i) {
		divName = this.paginationDivs[i];
		div = $(divName);
		if (div) {
		    element = this.getNewElement(displayText, enabled, pageNum, current);
			div.appendChild(element);
		}
	}
}

AjaxPagination.prototype.startPage = 0;
// [+] comentarii content video ------------------------------------------------
function openReplyBox(id_content, reply) {
    orig = $('reply_comment_form').remove();

    holder = $('adaugareply_' + reply);
    holder.appendChild(orig);

    form = $('add_comment_f');
    form['reply'].value = reply;
    form.show();
    $('errors_comment').hide();

    orig.show();
    if (reply < 0) {
        $('add_comment').show();
    } else {
        $('add_comment').hide();
    }
}

function closeReplyBoxDelayed(refresh) {
    closeReplyBox(1);
    setTimeout("Effect.Fade('errors_comment', { duration: 1.0 });", 2000);
    setTimeout("$('reply_comment_form').hide();", 3000);
    if (refresh) {
        setTimeout("window.ajaxPagination.gotoPage(1);", 3000);
    }
}

function closeReplyBox(delayed, refresh) {
    newForm = $('reply_comment_form');
    $('add_comment').hide();
    form = $('add_comment_f');
    form['reply'].value = '';
    form.hide();
    if (!delayed)
    newForm.hide();
}
// [-] comentarii content video ------------------------------------------------


// [+] Zona ajax comentarii ----------------------------------------------------
function fetchComments(limit, offset) {

	if (typeof(userId) != 'undefined') {
        div = $('ajax_comments');
        params = {limit: limit, offset: offset, user_id: userId};
        sn_getAjax('fetch_comments', params, 'ajax_comments');
    }


	if (typeof(contentId) != 'undefined') {
        div = $('comments');

        while (div.childNodes.length > 0) {
            div.removeChild(div.childNodes[0]);
        }
        params = {limit: limit, offset: offset, content_id: contentId, options: window.fetched3 ? 'v3' : ''};
        orig = $('reply_comment_form');
        if (orig) {
            orig.parentNode.removeChild(orig);
        }
        sn_getAjax('fetch_content_comments', params, 'comments');
    }
}

function sn_fetchContentCommentsHandler(result, resultElementName, userData) {
    if (result.code == 0) {
        result = result.text.evalJSON();
        element = $(resultElementName);

        if (typeof element != 'undefined') {
            Element.update(element, result.comments);
        }

        window.ajaxPagination.returnCall(result.num_comments);
        if($('nrComments')) $('nrComments').update(result.num_comments);
    }
}
// [-] Zona ajax comentarii ----------------------------------------------------


// Reply la comentariu
function reply_content_comment(form) {
    var f = (typeof (form) != 'undefined' ? $(form.id) : $('add_comment_f'));

    if(typeof(window.canSendComment) == 'undefined') window.canSendComment = 1;
    if (window.canSendComment != 1) return;
    else {
        if (f.message.value == 'login pentru a posta comentariu la acest film') {
            alert('Nu sunteti autentificat sau nu ati completat mesajul!');
            return;
        }
        if ($('posteaza_comentariu')) $('posteaza_comentariu').disabled = true;
        window.canSendComment = 0;
    }
    sn_getAjaxByQuery('post_reply_content_comment', f.serialize());
}

function assign_comment_reply(cid, user){
    var reply = $('id_post_reply');
    if (!reply) return;
    var reply_user = $$('#id_post_reply_user span')[0];
    reply.value = cid;
    reply_user.update(user);
    if (cid) $('id_post_reply_user').show();
    else $('id_post_reply_user').hide();
}

function sn_postReplyContentCommentHandler(result, resultElementName, userData) {
    if (result.code == 0) {
        if($('add_comment_f_content_tarea_main')) {
            $('add_comment_f_content_tarea_main').value = '';
            window.ajaxPagination.gotoPage(1);
        }
        else {
            $('add_comment_f').reset();
            $('errors_comment').update(result.text.text);
            $('errors_comment').show();
            closeReplyBoxDelayed(true);
        }
    } else {
        if($('add_comment_f_content_tarea_main')) {
            alert(result.text.text);
        }
        else {

            $('errors_comment').update(result.text.text);
            $('errors_comment').show();
        }
    }
    window.canSendComment = 1;
    if ($('posteaza_comentariu')) $('posteaza_comentariu').disabled = false;
}
//

// [+] Votare comentarii -------------------------------------------------------
function voteaza_comentariu(comment_id, nota) {
    customParams = {comment_id: comment_id, nota: nota};
    sn_getAjax('voteaza_comentariu', customParams, 'commentRating_' + comment_id);
}

function sn_voteazaComentariuHandler(result, resultElementName, userData) {
    if (result.code == 0) {
        //alert('Vot inregistrat');
        result = result.text.evalJSON();
        $(resultElementName).update(result['nota']);
    }
    else  {
        alert(result.text);
    }
}
function sn_voteazaComentariuErrorHandler(result, resultElementName, userData) {
    if (result.code == 1) {
        alert('Eroare la salvare');
    }
    else {
        alert('A aparut o eroare');
    }
}
// [-] Votare comentarii -------------------------------------------------------


function toggle_comment_form(elementId,targetId) {
    try {
        if($(elementId).visible()){
        	blind($(elementId));
        	if($(targetId)) $(targetId).update('Comenteaza');
        }
        else{
        	blindDown($(elementId));
        	$(targetId).update('Inchide');
        }
    }
    catch(e) {;}
}function paginare_ajax(){
	window.ajaxPagination = new AjaxPagination(this.arg1,this.arg2, this.arg3, null, this.arg4, this.arg5, this.arg6);
        window.ajaxPagination.buttons = {firstPage: '<<', prevSection: false, prevPage: '<', nextPage: '>', nextSection: false, lastPage: '>>'};
        window.ajaxPagination.setShowButtonsIfInactive(true);
        window.ajaxPagination.setCallbackFunction('fetchComments');
	    window.ajaxPagination.paginate();
};

function deleteChildNodes(parent) {
    while (parent.childNodes[0]) {
        parent.removeChild(parent.childNodes[0]);
    }
}

// Favorite
function add_favorite(content_id) {
    if (window.elementCache.exists('favorite')) {
        deleteChildNodes($('video_options_container'));
        window.elementCache.deploy('favorite', $('video_options_container'));
        return true;
    }

	customParams = {content_id: content_id};
	sn_getAjax('add_favorite', customParams);
}

function sn_addFavoriteHandler(result, resultElementName, userData)
{
	var code = result.code;
	result = result.text.evalJSON();
	try {
		$('video_options_container').update(result.text);
		window.elementCache.save('favorite', $('video_options_container'));
	} catch(e) {
		$('add_favorites').update(result.text);
		if (code == 0) {
		    $('delete_favorites').update('<br/><input type="submit" onclick="javascript:delete_favorite(\'' + result.id + '\');" value="Scoate din favorite">');
		}
	}
}

function delete_favorite(content_id) {
	customParams = {content_id: content_id};
	sn_getAjax('delete_favorite', customParams);
}

function sn_deleteFavoriteHandler(result, resultElementName, userData) {
	$('video_options_container').update(result.text);
    window.elementCache.deleteItem('favorite');
}


// Adaugare grup
function loadGroupsToggle(contentId) {
    if (window.elementCache.exists('groups')) {
        window.elementCache.deploy('groups', $('video_options_container'));
        return true;
    }
	customParams = {id: contentId,save_from: 'content' };
	sn_getAjax('f_savetogroup', customParams);
};

function sn_fSavetogroupHandler (result, resultElementName, userData){
	var code = result.code;
	result = result.text.evalJSON();
	$('video_options_container').update(result.text);
	window.elementCache.save('groups', $('video_options_container'));
}

function loadGroupsToggle3(contentId) {
    if (window.elementCache.exists('f_savetogroup3')) {
        if ($('add_to_group')) {
            emptyVideoContainer();
            return;
        }
        window.elementCache.deploy('f_savetogroup3', $('video_options_container'));
        return true;
    }
    customParams = {id: contentId || window.content.id};
    sn_getAjax('f_savetogroup3', customParams,  'video_options_container');
};

var sn_fSavetogroup3Handler = function(result, resultElementName) {
    $(resultElementName).update(result.text.evalJSON().text);
    window.elementCache.save('f_savetogroup3', $(resultElementName));
}

function s_loadPlaylistToggle(contentId) {
	var playlistsLoaded = ($('add_to_playlist_form_'+contentId) != null);
	if (!playlistsLoaded) {
		sn_updateByAjax('f_s_savelist',
			{
				save_from: 'content',
				id: contentId
			},
			'det_optiune_4'
		);
	} else emptyVideoContainer();
}

function s_loadGroupsToggle(contentId) {
    var groupsLoaded = ($('add_to_group_form_'+contentId) != null);
    if (!groupsLoaded) {
        groupsLoaded = true;
        sn_updateByAjax('f_s_savetogroup',
        	{
            	save_from: 'content',
            	id: contentId
        	},
            ($('video_options_container'))?'video_options_container':'det_optiune_6'
        )
    }
    else emptyVideoContainer();
};

// Adaugare playlist
function loadPlaylistToggle3(contentId) {
    if (window.elementCache.exists('add_to_list')) {
        if ($('add_to_list')) {
            emptyVideoContainer();
            return;
        }
        window.elementCache.deploy('add_to_list', $('video_options_container'));
        return true;
    }
    customParams = {id: contentId || window.content.id, save_from: 'content'};
    sn_getAjax('f_savelist3', customParams, 'video_options_container');
}
var sn_fSavelist3Handler = function(result, resultElementName) {
    $(resultElementName).update(result.text.evalJSON().text);
    window.elementCache.save('add_to_list', $(resultElementName));
}

function loadPlaylistToggle(contentId) {
    if (window.elementCache.exists('playlists')) {
        window.elementCache.deploy('playlists', $('video_options_container'));
        return true;
    }
	customParams = {id: contentId,save_from: 'content' };
	sn_getAjax('f_savelist', customParams, 'video_options_container');
}

function sn_fSavelistHandler (result, resultElementName, userData){
	var code = result.code;
	result = result.text.evalJSON();
	$(resultElementName).update(result.text);

	if (code == 222) {
	   window.elementCache.save('playlists', $(resultElementName));
	} else if (code == 223) {
	    window.elementCache.save('playlistsq', $(resultElementName));
	}
}

//
function loadReportForm3() {
    if (window.elementCache.exists('load_report_form3')) {
        if ($('raporteaza_input')) {
            emptyVideoContainer();
            return;
        }
        window.elementCache.deploy('load_report_form3', $('video_options_container'));
        return true;
    }
    customParams = {content_aid: window.content.id};
    sn_getAjax('load_report_form3', customParams, 'video_options_container');
}

function sn_loadReportForm3Handler(result, resultElementName) {
    $(resultElementName).update(result.text);
    window.elementCache.save('load_report_form3', $(resultElementName));
}

function addTofavorite3(cid) {
    if (window.elementCache.exists('add_favorite3')) {
        if ($('add_favorite3')) {
            emptyVideoContainer();
            return;
        }
        window.elementCache.deploy('add_favorite3', $('video_options_container'));
        return true;
    }
    customParams = {content_aid: cid || window.content.id};
    sn_getAjax('add_favorite3', customParams, 'video_options_container');
}
var sn_addFavorite3Handler = function(result, resultElementName) {
    $(resultElementName).update(result.text.evalJSON().text);
    window.elementCache.save('add_favorite3', $(resultElementName));
}

function delete_favorite3(cid) {
    if (window.elementCache.exists('delete_favorite3')) {
        if ($('delete_favorite3')) {
            emptyVideoContainer();
            return;
        }
        window.elementCache.deploy('delete_favorite3', $('video_options_container'));
        return true;
    }
    params = {content_aid: cid || window.content.id};
    sn_getAjax('delete_favorite3', params, 'video_options_container');
}
var sn_deleteFavorite3Handler = function(result, resultElementName) {
    $(resultElementName).update(result.text.evalJSON().text);
    window.elementCache.save('delete_favorite3', $(resultElementName));
}


// Raporteaza
function loadReportForm(content_aid,is_logged) {
	if (window.elementCache.exists('report_form')) {
		window.elementCache.deploy('report_form', $('video_options_container'));
		return true;
	}
	params = {content_aid: content_aid}
	sn_getAjax('load_report_form',params,'video_options_container');
}

function sn_loadReportFormHandler(result, resultElementName) {
    $(resultElementName).update(result.text);
    window.elementCache.save('report_form', $(resultElementName));
}


// Embed
function loadEmbedToggle(contentId) {
	sn_updateByAjax('embedLinks', {id: contentId}, 'det_optiune_7');
}

function embedToogle (contentId,from){
	if (typeof window.GeoRestrictedContent != 'undefined') {
		$('video_options_container').update('<div class="option_container">Acest material nu poate fi preluat</div>');
		return;
	}
    if (window.elementCache.exists('embed')) {
        window.elementCache.deploy('embed', $('video_options_container'));
        return true;
    }

	customParams = {id: contentId, from: from };
	sn_getAjax('embed', customParams);
}

function sn_embedHandler (result, resultElementName, userData) {
	result = result.text.evalJSON();
	$('video_options_container').update(result.text);
	make_embed_code();
	window.elementCache.save('embed', $('video_options_container'));
}

function toggle_embed(ev,cid) {
	var elem = Event.element(ev), optionsContainer = $('video_options_container');
	if(elem.hasClassName('add')) {
		if (!window.elementCache.exists('embeded')) {
			use_embed_settings(cid);
			elem.removeClassName('add');
			elem.addClassName('add_minus');
		} else {
			$('embeded').style.display = 'block';
			elem.removeClassName('add');
			elem.addClassName('add_minus');
			window.elementCache.deploy('embeded', $('embeded'));
		}
	} else {
		//$('embeded').style.display = 'none';
		remove_embed();
		elem.removeClassName('add_minus');
		elem.addClassName('add');
	}
}

function use_embed_settings(cid) {
	if($A($$('#embeded .titlu_upl')).size() > 0) {
		Effect.Appear('embeded',{duration: 0.4});
	} else if(cid) {
		params = {content_id: cid};
		sn_updateByAjax('get_embed_settings', params,'embeded', {onComplete: embed_code_options});
	}
}

function embed_code_options() {
    window.elementCache.save('embeded', $('embeded'));
	if ($('form_embed')) {
		$('form_embed').getElements().each(function(el){
			if (el.type == 'radio') Event.observe(el, 'click', make_embed_code);
			else Event.observe(el, 'change', make_embed_code);
		});
	}
	$$('.color_picker_close').each(function(dv) {
		Event.observe(dv,'click',function(event) {
			var id = (/[^0-9]*([0-9]+)/.exec(dv.id))[1];
			toggleColorPicker(event, id, 'hide');
		});
	});
	$$('.color_picker_show').each(function(dv) {
		Event.observe(dv,'click', function(event) {
			var id = (/[^0-9]*([0-9]+)/.exec(dv.id))[1];
			toggleColorPicker(event, id, 'show');
		});
	});
	Effect.Appear('embeded',{duration: 0.4});
}

function remove_embed(){
	Effect.Fade('embeded',{duration: 0.4});
}






// itemNames
function deactivate(link) {
	link.removeClassName('hovered_' + link.id);
	link.removeClassName('activat');
	try {
		$('video_options_container').hide();
	}
	catch(e) {
		div = $('det_' + link.id);
		div.hide();
	}
	document.getElementById('loginux').style.display = 'none';
}

function emptyVideoContainer() {
	try {
		if( !$('video_options_container').empty() ) {
			$('video_options_container').update('');
		}
	}
	catch(e) {;}
}


function activateButton(link) {
	$$('a.activat').each(function(link) {deactivate(link);});
	div = $('video_options_container');
	link.addClassName('hovered_' + link.id);
	link.addClassName('activat');
	document.getElementById('loginux').style.display = 'none';
	try {
	    eval(link.onActivate);
		div.show();
	}
	catch(e) {
		div = $('det_' + link.id);div.show();
	}
}

function toggleOption(link) {
	var optionsContainer = $('video_options_container'), itemName = false;

	if (link.hasClassName('hovered_' + link.id)) {
		deactivate(link);
	} else {
		activateButton(link);
	}
}

function closeVideoOptionsContainer() {
	if ($('video_options_container') && $('video_options_container').visible()) {
	   $('video_options_container').hide();
	   $$('a.activat').each(function(link){deactivate(link);});
	   emptyVideoContainer();
	}
}

ElementCache = Class.create();
Object.extend(ElementCache.prototype, {
    stash: {},
    postSaveDeploy: [],
    deleteItem: function (itemName) {
    	if (this.stash[itemName]) {
    		delete this.stash[itemName];
    	}
    },
    exists: function(itemName) {
        if (this.stash[itemName]) {
            return true;
        }
        return false;
    },
    deploy: function(itemName, parentContainer) {
    	var virtualContainer, childNodes, child, num, i;

    	if (this.stash[itemName]) {
    	    virtualContainer = this.stash[itemName];
    	    deleteChildNodes(parentContainer);
    		childNodes = virtualContainer.childNodes;
    		virtualContainer = this.stash[itemName];
    	    for (i = 0, num = childNodes.length; i < num; i++) {
    	        parentContainer.appendChild(childNodes[i].cloneNode(true));
    	    }
    	    this.execPostSaveDeploy();
    		return true;
    	} else {
    		return false;
    	}
    },
    save: function(itemName, parentContainer) {
        this.execPostSaveDeploy();
        var virtualContainer, childNodes, child, i, num;
        childNodes = parentContainer.childNodes;
        virtualContainer = parentContainer.cloneNode(true);
        this.deleteItem(itemName);
        this.stash[itemName] = virtualContainer;
    },
    addPostSaveDeploy: function(f) {
        if (typeof f == 'function') {
            this.postSaveDeploy.push(f);
        }
    },
    execPostSaveDeploy: function() {
        for (var i = this.postSaveDeploy.length - 1; i >= 0; i--) {
            this.postSaveDeploy[i].call();
        }
    }

});

window.elementCache = new ElementCache();

document.observe('dom:loaded', function() {
	$$('a.toggler').each(function(element) {
		Event.observe(element, 'click', function(event) {
			element = Event.findElement(event, 'a');
			toggleOption(element);
		});
	});

	if (typeof(window.GeoRestricted) != 'undefined') {
	    if ($('geoalert')) {
            $('geoalert').innerHTML = '<div class="geo_forbidden">Acest material nu poate fi vazut in tara dumneavoastra deoarece se afla sub incidenta copyright-ului.<br><br>This video is not available in your country due to copyright restrictions.</div>';
	    }
	}
});

function loadPlaylistToggleQ() {
    if (window.elementCache.exists('playlistsq')) {
        window.elementCache.deploy('playlistsq', $('playlist_form'));
    } else {
        sn_getAjax('f_savelist',
        {
            save_from: 'ql',
            id: 'ql'
        },
        'playlist_form'
        );
    }

    if($('playlist_form').visible()) {
        $('btn_toggle_s_ql').update('salveaza ca playlist');
        $('playlist_form').hide();
    }
    else {
        $('btn_toggle_s_ql').update('inchide lista');
        $('playlist_form').show();
    }
}

function loadPlaylistToggleQSearch() {
    if (window.elementCache.exists('playlistsqs')) {
        window.elementCache.deploy('playlistsqs', $('playlist_form'));
    } else {
        sn_getAjax('f_savelist',
        {
            save_from: 'ql_search',
            id: 'ql_search'
        },
        'playlist_form'
        );
    }

    if($('playlist_form').visible()) {
        $('btn_toggle_s_ql').update('salveaza ca playlist');
        $('playlist_form').hide();
    }
    else {
        $('btn_toggle_s_ql').update('inchide lista');
        $('playlist_form').show();
    }
}

function load_embed_links() {

    if (window.elementCache.exists('embedContentLinks')) {
        window.elementCache.deploy('embedContentLinks', $('video_options_container'));
        return true;
    }
    sn_getAjax('embed_links', {id: contentId});
}

function sn_embedLinksHandler(result, resultElementName, userData)
{
	var code = result.code;
	try {
		$('video_options_container').update(result.text);
		window.elementCache.save('embedContentLinks', $('video_options_container'));
	} catch(e) {
		$('video_options_container').update(result.text);
	}
}


function setBlackLightLayerHeight() {
	if ($('divSchimbaLumina')) $('divSchimbaLumina').setStyle({'height': getPageDimensions().height});
}

function schimbaLumina() {
	setBlackLightLayerHeight();
	var mode = $$('BODY')[0].hasClassName('luminaStinsa') ? 'off' : 'on';
	if (mode == 'on') {
		if (!$('divSchimbaLumina')) {
			new_div = new Element('DIV', {'id': 'divSchimbaLumina', 'style': 'height: ' + getPageDimensions().height + 'px;'});
			document.body.appendChild(new_div);
			Event.observe($('divSchimbaLumina'), 'click', schimbaLumina);
		}
		else {
			$('divSchimbaLumina').setStyle({'display': 'block'});
		}
		$$('BODY')[0].addClassName('luminaStinsa');
		$$('.cinemaBoard A')[0].removeClassName('light_on').addClassName('light_off');
	}
	else {
		$('divSchimbaLumina').setStyle({'display': 'none'});
		$$('BODY')[0].removeClassName('luminaStinsa');
		$$('.cinemaBoard A')[0].removeClassName('light_off').addClassName('light_on');
	}
}

function playerHC() {
	var narrowPlD = {0:'640px', 1:'390px'};
	var widePlD = {0:'800px', 1:'480px'};
	var widePlD_back = {0:'960px', 1:'480px'};
	var curPlWidth = $$('.player_bg')[0].getStyle('width');
	var nextD = (curPlWidth == narrowPlD[0]) ? widePlD : narrowPlD;
	var nextD_back = (curPlWidth == narrowPlD[0]) ? widePlD_back : narrowPlD;
 	$$('.player_bg')[0].setStyle({'width': nextD[0]});
 	$$('.player_bg')[0].setStyle({'height': nextD[1]});
 	if (curPlWidth == narrowPlD[0]) {
 		$$('.cinemaBoard A')[1].removeClassName('wide_off').addClassName('wide_on');
 	}
 	else {
 		$$('.cinemaBoard A')[1].removeClassName('wide_on').addClassName('wide_off');
 	}
 	$$('#content_det_show')[0].setStyle({'width': nextD_back[0]});
 	setBlackLightLayerHeight();
}

(function() {
    var fpRequired = '10.1.102', cont;
    var v2 = true;
    cont = $$('#content_det .descriere_video')[0] || $$('#content_det_show .descriere_video')[0];
    if (v2) cont = $('content_det') || $('content_det_show');
    if (!cont || !$('player220')) return;
    if (swfobject.hasFlashPlayerVersion(fpRequired)) return;
    var ins = new Element('div', {id: 'flash_warn_upg'});
    ins.innerHTML = '<p class="agewarning">Versiunea de plugin flash pare a fi depasita (sau plugin dezactivat), click <a href="http://get.adobe.com/flashplayer/" target="_blank">aici</a> pentru actualizare</p>';
    if (v2) ins.innerHTML = '<p style="border:1px solid #CCC;background-color:#FFF4A5; margin-bottom:10px; padding:5px; text-align:center; font-weight: bold;">Versiunea de plugin flash pare a fi depasita (sau plugin dezactivat), click <a href="http://get.adobe.com/flashplayer/" target="_blank">aici</a> pentru actualizare</p>';
    if (v2) cont.insert({before: ins});
    else cont.insert({after: ins});
})();

document.observe('dom:loaded', function() {
    $$('.trackable_ga').each(function(a) {
	Event.observe(a, 'click', function() {
    	    _gaq.push(['_trackEvent', 'Share', a.title, window.contentId]);
	}.bindAsEventListener());
    });
});
