/*  Prototype JavaScript framework, version 1.6.0
 *  (c) 2005-2007 Sam Stephenson
 *
 *  Prototype is freely distributable under the terms of an MIT-style license.
 *  For details, see the Prototype web site: http://www.prototypejs.org/
 *
 *--------------------------------------------------------------------------*/

var Prototype = {
  Version: '1.6.0',

  Browser: {
    IE:     !!(window.attachEvent && !window.opera),
    Opera:  !!window.opera,
    WebKit: navigator.userAgent.indexOf('AppleWebKit/') > -1,
    Gecko:  navigator.userAgent.indexOf('Gecko') > -1 && navigator.userAgent.indexOf('KHTML') == -1,
    MobileSafari: !!navigator.userAgent.match(/Apple.*Mobile.*Safari/)
  },

  BrowserFeatures: {
    XPath: !!document.evaluate,
    ElementExtensions: !!window.HTMLElement,
    SpecificElementExtensions:
      document.createElement('div').__proto__ &&
      document.createElement('div').__proto__ !==
        document.createElement('form').__proto__
  },

  ScriptFragment: '<script[^>]*>([\\S\\s]*?)<\/script>',
  JSONFilter: /^\/\*-secure-([\s\S]*)\*\/\s*$/,

  emptyFunction: function() { },
  K: function(x) { return x }
};

if (Prototype.Browser.MobileSafari)
  Prototype.BrowserFeatures.SpecificElementExtensions = false;

if (Prototype.Browser.WebKit)
  Prototype.BrowserFeatures.XPath = false;

/* Based on Alex Arnell's inheritance implementation. */
var Class = {
  create: function() {
    var parent = null, properties = $A(arguments);
    if (Object.isFunction(properties[0]))
      parent = properties.shift();

    function klass() {
      this.initialize.apply(this, arguments);
    }

    Object.extend(klass, Class.Methods);
    klass.superclass = parent;
    klass.subclasses = [];

    if (parent) {
      var subclass = function() { };
      subclass.prototype = parent.prototype;
      klass.prototype = new subclass;
      parent.subclasses.push(klass);
    }

    for (var i = 0; i < properties.length; i++)
      klass.addMethods(properties[i]);

    if (!klass.prototype.initialize)
      klass.prototype.initialize = Prototype.emptyFunction;

    klass.prototype.constructor = klass;

    return klass;
  }
};

Class.Methods = {
  addMethods: function(source) {
    var ancestor   = this.superclass && this.superclass.prototype;
    var properties = Object.keys(source);

    if (!Object.keys({ toString: true }).length)
      properties.push("toString", "valueOf");

    for (var i = 0, length = properties.length; i < length; i++) {
      var property = properties[i], value = source[property];
      if (ancestor && Object.isFunction(value) &&
          value.argumentNames().first() == "$super") {
        var method = value, value = Object.extend((function(m) {
          return function() { return ancestor[m].apply(this, arguments) };
        })(property).wrap(method), {
          valueOf:  function() { return method },
          toString: function() { return method.toString() }
        });
      }
      this.prototype[property] = value;
    }

    return this;
  }
};

var Abstract = { };

Object.extend = function(destination, source) {
  for (var property in source)
    destination[property] = source[property];
  return destination;
};

Object.extend(Object, {
  inspect: function(object) {
    try {
      if (object === undefined) return 'undefined';
      if (object === null) return 'null';
      return object.inspect ? object.inspect() : object.toString();
    } catch (e) {
      if (e instanceof RangeError) return '...';
      throw e;
    }
  },

  toJSON: function(object) {
    var type = typeof object;
    switch (type) {
      case 'undefined':
      case 'function':
      case 'unknown': return;
      case 'boolean': return object.toString();
    }

    if (object === null) return 'null';
    if (object.toJSON) return object.toJSON();
    if (Object.isElement(object)) return;

    var results = [];
    for (var property in object) {
      var value = Object.toJSON(object[property]);
      if (value !== undefined)
        results.push(property.toJSON() + ': ' + value);
    }

    return '{' + results.join(', ') + '}';
  },

  toQueryString: function(object) {
    return $H(object).toQueryString();
  },

  toHTML: function(object) {
    return object && object.toHTML ? object.toHTML() : String.interpret(object);
  },

  keys: function(object) {
    var keys = [];
    for (var property in object)
      keys.push(property);
    return keys;
  },

  values: function(object) {
    var values = [];
    for (var property in object)
      values.push(object[property]);
    return values;
  },

  clone: function(object) {
    return Object.extend({ }, object);
  },

  isElement: function(object) {
    return object && object.nodeType == 1;
  },

  isArray: function(object) {
    return object && object.constructor === Array;
  },

  isHash: function(object) {
    return object instanceof Hash;
  },

  isFunction: function(object) {
    return typeof object == "function";
  },

  isString: function(object) {
    return typeof object == "string";
  },

  isNumber: function(object) {
    return typeof object == "number";
  },

  isUndefined: function(object) {
    return typeof object == "undefined";
  }
});

Object.extend(Function.prototype, {
  argumentNames: function() {
    var names = this.toString().match(/^[\s\(]*function[^(]*\((.*?)\)/)[1].split(",").invoke("strip");
    return names.length == 1 && !names[0] ? [] : names;
  },

  bind: function() {
    if (arguments.length < 2 && arguments[0] === undefined) return this;
    var __method = this, args = $A(arguments), object = args.shift();
    return function() {
      return __method.apply(object, args.concat($A(arguments)));
    }
  },

  bindAsEventListener: function() {
    var __method = this, args = $A(arguments), object = args.shift();
    return function(event) {
      return __method.apply(object, [event || window.event].concat(args));
    }
  },

  curry: function() {
    if (!arguments.length) return this;
    var __method = this, args = $A(arguments);
    return function() {
      return __method.apply(this, args.concat($A(arguments)));
    }
  },

  delay: function() {
    var __method = this, args = $A(arguments), timeout = args.shift() * 1000;
    return window.setTimeout(function() {
      return __method.apply(__method, args);
    }, timeout);
  },

  wrap: function(wrapper) {
    var __method = this;
    return function() {
      return wrapper.apply(this, [__method.bind(this)].concat($A(arguments)));
    }
  },

  methodize: function() {
    if (this._methodized) return this._methodized;
    var __method = this;
    return this._methodized = function() {
      return __method.apply(null, [this].concat($A(arguments)));
    };
  }
});

Function.prototype.defer = Function.prototype.delay.curry(0.01);

Date.prototype.toJSON = function() {
  return '"' + this.getUTCFullYear() + '-' +
    (this.getUTCMonth() + 1).toPaddedString(2) + '-' +
    this.getUTCDate().toPaddedString(2) + 'T' +
    this.getUTCHours().toPaddedString(2) + ':' +
    this.getUTCMinutes().toPaddedString(2) + ':' +
    this.getUTCSeconds().toPaddedString(2) + 'Z"';
};

var Try = {
  these: function() {
    var returnValue;

    for (var i = 0, length = arguments.length; i < length; i++) {
      var lambda = arguments[i];
      try {
        returnValue = lambda();
        break;
      } catch (e) { }
    }

    return returnValue;
  }
};

RegExp.prototype.match = RegExp.prototype.test;

RegExp.escape = function(str) {
  return String(str).replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1');
};

/*--------------------------------------------------------------------------*/

var PeriodicalExecuter = Class.create({
  initialize: function(callback, frequency) {
    this.callback = callback;
    this.frequency = frequency;
    this.currentlyExecuting = false;

    this.registerCallback();
  },

  registerCallback: function() {
    this.timer = setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);
  },

  execute: function() {
    this.callback(this);
  },

  stop: function() {
    if (!this.timer) return;
    clearInterval(this.timer);
    this.timer = null;
  },

  onTimerEvent: function() {
    if (!this.currentlyExecuting) {
      try {
        this.currentlyExecuting = true;
        this.execute();
      } finally {
        this.currentlyExecuting = false;
      }
    }
  }
});
Object.extend(String, {
  interpret: function(value) {
    return value == null ? '' : String(value);
  },
  specialChar: {
    '\b': '\\b',
    '\t': '\\t',
    '\n': '\\n',
    '\f': '\\f',
    '\r': '\\r',
    '\\': '\\\\'
  }
});

Object.extend(String.prototype, {
  gsub: function(pattern, replacement) {
    var result = '', source = this, match;
    replacement = arguments.callee.prepareReplacement(replacement);

    while (source.length > 0) {
      if (match = source.match(pattern)) {
        result += source.slice(0, match.index);
        result += String.interpret(replacement(match));
        source  = source.slice(match.index + match[0].length);
      } else {
        result += source, source = '';
      }
    }
    return result;
  },

  sub: function(pattern, replacement, count) {
    replacement = this.gsub.prepareReplacement(replacement);
    count = count === undefined ? 1 : count;

    return this.gsub(pattern, function(match) {
      if (--count < 0) return match[0];
      return replacement(match);
    });
  },

  scan: function(pattern, iterator) {
    this.gsub(pattern, iterator);
    return String(this);
  },

  truncate: function(length, truncation) {
    length = length || 30;
    truncation = truncation === undefined ? '...' : truncation;
    return this.length > length ?
      this.slice(0, length - truncation.length) + truncation : String(this);
  },

  strip: function() {
    return this.replace(/^\s+/, '').replace(/\s+$/, '');
  },

  stripTags: function() {
    return this.replace(/<\/?[^>]+>/gi, '');
  },

  stripScripts: function() {
    return this.replace(new RegExp(Prototype.ScriptFragment, 'img'), '');
  },

  extractScripts: function() {
    var matchAll = new RegExp(Prototype.ScriptFragment, 'img');
    var matchOne = new RegExp(Prototype.ScriptFragment, 'im');
    return (this.match(matchAll) || []).map(function(scriptTag) {
      return (scriptTag.match(matchOne) || ['', ''])[1];
    });
  },

  evalScripts: function() {
    return this.extractScripts().map(function(script) { return eval(script) });
  },

  escapeHTML: function() {
    var self = arguments.callee;
    self.text.data = this;
    return self.div.innerHTML;
  },

  unescapeHTML: function() {
    var div = new Element('div');
    div.innerHTML = this.stripTags();
    return div.childNodes[0] ? (div.childNodes.length > 1 ?
      $A(div.childNodes).inject('', function(memo, node) { return memo+node.nodeValue }) :
      div.childNodes[0].nodeValue) : '';
  },

  toQueryParams: function(separator) {
    var match = this.strip().match(/([^?#]*)(#.*)?$/);
    if (!match) return { };

    return match[1].split(separator || '&').inject({ }, function(hash, pair) {
      if ((pair = pair.split('='))[0]) {
        var key = decodeURIComponent(pair.shift());
        var value = pair.length > 1 ? pair.join('=') : pair[0];
        if (value != undefined) value = decodeURIComponent(value);

        if (key in hash) {
          if (!Object.isArray(hash[key])) hash[key] = [hash[key]];
          hash[key].push(value);
        }
        else hash[key] = value;
      }
      return hash;
    });
  },

  toArray: function() {
    return this.split('');
  },

  succ: function() {
    return this.slice(0, this.length - 1) +
      String.fromCharCode(this.charCodeAt(this.length - 1) + 1);
  },

  times: function(count) {
    return count < 1 ? '' : new Array(count + 1).join(this);
  },

  camelize: function() {
    var parts = this.split('-'), len = parts.length;
    if (len == 1) return parts[0];

    var camelized = this.charAt(0) == '-'
      ? parts[0].charAt(0).toUpperCase() + parts[0].substring(1)
      : parts[0];

    for (var i = 1; i < len; i++)
      camelized += parts[i].charAt(0).toUpperCase() + parts[i].substring(1);

    return camelized;
  },

  capitalize: function() {
    return this.charAt(0).toUpperCase() + this.substring(1).toLowerCase();
  },

  underscore: function() {
    return this.gsub(/::/, '/').gsub(/([A-Z]+)([A-Z][a-z])/,'#{1}_#{2}').gsub(/([a-z\d])([A-Z])/,'#{1}_#{2}').gsub(/-/,'_').toLowerCase();
  },

  dasherize: function() {
    return this.gsub(/_/,'-');
  },

  inspect: function(useDoubleQuotes) {
    var escapedString = this.gsub(/[\x00-\x1f\\]/, function(match) {
      var character = String.specialChar[match[0]];
      return character ? character : '\\u00' + match[0].charCodeAt().toPaddedString(2, 16);
    });
    if (useDoubleQuotes) return '"' + escapedString.replace(/"/g, '\\"') + '"';
    return "'" + escapedString.replace(/'/g, '\\\'') + "'";
  },

  toJSON: function() {
    return this.inspect(true);
  },

  unfilterJSON: function(filter) {
    return this.sub(filter || Prototype.JSONFilter, '#{1}');
  },

  isJSON: function() {
    var str = this.replace(/\\./g, '@').replace(/"[^"\\\n\r]*"/g, '');
    return (/^[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]*$/).test(str);
  },

  evalJSON: function(sanitize) {
    var json = this.unfilterJSON();
    try {
      if (!sanitize || json.isJSON()) return eval('(' + json + ')');
    } catch (e) { }
    throw new SyntaxError('Badly formed JSON string: ' + this.inspect());
  },

  include: function(pattern) {
    return this.indexOf(pattern) > -1;
  },

  startsWith: function(pattern) {
    return this.indexOf(pattern) === 0;
  },

  endsWith: function(pattern) {
    var d = this.length - pattern.length;
    return d >= 0 && this.lastIndexOf(pattern) === d;
  },

  empty: function() {
    return this == '';
  },

  blank: function() {
    return /^\s*$/.test(this);
  },

  interpolate: function(object, pattern) {
    return new Template(this, pattern).evaluate(object);
  }
});

if (Prototype.Browser.WebKit || Prototype.Browser.IE) Object.extend(String.prototype, {
  escapeHTML: function() {
    return this.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');
  },
  unescapeHTML: function() {
    return this.replace(/&amp;/g,'&').replace(/&lt;/g,'<').replace(/&gt;/g,'>');
  }
});

String.prototype.gsub.prepareReplacement = function(replacement) {
  if (Object.isFunction(replacement)) return replacement;
  var template = new Template(replacement);
  return function(match) { return template.evaluate(match) };
};

String.prototype.parseQuery = String.prototype.toQueryParams;

Object.extend(String.prototype.escapeHTML, {
  div:  document.createElement('div'),
  text: document.createTextNode('')
});

with (String.prototype.escapeHTML) div.appendChild(text);

var Template = Class.create({
  initialize: function(template, pattern) {
    this.template = template.toString();
    this.pattern = pattern || Template.Pattern;
  },

  evaluate: function(object) {
    if (Object.isFunction(object.toTemplateReplacements))
      object = object.toTemplateReplacements();

    return this.template.gsub(this.pattern, function(match) {
      if (object == null) return '';

      var before = match[1] || '';
      if (before == '\\') return match[2];

      var ctx = object, expr = match[3];
      var pattern = /^([^.[]+|\[((?:.*?[^\\])?)\])(\.|\[|$)/, match = pattern.exec(expr);
      if (match == null) return before;

      while (match != null) {
        var comp = match[1].startsWith('[') ? match[2].gsub('\\\\]', ']') : match[1];
        ctx = ctx[comp];
        if (null == ctx || '' == match[3]) break;
        expr = expr.substring('[' == match[3] ? match[1].length : match[0].length);
        match = pattern.exec(expr);
      }

      return before + String.interpret(ctx);
    }.bind(this));
  }
});
Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/;

var $break = { };

var Enumerable = {
  each: function(iterator, context) {
    var index = 0;
    iterator = iterator.bind(context);
    try {
      this._each(function(value) {
        iterator(value, index++);
      });
    } catch (e) {
      if (e != $break) throw e;
    }
    return this;
  },

  eachSlice: function(number, iterator, context) {
    iterator = iterator ? iterator.bind(context) : Prototype.K;
    var index = -number, slices = [], array = this.toArray();
    while ((index += number) < array.length)
      slices.push(array.slice(index, index+number));
    return slices.collect(iterator, context);
  },

  all: function(iterator, context) {
    iterator = iterator ? iterator.bind(context) : Prototype.K;
    var result = true;
    this.each(function(value, index) {
      result = result && !!iterator(value, index);
      if (!result) throw $break;
    });
    return result;
  },

  any: function(iterator, context) {
    iterator = iterator ? iterator.bind(context) : Prototype.K;
    var result = false;
    this.each(function(value, index) {
      if (result = !!iterator(value, index))
        throw $break;
    });
    return result;
  },

  collect: function(iterator, context) {
    iterator = iterator ? iterator.bind(context) : Prototype.K;
    var results = [];
    this.each(function(value, index) {
      results.push(iterator(value, index));
    });
    return results;
  },

  detect: function(iterator, context) {
    iterator = iterator.bind(context);
    var result;
    this.each(function(value, index) {
      if (iterator(value, index)) {
        result = value;
        throw $break;
      }
    });
    return result;
  },

  findAll: function(iterator, context) {
    iterator = iterator.bind(context);
    var results = [];
    this.each(function(value, index) {
      if (iterator(value, index))
        results.push(value);
    });
    return results;
  },

  grep: function(filter, iterator, context) {
    iterator = iterator ? iterator.bind(context) : Prototype.K;
    var results = [];

    if (Object.isString(filter))
      filter = new RegExp(filter);

    this.each(function(value, index) {
      if (filter.match(value))
        results.push(iterator(value, index));
    });
    return results;
  },

  include: function(object) {
    if (Object.isFunction(this.indexOf))
      if (this.indexOf(object) != -1) return true;

    var found = false;
    this.each(function(value) {
      if (value == object) {
        found = true;
        throw $break;
      }
    });
    return found;
  },

  inGroupsOf: function(number, fillWith) {
    fillWith = fillWith === undefined ? null : fillWith;
    return this.eachSlice(number, function(slice) {
      while(slice.length < number) slice.push(fillWith);
      return slice;
    });
  },

  inject: function(memo, iterator, context) {
    iterator = iterator.bind(context);
    this.each(function(value, index) {
      memo = iterator(memo, value, index);
    });
    return memo;
  },

  invoke: function(method) {
    var args = $A(arguments).slice(1);
    return this.map(function(value) {
      return value[method].apply(value, args);
    });
  },

  max: function(iterator, context) {
    iterator = iterator ? iterator.bind(context) : Prototype.K;
    var result;
    this.each(function(value, index) {
      value = iterator(value, index);
      if (result == undefined || value >= result)
        result = value;
    });
    return result;
  },

  min: function(iterator, context) {
    iterator = iterator ? iterator.bind(context) : Prototype.K;
    var result;
    this.each(function(value, index) {
      value = iterator(value, index);
      if (result == undefined || value < result)
        result = value;
    });
    return result;
  },

  partition: function(iterator, context) {
    iterator = iterator ? iterator.bind(context) : Prototype.K;
    var trues = [], falses = [];
    this.each(function(value, index) {
      (iterator(value, index) ?
        trues : falses).push(value);
    });
    return [trues, falses];
  },

  pluck: function(property) {
    var results = [];
    this.each(function(value) {
      results.push(value[property]);
    });
    return results;
  },

  reject: function(iterator, context) {
    iterator = iterator.bind(context);
    var results = [];
    this.each(function(value, index) {
      if (!iterator(value, index))
        results.push(value);
    });
    return results;
  },

  sortBy: function(iterator, context) {
    iterator = iterator.bind(context);
    return this.map(function(value, index) {
      return {value: value, criteria: iterator(value, index)};
    }).sort(function(left, right) {
      var a = left.criteria, b = right.criteria;
      return a < b ? -1 : a > b ? 1 : 0;
    }).pluck('value');
  },

  toArray: function() {
    return this.map();
  },

  zip: function() {
    var iterator = Prototype.K, args = $A(arguments);
    if (Object.isFunction(args.last()))
      iterator = args.pop();

    var collections = [this].concat(args).map($A);
    return this.map(function(value, index) {
      return iterator(collections.pluck(index));
    });
  },

  size: function() {
    return this.toArray().length;
  },

  inspect: function() {
    return '#<Enumerable:' + this.toArray().inspect() + '>';
  }
};

Object.extend(Enumerable, {
  map:     Enumerable.collect,
  find:    Enumerable.detect,
  select:  Enumerable.findAll,
  filter:  Enumerable.findAll,
  member:  Enumerable.include,
  entries: Enumerable.toArray,
  every:   Enumerable.all,
  some:    Enumerable.any
});
function $A(iterable) {
  if (!iterable) return [];
  if (iterable.toArray) return iterable.toArray();
  var length = iterable.length, results = new Array(length);
  while (length--) results[length] = iterable[length];
  return results;
}

if (Prototype.Browser.WebKit) {
  function $A(iterable) {
    if (!iterable) return [];
    if (!(Object.isFunction(iterable) && iterable == '[object NodeList]') &&
        iterable.toArray) return iterable.toArray();
    var length = iterable.length, results = new Array(length);
    while (length--) results[length] = iterable[length];
    return results;
  }
}

Array.from = $A;

Object.extend(Array.prototype, Enumerable);

if (!Array.prototype._reverse) Array.prototype._reverse = Array.prototype.reverse;

Object.extend(Array.prototype, {
  _each: function(iterator) {
    for (var i = 0, length = this.length; i < length; i++)
      iterator(this[i]);
  },

  clear: function() {
    this.length = 0;
    return this;
  },

  first: function() {
    return this[0];
  },

  last: function() {
    return this[this.length - 1];
  },

  compact: function() {
    return this.select(function(value) {
      return value != null;
    });
  },

  flatten: function() {
    return this.inject([], function(array, value) {
      return array.concat(Object.isArray(value) ?
        value.flatten() : [value]);
    });
  },

  without: function() {
    var values = $A(arguments);
    return this.select(function(value) {
      return !values.include(value);
    });
  },

  reverse: function(inline) {
    return (inline !== false ? this : this.toArray())._reverse();
  },

  reduce: function() {
    return this.length > 1 ? this : this[0];
  },

  uniq: function(sorted) {
    return this.inject([], function(array, value, index) {
      if (0 == index || (sorted ? array.last() != value : !array.include(value)))
        array.push(value);
      return array;
    });
  },

  intersect: function(array) {
    return this.uniq().findAll(function(item) {
      return array.detect(function(value) { return item === value });
    });
  },

  clone: function() {
    return [].concat(this);
  },

  size: function() {
    return this.length;
  },

  inspect: function() {
    return '[' + this.map(Object.inspect).join(', ') + ']';
  },

  toJSON: function() {
    var results = [];
    this.each(function(object) {
      var value = Object.toJSON(object);
      if (value !== undefined) results.push(value);
    });
    return '[' + results.join(', ') + ']';
  }
});

// use native browser JS 1.6 implementation if available
if (Object.isFunction(Array.prototype.forEach))
  Array.prototype._each = Array.prototype.forEach;

if (!Array.prototype.indexOf) Array.prototype.indexOf = function(item, i) {
  i || (i = 0);
  var length = this.length;
  if (i < 0) i = length + i;
  for (; i < length; i++)
    if (this[i] === item) return i;
  return -1;
};

if (!Array.prototype.lastIndexOf) Array.prototype.lastIndexOf = function(item, i) {
  i = isNaN(i) ? this.length : (i < 0 ? this.length + i : i) + 1;
  var n = this.slice(0, i).reverse().indexOf(item);
  return (n < 0) ? n : i - n - 1;
};

Array.prototype.toArray = Array.prototype.clone;

function $w(string) {
  if (!Object.isString(string)) return [];
  string = string.strip();
  return string ? string.split(/\s+/) : [];
}

if (Prototype.Browser.Opera){
  Array.prototype.concat = function() {
    var array = [];
    for (var i = 0, length = this.length; i < length; i++) array.push(this[i]);
    for (var i = 0, length = arguments.length; i < length; i++) {
      if (Object.isArray(arguments[i])) {
        for (var j = 0, arrayLength = arguments[i].length; j < arrayLength; j++)
          array.push(arguments[i][j]);
      } else {
        array.push(arguments[i]);
      }
    }
    return array;
  };
}
Object.extend(Number.prototype, {
  toColorPart: function() {
    return this.toPaddedString(2, 16);
  },

  succ: function() {
    return this + 1;
  },

  times: function(iterator) {
    $R(0, this, true).each(iterator);
    return this;
  },

  toPaddedString: function(length, radix) {
    var string = this.toString(radix || 10);
    return '0'.times(length - string.length) + string;
  },

  toJSON: function() {
    return isFinite(this) ? this.toString() : 'null';
  }
});

$w('abs round ceil floor').each(function(method){
  Number.prototype[method] = Math[method].methodize();
});
function $H(object) {
  return new Hash(object);
};

var Hash = Class.create(Enumerable, (function() {
  if (function() {
    var i = 0, Test = function(value) { this.key = value };
    Test.prototype.key = 'foo';
    for (var property in new Test('bar')) i++;
    return i > 1;
  }()) {
    function each(iterator) {
      var cache = [];
      for (var key in this._object) {
        var value = this._object[key];
        if (cache.include(key)) continue;
        cache.push(key);
        var pair = [key, value];
        pair.key = key;
        pair.value = value;
        iterator(pair);
      }
    }
  } else {
    function each(iterator) {
      for (var key in this._object) {
        var value = this._object[key], pair = [key, value];
        pair.key = key;
        pair.value = value;
        iterator(pair);
      }
    }
  }

  function toQueryPair(key, value) {
    if (Object.isUndefined(value)) return key;
    return key + '=' + encodeURIComponent(String.interpret(value));
  }

  return {
    initialize: function(object) {
      this._object = Object.isHash(object) ? object.toObject() : Object.clone(object);
    },

    _each: each,

    set: function(key, value) {
      return this._object[key] = value;
    },

    get: function(key) {
      return this._object[key];
    },

    unset: function(key) {
      var value = this._object[key];
      delete this._object[key];
      return value;
    },

    toObject: function() {
      return Object.clone(this._object);
    },

    keys: function() {
      return this.pluck('key');
    },

    values: function() {
      return this.pluck('value');
    },

    index: function(value) {
      var match = this.detect(function(pair) {
        return pair.value === value;
      });
      return match && match.key;
    },

    merge: function(object) {
      return this.clone().update(object);
    },

    update: function(object) {
      return new Hash(object).inject(this, function(result, pair) {
        result.set(pair.key, pair.value);
        return result;
      });
    },

    toQueryString: function() {
      return this.map(function(pair) {
        var key = encodeURIComponent(pair.key), values = pair.value;

        if (values && typeof values == 'object') {
          if (Object.isArray(values))
            return values.map(toQueryPair.curry(key)).join('&');
        }
        return toQueryPair(key, values);
      }).join('&');
    },

    inspect: function() {
      return '#<Hash:{' + this.map(function(pair) {
        return pair.map(Object.inspect).join(': ');
      }).join(', ') + '}>';
    },

    toJSON: function() {
      return Object.toJSON(this.toObject());
    },

    clone: function() {
      return new Hash(this);
    }
  }
})());

Hash.prototype.toTemplateReplacements = Hash.prototype.toObject;
Hash.from = $H;
var ObjectRange = Class.create(Enumerable, {
  initialize: function(start, end, exclusive) {
    this.start = start;
    this.end = end;
    this.exclusive = exclusive;
  },

  _each: function(iterator) {
    var value = this.start;
    while (this.include(value)) {
      iterator(value);
      value = value.succ();
    }
  },

  include: function(value) {
    if (value < this.start)
      return false;
    if (this.exclusive)
      return value < this.end;
    return value <= this.end;
  }
});

var $R = function(start, end, exclusive) {
  return new ObjectRange(start, end, exclusive);
};

var Ajax = {
  getTransport: function() {
    return Try.these(
      function() {return new XMLHttpRequest()},
      function() {return new ActiveXObject('Msxml2.XMLHTTP')},
      function() {return new ActiveXObject('Microsoft.XMLHTTP')}
    ) || false;
  },

  activeRequestCount: 0
};

Ajax.Responders = {
  responders: [],

  _each: function(iterator) {
    this.responders._each(iterator);
  },

  register: function(responder) {
    if (!this.include(responder))
      this.responders.push(responder);
  },

  unregister: function(responder) {
    this.responders = this.responders.without(responder);
  },

  dispatch: function(callback, request, transport, json) {
    this.each(function(responder) {
      if (Object.isFunction(responder[callback])) {
        try {
          responder[callback].apply(responder, [request, transport, json]);
        } catch (e) { }
      }
    });
  }
};

Object.extend(Ajax.Responders, Enumerable);

Ajax.Responders.register({
  onCreate:   function() { Ajax.activeRequestCount++ },
  onComplete: function() { Ajax.activeRequestCount-- }
});

Ajax.Base = Class.create({
  initialize: function(options) {
    this.options = {
      method:       'post',
      asynchronous: true,
      contentType:  'application/x-www-form-urlencoded',
      encoding:     'UTF-8',
      parameters:   '',
      evalJSON:     true,
      evalJS:       true
    };
    Object.extend(this.options, options || { });

    this.options.method = this.options.method.toLowerCase();
    if (Object.isString(this.options.parameters))
      this.options.parameters = this.options.parameters.toQueryParams();
  }
});

Ajax.Request = Class.create(Ajax.Base, {
  _complete: false,

  initialize: function($super, url, options) {
    $super(options);
    this.transport = Ajax.getTransport();
    this.request(url);
  },

  request: function(url) {
    this.url = url;
    this.method = this.options.method;
    var params = Object.clone(this.options.parameters);

    if (!['get', 'post'].include(this.method)) {
      // simulate other verbs over post
      params['_method'] = this.method;
      this.method = 'post';
    }

    this.parameters = params;

    if (params = Object.toQueryString(params)) {
      // when GET, append parameters to URL
      if (this.method == 'get')
        this.url += (this.url.include('?') ? '&' : '?') + params;
      else if (/Konqueror|Safari|KHTML/.test(navigator.userAgent))
        params += '&_=';
    }

    try {
      var response = new Ajax.Response(this);
      if (this.options.onCreate) this.options.onCreate(response);
      Ajax.Responders.dispatch('onCreate', this, response);

      this.transport.open(this.method.toUpperCase(), this.url,
        this.options.asynchronous);

      if (this.options.asynchronous) this.respondToReadyState.bind(this).defer(1);

      this.transport.onreadystatechange = this.onStateChange.bind(this);
      this.setRequestHeaders();

      this.body = this.method == 'post' ? (this.options.postBody || params) : null;
      this.transport.send(this.body);

      /* Force Firefox to handle ready state 4 for synchronous requests */
      if (!this.options.asynchronous && this.transport.overrideMimeType)
        this.onStateChange();

    }
    catch (e) {
      this.dispatchException(e);
    }
  },

  onStateChange: function() {
    var readyState = this.transport.readyState;
    if (readyState > 1 && !((readyState == 4) && this._complete))
      this.respondToReadyState(this.transport.readyState);
  },

  setRequestHeaders: function() {
    var headers = {
      'X-Requested-With': 'XMLHttpRequest',
      'X-Prototype-Version': Prototype.Version,
      'Accept': 'text/javascript, text/html, application/xml, text/xml, */*'
    };

    if (this.method == 'post') {
      headers['Content-type'] = this.options.contentType +
        (this.options.encoding ? '; charset=' + this.options.encoding : '');

      /* Force "Connection: close" for older Mozilla browsers to work
       * around a bug where XMLHttpRequest sends an incorrect
       * Content-length header. See Mozilla Bugzilla #246651.
       */
      if (this.transport.overrideMimeType &&
          (navigator.userAgent.match(/Gecko\/(\d{4})/) || [0,2005])[1] < 2005)
            headers['Connection'] = 'close';
    }

    // user-defined headers
    if (typeof this.options.requestHeaders == 'object') {
      var extras = this.options.requestHeaders;

      if (Object.isFunction(extras.push))
        for (var i = 0, length = extras.length; i < length; i += 2)
          headers[extras[i]] = extras[i+1];
      else
        $H(extras).each(function(pair) { headers[pair.key] = pair.value });
    }

    for (var name in headers)
      this.transport.setRequestHeader(name, headers[name]);
  },

  success: function() {
    var status = this.getStatus();
    return !status || (status >= 200 && status < 300);
  },

  getStatus: function() {
    try {
      return this.transport.status || 0;
    } catch (e) { return 0 }
  },

  respondToReadyState: function(readyState) {
    var state = Ajax.Request.Events[readyState], response = new Ajax.Response(this);

    if (state == 'Complete') {
      try {
        this._complete = true;
        (this.options['on' + response.status]
         || this.options['on' + (this.success() ? 'Success' : 'Failure')]
         || Prototype.emptyFunction)(response, response.headerJSON);
      } catch (e) {
        this.dispatchException(e);
      }

      var contentType = response.getHeader('Content-type');
      if (this.options.evalJS == 'force'
          || (this.options.evalJS && contentType
          && contentType.match(/^\s*(text|application)\/(x-)?(java|ecma)script(;.*)?\s*$/i)))
        this.evalResponse();
    }

    try {
      (this.options['on' + state] || Prototype.emptyFunction)(response, response.headerJSON);
      Ajax.Responders.dispatch('on' + state, this, response, response.headerJSON);
    } catch (e) {
      this.dispatchException(e);
    }

    if (state == 'Complete') {
      // avoid memory leak in MSIE: clean up
      this.transport.onreadystatechange = Prototype.emptyFunction;
    }
  },

  getHeader: function(name) {
    try {
      return this.transport.getResponseHeader(name);
    } catch (e) { return null }
  },

  evalResponse: function() {
    try {
      return eval((this.transport.responseText || '').unfilterJSON());
    } catch (e) {
      this.dispatchException(e);
    }
  },

  dispatchException: function(exception) {
    (this.options.onException || Prototype.emptyFunction)(this, exception);
    Ajax.Responders.dispatch('onException', this, exception);
  }
});

Ajax.Request.Events =
  ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete'];

Ajax.Response = Class.create({
  initialize: function(request){
    this.request = request;
    var transport  = this.transport  = request.transport,
        readyState = this.readyState = transport.readyState;

    if((readyState > 2 && !Prototype.Browser.IE) || readyState == 4) {
      this.status       = this.getStatus();
      this.statusText   = this.getStatusText();
      this.responseText = String.interpret(transport.responseText);
      this.headerJSON   = this._getHeaderJSON();
    }

    if(readyState == 4) {
      var xml = transport.responseXML;
      this.responseXML  = xml === undefined ? null : xml;
      this.responseJSON = this._getResponseJSON();
    }
  },

  status:      0,
  statusText: '',

  getStatus: Ajax.Request.prototype.getStatus,

  getStatusText: function() {
    try {
      return this.transport.statusText || '';
    } catch (e) { return '' }
  },

  getHeader: Ajax.Request.prototype.getHeader,

  getAllHeaders: function() {
    try {
      return this.getAllResponseHeaders();
    } catch (e) { return null }
  },

  getResponseHeader: function(name) {
    return this.transport.getResponseHeader(name);
  },

  getAllResponseHeaders: function() {
    return this.transport.getAllResponseHeaders();
  },

  _getHeaderJSON: function() {
    var json = this.getHeader('X-JSON');
    if (!json) return null;
    json = decodeURIComponent(escape(json));
    try {
      return json.evalJSON(this.request.options.sanitizeJSON);
    } catch (e) {
      this.request.dispatchException(e);
    }
  },

  _getResponseJSON: function() {
    var options = this.request.options;
    if (!options.evalJSON || (options.evalJSON != 'force' &&
      !(this.getHeader('Content-type') || '').include('application/json')))
        return null;
    try {
      return this.transport.responseText.evalJSON(options.sanitizeJSON);
    } catch (e) {
      this.request.dispatchException(e);
    }
  }
});

Ajax.Updater = Class.create(Ajax.Request, {
  initialize: function($super, container, url, options) {
    this.container = {
      success: (container.success || container),
      failure: (container.failure || (container.success ? null : container))
    };

    options = options || { };
    var onComplete = options.onComplete;
    options.onComplete = (function(response, param) {
      this.updateContent(response.responseText);
      if (Object.isFunction(onComplete)) onComplete(response, param);
    }).bind(this);

    $super(url, options);
  },

  updateContent: function(responseText) {
    var receiver = this.container[this.success() ? 'success' : 'failure'],
        options = this.options;

    if (!options.evalScripts) responseText = responseText.stripScripts();

    if (receiver = $(receiver)) {
      if (options.insertion) {
        if (Object.isString(options.insertion)) {
          var insertion = { }; insertion[options.insertion] = responseText;
          receiver.insert(insertion);
        }
        else options.insertion(receiver, responseText);
      }
      else receiver.update(responseText);
    }

    if (this.success()) {
      if (this.onComplete) this.onComplete.bind(this).defer();
    }
  }
});

Ajax.PeriodicalUpdater = Class.create(Ajax.Base, {
  initialize: function($super, container, url, options) {
    $super(options);
    this.onComplete = this.options.onComplete;

    this.frequency = (this.options.frequency || 2);
    this.decay = (this.options.decay || 1);

    this.updater = { };
    this.container = container;
    this.url = url;

    this.start();
  },

  start: function() {
    this.options.onComplete = this.updateComplete.bind(this);
    this.onTimerEvent();
  },

  stop: function() {
    this.updater.options.onComplete = undefined;
    clearTimeout(this.timer);
    (this.onComplete || Prototype.emptyFunction).apply(this, arguments);
  },

  updateComplete: function(response) {
    if (this.options.decay) {
      this.decay = (response.responseText == this.lastText ?
        this.decay * this.options.decay : 1);

      this.lastText = response.responseText;
    }
    this.timer = this.onTimerEvent.bind(this).delay(this.decay * this.frequency);
  },

  onTimerEvent: function() {
    this.updater = new Ajax.Updater(this.container, this.url, this.options);
  }
});
function $(element) {
  if (arguments.length > 1) {
    for (var i = 0, elements = [], length = arguments.length; i < length; i++)
      elements.push($(arguments[i]));
    return elements;
  }
  if (Object.isString(element))
    element = document.getElementById(element);
  return Element.extend(element);
}

if (Prototype.BrowserFeatures.XPath) {
  document._getElementsByXPath = function(expression, parentElement) {
    var results = [];
    var query = document.evaluate(expression, $(parentElement) || document,
      null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
    for (var i = 0, length = query.snapshotLength; i < length; i++)
      results.push(Element.extend(query.snapshotItem(i)));
    return results;
  };
}

/*--------------------------------------------------------------------------*/

if (!window.Node) var Node = { };

if (!Node.ELEMENT_NODE) {
  // DOM level 2 ECMAScript Language Binding
  Object.extend(Node, {
    ELEMENT_NODE: 1,
    ATTRIBUTE_NODE: 2,
    TEXT_NODE: 3,
    CDATA_SECTION_NODE: 4,
    ENTITY_REFERENCE_NODE: 5,
    ENTITY_NODE: 6,
    PROCESSING_INSTRUCTION_NODE: 7,
    COMMENT_NODE: 8,
    DOCUMENT_NODE: 9,
    DOCUMENT_TYPE_NODE: 10,
    DOCUMENT_FRAGMENT_NODE: 11,
    NOTATION_NODE: 12
  });
}

(function() {
  var element = this.Element;
  this.Element = function(tagName, attributes) {
    attributes = attributes || { };
    tagName = tagName.toLowerCase();
    var cache = Element.cache;
    if (Prototype.Browser.IE && attributes.name) {
      tagName = '<' + tagName + ' name="' + attributes.name + '">';
      delete attributes.name;
      return Element.writeAttribute(document.createElement(tagName), attributes);
    }
    if (!cache[tagName]) cache[tagName] = Element.extend(document.createElement(tagName));
    return Element.writeAttribute(cache[tagName].cloneNode(false), attributes);
  };
  Object.extend(this.Element, element || { });
}).call(window);

Element.cache = { };

Element.Methods = {
  visible: function(element) {
    return $(element).style.display != 'none';
  },

  toggle: function(element) {
    element = $(element);
    Element[Element.visible(element) ? 'hide' : 'show'](element);
    return element;
  },

  hide: function(element) {
    $(element).style.display = 'none';
    return element;
  },

  show: function(element) {
    $(element).style.display = '';
    return element;
  },

  remove: function(element) {
    element = $(element);
    element.parentNode.removeChild(element);
    return element;
  },

  update: function(element, content) {
    element = $(element);
    if (content && content.toElement) content = content.toElement();
    if (Object.isElement(content)) return element.update().insert(content);
    content = Object.toHTML(content);
    element.innerHTML = content.stripScripts();
    content.evalScripts.bind(content).defer();
    return element;
  },

  replace: function(element, content) {
    element = $(element);
    if (content && content.toElement) content = content.toElement();
    else if (!Object.isElement(content)) {
      content = Object.toHTML(content);
      var range = element.ownerDocument.createRange();
      range.selectNode(element);
      content.evalScripts.bind(content).defer();
      content = range.createContextualFragment(content.stripScripts());
    }
    element.parentNode.replaceChild(content, element);
    return element;
  },

  insert: function(element, insertions) {
    element = $(element);

    if (Object.isString(insertions) || Object.isNumber(insertions) ||
        Object.isElement(insertions) || (insertions && (insertions.toElement || insertions.toHTML)))
          insertions = {bottom:insertions};

    var content, t, range;

    for (position in insertions) {
      content  = insertions[position];
      position = position.toLowerCase();
      t = Element._insertionTranslations[position];

      if (content && content.toElement) content = content.toElement();
      if (Object.isElement(content)) {
        t.insert(element, content);
        continue;
      }

      content = Object.toHTML(content);

      range = element.ownerDocument.createRange();
      t.initializeRange(element, range);
      t.insert(element, range.createContextualFragment(content.stripScripts()));

      content.evalScripts.bind(content).defer();
    }

    return element;
  },

  wrap: function(element, wrapper, attributes) {
    element = $(element);
    if (Object.isElement(wrapper))
      $(wrapper).writeAttribute(attributes || { });
    else if (Object.isString(wrapper)) wrapper = new Element(wrapper, attributes);
    else wrapper = new Element('div', wrapper);
    if (element.parentNode)
      element.parentNode.replaceChild(wrapper, element);
    wrapper.appendChild(element);
    return wrapper;
  },

  inspect: function(element) {
    element = $(element);
    var result = '<' + element.tagName.toLowerCase();
    $H({'id': 'id', 'className': 'class'}).each(function(pair) {
      var property = pair.first(), attribute = pair.last();
      var value = (element[property] || '').toString();
      if (value) result += ' ' + attribute + '=' + value.inspect(true);
    });
    return result + '>';
  },

  recursivelyCollect: function(element, property) {
    element = $(element);
    var elements = [];
    while (element = element[property])
      if (element.nodeType == 1)
        elements.push(Element.extend(element));
    return elements;
  },

  ancestors: function(element) {
    return $(element).recursivelyCollect('parentNode');
  },

  descendants: function(element) {
    return $A($(element).getElementsByTagName('*')).each(Element.extend);
  },

  firstDescendant: function(element) {
    element = $(element).firstChild;
    while (element && element.nodeType != 1) element = element.nextSibling;
    return $(element);
  },

  immediateDescendants: function(element) {
    if (!(element = $(element).firstChild)) return [];
    while (element && element.nodeType != 1) element = element.nextSibling;
    if (element) return [element].concat($(element).nextSiblings());
    return [];
  },

  previousSiblings: function(element) {
    return $(element).recursivelyCollect('previousSibling');
  },

  nextSiblings: function(element) {
    return $(element).recursivelyCollect('nextSibling');
  },

  siblings: function(element) {
    element = $(element);
    return element.previousSiblings().reverse().concat(element.nextSiblings());
  },

  match: function(element, selector) {
    if (Object.isString(selector))
      selector = new Selector(selector);
    return selector.match($(element));
  },

  up: function(element, expression, index) {
    element = $(element);
    if (arguments.length == 1) return $(element.parentNode);
    var ancestors = element.ancestors();
    return expression ? Selector.findElement(ancestors, expression, index) :
      ancestors[index || 0];
  },

  down: function(element, expression, index) {
    element = $(element);
    if (arguments.length == 1) return element.firstDescendant();
    var descendants = element.descendants();
    return expression ? Selector.findElement(descendants, expression, index) :
      descendants[index || 0];
  },

  previous: function(element, expression, index) {
    element = $(element);
    if (arguments.length == 1) return $(Selector.handlers.previousElementSibling(element));
    var previousSiblings = element.previousSiblings();
    return expression ? Selector.findElement(previousSiblings, expression, index) :
      previousSiblings[index || 0];
  },

  next: function(element, expression, index) {
    element = $(element);
    if (arguments.length == 1) return $(Selector.handlers.nextElementSibling(element));
    var nextSiblings = element.nextSiblings();
    return expression ? Selector.findElement(nextSiblings, expression, index) :
      nextSiblings[index || 0];
  },

  select: function() {
    var args = $A(arguments), element = $(args.shift());
    return Selector.findChildElements(element, args);
  },

  adjacent: function() {
    var args = $A(arguments), element = $(args.shift());
    return Selector.findChildElements(element.parentNode, args).without(element);
  },

  identify: function(element) {
    element = $(element);
    var id = element.readAttribute('id'), self = arguments.callee;
    if (id) return id;
    do { id = 'anonymous_element_' + self.counter++ } while ($(id));
    element.writeAttribute('id', id);
    return id;
  },

  readAttribute: function(element, name) {
    element = $(element);
    if (Prototype.Browser.IE) {
      var t = Element._attributeTranslations.read;
      if (t.values[name]) return t.values[name](element, name);
      if (t.names[name]) name = t.names[name];
      if (name.include(':')) {
        return (!element.attributes || !element.attributes[name]) ? null :
         element.attributes[name].value;
      }
    }
    return element.getAttribute(name);
  },

  writeAttribute: function(element, name, value) {
    element = $(element);
    var attributes = { }, t = Element._attributeTranslations.write;

    if (typeof name == 'object') attributes = name;
    else attributes[name] = value === undefined ? true : value;

    for (var attr in attributes) {
      var name = t.names[attr] || attr, value = attributes[attr];
      if (t.values[attr]) name = t.values[attr](element, value);
      if (value === false || value === null)
        element.removeAttribute(name);
      else if (value === true)
        element.setAttribute(name, name);
      else element.setAttribute(name, value);
    }
    return element;
  },

  getHeight: function(element) {
    return $(element).getDimensions().height;
  },

  getWidth: function(element) {
    return $(element).getDimensions().width;
  },

  classNames: function(element) {
    return new Element.ClassNames(element);
  },

  hasClassName: function(element, className) {
    if (!(element = $(element))) return;
    var elementClassName = element.className;
    return (elementClassName.length > 0 && (elementClassName == className ||
      new RegExp("(^|\\s)" + className + "(\\s|$)").test(elementClassName)));
  },

  addClassName: function(element, className) {
    if (!(element = $(element))) return;
    if (!element.hasClassName(className))
      element.className += (element.className ? ' ' : '') + className;
    return element;
  },

  removeClassName: function(element, className) {
    if (!(element = $(element))) return;
    element.className = element.className.replace(
      new RegExp("(^|\\s+)" + className + "(\\s+|$)"), ' ').strip();
    return element;
  },

  toggleClassName: function(element, className) {
    if (!(element = $(element))) return;
    return element[element.hasClassName(className) ?
      'removeClassName' : 'addClassName'](className);
  },

  // removes whitespace-only text node children
  cleanWhitespace: function(element) {
    element = $(element);
    var node = element.firstChild;
    while (node) {
      var nextNode = node.nextSibling;
      if (node.nodeType == 3 && !/\S/.test(node.nodeValue))
        element.removeChild(node);
      node = nextNode;
    }
    return element;
  },

  empty: function(element) {
    return $(element).innerHTML.blank();
  },

  descendantOf: function(element, ancestor) {
    element = $(element), ancestor = $(ancestor);

    if (element.compareDocumentPosition)
      return (element.compareDocumentPosition(ancestor) & 8) === 8;

    if (element.sourceIndex && !Prototype.Browser.Opera) {
      var e = element.sourceIndex, a = ancestor.sourceIndex,
       nextAncestor = ancestor.nextSibling;
      if (!nextAncestor) {
        do { ancestor = ancestor.parentNode; }
        while (!(nextAncestor = ancestor.nextSibling) && ancestor.parentNode);
      }
      if (nextAncestor) return (e > a && e < nextAncestor.sourceIndex);
    }

    while (element = element.parentNode)
      if (element == ancestor) return true;
    return false;
  },

  scrollTo: function(element) {
    element = $(element);
    var pos = element.cumulativeOffset();
    window.scrollTo(pos[0], pos[1]);
    return element;
  },

  getStyle: function(element, style) {
    element = $(element);
    style = style == 'float' ? 'cssFloat' : style.camelize();
    var value = element.style[style];
    if (!value) {
      var css = document.defaultView.getComputedStyle(element, null);
      value = css ? css[style] : null;
    }
    if (style == 'opacity') return value ? parseFloat(value) : 1.0;
    return value == 'auto' ? null : value;
  },

  getOpacity: function(element) {
    return $(element).getStyle('opacity');
  },

  setStyle: function(element, styles) {
    element = $(element);
    var elementStyle = element.style, match;
    if (Object.isString(styles)) {
      element.style.cssText += ';' + styles;
      return styles.include('opacity') ?
        element.setOpacity(styles.match(/opacity:\s*(\d?\.?\d*)/)[1]) : element;
    }
    for (var property in styles)
      if (property == 'opacity') element.setOpacity(styles[property]);
      else
        elementStyle[(property == 'float' || property == 'cssFloat') ?
          (elementStyle.styleFloat === undefined ? 'cssFloat' : 'styleFloat') :
            property] = styles[property];

    return element;
  },

  setOpacity: function(element, value) {
    element = $(element);
    element.style.opacity = (value == 1 || value === '') ? '' :
      (value < 0.00001) ? 0 : value;
    return element;
  },

  getDimensions: function(element) {
    element = $(element);
    var display = $(element).getStyle('display');
    if (display != 'none' && display != null) // Safari bug
      return {width: element.offsetWidth, height: element.offsetHeight};

    // All *Width and *Height properties give 0 on elements with display none,
    // so enable the element temporarily
    var els = element.style;
    var originalVisibility = els.visibility;
    var originalPosition = els.position;
    var originalDisplay = els.display;
    els.visibility = 'hidden';
    els.position = 'absolute';
    els.display = 'block';
    var originalWidth = element.clientWidth;
    var originalHeight = element.clientHeight;
    els.display = originalDisplay;
    els.position = originalPosition;
    els.visibility = originalVisibility;
    return {width: originalWidth, height: originalHeight};
  },

  makePositioned: function(element) {
    element = $(element);
    var pos = Element.getStyle(element, 'position');
    if (pos == 'static' || !pos) {
      element._madePositioned = true;
      element.style.position = 'relative';
      // Opera returns the offset relative to the positioning context, when an
      // element is position relative but top and left have not been defined
      if (window.opera) {
        element.style.top = 0;
        element.style.left = 0;
      }
    }
    return element;
  },

  undoPositioned: function(element) {
    element = $(element);
    if (element._madePositioned) {
      element._madePositioned = undefined;
      element.style.position =
        element.style.top =
        element.style.left =
        element.style.bottom =
        element.style.right = '';
    }
    return element;
  },

  makeClipping: function(element) {
    element = $(element);
    if (element._overflow) return element;
    element._overflow = Element.getStyle(element, 'overflow') || 'auto';
    if (element._overflow !== 'hidden')
      element.style.overflow = 'hidden';
    return element;
  },

  undoClipping: function(element) {
    element = $(element);
    if (!element._overflow) return element;
    element.style.overflow = element._overflow == 'auto' ? '' : element._overflow;
    element._overflow = null;
    return element;
  },

  cumulativeOffset: function(element) {
    var valueT = 0, valueL = 0;
    do {
      valueT += element.offsetTop  || 0;
      valueL += element.offsetLeft || 0;
      element = element.offsetParent;
    } while (element);
    return Element._returnOffset(valueL, valueT);
  },

  positionedOffset: function(element) {
    var valueT = 0, valueL = 0;
    do {
      valueT += element.offsetTop  || 0;
      valueL += element.offsetLeft || 0;
      element = element.offsetParent;
      if (element) {
        if (element.tagName == 'BODY') break;
        var p = Element.getStyle(element, 'position');
        if (p == 'relative' || p == 'absolute') break;
      }
    } while (element);
    return Element._returnOffset(valueL, valueT);
  },

  absolutize: function(element) {
    element = $(element);
    if (element.getStyle('position') == 'absolute') return;
    // Position.prepare(); // To be done manually by Scripty when it needs it.

    var offsets = element.positionedOffset();
    var top     = offsets[1];
    var left    = offsets[0];
    var width   = element.clientWidth;
    var height  = element.clientHeight;

    element._originalLeft   = left - parseFloat(element.style.left  || 0);
    element._originalTop    = top  - parseFloat(element.style.top || 0);
    element._originalWidth  = element.style.width;
    element._originalHeight = element.style.height;

    element.style.position = 'absolute';
    element.style.top    = top + 'px';
    element.style.left   = left + 'px';
    element.style.width  = width + 'px';
    element.style.height = height + 'px';
    return element;
  },

  relativize: function(element) {
    element = $(element);
    if (element.getStyle('position') == 'relative') return;
    // Position.prepare(); // To be done manually by Scripty when it needs it.

    element.style.position = 'relative';
    var top  = parseFloat(element.style.top  || 0) - (element._originalTop || 0);
    var left = parseFloat(element.style.left || 0) - (element._originalLeft || 0);

    element.style.top    = top + 'px';
    element.style.left   = left + 'px';
    element.style.height = element._originalHeight;
    element.style.width  = element._originalWidth;
    return element;
  },

  cumulativeScrollOffset: function(element) {
    var valueT = 0, valueL = 0;
    do {
      valueT += element.scrollTop  || 0;
      valueL += element.scrollLeft || 0;
      element = element.parentNode;
    } while (element);
    return Element._returnOffset(valueL, valueT);
  },

  getOffsetParent: function(element) {
    if (element.offsetParent) return $(element.offsetParent);
    if (element == document.body) return $(element);

    while ((element = element.parentNode) && element != document.body)
      if (Element.getStyle(element, 'position') != 'static')
        return $(element);

    return $(document.body);
  },

  viewportOffset: function(forElement) {
    var valueT = 0, valueL = 0;

    var element = forElement;
    do {
      valueT += element.offsetTop  || 0;
      valueL += element.offsetLeft || 0;

      // Safari fix
      if (element.offsetParent == document.body &&
        Element.getStyle(element, 'position') == 'absolute') break;

    } while (element = element.offsetParent);

    element = forElement;
    do {
      if (!Prototype.Browser.Opera || element.tagName == 'BODY') {
        valueT -= element.scrollTop  || 0;
        valueL -= element.scrollLeft || 0;
      }
    } while (element = element.parentNode);

    return Element._returnOffset(valueL, valueT);
  },

  clonePosition: function(element, source) {
    var options = Object.extend({
      setLeft:    true,
      setTop:     true,
      setWidth:   true,
      setHeight:  true,
      offsetTop:  0,
      offsetLeft: 0
    }, arguments[2] || { });

    // find page position of source
    source = $(source);
    var p = source.viewportOffset();

    // find coordinate system to use
    element = $(element);
    var delta = [0, 0];
    var parent = null;
    // delta [0,0] will do fine with position: fixed elements,
    // position:absolute needs offsetParent deltas
    if (Element.getStyle(element, 'position') == 'absolute') {
      parent = element.getOffsetParent();
      delta = parent.viewportOffset();
    }

    // correct by body offsets (fixes Safari)
    if (parent == document.body) {
      delta[0] -= document.body.offsetLeft;
      delta[1] -= document.body.offsetTop;
    }

    // set position
    if (options.setLeft)   element.style.left  = (p[0] - delta[0] + options.offsetLeft) + 'px';
    if (options.setTop)    element.style.top   = (p[1] - delta[1] + options.offsetTop) + 'px';
    if (options.setWidth)  element.style.width = source.offsetWidth + 'px';
    if (options.setHeight) element.style.height = source.offsetHeight + 'px';
    return element;
  }
};

Element.Methods.identify.counter = 1;

Object.extend(Element.Methods, {
  getElementsBySelector: Element.Methods.select,
  childElements: Element.Methods.immediateDescendants
});

Element._attributeTranslations = {
  write: {
    names: {
      className: 'class',
      htmlFor:   'for'
    },
    values: { }
  }
};


if (!document.createRange || Prototype.Browser.Opera) {
  Element.Methods.insert = function(element, insertions) {
    element = $(element);

    if (Object.isString(insertions) || Object.isNumber(insertions) ||
        Object.isElement(insertions) || (insertions && (insertions.toElement || insertions.toHTML)))
          insertions = { bottom: insertions };

    var t = Element._insertionTranslations, content, position, pos, tagName;

    for (position in insertions) {
      content  = insertions[position];
      position = position.toLowerCase();
      pos      = t[position];

      if (content && content.toElement) content = content.toElement();
      if (Object.isElement(content)) {
        pos.insert(element, content);
        continue;
      }

      content = Object.toHTML(content);
      tagName = ((position == 'before' || position == 'after')
        ? element.parentNode : element).tagName.toUpperCase();

      if (t.tags[tagName]) {
        var fragments = Element._getContentFromAnonymousElement(tagName, content.stripScripts());
        if (position == 'top' || position == 'after') fragments.reverse();
        fragments.each(pos.insert.curry(element));
      }
      else element.insertAdjacentHTML(pos.adjacency, content.stripScripts());

      content.evalScripts.bind(content).defer();
    }

    return element;
  };
}

if (Prototype.Browser.Opera) {
  Element.Methods._getStyle = Element.Methods.getStyle;
  Element.Methods.getStyle = function(element, style) {
    switch(style) {
      case 'left':
      case 'top':
      case 'right':
      case 'bottom':
        if (Element._getStyle(element, 'position') == 'static') return null;
      default: return Element._getStyle(element, style);
    }
  };
  Element.Methods._readAttribute = Element.Methods.readAttribute;
  Element.Methods.readAttribute = function(element, attribute) {
    if (attribute == 'title') return element.title;
    return Element._readAttribute(element, attribute);
  };
}

else if (Prototype.Browser.IE) {
  $w('positionedOffset getOffsetParent viewportOffset').each(function(method) {
    Element.Methods[method] = Element.Methods[method].wrap(
      function(proceed, element) {
        element = $(element);
        var position = element.getStyle('position');
        if (position != 'static') return proceed(element);
        element.setStyle({ position: 'relative' });
        var value = proceed(element);
        element.setStyle({ position: position });
        return value;
      }
    );
  });

  Element.Methods.getStyle = function(element, style) {
    element = $(element);
    style = (style == 'float' || style == 'cssFloat') ? 'styleFloat' : style.camelize();
    var value = element.style[style];
    if (!value && element.currentStyle) value = element.currentStyle[style];

    if (style == 'opacity') {
      if (value = (element.getStyle('filter') || '').match(/alpha\(opacity=(.*)\)/))
        if (value[1]) return parseFloat(value[1]) / 100;
      return 1.0;
    }

    if (value == 'auto') {
      if ((style == 'width' || style == 'height') && (element.getStyle('display') != 'none'))
        return element['offset' + style.capitalize()] + 'px';
      return null;
    }
    return value;
  };

  Element.Methods.setOpacity = function(element, value) {
    function stripAlpha(filter){
      return filter.replace(/alpha\([^\)]*\)/gi,'');
    }
    element = $(element);
    var currentStyle = element.currentStyle;
    if ((currentStyle && !currentStyle.hasLayout) ||
      (!currentStyle && element.style.zoom == 'normal'))
        element.style.zoom = 1;

    var filter = element.getStyle('filter'), style = element.style;
    if (value == 1 || value === '') {
      (filter = stripAlpha(filter)) ?
        style.filter = filter : style.removeAttribute('filter');
      return element;
    } else if (value < 0.00001) value = 0;
    style.filter = stripAlpha(filter) +
      'alpha(opacity=' + (value * 100) + ')';
    return element;
  };

  Element._attributeTranslations = {
    read: {
      names: {
        'class': 'className',
        'for':   'htmlFor'
      },
      values: {
        _getAttr: function(element, attribute) {
          return element.getAttribute(attribute, 2);
        },
        _getAttrNode: function(element, attribute) {
          var node = element.getAttributeNode(attribute);
          return node ? node.value : "";
        },
        _getEv: function(element, attribute) {
          var attribute = element.getAttribute(attribute);
          return attribute ? attribute.toString().slice(23, -2) : null;
        },
        _flag: function(element, attribute) {
          return $(element).hasAttribute(attribute) ? attribute : null;
        },
        style: function(element) {
          return element.style.cssText.toLowerCase();
        },
        title: function(element) {
          return element.title;
        }
      }
    }
  };

  Element._attributeTranslations.write = {
    names: Object.clone(Element._attributeTranslations.read.names),
    values: {
      checked: function(element, value) {
        element.checked = !!value;
      },

      style: function(element, value) {
        element.style.cssText = value ? value : '';
      }
    }
  };

  Element._attributeTranslations.has = {};

  $w('colSpan rowSpan vAlign dateTime accessKey tabIndex ' +
      'encType maxLength readOnly longDesc').each(function(attr) {
    Element._attributeTranslations.write.names[attr.toLowerCase()] = attr;
    Element._attributeTranslations.has[attr.toLowerCase()] = attr;
  });

  (function(v) {
    Object.extend(v, {
      href:        v._getAttr,
      src:         v._getAttr,
      type:        v._getAttr,
      action:      v._getAttrNode,
      disabled:    v._flag,
      checked:     v._flag,
      readonly:    v._flag,
      multiple:    v._flag,
      onload:      v._getEv,
      onunload:    v._getEv,
      onclick:     v._getEv,
      ondblclick:  v._getEv,
      onmousedown: v._getEv,
      onmouseup:   v._getEv,
      onmouseover: v._getEv,
      onmousemove: v._getEv,
      onmouseout:  v._getEv,
      onfocus:     v._getEv,
      onblur:      v._getEv,
      onkeypress:  v._getEv,
      onkeydown:   v._getEv,
      onkeyup:     v._getEv,
      onsubmit:    v._getEv,
      onreset:     v._getEv,
      onselect:    v._getEv,
      onchange:    v._getEv
    });
  })(Element._attributeTranslations.read.values);
}

else if (Prototype.Browser.Gecko && /rv:1\.8\.0/.test(navigator.userAgent)) {
  Element.Methods.setOpacity = function(element, value) {
    element = $(element);
    element.style.opacity = (value == 1) ? 0.999999 :
      (value === '') ? '' : (value < 0.00001) ? 0 : value;
    return element;
  };
}

else if (Prototype.Browser.WebKit) {
  Element.Methods.setOpacity = function(element, value) {
    element = $(element);
    element.style.opacity = (value == 1 || value === '') ? '' :
      (value < 0.00001) ? 0 : value;

    if (value == 1)
      if(element.tagName == 'IMG' && element.width) {
        element.width++; element.width--;
      } else try {
        var n = document.createTextNode(' ');
        element.appendChild(n);
        element.removeChild(n);
      } catch (e) { }

    return element;
  };

  // Safari returns margins on body which is incorrect if the child is absolutely
  // positioned.  For performance reasons, redefine Position.cumulativeOffset for
  // KHTML/WebKit only.
  Element.Methods.cumulativeOffset = function(element) {
    var valueT = 0, valueL = 0;
    do {
      valueT += element.offsetTop  || 0;
      valueL += element.offsetLeft || 0;
      if (element.offsetParent == document.body)
        if (Element.getStyle(element, 'position') == 'absolute') break;

      element = element.offsetParent;
    } while (element);

    return Element._returnOffset(valueL, valueT);
  };
}

if (Prototype.Browser.IE || Prototype.Browser.Opera) {
  // IE and Opera are missing .innerHTML support for TABLE-related and SELECT elements
  Element.Methods.update = function(element, content) {
    element = $(element);

    if (content && content.toElement) content = content.toElement();
    if (Object.isElement(content)) return element.update().insert(content);

    content = Object.toHTML(content);
    var tagName = element.tagName.toUpperCase();

    if (tagName in Element._insertionTranslations.tags) {
      $A(element.childNodes).each(function(node) { element.removeChild(node) });
      Element._getContentFromAnonymousElement(tagName, content.stripScripts())
        .each(function(node) { element.appendChild(node) });
    }
    else element.innerHTML = content.stripScripts();

    content.evalScripts.bind(content).defer();
    return element;
  };
}

if (document.createElement('div').outerHTML) {
  Element.Methods.replace = function(element, content) {
    element = $(element);

    if (content && content.toElement) content = content.toElement();
    if (Object.isElement(content)) {
      element.parentNode.replaceChild(content, element);
      return element;
    }

    content = Object.toHTML(content);
    var parent = element.parentNode, tagName = parent.tagName.toUpperCase();

    if (Element._insertionTranslations.tags[tagName]) {
      var nextSibling = element.next();
      var fragments = Element._getContentFromAnonymousElement(tagName, content.stripScripts());
      parent.removeChild(element);
      if (nextSibling)
        fragments.each(function(node) { parent.insertBefore(node, nextSibling) });
      else
        fragments.each(function(node) { parent.appendChild(node) });
    }
    else element.outerHTML = content.stripScripts();

    content.evalScripts.bind(content).defer();
    return element;
  };
}

Element._returnOffset = function(l, t) {
  var result = [l, t];
  result.left = l;
  result.top = t;
  return result;
};

Element._getContentFromAnonymousElement = function(tagName, html) {
  var div = new Element('div'), t = Element._insertionTranslations.tags[tagName];
  div.innerHTML = t[0] + html + t[1];
  t[2].times(function() { div = div.firstChild });
  return $A(div.childNodes);
};

Element._insertionTranslations = {
  before: {
    adjacency: 'beforeBegin',
    insert: function(element, node) {
      element.parentNode.insertBefore(node, element);
    },
    initializeRange: function(element, range) {
      range.setStartBefore(element);
    }
  },
  top: {
    adjacency: 'afterBegin',
    insert: function(element, node) {
      element.insertBefore(node, element.firstChild);
    },
    initializeRange: function(element, range) {
      range.selectNodeContents(element);
      range.collapse(true);
    }
  },
  bottom: {
    adjacency: 'beforeEnd',
    insert: function(element, node) {
      element.appendChild(node);
    }
  },
  after: {
    adjacency: 'afterEnd',
    insert: function(element, node) {
      element.parentNode.insertBefore(node, element.nextSibling);
    },
    initializeRange: function(element, range) {
      range.setStartAfter(element);
    }
  },
  tags: {
    TABLE:  ['<table>',                '</table>',                   1],
    TBODY:  ['<table><tbody>',         '</tbody></table>',           2],
    TR:     ['<table><tbody><tr>',     '</tr></tbody></table>',      3],
    TD:     ['<table><tbody><tr><td>', '</td></tr></tbody></table>', 4],
    SELECT: ['<select>',               '</select>',                  1]
  }
};

(function() {
  this.bottom.initializeRange = this.top.initializeRange;
  Object.extend(this.tags, {
    THEAD: this.tags.TBODY,
    TFOOT: this.tags.TBODY,
    TH:    this.tags.TD
  });
}).call(Element._insertionTranslations);

Element.Methods.Simulated = {
  hasAttribute: function(element, attribute) {
    attribute = Element._attributeTranslations.has[attribute] || attribute;
    var node = $(element).getAttributeNode(attribute);
    return node && node.specified;
  }
};

Element.Methods.ByTag = { };

Object.extend(Element, Element.Methods);

if (!Prototype.BrowserFeatures.ElementExtensions &&
    document.createElement('div').__proto__) {
  window.HTMLElement = { };
  window.HTMLElement.prototype = document.createElement('div').__proto__;
  Prototype.BrowserFeatures.ElementExtensions = true;
}

Element.extend = (function() {
  if (Prototype.BrowserFeatures.SpecificElementExtensions)
    return Prototype.K;

  var Methods = { }, ByTag = Element.Methods.ByTag;

  var extend = Object.extend(function(element) {
    if (!element || element._extendedByPrototype ||
        element.nodeType != 1 || element == window) return element;

    var methods = Object.clone(Methods),
      tagName = element.tagName, property, value;

    // extend methods for specific tags
    if (ByTag[tagName]) Object.extend(methods, ByTag[tagName]);

    for (property in methods) {
      value = methods[property];
      if (Object.isFunction(value) && !(property in element))
        element[property] = value.methodize();
    }

    element._extendedByPrototype = Prototype.emptyFunction;
    return element;

  }, {
    refresh: function() {
      // extend methods for all tags (Safari doesn't need this)
      if (!Prototype.BrowserFeatures.ElementExtensions) {
        Object.extend(Methods, Element.Methods);
        Object.extend(Methods, Element.Methods.Simulated);
      }
    }
  });

  extend.refresh();
  return extend;
})();

Element.hasAttribute = function(element, attribute) {
  if (element.hasAttribute) return element.hasAttribute(attribute);
  return Element.Methods.Simulated.hasAttribute(element, attribute);
};

Element.addMethods = function(methods) {
  var F = Prototype.BrowserFeatures, T = Element.Methods.ByTag;

  if (!methods) {
    Object.extend(Form, Form.Methods);
    Object.extend(Form.Element, Form.Element.Methods);
    Object.extend(Element.Methods.ByTag, {
      "FORM":     Object.clone(Form.Methods),
      "INPUT":    Object.clone(Form.Element.Methods),
      "SELECT":   Object.clone(Form.Element.Methods),
      "TEXTAREA": Object.clone(Form.Element.Methods)
    });
  }

  if (arguments.length == 2) {
    var tagName = methods;
    methods = arguments[1];
  }

  if (!tagName) Object.extend(Element.Methods, methods || { });
  else {
    if (Object.isArray(tagName)) tagName.each(extend);
    else extend(tagName);
  }

  function extend(tagName) {
    tagName = tagName.toUpperCase();
    if (!Element.Methods.ByTag[tagName])
      Element.Methods.ByTag[tagName] = { };
    Object.extend(Element.Methods.ByTag[tagName], methods);
  }

  function copy(methods, destination, onlyIfAbsent) {
    onlyIfAbsent = onlyIfAbsent || false;
    for (var property in methods) {
      var value = methods[property];
      if (!Object.isFunction(value)) continue;
      if (!onlyIfAbsent || !(property in destination))
        destination[property] = value.methodize();
    }
  }

  function findDOMClass(tagName) {
    var klass;
    var trans = {
      "OPTGROUP": "OptGroup", "TEXTAREA": "TextArea", "P": "Paragraph",
      "FIELDSET": "FieldSet", "UL": "UList", "OL": "OList", "DL": "DList",
      "DIR": "Directory", "H1": "Heading", "H2": "Heading", "H3": "Heading",
      "H4": "Heading", "H5": "Heading", "H6": "Heading", "Q": "Quote",
      "INS": "Mod", "DEL": "Mod", "A": "Anchor", "IMG": "Image", "CAPTION":
      "TableCaption", "COL": "TableCol", "COLGROUP": "TableCol", "THEAD":
      "TableSection", "TFOOT": "TableSection", "TBODY": "TableSection", "TR":
      "TableRow", "TH": "TableCell", "TD": "TableCell", "FRAMESET":
      "FrameSet", "IFRAME": "IFrame"
    };
    if (trans[tagName]) klass = 'HTML' + trans[tagName] + 'Element';
    if (window[klass]) return window[klass];
    klass = 'HTML' + tagName + 'Element';
    if (window[klass]) return window[klass];
    klass = 'HTML' + tagName.capitalize() + 'Element';
    if (window[klass]) return window[klass];

    window[klass] = { };
    window[klass].prototype = document.createElement(tagName).__proto__;
    return window[klass];
  }

  if (F.ElementExtensions) {
    copy(Element.Methods, HTMLElement.prototype);
    copy(Element.Methods.Simulated, HTMLElement.prototype, true);
  }

  if (F.SpecificElementExtensions) {
    for (var tag in Element.Methods.ByTag) {
      var klass = findDOMClass(tag);
      if (Object.isUndefined(klass)) continue;
      copy(T[tag], klass.prototype);
    }
  }

  Object.extend(Element, Element.Methods);
  delete Element.ByTag;

  if (Element.extend.refresh) Element.extend.refresh();
  Element.cache = { };
};

document.viewport = {
  getDimensions: function() {
    var dimensions = { };
    $w('width height').each(function(d) {
      var D = d.capitalize();
      dimensions[d] = self['inner' + D] ||
       (document.documentElement['client' + D] || document.body['client' + D]);
    });
    return dimensions;
  },

  getWidth: function() {
    return this.getDimensions().width;
  },

  getHeight: function() {
    return this.getDimensions().height;
  },

  getScrollOffsets: function() {
    return Element._returnOffset(
      window.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft,
      window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop);
  }
};
/* Portions of the Selector class are derived from Jack SlocumтАЩs DomQuery,
 * part of YUI-Ext version 0.40, distributed under the terms of an MIT-style
 * license.  Please see http://www.yui-ext.com/ for more information. */

var Selector = Class.create({
  initialize: function(expression) {
    this.expression = expression.strip();
    this.compileMatcher();
  },

  compileMatcher: function() {
    // Selectors with namespaced attributes can't use the XPath version
    if (Prototype.BrowserFeatures.XPath && !(/(\[[\w-]*?:|:checked)/).test(this.expression))
      return this.compileXPathMatcher();

    var e = this.expression, ps = Selector.patterns, h = Selector.handlers,
        c = Selector.criteria, le, p, m;

    if (Selector._cache[e]) {
      this.matcher = Selector._cache[e];
      return;
    }

    this.matcher = ["this.matcher = function(root) {",
                    "var r = root, h = Selector.handlers, c = false, n;"];

    while (e && le != e && (/\S/).test(e)) {
      le = e;
      for (var i in ps) {
        p = ps[i];
        if (m = e.match(p)) {
          this.matcher.push(Object.isFunction(c[i]) ? c[i](m) :
    	      new Template(c[i]).evaluate(m));
          e = e.replace(m[0], '');
          break;
        }
      }
    }

    this.matcher.push("return h.unique(n);\n}");
    eval(this.matcher.join('\n'));
    Selector._cache[this.expression] = this.matcher;
  },

  compileXPathMatcher: function() {
    var e = this.expression, ps = Selector.patterns,
        x = Selector.xpath, le, m;

    if (Selector._cache[e]) {
      this.xpath = Selector._cache[e]; return;
    }

    this.matcher = ['.//*'];
    while (e && le != e && (/\S/).test(e)) {
      le = e;
      for (var i in ps) {
        if (m = e.match(ps[i])) {
          this.matcher.push(Object.isFunction(x[i]) ? x[i](m) :
            new Template(x[i]).evaluate(m));
          e = e.replace(m[0], '');
          break;
        }
      }
    }

    this.xpath = this.matcher.join('');
    Selector._cache[this.expression] = this.xpath;
  },

  findElements: function(root) {
    root = root || document;
    if (this.xpath) return document._getElementsByXPath(this.xpath, root);
    return this.matcher(root);
  },

  match: function(element) {
    this.tokens = [];

    var e = this.expression, ps = Selector.patterns, as = Selector.assertions;
    var le, p, m;

    while (e && le !== e && (/\S/).test(e)) {
      le = e;
      for (var i in ps) {
        p = ps[i];
        if (m = e.match(p)) {
          // use the Selector.assertions methods unless the selector
          // is too complex.
          if (as[i]) {
            this.tokens.push([i, Object.clone(m)]);
            e = e.replace(m[0], '');
          } else {
            // reluctantly do a document-wide search
            // and look for a match in the array
            return this.findElements(document).include(element);
          }
        }
      }
    }

    var match = true, name, matches;
    for (var i = 0, token; token = this.tokens[i]; i++) {
      name = token[0], matches = token[1];
      if (!Selector.assertions[name](element, matches)) {
        match = false; break;
      }
    }

    return match;
  },

  toString: function() {
    return this.expression;
  },

  inspect: function() {
    return "#<Selector:" + this.expression.inspect() + ">";
  }
});

Object.extend(Selector, {
  _cache: { },

  xpath: {
    descendant:   "//*",
    child:        "/*",
    adjacent:     "/following-sibling::*[1]",
    laterSibling: '/following-sibling::*',
    tagName:      function(m) {
      if (m[1] == '*') return '';
      return "[local-name()='" + m[1].toLowerCase() +
             "' or local-name()='" + m[1].toUpperCase() + "']";
    },
    className:    "[contains(concat(' ', @class, ' '), ' #{1} ')]",
    id:           "[@id='#{1}']",
    attrPresence: "[@#{1}]",
    attr: function(m) {
      m[3] = m[5] || m[6];
      return new Template(Selector.xpath.operators[m[2]]).evaluate(m);
    },
    pseudo: function(m) {
      var h = Selector.xpath.pseudos[m[1]];
      if (!h) return '';
      if (Object.isFunction(h)) return h(m);
      return new Template(Selector.xpath.pseudos[m[1]]).evaluate(m);
    },
    operators: {
      '=':  "[@#{1}='#{3}']",
      '!=': "[@#{1}!='#{3}']",
      '^=': "[starts-with(@#{1}, '#{3}')]",
      '$=': "[substring(@#{1}, (string-length(@#{1}) - string-length('#{3}') + 1))='#{3}']",
      '*=': "[contains(@#{1}, '#{3}')]",
      '~=': "[contains(concat(' ', @#{1}, ' '), ' #{3} ')]",
      '|=': "[contains(concat('-', @#{1}, '-'), '-#{3}-')]"
    },
    pseudos: {
      'first-child': '[not(preceding-sibling::*)]',
      'last-child':  '[not(following-sibling::*)]',
      'only-child':  '[not(preceding-sibling::* or following-sibling::*)]',
      'empty':       "[count(*) = 0 and (count(text()) = 0 or translate(text(), ' \t\r\n', '') = '')]",
      'checked':     "[@checked]",
      'disabled':    "[@disabled]",
      'enabled':     "[not(@disabled)]",
      'not': function(m) {
        var e = m[6], p = Selector.patterns,
            x = Selector.xpath, le, m, v;

        var exclusion = [];
        while (e && le != e && (/\S/).test(e)) {
          le = e;
          for (var i in p) {
            if (m = e.match(p[i])) {
              v = Object.isFunction(x[i]) ? x[i](m) : new Template(x[i]).evaluate(m);
              exclusion.push("(" + v.substring(1, v.length - 1) + ")");
              e = e.replace(m[0], '');
              break;
            }
          }
        }
        return "[not(" + exclusion.join(" and ") + ")]";
      },
      'nth-child':      function(m) {
        return Selector.xpath.pseudos.nth("(count(./preceding-sibling::*) + 1) ", m);
      },
      'nth-last-child': function(m) {
        return Selector.xpath.pseudos.nth("(count(./following-sibling::*) + 1) ", m);
      },
      'nth-of-type':    function(m) {
        return Selector.xpath.pseudos.nth("position() ", m);
      },
      'nth-last-of-type': function(m) {
        return Selector.xpath.pseudos.nth("(last() + 1 - position()) ", m);
      },
      'first-of-type':  function(m) {
        m[6] = "1"; return Selector.xpath.pseudos['nth-of-type'](m);
      },
      'last-of-type':   function(m) {
        m[6] = "1"; return Selector.xpath.pseudos['nth-last-of-type'](m);
      },
      'only-of-type':   function(m) {
        var p = Selector.xpath.pseudos; return p['first-of-type'](m) + p['last-of-type'](m);
      },
      nth: function(fragment, m) {
        var mm, formula = m[6], predicate;
        if (formula == 'even') formula = '2n+0';
        if (formula == 'odd')  formula = '2n+1';
        if (mm = formula.match(/^(\d+)$/)) // digit only
          return '[' + fragment + "= " + mm[1] + ']';
        if (mm = formula.match(/^(-?\d*)?n(([+-])(\d+))?/)) { // an+b
          if (mm[1] == "-") mm[1] = -1;
          var a = mm[1] ? Number(mm[1]) : 1;
          var b = mm[2] ? Number(mm[2]) : 0;
          predicate = "[((#{fragment} - #{b}) mod #{a} = 0) and " +
          "((#{fragment} - #{b}) div #{a} >= 0)]";
          return new Template(predicate).evaluate({
            fragment: fragment, a: a, b: b });
        }
      }
    }
  },

  criteria: {
    tagName:      'n = h.tagName(n, r, "#{1}", c);   c = false;',
    className:    'n = h.className(n, r, "#{1}", c); c = false;',
    id:           'n = h.id(n, r, "#{1}", c);        c = false;',
    attrPresence: 'n = h.attrPresence(n, r, "#{1}"); c = false;',
    attr: function(m) {
      m[3] = (m[5] || m[6]);
      return new Template('n = h.attr(n, r, "#{1}", "#{3}", "#{2}"); c = false;').evaluate(m);
    },
    pseudo: function(m) {
      if (m[6]) m[6] = m[6].replace(/"/g, '\\"');
      return new Template('n = h.pseudo(n, "#{1}", "#{6}", r, c); c = false;').evaluate(m);
    },
    descendant:   'c = "descendant";',
    child:        'c = "child";',
    adjacent:     'c = "adjacent";',
    laterSibling: 'c = "laterSibling";'
  },

  patterns: {
    // combinators must be listed first
    // (and descendant needs to be last combinator)
    laterSibling: /^\s*~\s*/,
    child:        /^\s*>\s*/,
    adjacent:     /^\s*\+\s*/,
    descendant:   /^\s/,

    // selectors follow
    tagName:      /^\s*(\*|[\w\-]+)(\b|$)?/,
    id:           /^#([\w\-\*]+)(\b|$)/,
    className:    /^\.([\w\-\*]+)(\b|$)/,
    pseudo:       /^:((first|last|nth|nth-last|only)(-child|-of-type)|empty|checked|(en|dis)abled|not)(\((.*?)\))?(\b|$|(?=\s)|(?=:))/,
    attrPresence: /^\[([\w]+)\]/,
    attr:         /\[((?:[\w-]*:)?[\w-]+)\s*(?:([!^$*~|]?=)\s*((['"])([^\4]*?)\4|([^'"][^\]]*?)))?\]/
  },

  // for Selector.match and Element#match
  assertions: {
    tagName: function(element, matches) {
      return matches[1].toUpperCase() == element.tagName.toUpperCase();
    },

    className: function(element, matches) {
      return Element.hasClassName(element, matches[1]);
    },

    id: function(element, matches) {
      return element.id === matches[1];
    },

    attrPresence: function(element, matches) {
      return Element.hasAttribute(element, matches[1]);
    },

    attr: function(element, matches) {
      var nodeValue = Element.readAttribute(element, matches[1]);
      return Selector.operators[matches[2]](nodeValue, matches[3]);
    }
  },

  handlers: {
    // UTILITY FUNCTIONS
    // joins two collections
    concat: function(a, b) {
      for (var i = 0, node; node = b[i]; i++)
        a.push(node);
      return a;
    },

    // marks an array of nodes for counting
    mark: function(nodes) {
      for (var i = 0, node; node = nodes[i]; i++)
        node._counted = true;
      return nodes;
    },

    unmark: function(nodes) {
      for (var i = 0, node; node = nodes[i]; i++)
        node._counted = undefined;
      return nodes;
    },

    // mark each child node with its position (for nth calls)
    // "ofType" flag indicates whether we're indexing for nth-of-type
    // rather than nth-child
    index: function(parentNode, reverse, ofType) {
      parentNode._counted = true;
      if (reverse) {
        for (var nodes = parentNode.childNodes, i = nodes.length - 1, j = 1; i >= 0; i--) {
          var node = nodes[i];
          if (node.nodeType == 1 && (!ofType || node._counted)) node.nodeIndex = j++;
        }
      } else {
        for (var i = 0, j = 1, nodes = parentNode.childNodes; node = nodes[i]; i++)
          if (node.nodeType == 1 && (!ofType || node._counted)) node.nodeIndex = j++;
      }
    },

    // filters out duplicates and extends all nodes
    unique: function(nodes) {
      if (nodes.length == 0) return nodes;
      var results = [], n;
      for (var i = 0, l = nodes.length; i < l; i++)
        if (!(n = nodes[i])._counted) {
          n._counted = true;
          results.push(Element.extend(n));
        }
      return Selector.handlers.unmark(results);
    },

    // COMBINATOR FUNCTIONS
    descendant: function(nodes) {
      var h = Selector.handlers;
      for (var i = 0, results = [], node; node = nodes[i]; i++)
        h.concat(results, node.getElementsByTagName('*'));
      return results;
    },

    child: function(nodes) {
      var h = Selector.handlers;
      for (var i = 0, results = [], node; node = nodes[i]; i++) {
        for (var j = 0, children = [], child; child = node.childNodes[j]; j++)
          if (child.nodeType == 1 && child.tagName != '!') results.push(child);
      }
      return results;
    },

    adjacent: function(nodes) {
      for (var i = 0, results = [], node; node = nodes[i]; i++) {
        var next = this.nextElementSibling(node);
        if (next) results.push(next);
      }
      return results;
    },

    laterSibling: function(nodes) {
      var h = Selector.handlers;
      for (var i = 0, results = [], node; node = nodes[i]; i++)
        h.concat(results, Element.nextSiblings(node));
      return results;
    },

    nextElementSibling: function(node) {
      while (node = node.nextSibling)
	      if (node.nodeType == 1) return node;
      return null;
    },

    previousElementSibling: function(node) {
      while (node = node.previousSibling)
        if (node.nodeType == 1) return node;
      return null;
    },

    // TOKEN FUNCTIONS
    tagName: function(nodes, root, tagName, combinator) {
      tagName = tagName.toUpperCase();
      var results = [], h = Selector.handlers;
      if (nodes) {
        if (combinator) {
          // fastlane for ordinary descendant combinators
          if (combinator == "descendant") {
            for (var i = 0, node; node = nodes[i]; i++)
              h.concat(results, node.getElementsByTagName(tagName));
            return results;
          } else nodes = this[combinator](nodes);
          if (tagName == "*") return nodes;
        }
        for (var i = 0, node; node = nodes[i]; i++)
          if (node.tagName.toUpperCase() == tagName) results.push(node);
        return results;
      } else return root.getElementsByTagName(tagName);
    },

    id: function(nodes, root, id, combinator) {
      var targetNode = $(id), h = Selector.handlers;
      if (!targetNode) return [];
      if (!nodes && root == document) return [targetNode];
      if (nodes) {
        if (combinator) {
          if (combinator == 'child') {
            for (var i = 0, node; node = nodes[i]; i++)
              if (targetNode.parentNode == node) return [targetNode];
          } else if (combinator == 'descendant') {
            for (var i = 0, node; node = nodes[i]; i++)
              if (Element.descendantOf(targetNode, node)) return [targetNode];
          } else if (combinator == 'adjacent') {
            for (var i = 0, node; node = nodes[i]; i++)
              if (Selector.handlers.previousElementSibling(targetNode) == node)
                return [targetNode];
          } else nodes = h[combinator](nodes);
        }
        for (var i = 0, node; node = nodes[i]; i++)
          if (node == targetNode) return [targetNode];
        return [];
      }
      return (targetNode && Element.descendantOf(targetNode, root)) ? [targetNode] : [];
    },

    className: function(nodes, root, className, combinator) {
      if (nodes && combinator) nodes = this[combinator](nodes);
      return Selector.handlers.byClassName(nodes, root, className);
    },

    byClassName: function(nodes, root, className) {
      if (!nodes) nodes = Selector.handlers.descendant([root]);
      var needle = ' ' + className + ' ';
      for (var i = 0, results = [], node, nodeClassName; node = nodes[i]; i++) {
        nodeClassName = node.className;
        if (nodeClassName.length == 0) continue;
        if (nodeClassName == className || (' ' + nodeClassName + ' ').include(needle))
          results.push(node);
      }
      return results;
    },

    attrPresence: function(nodes, root, attr) {
      if (!nodes) nodes = root.getElementsByTagName("*");
      var results = [];
      for (var i = 0, node; node = nodes[i]; i++)
        if (Element.hasAttribute(node, attr)) results.push(node);
      return results;
    },

    attr: function(nodes, root, attr, value, operator) {
      if (!nodes) nodes = root.getElementsByTagName("*");
      var handler = Selector.operators[operator], results = [];
      for (var i = 0, node; node = nodes[i]; i++) {
        var nodeValue = Element.readAttribute(node, attr);
        if (nodeValue === null) continue;
        if (handler(nodeValue, value)) results.push(node);
      }
      return results;
    },

    pseudo: function(nodes, name, value, root, combinator) {
      if (nodes && combinator) nodes = this[combinator](nodes);
      if (!nodes) nodes = root.getElementsByTagName("*");
      return Selector.pseudos[name](nodes, value, root);
    }
  },

  pseudos: {
    'first-child': function(nodes, value, root) {
      for (var i = 0, results = [], node; node = nodes[i]; i++) {
        if (Selector.handlers.previousElementSibling(node)) continue;
          results.push(node);
      }
      return results;
    },
    'last-child': function(nodes, value, root) {
      for (var i = 0, results = [], node; node = nodes[i]; i++) {
        if (Selector.handlers.nextElementSibling(node)) continue;
          results.push(node);
      }
      return results;
    },
    'only-child': function(nodes, value, root) {
      var h = Selector.handlers;
      for (var i = 0, results = [], node; node = nodes[i]; i++)
        if (!h.previousElementSibling(node) && !h.nextElementSibling(node))
          results.push(node);
      return results;
    },
    'nth-child':        function(nodes, formula, root) {
      return Selector.pseudos.nth(nodes, formula, root);
    },
    'nth-last-child':   function(nodes, formula, root) {
      return Selector.pseudos.nth(nodes, formula, root, true);
    },
    'nth-of-type':      function(nodes, formula, root) {
      return Selector.pseudos.nth(nodes, formula, root, false, true);
    },
    'nth-last-of-type': function(nodes, formula, root) {
      return Selector.pseudos.nth(nodes, formula, root, true, true);
    },
    'first-of-type':    function(nodes, formula, root) {
      return Selector.pseudos.nth(nodes, "1", root, false, true);
    },
    'last-of-type':     function(nodes, formula, root) {
      return Selector.pseudos.nth(nodes, "1", root, true, true);
    },
    'only-of-type':     function(nodes, formula, root) {
      var p = Selector.pseudos;
      return p['last-of-type'](p['first-of-type'](nodes, formula, root), formula, root);
    },

    // handles the an+b logic
    getIndices: function(a, b, total) {
      if (a == 0) return b > 0 ? [b] : [];
      return $R(1, total).inject([], function(memo, i) {
        if (0 == (i - b) % a && (i - b) / a >= 0) memo.push(i);
        return memo;
      });
    },

    // handles nth(-last)-child, nth(-last)-of-type, and (first|last)-of-type
    nth: function(nodes, formula, root, reverse, ofType) {
      if (nodes.length == 0) return [];
      if (formula == 'even') formula = '2n+0';
      if (formula == 'odd')  formula = '2n+1';
      var h = Selector.handlers, results = [], indexed = [], m;
      h.mark(nodes);
      for (var i = 0, node; node = nodes[i]; i++) {
        if (!node.parentNode._counted) {
          h.index(node.parentNode, reverse, ofType);
          indexed.push(node.parentNode);
        }
      }
      if (formula.match(/^\d+$/)) { // just a number
        formula = Number(formula);
        for (var i = 0, node; node = nodes[i]; i++)
          if (node.nodeIndex == formula) results.push(node);
      } else if (m = formula.match(/^(-?\d*)?n(([+-])(\d+))?/)) { // an+b
        if (m[1] == "-") m[1] = -1;
        var a = m[1] ? Number(m[1]) : 1;
        var b = m[2] ? Number(m[2]) : 0;
        var indices = Selector.pseudos.getIndices(a, b, nodes.length);
        for (var i = 0, node, l = indices.length; node = nodes[i]; i++) {
          for (var j = 0; j < l; j++)
            if (node.nodeIndex == indices[j]) results.push(node);
        }
      }
      h.unmark(nodes);
      h.unmark(indexed);
      return results;
    },

    'empty': function(nodes, value, root) {
      for (var i = 0, results = [], node; node = nodes[i]; i++) {
        // IE treats comments as element nodes
        if (node.tagName == '!' || (node.firstChild && !node.innerHTML.match(/^\s*$/))) continue;
        results.push(node);
      }
      return results;
    },

    'not': function(nodes, selector, root) {
      var h = Selector.handlers, selectorType, m;
      var exclusions = new Selector(selector).findElements(root);
      h.mark(exclusions);
      for (var i = 0, results = [], node; node = nodes[i]; i++)
        if (!node._counted) results.push(node);
      h.unmark(exclusions);
      return results;
    },

    'enabled': function(nodes, value, root) {
      for (var i = 0, results = [], node; node = nodes[i]; i++)
        if (!node.disabled) results.push(node);
      return results;
    },

    'disabled': function(nodes, value, root) {
      for (var i = 0, results = [], node; node = nodes[i]; i++)
        if (node.disabled) results.push(node);
      return results;
    },

    'checked': function(nodes, value, root) {
      for (var i = 0, results = [], node; node = nodes[i]; i++)
        if (node.checked) results.push(node);
      return results;
    }
  },

  operators: {
    '=':  function(nv, v) { return nv == v; },
    '!=': function(nv, v) { return nv != v; },
    '^=': function(nv, v) { return nv.startsWith(v); },
    '$=': function(nv, v) { return nv.endsWith(v); },
    '*=': function(nv, v) { return nv.include(v); },
    '~=': function(nv, v) { return (' ' + nv + ' ').include(' ' + v + ' '); },
    '|=': function(nv, v) { return ('-' + nv.toUpperCase() + '-').include('-' + v.toUpperCase() + '-'); }
  },

  matchElements: function(elements, expression) {
    var matches = new Selector(expression).findElements(), h = Selector.handlers;
    h.mark(matches);
    for (var i = 0, results = [], element; element = elements[i]; i++)
      if (element._counted) results.push(element);
    h.unmark(matches);
    return results;
  },

  findElement: function(elements, expression, index) {
    if (Object.isNumber(expression)) {
      index = expression; expression = false;
    }
    return Selector.matchElements(elements, expression || '*')[index || 0];
  },

  findChildElements: function(element, expressions) {
    var exprs = expressions.join(','), expressions = [];
    exprs.scan(/(([\w#:.~>+()\s-]+|\*|\[.*?\])+)\s*(,|$)/, function(m) {
      expressions.push(m[1].strip());
    });
    var results = [], h = Selector.handlers;
    for (var i = 0, l = expressions.length, selector; i < l; i++) {
      selector = new Selector(expressions[i].strip());
      h.concat(results, selector.findElements(element));
    }
    return (l > 1) ? h.unique(results) : results;
  }
});

function $$() {
  return Selector.findChildElements(document, $A(arguments));
}
var Form = {
  reset: function(form) {
    $(form).reset();
    return form;
  },

  serializeElements: function(elements, options) {
    if (typeof options != 'object') options = { hash: !!options };
    else if (options.hash === undefined) options.hash = true;
    var key, value, submitted = false, submit = options.submit;

    var data = elements.inject({ }, function(result, element) {
      if (!element.disabled && element.name) {
        key = element.name; value = $(element).getValue();
        if (value != null && (element.type != 'submit' || (!submitted &&
            submit !== false && (!submit || key == submit) && (submitted = true)))) {
          if (key in result) {
            // a key is already present; construct an array of values
            if (!Object.isArray(result[key])) result[key] = [result[key]];
            result[key].push(value);
          }
          else result[key] = value;
        }
      }
      return result;
    });

    return options.hash ? data : Object.toQueryString(data);
  }
};

Form.Methods = {
  serialize: function(form, options) {
    return Form.serializeElements(Form.getElements(form), options);
  },

  getElements: function(form) {
    return $A($(form).getElementsByTagName('*')).inject([],
      function(elements, child) {
        if (Form.Element.Serializers[child.tagName.toLowerCase()])
          elements.push(Element.extend(child));
        return elements;
      }
    );
  },

  getInputs: function(form, typeName, name) {
    form = $(form);
    var inputs = form.getElementsByTagName('input');

    if (!typeName && !name) return $A(inputs).map(Element.extend);

    for (var i = 0, matchingInputs = [], length = inputs.length; i < length; i++) {
      var input = inputs[i];
      if ((typeName && input.type != typeName) || (name && input.name != name))
        continue;
      matchingInputs.push(Element.extend(input));
    }

    return matchingInputs;
  },

  disable: function(form) {
    form = $(form);
    Form.getElements(form).invoke('disable');
    return form;
  },

  enable: function(form) {
    form = $(form);
    Form.getElements(form).invoke('enable');
    return form;
  },

  findFirstElement: function(form) {
    var elements = $(form).getElements().findAll(function(element) {
      return 'hidden' != element.type && !element.disabled;
    });
    var firstByIndex = elements.findAll(function(element) {
      return element.hasAttribute('tabIndex') && element.tabIndex >= 0;
    }).sortBy(function(element) { return element.tabIndex }).first();

    return firstByIndex ? firstByIndex : elements.find(function(element) {
      return ['input', 'select', 'textarea'].include(element.tagName.toLowerCase());
    });
  },

  focusFirstElement: function(form) {
    form = $(form);
    form.findFirstElement().activate();
    return form;
  },

  request: function(form, options) {
    form = $(form), options = Object.clone(options || { });

    var params = options.parameters, action = form.readAttribute('action') || '';
    if (action.blank()) action = window.location.href;
    options.parameters = form.serialize(true);

    if (params) {
      if (Object.isString(params)) params = params.toQueryParams();
      Object.extend(options.parameters, params);
    }

    if (form.hasAttribute('method') && !options.method)
      options.method = form.method;

    return new Ajax.Request(action, options);
  }
};

/*--------------------------------------------------------------------------*/

Form.Element = {
  focus: function(element) {
    $(element).focus();
    return element;
  },

  select: function(element) {
    $(element).select();
    return element;
  }
};

Form.Element.Methods = {
  serialize: function(element) {
    element = $(element);
    if (!element.disabled && element.name) {
      var value = element.getValue();
      if (value != undefined) {
        var pair = { };
        pair[element.name] = value;
        return Object.toQueryString(pair);
      }
    }
    return '';
  },

  getValue: function(element) {
    element = $(element);
    var method = element.tagName.toLowerCase();
    return Form.Element.Serializers[method](element);
  },

  setValue: function(element, value) {
    element = $(element);
    var method = element.tagName.toLowerCase();
    Form.Element.Serializers[method](element, value);
    return element;
  },

  clear: function(element) {
    $(element).value = '';
    return element;
  },

  present: function(element) {
    return $(element).value != '';
  },

  activate: function(element) {
    element = $(element);
    try {
      element.focus();
      if (element.select && (element.tagName.toLowerCase() != 'input' ||
          !['button', 'reset', 'submit'].include(element.type)))
        element.select();
    } catch (e) { }
    return element;
  },

  disable: function(element) {
    element = $(element);
    element.blur();
    element.disabled = true;
    return element;
  },

  enable: function(element) {
    element = $(element);
    element.disabled = false;
    return element;
  }
};

/*--------------------------------------------------------------------------*/

var Field = Form.Element;
var $F = Form.Element.Methods.getValue;

/*--------------------------------------------------------------------------*/

Form.Element.Serializers = {
  input: function(element, value) {
    switch (element.type.toLowerCase()) {
      case 'checkbox':
      case 'radio':
        return Form.Element.Serializers.inputSelector(element, value);
      default:
        return Form.Element.Serializers.textarea(element, value);
    }
  },

  inputSelector: function(element, value) {
    if (value === undefined) return element.checked ? element.value : null;
    else element.checked = !!value;
  },

  textarea: function(element, value) {
    if (value === undefined) return element.value;
    else element.value = value;
  },

  select: function(element, index) {
    if (index === undefined)
      return this[element.type == 'select-one' ?
        'selectOne' : 'selectMany'](element);
    else {
      var opt, value, single = !Object.isArray(index);
      for (var i = 0, length = element.length; i < length; i++) {
        opt = element.options[i];
        value = this.optionValue(opt);
        if (single) {
          if (value == index) {
            opt.selected = true;
            return;
          }
        }
        else opt.selected = index.include(value);
      }
    }
  },

  selectOne: function(element) {
    var index = element.selectedIndex;
    return index >= 0 ? this.optionValue(element.options[index]) : null;
  },

  selectMany: function(element) {
    var values, length = element.length;
    if (!length) return null;

    for (var i = 0, values = []; i < length; i++) {
      var opt = element.options[i];
      if (opt.selected) values.push(this.optionValue(opt));
    }
    return values;
  },

  optionValue: function(opt) {
    // extend element because hasAttribute may not be native
    return Element.extend(opt).hasAttribute('value') ? opt.value : opt.text;
  }
};

/*--------------------------------------------------------------------------*/

Abstract.TimedObserver = Class.create(PeriodicalExecuter, {
  initialize: function($super, element, frequency, callback) {
    $super(callback, frequency);
    this.element   = $(element);
    this.lastValue = this.getValue();
  },

  execute: function() {
    var value = this.getValue();
    if (Object.isString(this.lastValue) && Object.isString(value) ?
        this.lastValue != value : String(this.lastValue) != String(value)) {
      this.callback(this.element, value);
      this.lastValue = value;
    }
  }
});

Form.Element.Observer = Class.create(Abstract.TimedObserver, {
  getValue: function() {
    return Form.Element.getValue(this.element);
  }
});

Form.Observer = Class.create(Abstract.TimedObserver, {
  getValue: function() {
    return Form.serialize(this.element);
  }
});

/*--------------------------------------------------------------------------*/

Abstract.EventObserver = Class.create({
  initialize: function(element, callback) {
    this.element  = $(element);
    this.callback = callback;

    this.lastValue = this.getValue();
    if (this.element.tagName.toLowerCase() == 'form')
      this.registerFormCallbacks();
    else
      this.registerCallback(this.element);
  },

  onElementEvent: function() {
    var value = this.getValue();
    if (this.lastValue != value) {
      this.callback(this.element, value);
      this.lastValue = value;
    }
  },

  registerFormCallbacks: function() {
    Form.getElements(this.element).each(this.registerCallback, this);
  },

  registerCallback: function(element) {
    if (element.type) {
      switch (element.type.toLowerCase()) {
        case 'checkbox':
        case 'radio':
          Event.observe(element, 'click', this.onElementEvent.bind(this));
          break;
        default:
          Event.observe(element, 'change', this.onElementEvent.bind(this));
          break;
      }
    }
  }
});

Form.Element.EventObserver = Class.create(Abstract.EventObserver, {
  getValue: function() {
    return Form.Element.getValue(this.element);
  }
});

Form.EventObserver = Class.create(Abstract.EventObserver, {
  getValue: function() {
    return Form.serialize(this.element);
  }
});
if (!window.Event) var Event = { };

Object.extend(Event, {
  KEY_BACKSPACE: 8,
  KEY_TAB:       9,
  KEY_RETURN:   13,
  KEY_ESC:      27,
  KEY_LEFT:     37,
  KEY_UP:       38,
  KEY_RIGHT:    39,
  KEY_DOWN:     40,
  KEY_DELETE:   46,
  KEY_HOME:     36,
  KEY_END:      35,
  KEY_PAGEUP:   33,
  KEY_PAGEDOWN: 34,
  KEY_INSERT:   45,

  cache: { },

  relatedTarget: function(event) {
    var element;
    switch(event.type) {
      case 'mouseover': element = event.fromElement; break;
      case 'mouseout':  element = event.toElement;   break;
      default: return null;
    }
    return Element.extend(element);
  }
});

Event.Methods = (function() {
  var isButton;

  if (Prototype.Browser.IE) {
    var buttonMap = { 0: 1, 1: 4, 2: 2 };
    isButton = function(event, code) {
      return event.button == buttonMap[code];
    };

  } else if (Prototype.Browser.WebKit) {
    isButton = function(event, code) {
      switch (code) {
        case 0: return event.which == 1 && !event.metaKey;
        case 1: return event.which == 1 && event.metaKey;
        default: return false;
      }
    };

  } else {
    isButton = function(event, code) {
      return event.which ? (event.which === code + 1) : (event.button === code);
    };
  }

  return {
    isLeftClick:   function(event) { return isButton(event, 0) },
    isMiddleClick: function(event) { return isButton(event, 1) },
    isRightClick:  function(event) { return isButton(event, 2) },

    element: function(event) {
      var node = Event.extend(event).target;
      return Element.extend(node.nodeType == Node.TEXT_NODE ? node.parentNode : node);
    },

    findElement: function(event, expression) {
      var element = Event.element(event);
      return element.match(expression) ? element : element.up(expression);
    },

    pointer: function(event) {
      return {
        x: event.pageX || (event.clientX +
          (document.documentElement.scrollLeft || document.body.scrollLeft)),
        y: event.pageY || (event.clientY +
          (document.documentElement.scrollTop || document.body.scrollTop))
      };
    },

    pointerX: function(event) { return Event.pointer(event).x },
    pointerY: function(event) { return Event.pointer(event).y },

    stop: function(event) {
      Event.extend(event);
      event.preventDefault();
      event.stopPropagation();
      event.stopped = true;
    }
  };
})();

Event.extend = (function() {
  var methods = Object.keys(Event.Methods).inject({ }, function(m, name) {
    m[name] = Event.Methods[name].methodize();
    return m;
  });

  if (Prototype.Browser.IE) {
    Object.extend(methods, {
      stopPropagation: function() { this.cancelBubble = true },
      preventDefault:  function() { this.returnValue = false },
      inspect: function() { return "[object Event]" }
    });

    return function(event) {
      if (!event) return false;
      if (event._extendedByPrototype) return event;

      event._extendedByPrototype = Prototype.emptyFunction;
      var pointer = Event.pointer(event);
      Object.extend(event, {
        target: event.srcElement,
        relatedTarget: Event.relatedTarget(event),
        pageX:  pointer.x,
        pageY:  pointer.y
      });
      return Object.extend(event, methods);
    };

  } else {
    Event.prototype = Event.prototype || document.createEvent("HTMLEvents").__proto__;
    Object.extend(Event.prototype, methods);
    return Prototype.K;
  }
})();

Object.extend(Event, (function() {
  var cache = Event.cache;

  function getEventID(element) {
    if (element._eventID) return element._eventID;
    arguments.callee.id = arguments.callee.id || 1;
    return element._eventID = ++arguments.callee.id;
  }

  function getDOMEventName(eventName) {
    if (eventName && eventName.include(':')) return "dataavailable";
    return eventName;
  }

  function getCacheForID(id) {
    return cache[id] = cache[id] || { };
  }

  function getWrappersForEventName(id, eventName) {
    var c = getCacheForID(id);
    return c[eventName] = c[eventName] || [];
  }

  function createWrapper(element, eventName, handler) {
    var id = getEventID(element);
    var c = getWrappersForEventName(id, eventName);
    if (c.pluck("handler").include(handler)) return false;

    var wrapper = function(event) {
      if (!Event || !Event.extend ||
        (event.eventName && event.eventName != eventName))
          return false;

      Event.extend(event);
      handler.call(element, event)
    };

    wrapper.handler = handler;
    c.push(wrapper);
    return wrapper;
  }

  function findWrapper(id, eventName, handler) {
    var c = getWrappersForEventName(id, eventName);
    return c.find(function(wrapper) { return wrapper.handler == handler });
  }

  function destroyWrapper(id, eventName, handler) {
    var c = getCacheForID(id);
    if (!c[eventName]) return false;
    c[eventName] = c[eventName].without(findWrapper(id, eventName, handler));
  }

  function destroyCache() {
    for (var id in cache)
      for (var eventName in cache[id])
        cache[id][eventName] = null;
  }

  if (window.attachEvent) {
    window.attachEvent("onunload", destroyCache);
  }

  return {
    observe: function(element, eventName, handler) {
      element = $(element);
      var name = getDOMEventName(eventName);

      var wrapper = createWrapper(element, eventName, handler);
      if (!wrapper) return element;

      if (element.addEventListener) {
        element.addEventListener(name, wrapper, false);
      } else {
        element.attachEvent("on" + name, wrapper);
      }

      return element;
    },

    stopObserving: function(element, eventName, handler) {
      element = $(element);
      var id = getEventID(element), name = getDOMEventName(eventName);

      if (!handler && eventName) {
        getWrappersForEventName(id, eventName).each(function(wrapper) {
          element.stopObserving(eventName, wrapper.handler);
        });
        return element;

      } else if (!eventName) {
        Object.keys(getCacheForID(id)).each(function(eventName) {
          element.stopObserving(eventName);
        });
        return element;
      }

      var wrapper = findWrapper(id, eventName, handler);
      if (!wrapper) return element;

      if (element.removeEventListener) {
        element.removeEventListener(name, wrapper, false);
      } else {
        element.detachEvent("on" + name, wrapper);
      }

      destroyWrapper(id, eventName, handler);

      return element;
    },

    fire: function(element, eventName, memo) {
      element = $(element);
      if (element == document && document.createEvent && !element.dispatchEvent)
        element = document.documentElement;

      if (document.createEvent) {
        var event = document.createEvent("HTMLEvents");
        event.initEvent("dataavailable", true, true);
      } else {
        var event = document.createEventObject();
        event.eventType = "ondataavailable";
      }

      event.eventName = eventName;
      event.memo = memo || { };

      if (document.createEvent) {
        element.dispatchEvent(event);
      } else {
        element.fireEvent(event.eventType, event);
      }

      return event;
    }
  };
})());

Object.extend(Event, Event.Methods);

Element.addMethods({
  fire:          Event.fire,
  observe:       Event.observe,
  stopObserving: Event.stopObserving
});

Object.extend(document, {
  fire:          Element.Methods.fire.methodize(),
  observe:       Element.Methods.observe.methodize(),
  stopObserving: Element.Methods.stopObserving.methodize()
});

(function() {
  /* Support for the DOMContentLoaded event is based on work by Dan Webb,
     Matthias Miller, Dean Edwards and John Resig. */

  var timer, fired = false;

  function fireContentLoadedEvent() {
    if (fired) return;
    if (timer) window.clearInterval(timer);
    document.fire("dom:loaded");
    fired = true;
  }

  if (document.addEventListener) {
    if (Prototype.Browser.WebKit) {
      timer = window.setInterval(function() {
        if (/loaded|complete/.test(document.readyState))
          fireContentLoadedEvent();
      }, 0);

      Event.observe(window, "load", fireContentLoadedEvent);

    } else {
      document.addEventListener("DOMContentLoaded",
        fireContentLoadedEvent, false);
    }

  } else {
    document.write("<script id=__onDOMContentLoaded defer src=//:><\/script>");
    $("__onDOMContentLoaded").onreadystatechange = function() {
      if (this.readyState == "complete") {
        this.onreadystatechange = null;
        fireContentLoadedEvent();
      }
    };
  }
})();
/*------------------------------- DEPRECATED -------------------------------*/

Hash.toQueryString = Object.toQueryString;

var Toggle = { display: Element.toggle };

Element.Methods.childOf = Element.Methods.descendantOf;

var Insertion = {
  Before: function(element, content) {
    return Element.insert(element, {before:content});
  },

  Top: function(element, content) {
    return Element.insert(element, {top:content});
  },

  Bottom: function(element, content) {
    return Element.insert(element, {bottom:content});
  },

  After: function(element, content) {
    return Element.insert(element, {after:content});
  }
};

var $continue = new Error('"throw $continue" is deprecated, use "return" instead');

// This should be moved to script.aculo.us; notice the deprecated methods
// further below, that map to the newer Element methods.
var Position = {
  // set to true if needed, warning: firefox performance problems
  // NOT neeeded for page scrolling, only if draggable contained in
  // scrollable elements
  includeScrollOffsets: false,

  // must be called before calling withinIncludingScrolloffset, every time the
  // page is scrolled
  prepare: function() {
    this.deltaX =  window.pageXOffset
                || document.documentElement.scrollLeft
                || document.body.scrollLeft
                || 0;
    this.deltaY =  window.pageYOffset
                || document.documentElement.scrollTop
                || document.body.scrollTop
                || 0;
  },

  // caches x/y coordinate pair to use with overlap
  within: function(element, x, y) {
    if (this.includeScrollOffsets)
      return this.withinIncludingScrolloffsets(element, x, y);
    this.xcomp = x;
    this.ycomp = y;
    this.offset = Element.cumulativeOffset(element);

    return (y >= this.offset[1] &&
            y <  this.offset[1] + element.offsetHeight &&
            x >= this.offset[0] &&
            x <  this.offset[0] + element.offsetWidth);
  },

  withinIncludingScrolloffsets: function(element, x, y) {
    var offsetcache = Element.cumulativeScrollOffset(element);

    this.xcomp = x + offsetcache[0] - this.deltaX;
    this.ycomp = y + offsetcache[1] - this.deltaY;
    this.offset = Element.cumulativeOffset(element);

    return (this.ycomp >= this.offset[1] &&
            this.ycomp <  this.offset[1] + element.offsetHeight &&
            this.xcomp >= this.offset[0] &&
            this.xcomp <  this.offset[0] + element.offsetWidth);
  },

  // within must be called directly before
  overlap: function(mode, element) {
    if (!mode) return 0;
    if (mode == 'vertical')
      return ((this.offset[1] + element.offsetHeight) - this.ycomp) /
        element.offsetHeight;
    if (mode == 'horizontal')
      return ((this.offset[0] + element.offsetWidth) - this.xcomp) /
        element.offsetWidth;
  },

  // Deprecation layer -- use newer Element methods now (1.5.2).

  cumulativeOffset: Element.Methods.cumulativeOffset,

  positionedOffset: Element.Methods.positionedOffset,

  absolutize: function(element) {
    Position.prepare();
    return Element.absolutize(element);
  },

  relativize: function(element) {
    Position.prepare();
    return Element.relativize(element);
  },

  realOffset: Element.Methods.cumulativeScrollOffset,

  offsetParent: Element.Methods.getOffsetParent,

  page: Element.Methods.viewportOffset,

  clone: function(source, target, options) {
    options = options || { };
    return Element.clonePosition(target, source, options);
  }
};

/*--------------------------------------------------------------------------*/

if (!document.getElementsByClassName) document.getElementsByClassName = function(instanceMethods){
  function iter(name) {
    return name.blank() ? null : "[contains(concat(' ', @class, ' '), ' " + name + " ')]";
  }

  instanceMethods.getElementsByClassName = Prototype.BrowserFeatures.XPath ?
  function(element, className) {
    className = className.toString().strip();
    var cond = /\s/.test(className) ? $w(className).map(iter).join('') : iter(className);
    return cond ? document._getElementsByXPath('.//*' + cond, element) : [];
  } : function(element, className) {
    className = className.toString().strip();
    var elements = [], classNames = (/\s/.test(className) ? $w(className) : null);
    if (!classNames && !className) return elements;

    var nodes = $(element).getElementsByTagName('*');
    className = ' ' + className + ' ';

    for (var i = 0, child, cn; child = nodes[i]; i++) {
      if (child.className && (cn = ' ' + child.className + ' ') && (cn.include(className) ||
          (classNames && classNames.all(function(name) {
            return !name.toString().blank() && cn.include(' ' + name + ' ');
          }))))
        elements.push(Element.extend(child));
    }
    return elements;
  };

  return function(className, parentElement) {
    return $(parentElement || document.body).getElementsByClassName(className);
  };
}(Element.Methods);

/*--------------------------------------------------------------------------*/

Element.ClassNames = Class.create();
Element.ClassNames.prototype = {
  initialize: function(element) {
    this.element = $(element);
  },

  _each: function(iterator) {
    this.element.className.split(/\s+/).select(function(name) {
      return name.length > 0;
    })._each(iterator);
  },

  set: function(className) {
    this.element.className = className;
  },

  add: function(classNameToAdd) {
    if (this.include(classNameToAdd)) return;
    this.set($A(this).concat(classNameToAdd).join(' '));
  },

  remove: function(classNameToRemove) {
    if (!this.include(classNameToRemove)) return;
    this.set($A(this).without(classNameToRemove).join(' '));
  },

  toString: function() {
    return $A(this).join(' ');
  }
};

Object.extend(Element.ClassNames.prototype, Enumerable);

/*--------------------------------------------------------------------------*/

Element.addMethods();


/// MESSAGES

var SYSTEM = new Object;
SYSTEM.PAGINATION = new Object();
SYSTEM.PAGINATION.DEFAULT = 10;
SYSTEM.PAGINATION.userPhoto = 4;
SYSTEM.SIZES = new Object();
SYSTEM.SIZES.MEDIUMX = 320;
SYSTEM.SIZES.MEDIUMY = 300;
SYSTEM.SIZES.AVATAR = 80;
SYSTEM.ANIMATION_TIME = 600;
SYSTEM.TOOLTIP_WIDTH = 200;
SYSTEM.TOOLTIP_HIDE_DELAY = 200;
SYSTEM.EVENT_TITLE_LENGTH = 600;

SYSTEM.LOGIN = new Object();
SYSTEM.LOGIN.EMAIL = 'Ваш e-mail';
SYSTEM.LOGIN.PASSWORD = 'Пароль';

//SYSTEM.STATIC_HTTP = 'http://192.168.0.100:8080/static_tmp/';
SYSTEM.STATIC_HTTP = 'http://fotogolos.ru/static/';
//SYSTEM.STATIC_HTTP = 'http://localhost:8081/drchlk_static/';
SYSTEM.SPACE = SYSTEM.STATIC_HTTP+'resources/space.gif';
SYSTEM.WAIT = SYSTEM.STATIC_HTTP+'resources/wait2.gif';
SYSTEM.SMILES_HTTP = SYSTEM.STATIC_HTTP+'smiles/';
SYSTEM.SYMP_HTTP = SYSTEM.STATIC_HTTP+'symps/';
SYSTEM.AVATAR = new Object();
SYSTEM.AVATAR.HTTP = SYSTEM.STATIC_HTTP+'avatars/';
SYSTEM.AVATAR.EXTENSION = 'gif';

var MSG = new Object(); 
MSG.REG = new Object();
MSG.WAIT1 = 'Подождите.&nbsp;&nbsp;';
MSG.WAIT2 = 'Подождите&nbsp;.&nbsp;';
MSG.WAIT3 = 'Подождите&nbsp;&nbsp;.';
MSG.REG.NO_EMAIL = 'Не указан e-mail';
MSG.REG.WRONG_EMAIL = 'Неверный формат e-mail';
MSG.REG.NO_PASS = 'Не указан пароль';
MSG.REG.PASS_MISMATCH = 'Не совпадение значений';
MSG.REG.SHORT_PASS = 'Пароль слишком короткий';
MSG.REG.NO_NAME = 'Не указано Имя';
MSG.REG.SHORT_NAME = 'Имя слишком короткое';
MSG.REG.NO_GENDER = 'Не указан Ваш пол';
MSG.REG.NO_DATE = 'Не указана дата рождения';
MSG.REG.WRONG_DATE = 'Неверная дата';
MSG.REG.NO_COUNTRY = 'Не выбрана страна';
MSG.REG.NO_CITY = 'Не выбран город';
MSG.REG.DUPLICATE_EMAIL = 'Пользователь с таким e-mail уже существует.';
MSG.REG.WRONG_ICQ = 'Не верный номер ICQ';
MSG.REG.SERVER_ERROR = 'Ошибка сервера';
MSG.INV = new Object();
MSG.INV.NO_EMAIL = 'Не указан e-mail';
MSG.INV.WRONG_EMAIL = 'Неверный формат e-mail';
MSG.INF = new Object();
MSG.INF.PHOTO_ADDED_TO_CONTEST = 'Фотография добавлена';
MSG.INF.FAVORITES_LIMIT = 'Вы больше не можете добавлять конкурсы в списох избранных. Достигнут лимит избранных конкурсов.';
MSG.INF.INVITE_SENT = 'Ваше приглашение отправленно';
MSG.INF.REPORT_SENT = 'Спасибо, Ваша жалоба будет рассмотрена в ближайшее время.';
MSG.INF.NO_PHOTOS_FOUND = 'У Вас нет подходящих фотографий';
MSG.INF.REQUEST_SENT_TO_CONTEST = 'Запрос на добавление фотографии отправлен';
MSG.INF.CONTEST_ADDED_TO_PHOTO = 'Фотография добавлена в конкурс';
MSG.INF.REQUEST_SENT_TO_PHOTO = 'Запрос на добавление фотографии отправлен';
MSG.INF.ADD_TO_FAV = 'Добавить в список избранных';
MSG.INF.REMOVE_FROM_FAV = 'Удалить из списка избранных';
MSG.CONFIRM = new Object();
MSG.CONFIRM.ADD_PHOTO_TO_CONTEST = 'Добавить выбранную фотографию в конкурс?';
MSG.CONFIRM.SEND_REQUEST_TO_CONTEST = 'Отправить запрос на добавление фотографии в конкурс?';
MSG.CONFIRM.ADD_CONTEST_TO_PHOTO = 'Вы хотите добавить фотографию в выбранный конкурс?';
MSG.CONFIRM.SEND_REQUEST_TO_PHOTO = 'Вы хотите отправить запрос на добавление фотографии в выбранный конкурс?';
MSG.CONFIRM.SEND_REPORT = 'Вы хотите отправить жалобу на выбранную фотографию?';
MSG.CONFIRM.DEL_MESSAGE = 'Вы действительно хотите удалить сообщение?';
MSG.CONFIRM.DELETE_PHOTO = 'Вы действительно хотите удалить выбранную фотографию?';
MSG.CONFIRM.LEAVE_CONTEST = 'Покинуть конкурс?';
MSG.CONFIRM.CANCEL_REQUEST = 'Отменить заявку?';
MSG.CONFIRM.CONTEST_CREATE = 'Вы действительно хотите создать конкурс?';
MSG.CONFIRM.CONTEST_DELETE = 'Вы действительно хотите удалить конкурс?';
MSG.CONFIRM.COMMENT_DELETE = 'Вы действительно хотите удалить комментарий?';
MSG.CONFIRM.YES = 'Да';
MSG.CONFIRM.NO = 'Нет';
MSG.CONFIRM.CLOSE = 'Закрыть';
MSG.UPL = new Object();
MSG.UPL.WRONG_RATIO = 'Неверные пропорции фотографии';
MSG.UPL.WRONG_FILE_SIZE = 'Слишком большой размер файла';
MSG.UPL.WRONG_PICTURE_SIZE = 'Размер фотографии слишком маленький';
MSG.UPL.WRONG_AVATAR_SIZE = 'Неподходящий размер аватара. Допустимый размер 80x80.';
MSG.UPL.PROCESSING_ERROR = 'Ошибка обработки фотографии';
MSG.UPL.DEFAULT = 'Фотография не может быть загружена';
MSG.CON = new Object();
MSG.CON.NO_NAME = 'Не указано имя конкурса';
MSG.CON.SHORT_NAME = 'Имя конкурса слишком короткое'; 
MSG.CON.LONG_NAME = 'Имя конкурса слишком длинное';
MSG.CON.NO_DESCR = 'Не задано описание конкурса';
MSG.CON.SHORT_DESCR = 'Описание конкурса слишком короткое'; 
MSG.CON.LONG_DESCR = 'Описание конкурса слишком длинное';
MSG.CON.NO_DATE = 'Не указана дата окончания конкурса';
MSG.CON.WRONG_DATE = 'Неверная дата';
MSG.CON.ERR_DATE = 'Продолжительность конкурса должна быть более 15 дней';
MSG.ME = new Object();
MSG.ME.TXT_TO_SHORT = 'Сообщение слишком короткое';
MSG.ME.BAD_WORDS = 'Недопустимые слова в сообщении';
MSG.ME.FUNCTION_BLOCKED = 'Функция заблокирована на несколько дней';
MSG.ME.TXT_TO_LONG = 'Сообщение слишком длинное';
MSG.ME.COMMENT = 'Ваш комментарий';
MSG.ME.REPLY = 'Ваш ответ';
MSG.ME.PRIVATE_MESSAGE = 'Личное сообщение';
MSG.ME.REPLY_EDIT = 'Редактирование ответа';
MSG.ME.POST = 'Добавить';
MSG.ME.SEND = 'Отправить';
MSG.ME.SAVE = 'Сохранить';
MSG.ME.LOADING = 'Загрузка...';
MSG.FILTER = new Object();
MSG.FILTER.ALL = 'все';
MSG.FILTER.PERSONAL = 'личные';
MSG.FILTER.KID = 'детские';
MSG.FILTER.ANIMAL = 'питомцы';
MSG.FILTER.OTHER = 'другое';

var PHOTO = new Object();
PHOTO.META_A = 'Фотография уже добавлена';
PHOTO.META_R = 'Запрос на добавление отправлен';
PHOTO.META_L = 'Максимальное кол-во конкурсов';

MSG.TITLE = new Object();
MSG.TITLE.ERROR = 'Ошибка';
MSG.TITLE.INFORMATION = 'Внимание';
MSG.TITLE.WRONG_LOGIN = 'Ошибка авторизации';

var LOC = new Object();
LOC.COUNTRIES_MAP = new Hash({19 : 'Австралия', 20 : 'Австрия', 5 : 'Азербайджан', 21 : 'Албания', 22 : 'Алжир', 23 : 'Американское Самоа', 24 : 'Ангилья', 25 : 'Ангола', 26 : 'Андорра', 27 : 'Антигуа и Барбуда', 28 : 'Аргентина', 6 : 'Армения', 29 : 'Аруба', 30 : 'Афганистан', 31 : 'Багамы', 32 : 'Бангладеш', 33 : 'Барбадос', 34 : 'Бахрейн', 3 : 'Беларусь', 35 : 'Белиз', 36 : 'Бельгия', 37 : 'Бенин', 38 : 'Бермуды', 39 : 'Болгария', 40 : 'Боливия', 41 : 'Босния и Герцеговина', 42 : 'Ботсвана', 43 : 'Бразилия', 44 : 'Бруней-Даруссалам', 45 : 'Буркина-Фасо', 46 : 'Бурунди', 47 : 'Бутан', 48 : 'Вануату', 49 : 'Великобритания', 50 : 'Венгрия', 51 : 'Венесуэла', 52 : 'Виргинские острова, Британские', 53 : 'Виргинские острова, США', 54 : 'Восточный Тимор', 55 : 'Вьетнам', 56 : 'Габон', 57 : 'Гаити', 58 : 'Гайана', 59 : 'Гамбия', 60 : 'Гана', 61 : 'Гваделупа', 62 : 'Гватемала', 63 : 'Гвинея', 64 : 'Гвинея-Бисау', 65 : 'Германия', 66 : 'Гибралтар', 67 : 'Гондурас', 68 : 'Гонконг', 69 : 'Гренада', 70 : 'Гренландия', 71 : 'Греция', 7 : 'Грузия', 72 : 'Гуам', 73 : 'Дания', 231 : 'Джибути', 74 : 'Доминика', 75 : 'Доминиканская Республика', 76 : 'Египет', 77 : 'Замбия', 78 : 'Западная Сахара', 79 : 'Зимбабве', 8 : 'Израиль', 80 : 'Индия', 81 : 'Индонезия', 82 : 'Иордания', 83 : 'Ирак', 84 : 'Иран', 85 : 'Ирландия', 86 : 'Исландия', 87 : 'Испания', 88 : 'Италия', 89 : 'Йемен', 90 : 'Кабо-Верде', 4 : 'Казахстан', 91 : 'Камбоджа', 92 : 'Камерун', 10 : 'Канада', 93 : 'Катар', 94 : 'Кения', 95 : 'Кипр', 96 : 'Кирибати', 97 : 'Китай', 98 : 'Колумбия', 99 : 'Коморы', 100 : 'Конго', 101 : 'Конго, демократическая республика', 102 : 'Коста-Рика', 104 : 'Куба', 105 : 'Кувейт', 11 : 'Кыргызстан', 106 : 'Лаос', 12 : 'Латвия', 107 : 'Лесото', 108 : 'Либерия', 109 : 'Ливан', 110 : 'Ливийская Арабская Джамахирия', 13 : 'Литва', 111 : 'Лихтенштейн', 112 : 'Люксембург', 113 : 'Маврикий', 114 : 'Мавритания', 115 : 'Мадагаскар', 116 : 'Макао', 117 : 'Македония', 118 : 'Малави', 119 : 'Малайзия', 120 : 'Мали', 121 : 'Мальдивы', 122 : 'Мальта', 123 : 'Марокко', 124 : 'Мартиника', 125 : 'Маршалловы Острова', 126 : 'Мексика', 127 : 'Микронезия, федеративные штаты', 128 : 'Мозамбик', 15 : 'Молдова', 129 : 'Монако', 130 : 'Монголия', 131 : 'Монтсеррат', 132 : 'Мьянма', 133 : 'Намибия', 134 : 'Науру', 135 : 'Непал', 136 : 'Нигер', 137 : 'Нигерия', 138 : 'Нидерландские Антилы', 139 : 'Нидерланды', 140 : 'Никарагуа', 141 : 'Ниуэ', 142 : 'Новая Зеландия', 143 : 'Новая Каледония', 144 : 'Норвегия', 145 : 'Объединенные Арабские Эмираты', 146 : 'Оман', 147 : 'Остров Мэн', 148 : 'Остров Норфолк', 149 : 'Острова Кайман', 150 : 'Острова Кука', 151 : 'Острова Теркс и Кайкос', 152 : 'Пакистан', 153 : 'Палау', 154 : 'Палестинская автономия', 155 : 'Панама', 156 : 'Папуа - Новая Гвинея', 157 : 'Парагвай', 158 : 'Перу', 159 : 'Питкерн', 160 : 'Польша', 161 : 'Португалия', 162 : 'Пуэрто-Рико', 163 : 'Реюньон', 1 : 'Россия', 164 : 'Руанда', 165 : 'Румыния', 166 : 'Сальвадор', 167 : 'Самоа', 168 : 'Сан-Марино', 169 : 'Сан-Томе и Принсипи', 170 : 'Саудовская Аравия', 171 : 'Свазиленд', 172 : 'Святая Елена', 173 : 'Северная Корея', 174 : 'Северные Марианские острова', 175 : 'Сейшелы', 176 : 'Сенегал', 177 : 'Сент-Винсент', 178 : 'Сент-Китс и Невис', 179 : 'Сент-Люсия', 180 : 'Сент-Пьер и Микелон', 181 : 'Сербия и Черногория', 182 : 'Сингапур', 183 : 'Сирийская Арабская Республика', 184 : 'Словакия', 185 : 'Словения', 186 : 'Соломоновы Острова', 187 : 'Сомали', 188 : 'Судан', 189 : 'Суринам', 9 : 'США', 190 : 'Сьерра-Леоне', 16 : 'Таджикистан', 191 : 'Таиланд', 192 : 'Тайвань', 193 : 'Танзания', 194 : 'Того', 195 : 'Токелау', 196 : 'Тонга', 197 : 'Тринидад и Тобаго', 198 : 'Тувалу', 199 : 'Тунис', 17 : 'Туркмения', 200 : 'Турция', 201 : 'Уганда', 18 : 'Узбекистан', 2 : 'Украина', 202 : 'Уоллис и Футуна', 203 : 'Уругвай', 204 : 'Фарерские острова', 205 : 'Фиджи', 206 : 'Филиппины', 207 : 'Финляндия', 208 : 'Фолклендские острова', 209 : 'Франция', 210 : 'Французская Гвиана', 211 : 'Французская Полинезия', 212 : 'Хорватия', 213 : 'Центрально-Африканская Республика', 214 : 'Чад', 230 : 'Черногория', 215 : 'Чехия', 216 : 'Чили', 217 : 'Швейцария', 218 : 'Швеция', 219 : 'Шпицберген и Ян Майен', 220 : 'Шри-Ланка', 221 : 'Эквадор', 222 : 'Экваториальная Гвинея', 223 : 'Эритрея', 14 : 'Эстония', 224 : 'Эфиопия', 225 : 'Югославия', 226 : 'Южная Корея', 227 : 'Южно-Африканская Республика', 228 : 'Ямайка', 229 : 'Япония'});
LOC.LOADING_ID = '-1';
LOC.LOADING = 'Загрузка...';
LOC.CNTR_MESSAGE = 'Не выбрано'; // Change registration.jsp also
LOC.CNTR_NOT_DEFINED = 'Не важно';
LOC.CNTR_ID = '0';
LOC.CITY_MESSAGE = 'Не выбрано'; // Change registration.jsp also
LOC.CITY_NOT_DEFINED = 'Не важно';
LOC.CITY_ID = '0';
LOC.OTHER_MESSAGE = '- Другой город -';
LOC.OTHER_ID = '-1';

/// SCRIPT

//var h = off/60;
//var m = off%60;
//var sight = '+';
//if (h>0) sight = '-';
//h = Math.abs(h);
//if (sight=='+')
//	h = Math.floor(h);
//else
//	h = Math.ceil(h);
//m = Math.abs(m);
//if (h<10) h='0'+h;
//if (m<10) m='0'+m;
//setCookie('userTimeZone','GMT'+sight+h+m,1);

// set user's time zone
var d = new Date();
d.setFullYear(2008,0,1);
var off = d.getTimezoneOffset()*60000;
var sight = "";
if (off>0) {
	sight = "-";
} else {
	off=-1*off;
}
setCookie('userTimeZone',sight+off,1);

function setCookie(c_name,value,expiredays) {
	var exdate=new Date();
	exdate.setDate(exdate.getDate()+expiredays);
	document.cookie=c_name+ "=" +escape(value)+
	((expiredays==null) ? "" : ";expires="+exdate.toGMTString());
}

var Helpers = new Object(); 
Helpers.refresh = function() {
	top.location=window.location.href;
}
Helpers.numberToString = function(num) {
	var number = 0 + num;
	if (number<0) number = 0;
	if (number>999) {
		var zeros = "";
		if (number%1000<100) zeros += "0";
		if (number%1000<10) zeros += "0";
		return ""+Math.floor(number/1000)+","+zeros+number%1000;
	}
	return ""+number;
}
Helpers.getJSButton = function(text,width) {
	var btn = new Element('table',{'class':'pointer','style':'width: '+width+'px'});
	var body = new Element('tbody');
	var tr = new Element('tr');
	var td1 = new Element('td',{'class':'gif bck82'});
	var img1 = new Element('img',{'src':SYSTEM.SPACE,'width':'5'});	
	var td2 = new Element('td',{'class':'pngh bck88 t-12 t-b c-w t-nu padl5 padr5','align':'center'});	
	var td3 = new Element('td',{'class':'gif bck83'});
	var img3 = new Element('img',{'src':SYSTEM.SPACE,'width':'5'});
	td1.insert(img1);td3.insert(img3);	
	td2.insert(text);
	tr.insert(td1).insert(td2).insert(td3);
	body.insert(tr);
	btn.insert(body);
	return btn;	
}
//<table id="av_editor_apply" class="pointer"><tr>
//	<td class="gif bck82"></td>
//	<td class="pngh bck88"><a class="t-12 t-b c-w t-nu padl5 padr5" href="javascript:void(0);">Принять</a></td>
//	<td class="gif bck83"></td>
//</tr></table>

Helpers.getSelectionLabel = function(selectionId) {
	var el = $(selectionId);
	if (el==null || el.selectedIndex==0) return "";
	return el.options[el.selectedIndex].innerHTML;
}

Helpers.setSelection = function(selectionId, value) {
	if (value==null) return;
	var sel=$(selectionId);
	if (sel!=null) {
		for(index = 0; index < sel.length; index++) {
			if(sel[index].value == value)
				sel.selectedIndex = index;
		}
	}
}
Helpers.getSelection = function(selectionId) {
	var sel=$(selectionId);
	if (sel==null) return "";
	return sel.value;
}
function Select_Value_Set(SelectName, Value) {
  eval('SelectObject = document.' + 
    SelectName + ';');
  for(index = 0; 
    index < SelectObject.length; 
    index++) {
   if(SelectObject[index].value == Value)
     SelectObject.selectedIndex = index;
   }
}
Helpers.getTime = function() {
	var d = new Date();
	return d.getTime();
}
Helpers.getElementByEvent = function (e) {
	if (e.target) {
		targ=e.target;
	} else if (e.srcElement) {
		targ=e.srcElement;
	} if (targ.nodeType==3) {
		targ = targ.parentNode;
	}
	return targ;
}
Helpers.getKeyNum = function (e) {
	var keynum = 0;
	if(window.event) {
		keynum = e.keyCode
	} else if(e.which) {
		keynum = e.which
	}
	return keynum;
}
Helpers.getDocHeight = function () {
  var myHeight = 0;
  if( typeof( window.innerWidth ) == 'number' ) {
    //Non-IE
    myHeight = window.innerHeight;
  } else if( document.documentElement && ( document.documentElement.clientWidth || document.documentElement.clientHeight ) ) {
    //IE 6+ in 'standards compliant mode'
    myHeight = document.documentElement.clientHeight;
  } else if( document.body && ( document.body.clientWidth || document.body.clientHeight ) ) {
    //IE 4 compatible
    myHeight = document.body.clientHeight;
  }
  return myHeight;
}
Helpers.getScrollY=function() {
	return Helpers.f_filterResults (
		window.pageYOffset ? window.pageYOffset : 0,
		document.documentElement ? document.documentElement.scrollTop : 0,
		document.body ? document.body.scrollTop : 0
	);
}
Helpers.getScrollX=function() {
	return Helpers.f_filterResults (
		window.pageXOffset ? window.pageXOffset : 0,
		document.documentElement ? document.documentElement.scrollLeft : 0,
		document.body ? document.body.scrollLeft : 0
	);
}
Helpers.f_filterResults=function(n_win, n_docel, n_body) {
	var n_result = n_win ? n_win : 0;
	if (n_docel && (!n_result || (n_result > n_docel)))
		n_result = n_docel;
	return n_body && (!n_result || (n_result > n_body)) ? n_body : n_result;
}
Helpers.getDocWidth = function () {
	return $('body').getWidth();
}

Helpers.blockScreen = function (zIndex) {
	Helpers.initBlocking();
	Helpers.blockPosition=zIndex;
	if (zIndex==0) {
		Helpers.unBlockScreen();
	} else {
		if ($('banner1')!=null)
			$('banner1').hide();
		Helpers.blocking.style.zIndex=zIndex;
		Helpers.blocking2.style.zIndex=zIndex;
		Helpers.blocking2.show();
		Helpers.blocking.show();
//		alert(Helpers.blocking2.getWidth());
		Helpers.blocking.className='blocking';
//		if (Helpers.scrollDetectorRunning==0) {
//			Helpers.scrollDetector();
//		}
	}
}
/*
Helpers.scrollDetector = function () {
	Helpers.scrollDetectorRunning=1;
	if (Helpers.blockPosition!=0) {
		var newScrollPosition=Helpers.getScrollY();
		if (newScrollPosition!=Helpers.scrollPosition) {
			Helpers.scrollPosition=newScrollPosition;
			Helpers.movePops();
		}
		setTimeout("Helpers.scrollDetector();",300);
	} else {
		Helpers.scrollDetectorRunning=0;
	}
}
*/
Helpers.unBlockScreen = function () {
	if ($('banner1')!=null)
		$('banner1').show();
	Helpers.initBlocking();
	Helpers.blocking.hide();
	Helpers.blocking2.hide();
}
Helpers.init = function() {
//	Helpers.blocking = new Element('div',{'class':'blocking'});
//	$('body').insert(Helpers.blocking);
//	Helpers.blocking.hide();
//	Helpers.blocking.setStyle({height:''+$('body').getHeight()+'px',width:''+$('body').getWidth()+'px'});
//	Helpers.scrollPositon=Helpers.getScrollY();
//	Helpers.scrollDetectorRunning=0;
//	dp_cal1 = new Epoch('cal1',$('r_date'),$('r_date_pop'));
}
Helpers.bodyResize = function() {
	Helpers.initBlocking();
	Helpers.blocking.setStyle({height:''+$('mainTable').getHeight()+'px',width:''+$('mainTable').getWidth()+'px'});
	Helpers.blocking2.clonePosition(Helpers.blocking);
	Helpers.movePops();
}
Helpers.initBlocking = function() {
//alert($('body').getWidth());
//alert($('mainTable').getWidth());
	var init = 0;
	if (Helpers.blocking==undefined) init = 1;
	if (init == 1) {
		Helpers.blocking = new Element('div',{'class':'blocking'});
		Helpers.blocking2 = new Element('iframe',{'class':'abs transparent'});
		$('body').insert(Helpers.blocking2);
		$('body').insert(Helpers.blocking);
	}
//	alert('init '+$('mainTable').getHeight());
	Helpers.blocking.setStyle({height:''+$('mainTable').getHeight()+'px',width:''+$('mainTable').getWidth()+'px'});
//	Helpers.blocking2.setStyle({height:''+$('mainTable').getHeight()+'px',width:''+$('body').getWidth()+'px'});
	Helpers.blocking2.clonePosition(Helpers.blocking);
	if (init == 1) {
		Helpers.blocking.hide();
		Helpers.blocking2.hide();
	}
}

Helpers.movePops=function() {
	Popups.zIndex.each(function(pair) {
		var pop=$(pair.key);
		var popPanel=$(pop);
//		var top=Helpers.getScrollY()+(Helpers.getDocHeight()-popPanel.getHeight())/2;
		var left=(Helpers.getDocWidth()-popPanel.getWidth())/2;
		if (left<0) left=0;
//		popPanel.setStyle({top:''+top+'px',left:''+left+'px'});
		popPanel.setStyle({left:''+left+'px'});
	});
}

Helpers.keyPressed = function(event) {
	if (Helpers.check_esc(event)) {
		if (Popups.waitWindowId=='') {
			var popId=Popups.queue.last();
			var beforeCloseFn=Popups.queueBeforeCloseFn.last();
			var afterCloseFn=Popups.queueAfterCloseFn.last();
			if (popId!=undefined) {
				
				if (beforeCloseFn==undefined || beforeCloseFn()) {
					Popups.closePopup(popId)
					if (afterCloseFn!=undefined) afterCloseFn();
				}
				
			}
		}
	}
}

Helpers.check_esc = function(eventobjekt) {
	var var_key = 0;
	if (window.event && window.event.keyCode) {
	var_key = window.event.keyCode;
	}
	else if (eventobjekt && eventobjekt.keyCode) {
	var_key = eventobjekt.keyCode;
	}
	return (var_key == 27);
}

Helpers.rpc = function(url, parametersHash, onSuccessFunc, onFailFunc) {
	Popups.doNotClose++;
	new Ajax.Request(''+url+Helpers.getTime(), { 
		method:'post',
		parameters: parametersHash.toQueryString(),
		onSuccess: function(transport) {
			Popups.doNotClose--;
			if (transport.responseText=='') {
				if (onFailFunc==undefined)
					Popups.defaultError(); // empty response
				else
					onFailFunc('empty_response');
			} else {
				if (transport.responseText.substr(0,4)=='_err') {
					if (onFailFunc==undefined)
						Popups.defaultError(); // server returned error
					else
						onFailFunc(transport.responseText.substr(5));
				} else if (transport.responseText.substr(0,10)=='_notLogged') {
					uLog.postponedLink=top.location;
					Init.main('notLoggedRPC');
				} else {
					onSuccessFunc(transport.responseText);
				}
			}
		},
		onFailure: function(transport) {
			Popups.doNotClose--;
			if (onFailFunc==undefined)
				Popups.defaultError(); // bad response (server is down)
			else
				onFailFunc('failure');
		}
	});
}
Helpers.clear = function(el) {
	el.childElements().each(function (currentEl) {currentEl.remove()});
}
Helpers.isOperaVarInit = false;
Helpers.isOpera = function() {
	if (!Helpers.isOperaVarInit)
		Helpers.isOperaVar = navigator.userAgent.indexOf('Opera') > -1;
		Helpers.isOperaVarInit=true;
	return Helpers.isOperaVar;
}
Helpers.fireEvent = function(element,event){
    if (document.createEventObject){
        // dispatch for IE
        var evt = document.createEventObject();
        return element.fireEvent('on'+event,evt)
    }
    else{
        // dispatch for firefox + others
        var evt = document.createEvent("HTMLEvents");
        evt.initEvent(event, true, true ); // event type,bubbling,cancelable
        return !element.dispatchEvent(evt);
    }
}
Helpers.getMediumPhotoUrl = function(id) {
	return SYSTEM.URL.IMAGE_ROOT_HTTP+Helpers.getPhotoSubFolder(id)+SYSTEM.URL.PREFIX_MEDIUM+id+'.jpg';
}
Helpers.empty = function(result) {
//	alert('empty function: result='+result);
}

var Location = new Object();
Location.cntrCache = new Hash();
Location.cityCache = new Hash();
Location.currKeys = new Array();
Location.selIndex=0;
Location.selId=0;
Location.mSelIndex=0;
Location.mSelId=0;
Location.maxIndex=0;
Location.prevPattern='';
Location.click=0;
Location.threads=0;
Location.initialized=0;
Location.defCntrOption='';
Location.defCityOption='';
Location.prevCountryValue=-1;
Location.init = function(cntrElName, townElName, otherPanelName, otherElName, defCntrOption, defCityOption) {
	Location.otherBlur();
	Location.defCntrOption=defCntrOption;
	Location.defCityOption=defCityOption;
	Location.cityCache = new Hash();
	Location.cntr=$(cntrElName);
//	alert(Location.cntr);
	Location.town=$(townElName);
	Location.otherPanel=$(otherPanelName);
	Location.other=$(otherElName);

	Location.cityList = new Element('div',{'class':'cityList'});
	Location.cityListBlock = new Element('iframe',{'class':'abs a998 transparent'});
	$('body').insert(Location.cityList);
	$('body').insert(Location.cityListBlock);
	Location.cityList.hide();
	Location.cityListBlock.hide();

	Location.cntr.observe('change',Location.cntrOnChange);
	Location.town.observe('change',Location.townOnChange);
	Location.cntr.observe('keyup',Location.cntrOnChange);
	Location.town.observe('keyup',Location.townOnChange);
	Location.other.observe('keyup',Location.otherChanged);
	Location.other.observe('keydown',Location.otherPositionChanged);
	Location.other.observe('blur',function() {setTimeout("Location.otherBlur();",200);});
//	Location.cntr[0].selected=true; // FireFox fix
//	Location.cntrOnChange();
	Location.initialized=1;
}
Location.otherBlur = function() {
	if (Location.click==0) {
		if (Location.initialized==1) {
			Location.other.value='';
			Location.prevPattern='';
			Location.other.value='';
			Location.cityList.hide();
			Location.cityListBlock.hide();
		}
	}	
}
Location.threadsManager = function(action) {
	if ('inc'==action) {
		Location.threads++;
	} else if ('dec'==action) {
		Location.threads--;
	}
//	if (Location.threads>0) {
//		Location.other.className='otherInputBlocked';
//	} else {
//		Location.other.className='cntrl-ta ';
//	}
}
Location.insertOption = function(el, id, value) {
	var newOption = new Element("option", {'value':id, 'id':'tl'+id});
	newOption.insert(value);
	el.insert(newOption);
}
Location.clearSelect = function(el) {
	for (var i=0; i<el.length; i++) {
		el.remove(0);
	}	
}
Location.cntrOnChange = function() {
	Location.otherPanel.hide();
	cntrEl=Location.cntr;
	if (cntrEl.value==Location.prevCountryValue) return; //FF & Opera fix;
	Location.prevCountryValue=cntrEl.value;
	if (cntrEl.value=='all') {
		Helpers.clear(cntrEl);
		Location.insertOption(cntrEl, LOC.CNTR_ID, Location.defCntrOption);
		LOC.COUNTRIES_MAP.each(function (pair) {
			Location.insertOption(cntrEl, pair.key, pair.value);
		});
		Helpers.clear(Location.town);
		Location.insertOption(Location.town, LOC.CITY_ID, Location.defCityOption);
		Location.town.disabled=true;
	} else if (cntrEl.value=='0') {
		Helpers.clear(Location.town);
		Location.insertOption(Location.town, LOC.CITY_ID, Location.defCityOption);
		Location.town.disabled=true;
	} else {
		Location.cityCache = new Hash();
		Location.town.disabled=true;
		Helpers.clear(Location.town);
		Location.insertOption(Location.town, LOC.LOADING_ID, LOC.LOADING);
		Location.uploadTowns();
	}
}
Location.townOnChange = function() {
	el=Location.town;
	if (el.value==LOC.OTHER_ID) {
		Location.otherPanel.show();
		Location.other.value='';
		Location.other.focus();
	} else {
		Location.otherPanel.hide();
	}
}
Location.otherPositionChanged = function(ev) {
	var key = Helpers.getKeyNum(ev);
	if (key==38) { //up
		if (Location.selIndex>1) {
			Location.selIndex--;
			Location.selId=Location.currKeys[Location.selIndex-1];
			Location.selectPosition(Location.selIndex);
		}
	} else if (key==40) { //down
		if (Location.selIndex<Location.maxIndex) {
			Location.selIndex++;
			Location.selId=Location.currKeys[Location.selIndex-1];
			Location.selectPosition(Location.selIndex);
		}
	} else if (key==13) { //enter
		if (Location.selIndex!=0) {
			var id = Location.selId;
			var name = Location.cityCache.get(Location.other.value).get(Location.selId).get('name');
			Location.addFromList(id, name);
		}
		return false;
	}
    return true;
}
Location.addFromList=function(id, name) {
	Location.cntrCache.get(Location.cntr.value).set(id, new Hash({'name':name,'region1':'','region2':''}));
	Location.uploadTownsMap(Location.cntrCache.get(Location.cntr.value));
	Location.click=0;
	Location.otherBlur();
	Location.otherPanel.hide();
	setTimeout("$('tl"+id+"').selected=true;Location.town.focus();",0); // opera fix
}

Location.otherChanged = function() {
	if (Location.other.value!='') {
		if (Location.prevPattern!=Location.other.value) {
			Location.prevPattern=Location.other.value;
			var cachedRes = Location.cityCache.get(Location.other.value);
			if (cachedRes==undefined) {
				var map = new Hash();
				map.set('country', Location.cntr.value);
				map.set('pattern', Location.other.value);
				Location.threadsManager('inc');
				Helpers.rpc('/rpc/towns/', map, Location.otherChangedSuccess, Location.otherChangedFail);
			} else {
				Location.otherChangedMap(cachedRes);
			}
		}
	} else {
		Location.prevPattern='';
		Location.otherChangedMap(new Hash());
	}
}
Location.otherChangedSuccess = function(result) {
	Location.threadsManager('dec');
	var map = eval(result);
	Location.cityCache.set(map.get('pattern'), map.get('values'));
	// make sure that it's a last response
	if (Location.other.value==map.get('pattern')) {
		Location.otherChangedMap(map.get('values'));
	}
}
Location.otherChangedFail = function(result) {
	Location.threadsManager('dec');
}
Location.otherChangedMap = function(map) {
	if (map.keys().length>0) {
		Helpers.clear(Location.cityList);

		
		Location.fillCityList(map, Location.selId);

		var positions = Location.other.cumulativeOffset();
		var listH = Location.cityList.getHeight();
		var totalH = $('mainTable').getHeight();
		var controlTop = positions[1];
		var controlH = 19;
		var listTop=0;
//		alert(totalH+' '+listH+' '+controlH);
		if (listH<controlTop && (totalH-controlTop-controlH)<listH) {
			// show at top
			listTop=controlTop-listH;
		} else {
			// show at bottom
			listTop=controlTop+controlH;
		}

		Location.cityList.setStyle({'width':''+Location.other.getWidth()-2+'px',top:''+listTop+'px',left:''+positions[0]+'px'});
		Location.cityList.show();
		Location.cityListBlock.clonePosition(Location.cityList);
		Location.cityListBlock.show();


	} else {
		Location.cityList.hide();
		Location.cityListBlock.hide();
		Location.selIndex=0;
		Location.selId=0;
	}
}
Location.fillCityList = function(map, selId) {
	Location.currKeys=map.keys();
	Location.maxIndex=map.keys().length;
	var pos=0;
	var selectPosition=0;
	map.each(function(pair) {
		pos++;
		var mPos=pos;
		if (pair.key==selId) {
			selectPosition=pos;
		}
		var el = new Element('div',{'class':'cityListRow'});
		el.observe('mouseover',function() {
			el.className='cityListSelectedRow';
		});
		el.observe('mouseout',function() {
			if (mPos!=Location.selIndex)
				el.className='cityListRow';
		});
		el.observe('click',function() {
			Location.click=1;
			Location.addFromList(pair.key, pair.value.get('name'));
		});
		var element = pair.value.get('name');
		if (pair.value.get('region1')!='') element+='<br><div class="cityListSmallText">'+pair.value.get('region1')+'</div>';
		if (pair.value.get('region2')!='') element+='<div class="cityListSmallText">'+pair.value.get('region2')+'</div>';
//		el.insert(pair.value.get('name'));
		el.insert(element);
		Location.cityList.insert(el);
	});
	if (selectPosition==0) selectPosition=1;
	Location.selectPosition(selectPosition);
}
Location.selectPosition = function(position) {
	Location.selIndex=position;
	Location.selId=Location.currKeys[position-1];
	var i=0;
	Location.cityList.childElements().each(function(el) {
		i++;
		if (i==position) {
			el.className='cityListSelectedRow';
		} else {
			el.className='cityListRow';
		}
	});
}

Location.uploadTowns = function() {
	var cachedRes = Location.cntrCache.get(Location.cntr.value);
	if (cachedRes==undefined) {
		var map = new Hash();
		map.set('country', Location.cntr.value);
		Helpers.rpc('/rpc/towns/', map, Location.uploadTownsSuccess, Location.uploadTownsFail);
	} else {
		Location.uploadTownsMap(cachedRes);
	}
}
Location.uploadTownsSuccess = function(result) {
	var map = eval(result);
	Location.uploadTownsSuccessNoEval(map);
}
Location.uploadTownsSuccessNoEval = function(map) {
	Location.cntrCache.set(map.get('country'),map.get('values'));
	Location.uploadTownsMap(map.get('values'));
}
Location.uploadTownsMap = function(map) {
	Helpers.clear(Location.town);
	Location.insertOption(Location.town, LOC.CITY_ID, Location.defCityOption);
	if (map.keys().length>0) {
		map.each(function (pair) {
			Location.insertOption(Location.town, pair.key, pair.value.get('name'));
		});
	}
 
	Location.insertOption(Location.town, LOC.OTHER_ID, LOC.OTHER_MESSAGE);
	Location.town.disabled=false;
}
Location.uploadTownsFail = function(result) {
	Helpers.clear(Location.town);
}
Location.fillCntrCache = function(cntrElName, cityElName) {
	var cntrId = $(cntrElName).value;
	var el = $(cityElName);
	var cityMap = new Hash();
	for (var i = 0; i < el.options.length; i++) {
		if (el.options[i].value>0) {
			var vals = new Hash({'name':el.options[i].innerHTML,'region1':'','region2':''});
			cityMap.set(el.options[i].value,vals);
		}
	}
	Location.cntrCache.set(cntrId,cityMap);
}

var votesFilter = new Object(); 
votesFilter.filter = '';
votesFilter.contestId = 0;
votesFilter.disableCurrent = false;
votesFilter.selectFilter = function (filter, contestId) {
	votesFilter.unMarkCurrent();
	votesFilter.filter=filter;
	votesFilter.contestId=contestId;
	if ('all'==filter) {
		votesFilter.updateLinkAndSession(filter, contestId);
		$('filterAll').className='bck22 t-11 c-g3 t-b';	
		$('filterAll1').className='gif bck20 fr';	
		$('filterAll2').className='gif bck21 fr';	
		$('voteFilter').value='all';	
	} else if ('current'==filter) {
		votesFilter.updateLinkAndSession(filter, contestId);		
		$('filterCurrent').className='bck22 t-11 c-g3 t-b';		
		$('filterCurrent1').className='gif bck20 fr';		
		$('filterCurrent2').className='gif bck21 fr';		
		$('voteFilter').value='current';	
	}
}
votesFilter.unMarkCurrent = function () {
	if (votesFilter.filter=='' || votesFilter.filter=='all') {
		$('filterAll').className='pointer t-11 c-b1 t-u';
		$('filterAll1').className='bck23';
		$('filterAll2').className='bck23';
	}
	if (votesFilter.filter=='' || votesFilter.filter=='favorites') {
		$('filterFavorites').className='pointer t-11 c-b1 t-u';
		$('filterFavorites1').className='bck23';
		$('filterFavorites2').className='bck23';
	}

	if (votesFilter.filter=='' || votesFilter.filter=='current') {
		$('filterCurrent1').className='bck23';
		$('filterCurrent2').className='bck23';
		if (votesFilter.disableCurrent==true) {
			$('filterCurrent').className='t-11 c-g3';
		} else {
			$('filterCurrent').className='pointer t-11 c-b1 t-u';
		}
	}
 
}
votesFilter.updateLinkAndSession = function (filter, contestId) {
	var map = new Hash();
	map.set('filter', filter);
	map.set('contestId', contestId);
	Helpers.rpc('/rpc/filter/', map, votesFilter.updateLinkAndSessionSucces, Helpers.empty);
}
votesFilter.updateLinkAndSessionSucces = function (result) {
	if ('all'==votesFilter.filter) {
		$('mainLink').href='/vote';
	} else if ('favorites'==votesFilter.filter) {
		$('mainLink').href='/vote/favorites';
	} else if ('current'==votesFilter.filter) {
		$('mainLink').href='/vote/'+votesFilter.contestId;
	}
}

var uLog = new Object();
uLog.postponedLink='';
uLog.logged=false;
uLog.doNotRefreshPage=false;
uLog.goIfLogged = function(url) {
	if (url==undefined) url=top.location;
	if (uLog.logged) {
		top.location=url;
	} else {
		uLog.postponedLink=url;
		uLog.openRegWnd();
	}
}
uLog.actIfLogged = function(fn) {
	if (uLog.logged) {
		fn();
	} else {
		uLog.openRegWnd();
	}
}
uLog.openRegistrationWindow = function() {
	uLog.postponedLink='';
	uLog.redirect=0;
	uLog.openRegWnd();
}
Helpers.restoreElements = Helpers.empty;
uLog.openRegWnd = function() {
	Location.init('r_country','r_town','r_town_other_panel','r_town_other',LOC.CNTR_MESSAGE,LOC.CITY_MESSAGE);
//	$('rlogin_email').value=$('login_email').value;
	Reg.windowId=Popups.showPopupMix('', 'registration', function() {Location.otherBlur();return true}, Helpers.restoreElements);
}
uLog.login = function(source) {
	uLog.source=source;
	var email='';
	var pass='';
	var map = new Hash();
	if ('r'==source) {
		uLog.redirect=1;
		Btns.disable('r_login');
		email=$('rlogin_email').value;
		pass=$('rlogin_password').value;
	} else if ('b'==source) {
		uLog.redirect=1;
		Btns.disable('b_login');
		email=$('b_email').value;
		pass=$('b_pass').value;
		map.set('redirect','true');
	} else {
		uLog.redirect=0;
		Btns.disable('l_login');
		email=$('login_email').value;
		pass=$('login_password').value;
	}

	if (uLog.redirect==1) {
		var toVal = uLog.postponedLink;
		if (toVal=='') {
			var postponedEl = $('postponedURI');
			if (postponedEl!=null) {
				toVal=postponedEl.innerHTML;
			}
		}
	}

	map.set('email',email);
	map.set('password',pass);
	map.set('destination',toVal);
	var el = $('keepLogged');
	if (el!=null) {
		map.set('keepLogged',el.checked);
	}
	Helpers.rpc('/rpc/login/',map,uLog.loginSuccess,uLog.loginFail);
}
uLog.loginSuccess = function(result) {
//	alert(uLog.doNotRefreshPage);
	if (uLog.doNotRefreshPage==true) {
		Popups.closeLast();
		Btns.enableAll();
		return;
	}
	if (uLog.redirect==1) {
		var toVal = uLog.postponedLink;
		if (toVal=='') {
			var postponedEl = $('postponedURI');
			if (postponedEl!=null) {
				toVal=postponedEl.innerHTML;
			}
		}
		if (toVal!='') {
//			alert('redirect to '+toVal);
			top.location=toVal;
		} else {
//			alert('redirect to self page');
			top.location=window.location.href;
		}
	} else {
//		alert('refresh');
		top.location=window.location.href;
	}
}
uLog.loginFail = function(result) {
	var source = uLog.source;
//	alert('source='+source);
	if ('r'==source) {
		Btns.enable('r_login');
	} else if ('b'==source) {
		Btns.enable('b_login');
	} else {
		Btns.enable('l_login');
	}
	Popups.defaultError();
}
//uLog.login2 = function(source) {
//	alert(source);
//	var fromEl = $(source+'_from');
//	var toEl = $(source+'_to');
//	var formEl = $(source+'_form');
//
//	var toVal = uLog.postponedLink;
//	if (toVal=='') {
//		var postponedEl = $('postponedURI');
//		if (postponedEl!=null) {
//			toVal=postponedEl.innerHTML;
//		}
//	}
//	fromEl.value=$('uri').innerHTML;
//	toEl.value=toVal;
//	if ('r'==source) {
//		Btns.disable('r_login');
//	} else if ('b'==source) {
//		Btns.disable('b_login');
//	} else {
//		Btns.disable('l_login');
//	}
//	formEl.submit();
//}
uLog.sendPassword=function() {
	var map = new Hash();
	$('bl_email_err').hide();
	map.set('email',$('b_email').value);
	Btns.disable('b_send');
	Helpers.rpc('/rpc/password/',map,uLog.sendPasswordSucces,uLog.sendPasswordFail);
}
uLog.sendPasswordSucces=function(result) {
	Btns.enable('b_send');
	if (result=='success') {
		uLog.emailSentWndId=Popups.showPopup(MSG.TITLE.WRONG_LOGIN,'email_sent');
		$('bl_email_err').hide();
		$('b_email').removeClassName('cntrl-err');
	} else {
		$('bl_email_err').show();
		$('b_email').addClassName('cntrl-err');
	}
}
uLog.sendPasswordFail=function() {
	Btns.enable('b_send');
	Popups.defaultError();
}
uLog.loginFocus=function(param) {
	var el=$('login_email');
	if (el.value==SYSTEM.LOGIN.EMAIL) {
		el.value='';
		var el2=$('login_password');
		el2.value='';
	}
	$('login_text').hide();
	var pas=$('login_password');
	pas.show();
	if (param==1) {
		pas.focus();
	}
}
uLog.loginBlur=function() {
	var el1=$('login_email');
	var el2=$('login_password');
	if (el1.value=='' && el2.value=='') {
		el1.value=SYSTEM.LOGIN.EMAIL;
		el2.hide();
		$('login_text').show();
	}
}

var Fav = new Object();
Fav.contestId=0;
Fav.contests = new Hash();
Fav.add = function(contestId) {
	uLog.actIfLogged(function() {Fav.action(contestId,'add')});
}
Fav.remove = function(contestId) {
	uLog.actIfLogged(function() {Fav.action(contestId,'remove')});
}
Fav.action = function(contestId, action) {
	if (Fav.contests.get(contestId)!=undefined) {
		action=Fav.contests.get(contestId);
	};
	Fav.contestId=contestId;
	var parameters = new Hash();
	parameters.set('contestId',contestId);
	parameters.set('action',action);
	if (action=='add') {
		Helpers.rpc('/rpc/favorites/', parameters, Fav.mark, Helpers.empty);
	} else {
		Helpers.rpc('/rpc/favorites/', parameters, Fav.clear, Helpers.empty);
	}
};
Fav.mark = function(res) {
	if (res=='limit') {
		Popups.showMessage(MSG.INF.FAVORITES_LIMIT);
	} else {
		Fav.contests.set(Fav.contestId, "remove");
		var fav1=$('fav'+Fav.contestId);
		if (fav1!=null) {
			fav1.className='gif bck24 fl pointer';
			fav1.title=MSG.INF.REMOVE_FROM_FAV;
		}
	}
}
Fav.clear = function() {
	Fav.contests.set(Fav.contestId, "add");
	var fav1=$('fav'+Fav.contestId);
//	var fav2=$('tfav'+Fav.contestId);
	if (fav1!=null) {
		fav1.className='gif bck25 fl pointer';
		fav1.title=MSG.INF.ADD_TO_FAV;
	}
//	if (fav2!=null)
//		fav2.className='gif bck25 fl';
}

var Rprt = new Object();
Rprt.ownerId=0;
Rprt.commentId=0;
Rprt.photoId=0;
Rprt.messageId=0;
Rprt.type;
Rprt.reportComment = function(commentId) {
	Rprt.photoId=$('curr_photo_id').innerHTML;
	Rprt.commentId=commentId;
	Rprt.type='c';
	Popups.showPopupW('','reportPanel');
	Btns.register('report_yes',Rprt.reportSubmit);
	Btns.register('report_no',Popups.closeLast);
}
Rprt.reportMessage = function(ownerId, messageId) {
	Rprt.ownerId=ownerId;
	Rprt.messageId=messageId;
	Rprt.type='m';
	Popups.showPopupW('','reportPanel');
	Btns.register('report_yes',Rprt.reportSubmit);
	Btns.register('report_no',Popups.closeLast);
}
Rprt.reportSubmit = function() {
	var map = new Hash();
	if (Rprt.type == 'c') {
		map.set('comment_id',Rprt.commentId);
		map.set('photo_id',Rprt.photoId);
		map.set('type','c');
	} else {
		map.set('owner',Rprt.ownerId);
		map.set('message_id',Rprt.messageId);
		map.set('type','m');
	}
		Helpers.rpc('/rpc/report/',map,Rprt.reportSubmitSuccess,Rprt.reportSubmitFail);
}
Rprt.reportSubmitSuccess = function() {
	Popups.closeLast();
	Popups.showMessage(MSG.INF.REPORT_SENT);
//	$('rep'+Rprt.photoId).hide();
//	$('rep'+Rprt.photoId).update('&nbsp;');
}
Rprt.reportSubmitFail = function() {
	Popups.defaultError();
}

var UFav = new Object();
UFav.userId=0;
UFav.users = new Hash();
UFav.add = function(userId) {
	uLog.actIfLogged(function() {UFav.action(userId,'add')});
}
UFav.remove = function(userId) {
	uLog.actIfLogged(function() {UFav.action(userId,'remove')});
}
UFav.action = function(userId, action) {
	if (UFav.users.get(userId)!=undefined) {
		action=UFav.users.get(userId);
	};
	UFav.userId=userId;
	var parameters = new Hash();
	parameters.set('userId',userId);
	parameters.set('action',action);
	if (action=='add') {
		Helpers.rpc('/rpc/friends/', parameters, UFav.mark, Helpers.empty);
	} else {
		Helpers.rpc('/rpc/friends/', parameters, UFav.clear, Helpers.empty);
	}
};
UFav.mark = function() {
	UFav.users.set(UFav.userId, "remove");
	var fav1=$('ufav'+UFav.userId);
	fav1.className='gif bck43 fl pointer';
	fav1.title=MSG.INF.REMOVE_FROM_FAV;
}
UFav.clear = function() {
	UFav.users.set(UFav.userId, "add");
	var fav1=$('ufav'+UFav.userId);
	fav1.className='gif bck44 fl pointer';
	fav1.title=MSG.INF.ADD_TO_FAV;
}

var Reg = new Object();
Reg.windowId=null;
Reg.validationResult=true;
Reg.registration = function() {
	if (Reg.validate()) {
		var postMap = new Hash();
		postMap.set('email',$('r_email').value);
		postMap.set('password',$('r_pass1').value);
		postMap.set('name',$('r_name').value);
		var gender='m';
		if ($('r_gender_f').checked) gender='f';
		postMap.set('gender',gender);
		postMap.set('country',$('r_country').value);
		postMap.set('city',$('r_town').value);
		postMap.set('day',$('r_day').value);
		postMap.set('month',$('r_month').value);
		postMap.set('year',$('r_year').value);
		postMap.set('erotic',$('r_erotic').checked);
		Reg.waitStart();
		Helpers.rpc('/rpc/registration/', postMap, Reg.success, Reg.fail);
	}
//	Reg.waitStart();
};
Reg.waitStart = function() {
	Btns.disable('r_register');
//	Btns.enable('r_register');
}
Reg.waitEnd = function() {
	Btns.enable('r_register');
}
Reg.success = function(result) {
	Reg.waitEnd();
	top.location='/profile';
}
Reg.fail = function(result) {
	Reg.waitEnd();
	if (result=='email_exists') {
		Reg.showError('r_email_err',MSG.REG.DUPLICATE_EMAIL);
	} else {
		Popups.defaultError();
	}
}
Reg.dateChanged = function() {
	var is18 = false;
	var d = $('r_day').value;
	var m = $('r_month').value;
	var y = $('r_year').value;
	var currDate = new Date();
	var currD = currDate.getDate();
	var currM = currDate.getMonth()+1;
	var currY = currDate.getFullYear();
//	alert(currY+' '+y);
	if ((currY-y)>18) {
		is18 = true;
	} else if ((currY-y)==18) {
		if (currM>m) {
			is18 = true;
		} else if (currM==m) {
			if (currD>=d) {
				is18=true;
			}
		}
	}
	var erotic = $('r_erotic');
	if (is18) {
		erotic.disabled=false;
	} else {
		erotic.checked=false;
		erotic.disabled=true;
	}
}
Reg.showError = function(elName,errMessage) {
	var el=$(elName);
	el.update(errMessage);	
	el.up().show();	
};
Reg.hideErrors = function() {
	$('r_email_err').up().hide();
	$('r_pass_err').up().hide();
	$('r_name_err').up().hide();
	$('r_gender_err').up().hide();
	$('r_country_err').up().hide();
	$('r_town_err').up().hide();
	$('r_date_err').up().hide();
	$('r_email').removeClassName('cntrl-err');
	$('r_pass1').removeClassName('cntrl-err');
	$('r_pass2').removeClassName('cntrl-err');
	$('r_name').removeClassName('cntrl-err');
	$('r_country').removeClassName('cntrl-err');
	$('r_town').removeClassName('cntrl-err');
	$('r_town_other').removeClassName('cntrl-err');
	$('r_day').removeClassName('cntrl-err');
	$('r_month').removeClassName('cntrl-err');
	$('r_year').removeClassName('cntrl-err');
};
Reg.validate = function() {
	Reg.validationResult=true;
	Reg.hideErrors();
	Reg.validateEmail();
	Reg.validatePassword();
	Reg.validateName();
	Reg.validateGender();
	Reg.validateDate();
	Reg.validateLocation();
	return Reg.validationResult;
}
Reg.validateEmail = function() {
	var email = $('r_email').value;
	if (email.length==0) {
		Reg.validationResult=false;
		Reg.showError('r_email_err',MSG.REG.NO_EMAIL);
		$('r_email').addClassName('cntrl-err');
		return;
	}
//	var expr = /^([A-Za-z0-9_\-\.])+\@([A-Za-z0-9_\-\.])+\.([A-Za-z]{2,4})$/;
//	if(expr.test(email) == false) {
	if (Validate.validateEmail(email) == false) {
		Reg.validationResult=false;
		Reg.showError('r_email_err',MSG.REG.WRONG_EMAIL);
		$('r_email').addClassName('cntrl-err');
		return;
	}
}
Reg.validatePassword = function() {
	var pass1 = $('r_pass1').value;
	var pass2 = $('r_pass2').value;
	if (pass1.length==0 && pass2.length==0) {
		Reg.validationResult=false;
		Reg.showError('r_pass_err',MSG.REG.NO_PASS);
		$('r_pass1').addClassName('cntrl-err');
		$('r_pass2').addClassName('cntrl-err');
		return;
	}
	if (pass1!=pass2) {
		Reg.validationResult=false;
		Reg.showError('r_pass_err',MSG.REG.PASS_MISMATCH);
		$('r_pass1').addClassName('cntrl-err');
		$('r_pass2').addClassName('cntrl-err');
		return;
	}
	if (pass1.length<6) {
		Reg.validationResult=false;
		Reg.showError('r_pass_err',MSG.REG.SHORT_PASS);
		$('r_pass1').addClassName('cntrl-err');
		$('r_pass2').addClassName('cntrl-err');
		return;
	}
}
Reg.validateName = function() {
	var name = $('r_name').value;
	if (name.length==0) {
		Reg.validationResult=false;
		Reg.showError('r_name_err',MSG.REG.NO_NAME);
		$('r_name').addClassName('cntrl-err');
		return;
	}
	if (name.length<4) {
		Reg.validationResult=false;
		Reg.showError('r_name_err',MSG.REG.SHORT_NAME);
		$('r_name').addClassName('cntrl-err');
		return;
	}
}
Reg.validateGender = function() {
	var gender_m = $('r_gender_m').checked;
	var gender_f = $('r_gender_f').checked;
	if (gender_m==false && gender_f==false) {
		Reg.validationResult=false;
		Reg.showError('r_gender_err',MSG.REG.NO_GENDER);
		return;
	}
}
Reg.validateDate = function() {
	var d = $('r_day').value;
	var m = $('r_month').value;
	var y = $('r_year').value;
	if (d==0 || m==0 || y==0) {
		Reg.validationResult=false;
		Reg.showError('r_date_err',MSG.REG.NO_DATE);
		$('r_day').addClassName('cntrl-err');
		$('r_month').addClassName('cntrl-err');
		$('r_year').addClassName('cntrl-err');
		return;
	}
	var tmp = new Date();
	tmp.setFullYear(y,(m-1),d);
	if (tmp.getDate()!=d) {
		Reg.validationResult=false;
		Reg.showError('r_date_err',MSG.REG.WRONG_DATE);
		$('r_day').addClassName('cntrl-err');
		$('r_month').addClassName('cntrl-err');
		$('r_year').addClassName('cntrl-err');
		return;
	}
}
Reg.validateLocation = function() {
	var country = $('r_country').value;
	var city = $('r_town').value;
	if (country==LOC.CNTR_ID) {
		Reg.validationResult=false;
		Reg.showError('r_country_err',MSG.REG.NO_COUNTRY);
		$('r_country').addClassName('cntrl-err');
		return;
	}
	if (city==LOC.CITY_ID || city==LOC.OTHER_ID) {
		Reg.validationResult=false;
		Reg.showError('r_town_err',MSG.REG.NO_CITY);
		$('r_town').addClassName('cntrl-err');
		$('r_town_other').addClassName('cntrl-err');
		return;
	}
}
Reg.validateICQ = function() {
	var icq = $('r_icq').value;
	if (icq!='') {
		var RegExp = /[0-9]*/;
		if (icq!=icq.match(RegExp) || icq<100000 || icq>999999999) {
			Reg.validationResult=false;
			Reg.showError('r_icq_err',MSG.REG.WRONG_ICQ);
			$('r_icq').addClassName('cntrl-err');
		}
	}
}
var Validate = new Object();
Validate.validateEmail=function(email) {
	var expr = /^([A-Za-z0-9_\-\.])+\@([A-Za-z0-9_\-\.])+\.([A-Za-z]{2,4})$/;
	return expr.test(email)
}

var Popups = new Object();
Popups.currentZ = 100;
Popups.zIndex = new Hash();
Popups.queue=Array();
Popups.queueBeforeCloseFn=Array();
Popups.queueAfterCloseFn=Array();
Popups.reusableBody = new Hash();
Popups.waitWindowId='';
Popups.doNotClose = 0;
Popups.topRow='';
Popups.bottomRow='';
Popups.defaultError = function() {
	Popups.showMessage(MSG.REG.SERVER_ERROR);
}
Popups.showPopup = function(title, contentId, beforeCloseFn, afterCloseFn) {
	Popups.topRow='gray';
	Popups.bottomRow='gray';
	return Popups.makePopup(title, contentId, 1, 1, beforeCloseFn, afterCloseFn);
}
Popups.showPopupW = function(title, contentId, beforeCloseFn, afterCloseFn) {
	Popups.topRow='white';
	Popups.bottomRow='white';
	return Popups.makePopup(title, contentId, 1, 1, beforeCloseFn, afterCloseFn);
}
Popups.showPopupDark = function(title, contentId, beforeCloseFn, afterCloseFn) {
	Popups.topRow='dark';
	Popups.bottomRow='dark';
	return Popups.makePopup(title, contentId, 1, 1, beforeCloseFn, afterCloseFn);
}
Popups.showPopupMix = function(title, contentId, beforeCloseFn, afterCloseFn) {
	Popups.topRow='gray';
	Popups.bottomRow='white';
	return Popups.makePopup(title, contentId, 1, 1, beforeCloseFn, afterCloseFn);
}
Popups.showImg = function(width, height, url) {
	Popups.topRow='white';
	Popups.bottomRow='white';
	var img = new Element('img',{'src':url,'width':width,'height':height,'border':'0','class':'pointer'});
	img.observe('click', function() {Popups.closeLast()});
	var div = new Element('div',{'align':'center', 'style':'background:#ffffff; width: '+(width+20)+'px; height: '+(height+20)+'px','class':'pada10'})
	$('hiddenBlock').insert(img);
//	alert(img.complete);
	if (img.complete) {
		div.update(img);
	} else {
		div.update('<table width="'+width+'" height="'+height+'"><tr><td align="center"><img src="'+SYSTEM.WAIT+'" /></td></tr></table>');
		img.observe('load',function() {div.update(img);});
	}
	$('hiddenBlock').insert(div);
	return Popups.makePopup('', div.identify(), 1, 1);
}
Popups.showMessage = function(message) {
	Popups.blockConfirm=0;
	Popups.topRow='white';
	Popups.bottomRow='white';
	var popPanel = new Element('table',{'width':'400','style':'background:#ffffff'});
	var popPanelBody = new Element('tbody');
	var topRow = new Element('tr');
	var middleRow = new Element('tr',{'height':'10'}); var middleCell = new Element('td');middleRow.insert(middleCell);
	var lastRow = new Element('tr',{'height':'5'}); var lastCell = new Element('td');lastRow.insert(lastCell);
	var bottomRow = new Element('tr');
	var topCell = new Element('td',{'class':'padlr22'});
	var bottomCell = new Element('td',{'class':'padlr22','align':'center'});
	var buttonPanel = new Element('table',{'width':'100%'});
	var buttonBody = new Element('tbody');
	var buttonRow = new Element('tr');
	var buttonCell1 = new Element('td',{'align':'center'});
	var okButton = Helpers.getJSButton(MSG.CONFIRM.CLOSE,60);
	var okButtonId = okButton.identify();
	popPanel.writeAttribute('cellSpacing','0');
	popPanel.insert(popPanelBody);
	popPanelBody.insert(topRow).insert(middleRow).insert(bottomRow).insert(lastRow);
	topRow.insert(topCell);
	bottomRow.insert(bottomCell);
	topCell.insert('<table width="100%"><tr><td width="1"><img src="'+SYSTEM.SPACE+'" class="png bck185"</td>'+
		'<td width="10"></td><td class="t-13 c-g3 t-b">'+message+'</td></tr></table>');
	buttonCell1.insert(okButton);
	buttonRow.insert(buttonCell1);
	buttonBody.insert(buttonRow);
	buttonPanel.insert(buttonBody);
	bottomCell.insert(buttonPanel);

	$('hiddenBlock').insert(popPanel);

	var popId=Popups.makePopup('', popPanel.identify(), 0, 1);
	
	Btns.register(okButtonId,function(e){
		Popups.closePopup(popId);
	});
	
	return popId;
	
}
Popups.showWait = function(messageId) {
	var popPanel = new Element('table',{'border':'1'});
	var popPanelBody = new Element('tbody');
	var topRow = new Element('tr');
	var topCell = new Element('td');
	popPanel.writeAttribute('cellSpacing','0');
	popPanel.insert(popPanelBody);
	popPanelBody.insert(topRow);
	topRow.insert(topCell);
	topCell.insert("Loading...");
	$('hiddenBlock').insert(popPanel);
	Popups.waitWindowId=Popups.makePopup("Server connection", popPanel.identify(), 0, 0);
}
Popups.hideWait = function() {
	Popups.closePopup(Popups.waitWindowId);
	Popups.waitWindowId='';
}
Popups.showConfirm = function(message, yesFn, noFn, closeOnClick) {
	Popups.blockConfirm=0;
	Popups.topRow='white';
	Popups.bottomRow='white';
	if (closeOnClick==undefined) {
		closeOnClick=1;
	}
	var popPanel = new Element('table',{'width':'400','style':'background:#ffffff'});
	var popPanelBody = new Element('tbody');
	var topRow = new Element('tr');
	var middleRow = new Element('tr',{'height':'10'}); var middleCell = new Element('td');middleRow.insert(middleCell);
	var lastRow = new Element('tr',{'height':'5'}); var lastCell = new Element('td');lastRow.insert(lastCell);
	var bottomRow = new Element('tr');
	var topCell = new Element('td',{'class':'padlr22'});
	var bottomCell = new Element('td',{'class':'padlr22','align':'center'});
	var buttonPanel = new Element('table',{'width':'100%'});
	var buttonBody = new Element('tbody');
	var buttonRow = new Element('tr');
	var buttonCell1 = new Element('td',{'width':'50%','align':'right'});
	var buttonCell2 = new Element('td',{'width':'50%','align':'left'});
	var buttonCell3 = new Element('td',{'width':'10'});
	var img = new Element('img',{'src':SYSTEM.SPACE,'style':'width:10px;'});
	buttonCell3.insert(img);
	var yesButton = Helpers.getJSButton(MSG.CONFIRM.YES,60);
	var noButton = Helpers.getJSButton(MSG.CONFIRM.NO,60);
	var yesButtonId = yesButton.identify();
	var noButtonId = noButton.identify();
	popPanel.writeAttribute('cellSpacing','0');
	popPanel.insert(popPanelBody);
	popPanelBody.insert(topRow).insert(middleRow).insert(bottomRow).insert(lastRow);
	topRow.insert(topCell);
	bottomRow.insert(bottomCell);
	topCell.insert('<table width="100%"><tr><td width="1"><img src="'+SYSTEM.SPACE+'" class="png bck184"</td>'+
		'<td width="10"></td><td class="t-13 c-g3 t-b">'+message+'</td></tr></table>');
	buttonCell1.insert(yesButton);
	buttonCell2.insert(noButton);
	buttonRow.insert(buttonCell1).insert(buttonCell3).insert(buttonCell2);
	buttonBody.insert(buttonRow);
	buttonPanel.insert(buttonBody);
	bottomCell.insert(buttonPanel);

	$('hiddenBlock').insert(popPanel);

	var popId=Popups.makePopup('', popPanel.identify(), 0, 1);
	
	Btns.register(yesButtonId,function(e){
		if (Popups.blockConfirm==1) return;
		Popups.blockConfirm=1;
		Btns.disable(yesButtonId);
		if (closeOnClick==1){Popups.closePopup(popId)};
		yesFn()
	});
	Btns.register(noButtonId,function(e){
		if (Popups.blockConfirm==1) return;
		Popups.blockConfirm=1;
		Btns.disable(noButtonId);
		if (closeOnClick==1){Popups.closePopup(popId)};
		if (noFn!=undefined) {noFn()}
	});
	
	return popId;
	
}
// TODO: change this method
Popups.makeConfirmWaiting = function() {
//	Popups.confirmBottomPanel.update('Uploading...');
//	Popups.confirmHiddenRow.show();
//	Popups.confirmHiddenRow.down().insert('Uploading...');
}

Popups.makePopup = function(title, contentId, reusable, isClosable, beforeCloseFn, afterCloseFn) {
	var content=$(contentId);
	if (isClosable==undefined) isClosable=0;

	Popups.currentZ++;
	Helpers.blockScreen(Popups.currentZ);

	var pop = new Element('table');
	var popId = pop.identify();
	Popups.zIndex.set(popId,Popups.currentZ);
	if (reusable!=0) Popups.reusableBody.set(popId,contentId);
	$('body').insert(pop);
	pop.absolutize();

	// Make nice popup window
	var t = 'g';
	var b = 'g';
	if (Popups.topRow=='white') 
		t = 'w';
	if (Popups.bottomRow=='white') 
		b = 'w';
	if (Popups.topRow=='dark') 
		t = 'd';
	if (Popups.bottomRow=='dark') 
		b = 'd';
	
	// Top row table
	var trTable = new Element('table',{'width':'100%','height':'7'});
	var trBody = new Element('tbody');
	var trRow = new Element('tr');
	var trTd1 = new Element('td',{'width':'7'});
	var trTd2 = new Element('td',{'width':'100%','class':'poprow'+t});
	var trTd3 = new Element('td',{'width':'7'});
	var trDiv1 = new Element('div',{'class':'pop'+t+'tl'});
	var trDiv3 = new Element('div',{'class':'pop'+t+'tr'});
	trTd1.insert(trDiv1);trTd3.insert(trDiv3);
	trRow.insert(trTd1).insert(trTd2).insert(trTd3);
	trBody.insert(trRow);
	trTable.insert(trBody);
	
	// Bottom row table
	var brTable = new Element('table',{'width':'100%','height':'7'});
	var brBody = new Element('tbody');
	var brRow = new Element('tr');
	var brTd1 = new Element('td',{'width':'7'});
	var brTd2 = new Element('td',{'width':'100%','class':'poprow'+t});
	var brTd3 = new Element('td',{'width':'7'});
	var brDiv1 = new Element('div',{'class':'pop'+b+'bl'});
	var brDiv3 = new Element('div',{'class':'pop'+b+'br'});
	brTd1.insert(brDiv1);brTd3.insert(brDiv3);
	brRow.insert(brTd1).insert(brTd2).insert(brTd3);
	brBody.insert(brRow);
	brTable.insert(brBody);
	
	// main table
	var mBody = new Element('tbody');
	var mRow1 = new Element('tr');
	var mRow2 = new Element('tr',{'height':'17'});
	var mRow3 = new Element('tr');
	var mRow4 = new Element('tr',{'height':'17'});
	var mRow5 = new Element('tr');
	var mCell1 = new Element('td');
	var mCell2 = new Element('td',{'class':'poprow'+t+' padr5'});
	var mCell3 = new Element('td');
	var mCell4 = new Element('td',{'class':'poprow'+b});
	var mCell5 = new Element('td');
	
	mCell1.insert(trTable);
	mCell3.insert(content);
	mCell5.insert(brTable);
	mRow1.insert(mCell1);
	mRow2.insert(mCell2);
	mRow3.insert(mCell3);
	mRow4.insert(mCell4);
	mRow5.insert(mCell5);
//	mBody.insert(mRow1).insert(mRow2).insert(mRow3).insert(mRow4).insert(mRow5);
	mBody.insert(mRow1).insert(mRow2).insert(mRow3).insert(mRow5);
	pop.insert(mBody);
	
	if (isClosable!=0) {
		var closeBtn = new Element('div' ,{'class':'popclose fr'});
		closeBtn.observe('click', function (event) {
			if (Popups.doNotClose>0) return;
			if (beforeCloseFn==undefined || beforeCloseFn()) {
				Popups.closePopup(popId)
				if (afterCloseFn!=undefined) afterCloseFn();
			}
		});
		closeBtn.observe('mouseover', function (event) {
			closeBtn.className='popcloseover fr';
		});
		closeBtn.observe('mouseout', function (event) {
			closeBtn.className='popclose fr';
		});
		mCell2.insert(closeBtn);
	}
	
	var top=Helpers.getScrollY()+(Helpers.getDocHeight()-pop.getHeight())/2;
	var left=(Helpers.getDocWidth()-pop.getWidth())/2;
	if (top<0) top=0;
	if (left<0) left=0;
	var w=pop.getWidth();
	var h=pop.getHeight();
	
//	pop.setStyle({top:''+top+'px',left:''+left+'px',zIndex:''+Popups.currentZ,width:''+w+'px',height:''+h+'px'});
	pop.setStyle({top:''+top+'px',left:''+left+'px',zIndex:''+Popups.currentZ,width:''+w+'px'});
	
	// add to popups queue
	if (isClosable==1) {
		Popups.queue[Popups.queue.length]=popId;
		Popups.queueBeforeCloseFn[Popups.queueBeforeCloseFn.length]=beforeCloseFn;
		Popups.queueAfterCloseFn[Popups.queueAfterCloseFn.length]=afterCloseFn;
	}
	Helpers.initBlocking();
	return popId;
}
Popups.closePopup=function(popId) {
	if (Popups.doNotClose>0) return;
	Popups.zIndex.unset(popId);
	var max=0;
	Popups.zIndex.each(function(pair) {
		if (pair.value>max) max=pair.value;
	});

	var popDiv = $(popId);
	var reusableBlock=Popups.reusableBody.get(popId);
	if (reusableBlock!=undefined) {
		$('hiddenBlock').insert($(reusableBlock));
	}

	popDiv.remove();
	Helpers.blockScreen(max);

	// update queues
	var tmp=Array();
	for (i=0;i<(Popups.queue.length-1);i++) {
		tmp[i]=Popups.queue[i];
	}
	Popups.queue=tmp;
	var tmp=Array();
	for (i=0;i<(Popups.queueBeforeCloseFn.length-1);i++) {
		tmp[i]=Popups.queueBeforeCloseFn[i];
	}
	Popups.queueBeforeCloseFn=tmp;
	var tmp=Array();
	for (i=0;i<(Popups.queueAfterCloseFn.length-1);i++) {
		tmp[i]=Popups.queueAfterCloseFn[i];
	}
	Popups.queueAfterCloseFn=tmp;
	
}
Popups.closeLast = function() {
//	alert(Popups.doNotClose);
	if (Popups.doNotClose>0) return;
	var popId=Popups.queue.last();
	var beforeCloseFn=Popups.queueBeforeCloseFn.last();
	var afterCloseFn=Popups.queueAfterCloseFn.last();
	if (popId!=undefined) {
		if (beforeCloseFn==undefined || beforeCloseFn()) {
			Popups.closePopup(popId)
			if (afterCloseFn!=undefined) afterCloseFn();
		}
	}
}

var Pagination = new Object();
Pagination.pageType='';
Pagination.mainPanel=null;
Pagination.paginationPanelId='';
Pagination.currentPage=0;
Pagination.perPage=0;
Pagination.inProcess=0;
Pagination.waitEl=null;
Pagination.isTable=0;
Pagination.afterLoadFn=undefined;
Pagination.init = function(pageType, contentPanelId, paginationPanelId, currentPage, pagesTotal, beforePageSwitchFn, afterLoadFn) {
	if (contentPanelId.substr(0,5)=='table') {
		Pagination.isTable=1;
	} else {
		Pagination.isTable=0;
	}		
	Pagination.beforePageSwitchFn=beforePageSwitchFn;
	Pagination.afterLoadFn=afterLoadFn;
	Pagination.pageType=pageType;
	Pagination.mainPanel=$(contentPanelId);
	Pagination.paginationPanelId=paginationPanelId;
	Pagination.currentPage=currentPage;
	Pagination.perPage = SYSTEM.PAGINATION.DEFAULT;
	var tmp = eval("SYSTEM.PAGINATION."+pageType);
	if (tmp!=undefined) Pagination.perPage=tmp;
	Pager.buildPager('mainPager', paginationPanelId, Pagination.goPage, pagesTotal, currentPage);
	
}
Pagination.refresh = function() {
	Pagination.goPage(Pagination.currentPage);
}
Pagination.goPage = function(page) {
	if (Pagination.inProcess==0) {
//		Pager.selectPage('mainPager',page);
		var map = new Hash();
		if (Pagination.beforePageSwitchFn!=undefined) {
			map = Pagination.beforePageSwitchFn();
		}
		map.set('pageType',Pagination.pageType);
		map.set('page',page);
		Pagination.inProcess=1;
		Pagination.startWait();
		Helpers.rpc('/rpc/get_page/', map, Pagination.goPageSucces, Pagination.goPageFail);
	}
};
Pagination.goPageSucces = function(result) {
	Pagination.inProcess=0;
	Pagination.stopWait();
	var current=1*result.substr(4,6);
	Pagination.currentPage=current;
	var total=1*result.substr(10,6);
	Pagination.updateMainPanel(result);
	Pager.buildPager('mainPager', Pagination.paginationPanelId, Pagination.goPage, total, current);
//	Pagination.goPage(current);
	if (Pagination.afterLoadFn!=undefined)
		Pagination.afterLoadFn();
};
Pagination.goPageFail = function(result) {
	Pagination.inProcess=0;
	Pagination.stopWait();
	Popups.defaultError();
};
Pagination.updateMainPanel = function(content) {
//	alert(Pagination.isTable);
	if (Pagination.isTable==1) {
		var mainEl = null;
		Pagination.mainPanel.down().childElements().each(function(el) {
			if (el.id.substring(0,3)!='dnr' && el.id!='paginator_wait') el.remove();
			if (el.id=='dnrMain') mainEl=$(el.id);
		});
//		content.show();
		if (mainEl!=null) {
			mainEl.insert({after:content});
		} else {
			Pagination.mainPanel.down().insert(content);
		}
	} else {
		Pagination.mainPanel.update(content);
	}
}
Pagination.startWait = function() {
	if (Pagination.waitEl==null) {
		var pt = Pagination.pageType;
		// TODO: add specific waits
		Pagination.waitEl=$('pagination_waitCommon');
	}
	if (Pagination.waitEl!=null) Pagination.updateMainPanel(Pagination.waitEl);
}
Pagination.stopWait = function() {
	if (Pagination.waitEl!=null) $('hiddenBlock').insert(Pagination.waitEl);
}

var Pager = new Object();
Pager.pages = new Hash();
Pager.length = 5;
Pager.elName = new Hash();
Pager.fn = new Hash();
Pager.buildPager = function(id, elName, fn, pages, current) {

	Pager.pages.set(id,pages);
	Pager.elName.set(id,elName);
	Pager.fn.set(id,fn);
	var el = $(elName);
	if (el==null) return;
	el.update('');
	if (pages<2) return;

/////////////
	var currentPage = parseInt(current);
	var pagesTotal = parseInt(pages);
	var start = parseInt(currentPage)-(Pager.length-1)/2;
	var end = parseInt(currentPage)+(Pager.length-1)/2;

	if (start<1) {
		start=1;
		if (pagesTotal>=Pager.length) {
			end=Pager.length;
		} else {
			end=pagesTotal;
		}
	}
	if (end>pagesTotal) {
		end=pagesTotal;
		if (pagesTotal>=Pager.length) {
			start=end-Pager.length+1;
		} else {
			start=1;
		}
	}
	
	var left = true;
	var right = true;
	if (currentPage==1) left=false;
	if (currentPage==end) right=false;
/////////////

	var mainTable=new Element('table',{'align':'center','height':'21','width':'100%'});
	var mainBody=new Element('tbody');
	var mainTr = new Element('tr');
	mainTable.insert(mainBody);
	mainBody.insert(mainTr);
	var pagerTable=new Element('table',{'align':'center','height':'21'});
	var pagerBody=new Element('tbody');
	var tr = new Element('tr');
	pagerTable.insert(pagerBody);
	
	var firstTd = new Element('td',{'width':'100','class':'padr22'});
	var mainTd = new Element('td',{'align':'center'});
	var lastTd = new Element('td',{'width':'100','align':'right','class':'t-11 c-g1 padr22'});
	mainTr.insert(firstTd).insert(mainTd).insert(lastTd);
	mainTd.insert(pagerTable);
	lastTd.insert('страница '+currentPage+' из '+pagesTotal);

	var tds=0;

	if (left) {
		var img1 = new Element('img',{'class':'gif bck113 pointer','src':SYSTEM.SPACE,'border':'0'});
		img1.observe('click', function() {
			fn(1)
		});
		var td1=new Element('td');
		tds++;
		td1.insert(img1);
		var td2 = new Element('td',{'width':'10'});
		tds++;
		var img2 = new Element('img',{'class':'gif bck112 pointer','src':SYSTEM.SPACE,'border':'0'});
		img2.observe('click', function() {
			fn(parseInt(currentPage-1));
		});
		var td3=new Element('td');
		tds++;
		td3.insert(img2);
		tr.insert(td1).insert(td2).insert(td3);
	} else {
		var img1 = new Element('img',{'class':'gif bck119','src':SYSTEM.SPACE,'border':'0'});
		var td1=new Element('td');
		tds++;
		td1.insert(img1);
		var td2 = new Element('td',{'width':'10'});
		tds++;
		var img2 = new Element('img',{'class':'gif bck118','src':SYSTEM.SPACE,'border':'0'});
		var td3=new Element('td');
		tds++;
		td3.insert(img2);
		tr.insert(td1).insert(td2).insert(td3);
	}
	var td4 = new Element('td',{'width':'10'});
	tds++;
	tr.insert(td4);

	for (var i = start; i <= end; i++) {
		if (i==currentPage) {
			var t1 = new Element('td',{'class':'gif bck108'});
			tds++;
			var t2 = new Element('td',{'class':'t-12 t-b c-w padlr5 col8'});
			tds++;
			t2.insert(i);
			var t3 = new Element('td',{'class':'gif bck109'});
			tds++;
			tr.insert(t1).insert(t2).insert(t3);
		} else {
			var t1 = new Element('td',{'class':'gif bck110'});
			tds++;
			var t2 = new Element('td',{'id':'pgr_'+i,'class':'padlr5 col7'});
			t2.observe('click', function() {
				var p = this.id.substr(4);
				fn(p)
			});
			tds++;
			var d = new Element('div',{'class':'t-12 c-g1 t-u pointer'});
			d.insert(i);
			t2.insert(d);
			var t3 = new Element('td',{'class':'gif bck111'});
			tds++;
			tr.insert(t1).insert(t2).insert(t3);
		}
		if (i!=end) {
			var t4=new Element('td',{'width':'5'});
			tds++;
			tr.insert(t4);
		}
	}
	
	var td5 = new Element('td',{'width':'10'});
	tds++;
	tr.insert(td5);

	if (right) {
		var img1 = new Element('img',{'class':'gif bck115 pointer','src':SYSTEM.SPACE,'border':'0'});
		img1.observe('click', function() {
			fn(parseInt(currentPage+1))
		});
		var td1=new Element('td');
		tds++;
		td1.insert(img1);
		var td2 = new Element('td',{'width':'10'});
		tds++;
		var img2 = new Element('img',{'class':'gif bck114 pointer','src':SYSTEM.SPACE,'border':'0'});
		img2.observe('click', function() {
			fn(pagesTotal)
		});
		var td3=new Element('td');
		tds++;
		td3.insert(img2);
		tr.insert(td1).insert(td2).insert(td3);
	} else {
		var img1 = new Element('img',{'class':'gif bck117','src':SYSTEM.SPACE,'border':'0'});
		var td1=new Element('td');
		tds++;
		td1.insert(img1);
		var td2 = new Element('td',{'width':'10'});
		tds++;
		var img2 = new Element('img',{'class':'gif bck116','src':SYSTEM.SPACE,'border':'0'});
		var td3=new Element('td');
		tds++;
		td3.insert(img2);
		tr.insert(td1).insert(td2).insert(td3);
	}
	var td4 = new Element('td',{'width':'10'});
	tds++;
	tr.insert(td4);

	// spans
	var topTd = new Element('td',{'colspan':tds});
	var bottomTd = new Element('td',{'colspan':tds});
	var topTr = new Element('tr',{'height':'10'});
	var bottomTr = new Element('tr',{'height':'10'});

	pagerBody.insert(topTr);
	pagerBody.insert(tr);
	pagerBody.insert(bottomTr);

	el.insert(mainTable);
}
//Pager.selectPage = function(id, page) {
//	Pager.buildPager(id,Pager.elName.get(id),Pager.fn.get(id),Pager.pages.get(id),page);
//};

var OptList = new Object();
OptList.selected = new Hash();
OptList.className = new Hash();
OptList.onClickFn = new Hash();
OptList.beforeClickFn = new Hash();
OptList.register = function(elName, selected, selClassName, onClickFn) {
	
	if (selected==undefined) selected=1;
	if (selClassName==undefined || selClassName=='' || selClassName=='default') selClassName='olSelected';
	OptList.className.set(elName, selClassName);
	OptList.onClickFn.set(elName, onClickFn);
	
	var len = elName.length;
	var pos = 0;
	$(elName).childElements().each(function(el){
		pos++;
		var val = el.identify().substr(len+1);

		if (pos==selected) OptList.selectOption(elName, el);

		el.observe('click',function() {
			OptList.selectOption(elName, el);
			if (OptList.onClickFn.get(elName)!=undefined) OptList.onClickFn.get(elName)(OptList.getValue(elName));
		}); 
	});
}
OptList.markOption = function(optList, option) {
	OptList.selectOption(optList,$(optList+'_'+option));
}
OptList.selectOption = function(optList, element) {
	var prevEl = OptList.selected.get(optList);
	if (prevEl!=undefined) {
		prevEl.removeClassName(OptList.className.get(optList));
	}
	element.addClassName(OptList.className.get(optList));
	OptList.selected.set(optList, element);
}
OptList.getValue = function(optList) {
	var id = OptList.selected.get(optList).identify();
	return id.substr(optList.length+1);
}
OptList.getStringValue = function(optList) {
	return OptList.selected.get(optList).innerHTML;
}

var NOptList = new Object();
NOptList.selected = new Hash();
NOptList.onClickFn = new Hash();
NOptList.register = function(elName, selected, onClickFn) {
	
	if (selected==undefined) selected=1;
	NOptList.onClickFn.set(elName, onClickFn);
	
	var len = elName.length;
	var pos = 0;
	$(elName).childElements().each(function(el){
		var id = el.identify();
		var type = id.substr(len+1,1);
		if (type=='v') {
			pos++;
			var val = id.substr(len+3);
			var a = new Array();

			el.observe('click',function() {
				NOptList.selectOption(elName, el);
				if (NOptList.onClickFn.get(elName)!=undefined) NOptList.onClickFn.get(elName)(val);
			}); 

			if (pos==selected) NOptList.selectOption(elName, el);
		}

	});
}
NOptList.selectOption = function(optList, element) {
	var prevEl = NOptList.selected.get(optList);
	if (prevEl!=undefined) {
		// unselect
		prevEl.previous().className='bck23';
		prevEl.className='padlr5 pointer t-11 c-b1 t-u';
		prevEl.next().className='bck23';
	}
	// select new
	element.previous().className='gif bck20 fr';
	element.className='padlr5 bck22 t-11 c-g3';
	element.next().className='gif bck21 fl';
	NOptList.selected.set(optList, element);
}
NOptList.getValue = function(optList) {
	var id = NOptList.selected.get(optList).identify();
	return id.substr(optList.length+3);
}

var AvEditor = new Object();
AvEditor.top=0;
AvEditor.left=0;
AvEditor.width=0;
AvEditor.height=0;
AvEditor.scaleTop=0;
AvEditor.scaleLeft=0;
AvEditor.scaleWidth=0;
AvEditor.scaleHeight=0;
AvEditor.size=85;
AvEditor.posX=0;
AvEditor.posY=0;
AvEditor.minSize=0;
AvEditor.maxSize=0;
AvEditor.dragg=0;
AvEditor.imgId=0;
AvEditor.k=1;
AvEditor.slider=null;
AvEditor.sizes = new Array();
AvEditor.step=0;
AvEditor.steps=51;
AvEditor.position=25;
AvEditor.register = function(elName, imgId, imgUrl, medX, medY, bigX, bigY) {
	AvEditor.imgId=imgId;
	$('av_editor').writeAttribute('style','background: url('+imgUrl+');width:'+medX+'px;height:'+medY+'px;');
	var el = $(elName);
	if (el!=null) {
		var body=$('body');
		// min size
		if (bigX>bigY) {
			AvEditor.k=SYSTEM.SIZES.MEDIUMX/bigX;
			AvEditor.minSize=Math.round(SYSTEM.SIZES.AVATAR*AvEditor.k);
		} else {
			AvEditor.k=SYSTEM.SIZES.MEDIUMY/bigY;
			AvEditor.minSize=Math.round(SYSTEM.SIZES.AVATAR*AvEditor.k);
		}
		// div sizes
		AvEditor.left=el.cumulativeOffset()[0];
		AvEditor.top=el.cumulativeOffset()[1];
		AvEditor.width=el.getWidth();
		AvEditor.height=el.getHeight();

		// max size
		if (AvEditor.width>AvEditor.height) {
			AvEditor.maxSize=AvEditor.height;
		} else {
			AvEditor.maxSize=AvEditor.width;
		}
		
		// generate div sizes
		AvEditor.step = (AvEditor.maxSize-AvEditor.minSize)/(AvEditor.steps-1); // steps-1
		AvEditor.size=AvEditor.getSize(AvEditor.position);
		
		// build scale
		$('scaleRow').setStyle({'height':''+(medY-54)+'px'});
		$('av_scalePanel').down().setStyle({'height':''+(medY-50)+'px'});
		
		var panel = $('av_scalePanel');
		AvEditor.scaleLeft=panel.cumulativeOffset()[0];
		AvEditor.scaleTop=panel.cumulativeOffset()[1];
		AvEditor.scaleWidth=panel.getWidth();
		AvEditor.scaleHeight=panel.getHeight();
		if (AvEditor.slider==null) {
			AvEditor.slider = new Element('img',{'class':'avSlider gif bck140','src':SYSTEM.SPACE,'width':'17','height':'38'});
			body.insert(AvEditor.slider);
		} else {
			AvEditor.slider.show();
		}
		AvEditor.placeSlider(AvEditor.position);
//		alert(AvEditor.scaleLeft+' '+AvEditor.scaleTop+' '+AvEditor.scaleWidth+' '+AvEditor.scaleHeight);

//		alert(AvEditor.left+' '+AvEditor.top+' '+AvEditor.width+' '+AvEditor.height);

		// draw elements
		AvEditor.el1=AvEditor.getElement();body.insert(AvEditor.el1);
		AvEditor.el2=AvEditor.getElement();body.insert(AvEditor.el2);
		AvEditor.el3=AvEditor.getElement();body.insert(AvEditor.el3);
		AvEditor.el4=AvEditor.getElement();body.insert(AvEditor.el4);
		AvEditor.el1.observe('mousemove',AvEditor.mouseMove);
		AvEditor.el2.observe('mousemove',AvEditor.mouseMove);
		AvEditor.el3.observe('mousemove',AvEditor.mouseMove);
		AvEditor.el4.observe('mousemove',AvEditor.mouseMove);

		body.insert('<div class="avBorder" id="dragger" onMouseDown="AvEditor.mouseDown(event);return false;" onMouseUp="AvEditor.mouseUp(event);return false;" onMouseMove="AvEditor.mouseMove(event);return false;" onMouseOut="AvEditor.mouseOut(event);return false;"></div>');
		AvEditor.el5=$('dragger');
//		alert(AvEditor.left+' '+AvEditor.top+' '+AvEditor.width+' '+AvEditor.height);
		AvEditor.redraw();
//		alert(AvEditor.el4.getDimensions()[0]+' '+AvEditor.el4.getDimensions()[1]);
		AvEditor.startImageLoad();
	}
}
AvEditor.isSliding=0;
AvEditor.startSliding = function(direction) {
	AvEditor.isSliding=1;
	AvEditor.slide(direction);
}
AvEditor.stopSliding = function() {
	AvEditor.isSliding=0;
}
AvEditor.slide = function(direction) {
	if (AvEditor.isSliding==1) {
		AvEditor.changePos(direction);
		setTimeout('AvEditor.slide("'+direction+'")',10);
	};
	
}
AvEditor.changePos = function(direction) {
	if ('inc'==direction) AvEditor.position++;
	if ('dec'==direction) AvEditor.position--;
	if (AvEditor.position<1) AvEditor.position=1;
	if (AvEditor.position>AvEditor.steps) AvEditor.position=AvEditor.steps;
	AvEditor.placeSlider(AvEditor.position);
	AvEditor.resize(AvEditor.position);
}
AvEditor.getSize = function(pos) {
	return Math.round(AvEditor.minSize+((pos-1)*AvEditor.step));
}
AvEditor.placeSlider = function(pos) {
	var percent = 0;
	if (pos>0) {
		percent=1-(pos/AvEditor.steps);
	}
	var topOff = parseInt(Math.round((AvEditor.scaleHeight-38)*percent)+AvEditor.scaleTop);
	var leftOff = 4+AvEditor.scaleLeft;
	AvEditor.slider.setStyle({'top':''+topOff+'px','left':''+leftOff+'px'});
}
AvEditor.getDimensions = function() {
	var res = Array();
	var x1=Math.round(AvEditor.posX/AvEditor.k);
	var y1=Math.round(AvEditor.posY/AvEditor.k);
	var size = Math.round(AvEditor.size/AvEditor.k);
	res[0]=x1;res[1]=y1;res[2]=x1+size;res[3]=y1+size;
	return res;
}
AvEditor.mouseDown = function(e) {
	AvEditor.dragg=1;
	AvEditor.mouseX=e.clientX;
	AvEditor.mouseY=e.clientY;
}
AvEditor.mouseUp = function(e) {
	AvEditor.dragg=0;
	AvEditor.startImageLoad();
}
AvEditor.mouseOut = function(e) {
	var x=e.clientX;
	var y=e.clientY;
	if (x>(AvEditor.left+AvEditor.width) || x<AvEditor.left || y>(AvEditor.top+AvEditor.height) || y<AvEditor.top) {
		AvEditor.dragg=0;
	}
}
AvEditor.mouseMove = function(e) {
//	e.preventDefault();
	if (AvEditor.dragg==1) {
		AvEditor.posX+=(e.clientX-AvEditor.mouseX);
		AvEditor.posY+=(e.clientY-AvEditor.mouseY);
		AvEditor.mouseX=e.clientX;
		AvEditor.mouseY=e.clientY;
		AvEditor.validatePositions();
		AvEditor.redraw();
	}
}
AvEditor.getElement = function() {
	var el = new Element('div',{'class':'av'});
	el.insert('<img src="'+SYSTEM.SPACE+'" width="1" height="1">');
	return el;
}
AvEditor.resize = function(pos) {
	var newSize = AvEditor.getSize(pos);
	if (newSize==AvEditor.size) return;
	var offset = Math.round((AvEditor.size-newSize)/2);
	AvEditor.size=newSize;
	AvEditor.posX+=offset;
	AvEditor.posY+=offset;
	AvEditor.validatePositions();
	AvEditor.redraw();
	AvEditor.startImageLoad();
}
AvEditor.validatePositions = function() {
	if (AvEditor.posX<0) AvEditor.posX=0;
	if (AvEditor.posY<0) AvEditor.posY=0;
	if (AvEditor.posX+AvEditor.size>AvEditor.width) AvEditor.posX=AvEditor.width-AvEditor.size;
	if (AvEditor.posY+AvEditor.size>AvEditor.height) AvEditor.posY=AvEditor.height-AvEditor.size;
}
AvEditor.redraw = function() {
	var top = AvEditor.top;
	var left = AvEditor.left;
	if (AvEditor.posY>0)
		AvEditor.el1.setStyle({'display':'block','top':''+top+'px','left':''+left+'px',width:''+(AvEditor.width)+'px',height:''+(AvEditor.posY)+'px'});
	else 
		AvEditor.el1.setStyle({'display':'none'});

	var top = AvEditor.top+AvEditor.posY+AvEditor.size;
	var left = AvEditor.left;
	if (AvEditor.height-AvEditor.posY-AvEditor.size>0) 
		AvEditor.el2.setStyle({'display':'block',top:''+top+'px',left:''+left+'px',width:''+(AvEditor.width)+'px',height:''+(AvEditor.height-AvEditor.posY-AvEditor.size)+'px'});
	else 
		AvEditor.el2.setStyle({'display':'none'});

	var top = AvEditor.top+AvEditor.posY;
	var left = AvEditor.left;
	if (AvEditor.posX>0)
		AvEditor.el3.setStyle({'display':'block',top:''+top+'px',left:''+left+'px',width:''+(AvEditor.posX)+'px',height:''+(AvEditor.size)+'px'});
	else 
		AvEditor.el3.setStyle({'display':'none',top:''+top+'px',left:''+left+'px',width:''+(AvEditor.posX)+'px',height:''+(AvEditor.size)+'px'});

	var top = AvEditor.top+AvEditor.posY;
	var left = AvEditor.left+AvEditor.size+AvEditor.posX;
	if ((AvEditor.width-AvEditor.size-AvEditor.posX)>0)
		AvEditor.el4.setStyle({'display':'block',top:''+top+'px',left:''+left+'px',width:''+(AvEditor.width-AvEditor.size-AvEditor.posX)+'px',height:''+(AvEditor.size)+'px'});
	else 
		AvEditor.el4.setStyle({'display':'none',top:''+top+'px',left:''+left+'px',width:''+(AvEditor.width-AvEditor.size-AvEditor.posX)+'px',height:''+(AvEditor.size)+'px'});

	var top = AvEditor.top+AvEditor.posY;
	var left = AvEditor.left+AvEditor.posX;
	AvEditor.el5.setStyle({top:''+top+'px',left:''+left+'px',width:''+(AvEditor.size-2)+'px',height:''+(AvEditor.size-2)+'px'});

}
AvEditor.unRegister = function() {
	AvEditor.el1.remove();
	AvEditor.el2.remove();
	AvEditor.el3.remove();
	AvEditor.el4.remove();
	AvEditor.el5.remove();
	AvEditor.posX=0;
	AvEditor.posY=0;
	AvEditor.position=25;
	AvEditor.slider.hide();
}

AvEditor.prevImage = null;
AvEditor.loading = 0;
AvEditor.needReload = 0;
AvEditor.startImageLoad = function() {
	if (AvEditor.loading==1) {
		AvEditor.needReload = 1;
	} else {
		AvEditor.loading=1;
		$('av_editor_preview_table').show();
		if (AvEditor.prevImage!=null) AvEditor.prevImage.hide();
		var dim = AvEditor.getDimensions();
		AvEditor.prevImage = new Element('img',{'border':'0','width':'80','height':'80','src':'/avatar?x1='+dim[0]+'&x2='+dim[2]+'&y1='+dim[1]+'&y2='+dim[3]+'&imgId='+AvEditor.imgId+'&t='+Helpers.getTime()});
		AvEditor.prevImage.observe('load',AvEditor.imageLoaded);
	}	
}
AvEditor.imageLoaded = function() {
	AvEditor.loading=0;
	if (AvEditor.needReload==1) {
		AvEditor.needReload=0;
		AvEditor.startImageLoad();		
	} else {
		$('av_editor_preview_table').hide();
		if (AvEditor.prevImage!=null) {
			$('av_editor_preview_panel').insert(AvEditor.prevImage);
		}	
	}
}



// Photo Picker
var PhotoPicker = new Object();
PhotoPicker.photos = new Array();
PhotoPicker.photoPickerWndId = 0;
PhotoPicker.perPage=12;
//PhotoPicker.title='';
//PhotoPicker.onSuccessCloseFn=undefined;
PhotoPicker.open = function() {
//	var body = $('picker_content');
//	Helpers.clear(body);
//	body.update('');
//	body.insert($('photo_picker_wait'));
	PhotoPicker.photoPickerWndId=Popups.showPopupW('', 'common_wait');
}
PhotoPicker.openSuccess = function(result) {
//	$('hiddenBlock').insert($('photo_picker_wait'));
	Popups.closeLast();
	PhotoPicker.photos=eval(result);
	if (PhotoPicker.photos.length==0) {
		PhotoPicker.showEmpty();
	} else {
		PhotoPicker.showPage(1);
		PhotoPicker.photoPickerWndId=Popups.showPopupW('', 'photo_picker');
	}
}
PhotoPicker.openFail = function(result) {
//	$('hiddenBlock').insert($('photo_picker_wait'));
	Popups.closeLast();
	Popups.defaultError();
//	PhotoPicker.showEmpty();
//	PhotoPicker.photoPickerWndId=Popups.showPopupW('', 'photo_picker');
}
PhotoPicker.showPage = function(page) {
	Pager.buildPager('pickerPager', 'picker_pager', PhotoPicker.showPage, Math.ceil(PhotoPicker.photos.length/PhotoPicker.perPage), page);
//	alert(page);
	var body = $('picker_content');
	Helpers.clear(body);
	body.update('');

	TableBuilder.init(4,15,15);
	
	var last = page*PhotoPicker.perPage;
	if (last>PhotoPicker.photos.length) last=PhotoPicker.photos.length;
	for (var i = (page-1)*PhotoPicker.perPage; i < last; i++) {
		var val = PhotoPicker.photos[i];
		var meta = val.get('meta');

		// process meta
		var msg='';
		if ('a'==meta) {
			msg=PHOTO.META_A;
		} else if ('r'==meta) {
			msg=PHOTO.META_R;
		} else if ('l'==meta) {
			msg=PHOTO.META_L;
		}
		var bck = 'col2';
		if (msg!='') bck = 'col12';

		var tableO = new Element('table');
		var bodyO = new Element('tbody');
		var trO = new Element('tr');
		var tdO = new Element('td',{'style':'padding:1px;background: #d9d9d9;'});
		trO.insert(tdO);bodyO.insert(trO);tableO.insert(bodyO);
		var tableI = new Element('table');
		var bodyI = new Element('tbody');
		var trI = new Element('tr');
		var tdI = new Element('td',{'style':'padding:9px;','class':bck});
		trI.insert(tdI);bodyI.insert(trI);tableI.insert(bodyI);

		var img = new Element('img', {id:'pp_'+val.get('phId'),src:val.get('imgUrl'), width:val.get('w'), height:val.get('h'), title:msg});
		tdI.insert(img);
		tdO.insert(tableI);
		TableBuilder.addEl(tableO);

		if (meta=='null' || meta==undefined) {
			img.observe('mouseover', function(e) {
				Helpers.getElementByEvent(e).up().className='col9';
			});
			img.observe('mouseout', function(e) {
				Helpers.getElementByEvent(e).up().className='col2';
			});
			img.observe('click', PhotoPicker.onClick);
			img.writeAttribute('style','cursor:pointer');
		}

	}
	body.insert(TableBuilder.getTable());
}
PhotoPicker.showEmpty = function() {
	Popups.showMessage(MSG.INF.NO_PHOTOS_FOUND);
//	$('picker_content').insert('no photos found');
}

var TableBuilder = new Object();
TableBuilder.cells = 3;
TableBuilder.body = undefined;
TableBuilder.table = undefined;
TableBuilder.row = undefined;
TableBuilder.cell=1;
TableBuilder.rowsCount=0;
TableBuilder.xSpan=0;
TableBuilder.ySpan=0;
TableBuilder.init = function(cells,xSpan,ySpan) {
	TableBuilder.cell=1;
	TableBuilder.xSpan=0;
	TableBuilder.ySpan=0;
	TableBuilder.rowsCount=0;
	if (xSpan!=undefined) TableBuilder.xSpan=xSpan;
	if (ySpan!=undefined) TableBuilder.ySpan=ySpan;
	if (cells!=undefined) TableBuilder.cells=cells;
	if (TableBuilder.xSpan==-1) {
//		TableBuilder.table = new Element('table',{'border':'1','width':'100%'});
		TableBuilder.table = new Element('table',{'width':'100%'});
	} else {
		TableBuilder.table = new Element('table');
//		TableBuilder.table = new Element('table',{'border':'1'});
	}
	TableBuilder.body = new Element('tbody');
	TableBuilder.table.insert(TableBuilder.body);
}
TableBuilder.addEl = function(el) {
	if (TableBuilder.cell==1) {
		TableBuilder.rowsCount++;
		// add y span if needed
		if (TableBuilder.ySpan!=0 && TableBuilder.rowsCount>1) {
			var tds=TableBuilder.cells;
			if (TableBuilder.ySpan!=0) tds+=(TableBuilder.cells-1);
			var row = new Element('tr',{'height':TableBuilder.ySpan});
			var innerTd = new Element('td',{'colspan':tds});
			row.insert(innerTd);
			TableBuilder.body.insert(row);
		}
		TableBuilder.row = new Element('tr');
		TableBuilder.body.insert(TableBuilder.row);
	}
	// insert x span if needed
	if (TableBuilder.cell>1 && TableBuilder.xSpan!=0) {
		var spanTd;
		if (TableBuilder.xSpan==-1) {
			spanTd = new Element('td',{'width':'10%'});
		} else {
			spanTd = new Element('td',{'width':TableBuilder.xSpan});
			spanTd.insert(new Element('img',{'src':SYSTEM.SPACE,'width':TableBuilder.xSpan,'height':'1'}));
		}
		TableBuilder.row.insert(spanTd);
	} 
	var td = new Element('td',{'align':'center','valign':'bottom'});
	td.insert(el);
	TableBuilder.row.insert(td);
	TableBuilder.cell++;
	if (TableBuilder.cell>TableBuilder.cells) {
		TableBuilder.cell=1;
	}
}
TableBuilder.getTable = function() {
	if (TableBuilder.cell!=1) {
		while (TableBuilder.cell<=TableBuilder.cells) {
			TableBuilder.row.insert(new Element('td'));
			TableBuilder.row.insert(new Element('td'));
			TableBuilder.cell++;
		}
	}
	return TableBuilder.table; 
}
TableBuilder.wrapWithTable = function(el,width, styleName, padding) {
	var tbl = new Element('table',{'width':width, 'class':styleName});
	var tbody = new Element('tbody');
	var tr = new Element('tr');
	var td = new Element('td',{'style':'padding:'+padding+'px;'});
	td.insert(el);
	tr.insert(td);
	tbody.insert(tr);
	tbl.insert(tbody);
	return tbl;
}

var ContestPhotoPicker = new Object();
ContestPhotoPicker.invCode=undefined;
ContestPhotoPicker.open = function(contestId, isPublic, invCode) {
	PhotoPicker.onClick=ContestPhotoPicker.onClick;
	ContestPhotoPicker.contestId=contestId;
	ContestPhotoPicker.isPublic=isPublic;
	ContestPhotoPicker.invCode=invCode;
//	PhotoPicker.title = 'prived!';
//	PhotoPicker.infoEl = $('sdp_info');

	PhotoPicker.open();

	var map = new Hash({'contest':contestId});
	Helpers.rpc('/rpc/photo_picker/',map,PhotoPicker.openSuccess,PhotoPicker.openFail);
}
ContestPhotoPicker.onClick = function(e) {
	ContestPhotoPicker.selectedPhotoId = Helpers.getElementByEvent(e).identify().substr(3);
	var msg = MSG.CONFIRM.SEND_REQUEST_TO_CONTEST;
	if (ContestPhotoPicker.isPublic) {
		msg=MSG.CONFIRM.ADD_PHOTO_TO_CONTEST;
	}
	ContestPhotoPicker.confirmId = Popups.showConfirm(msg,ContestPhotoPicker.addPhotoToContest,ContestPhotoPicker.closeConfirm,0);
}
ContestPhotoPicker.addPhotoToContest = function() {
	Popups.makeConfirmWaiting();
	var map = new Hash();
	map.set('photoId',ContestPhotoPicker.selectedPhotoId);
	if (ContestPhotoPicker.invCode!=undefined) {
		map.set('invCode',ContestPhotoPicker.invCode);
		Helpers.rpc('/rpc/photo_to_contest_inv/',map,ContestPhotoPicker.addPhotoToContestSuccess,ContestPhotoPicker.addPhotoToContestFail);
	} else {
		map.set('contestId',ContestPhotoPicker.contestId);
		Helpers.rpc('/rpc/photo_to_contest/',map,ContestPhotoPicker.addPhotoToContestSuccess,ContestPhotoPicker.addPhotoToContestFail);
	}
}
ContestPhotoPicker.addPhotoToContestSuccess = function(result) {
	Popups.closePopup(ContestPhotoPicker.confirmId);
	Popups.closePopup(PhotoPicker.photoPickerWndId);
//	if (PhotoPicker.onSuccessCloseFn!=undefined)
//		PhotoPicker.onSuccessCloseFn();
	if (result.substring(0,5)=='cont:') {
			Popups.showMessage('Фотография не может быть добавлена, поскольку уже участвует в конкурсе "'+result.substring(5)+'"');
	} else if (result.substring(0,6)=='limit:') {
		Popups.showMessage('В одном конкурсе может участвовать не более "'+result.substring(6)+'" Ваших фотографий');
	} else {

		if (ContestPhotoPicker.isPublic) {
			Popups.showMessage(MSG.INF.PHOTO_ADDED_TO_CONTEST);
		} else {
			Popups.showMessage(MSG.INF.REQUEST_SENT_TO_CONTEST);
		}

	}

}
ContestPhotoPicker.addPhotoToContestFail = function(result) {
	Popups.closePopup(ContestPhotoPicker.confirmId);
	Popups.defaultError();
}
ContestPhotoPicker.closeConfirm = function() { 
	Popups.closePopup(ContestPhotoPicker.confirmId);
}

var AvatarPhotoPicker = new Object();
AvatarPhotoPicker.open = function() {
	PhotoPicker.onClick=AvatarPhotoPicker.onClick;
//	PhotoPicker.title = 'prived!';
	PhotoPicker.open();
	Helpers.rpc('/rpc/photo_picker_all/',new Hash(),PhotoPicker.openSuccess,PhotoPicker.openFail);
}
AvatarPhotoPicker.onClick = function(e) {
	AvatarPhotoPicker.selectedPhotoId = Helpers.getElementByEvent(e).identify().substr(3);
	var imgMap = new Hash();
	PhotoPicker.photos.each(function (map) {
		if (map.get('phId')==AvatarPhotoPicker.selectedPhotoId) {
			imgMap = map;
		}
	})
	Popups.showPopupW('','av_editor_panel', function(){return true;}, AvEditor.unRegister);
//	alert(imgMap.inspect());
	AvEditor.register('av_editor',imgMap.get('imgId'),imgMap.get('imgMUrl'),imgMap.get('wm'),imgMap.get('hm'),imgMap.get('wb'),imgMap.get('hb'));
}
AvatarPhotoPicker.applyCustomAvatar = function() {
	var dim = AvEditor.getDimensions();
	var map = new Hash();
	map.set('x1',dim[0]);
	map.set('y1',dim[1]);
	map.set('x2',dim[2]);
	map.set('y2',dim[3]);
	map.set('imgId',AvEditor.imgId);
//	$('av_editor_wait').show();
	Btns.disable('av_editor_apply');
	Helpers.rpc('/rpc/change_avatar/',map,AvatarPhotoPicker.applyCustomAvatarSucces,AvatarPhotoPicker.applyCustomAvatarFail);
}
AvatarPhotoPicker.applyCustomAvatarSucces = function(result) {
//	$('av_editor_wait').hide();
	Btns.enable('av_editor_apply');
	Popups.closeLast();
	Popups.closeLast();
	Popups.closeLast();
	$('ud_avatar').writeAttribute('src',result);
	$('av_pckr_avatar').writeAttribute('src',result);
}
AvatarPhotoPicker.applyCustomAvatarFail = function() {
//	$('av_editor_wait').hide();
	Btns.enable('av_editor_apply');
//	alert('applyCustomAvatarFail');
//	Popups.defaultError(); 
}
AvatarPhotoPicker.onOver = function(e) {
	Helpers.getElementByEvent(e).addClassName('highlight');
} 
AvatarPhotoPicker.onOut = function(e) {
	Helpers.getElementByEvent(e).removeClassName('highlight');
} 
AvatarPhotoPicker.onAvatarClick = function(e) {
	var el = Helpers.getElementByEvent(e);
	AvatarPhotoPicker.selectedAvatarId=el.identify().substr(8);
	$('av_picker_avatar').writeAttribute('src',el.src);
} 
//AvatarPhotoPicker.apply = function() {
//	var map = new Hash();
//	map.set('avatarId',AvatarPhotoPicker.selectedAvatarId);
//	$('av_picker_wait').show();
//	Helpers.rpc('/rpc/change_avatar_id/',map,AvatarPhotoPicker.applySuccess,AvatarPhotoPicker.applySuccess);
//} 
//AvatarPhotoPicker.applySuccess = function() {
//	$('av_picker_wait').hide();
////	Popups.closePopup(UserMain.avPickerWndId);
//	$('ud_avatar').writeAttribute('src',$('av_picker_avatar').readAttribute('src'));
//	$('av_picker_avatar').writeAttribute('src',$('av_picker_avatar').readAttribute('src'));
//} 
//AvatarPhotoPicker.applyFail = function() {
//	$('av_picker_wait').hide();
//} 
var Invite = new Object();
Invite.code='';
Invite.open = function(code) {
	Invite.code=code;
	Popups.showPopup('invite wnd', $('invitation'));
}
Invite.send = function() {
	$('inv_email_err').update('');
	$('inv_email_err').up().hide();
//	$('inv_email_sent').hide();
	var email = $('inv_email').value;
	if (email.length<1) {
		$('inv_email_err').update(MSG.INV.NO_EMAIL);
		$('inv_email_err').up().show();
		return;
	}
	if (Validate.validateEmail(email)==false) {
		$('inv_email_err').update(MSG.INV.WRONG_EMAIL);
		$('inv_email_err').up().show();
		return;
	}
//	$('inv_wait').show();
	var map = new Hash();
	map.set('email', email);
	map.set('invCode',Invite.code);
	Btns.disable('b_send');
	Helpers.rpc('/rpc/send_invite/',map,Invite.sendSucces,Invite.sendFail);
}
Invite.sendSucces = function() {
	Btns.enable('b_send');
	$('inv_email').value='';
	Popups.closeLast();
	Popups.showMessage(MSG.INF.INVITE_SENT);
//	$('inv_wait').hide();
//	$('inv_email_sent').show();
}
Invite.sendFail = function() {
	Btns.enable('b_send');
//	$('inv_wait').hide();
	Popups.defaultError();
//	$('inv_email_err').update(MSG.INV.SERVER_ERROR);
//	$('inv_email_err').up().show();
}

var phCom = new Object();
phCom.photoId = 0;
phCom.addComment = function() {
	phCom.photoId=$('curr_photo_id').innerHTML;
	var txt = me.getValue('postMain');
	var map = new Hash();
	map.set('photoId',phCom.photoId);
	map.set('message',txt);
	Helpers.rpc('/rpc/add_comment/',map,phCom.addCommentSuccess,phCom.addCommentFail);
}
phCom.addCommentSuccess = function(result) {
//	Btn.wait('me_postMain_submit',false);
	Btns.enable('me_postMain_submit');
	me.reset('postMain');
	Pagination.refresh();
}
phCom.addCommentFail = function(result) {
	Btns.enable('me_postMain_submit');
	if (result=='bad_words') {
		Popups.showMessage(MSG.ME.BAD_WORDS);
	} else if (result=='silent_mode') {
		Popups.showMessage(MSG.ME.FUNCTION_BLOCKED);
	} else {
		Popups.defaultError();
	}
}
phCom.prepareMap = function() {
	return new Hash({'photoId':$('curr_photo_id').innerHTML});
}
phCom.deleteMessage = function(commentId) {
	phCom.commentId = commentId;
	phCom.confirmId = Popups.showConfirm(MSG.CONFIRM.COMMENT_DELETE,phCom.deleteMessageYes, function(){Popups.closeLast()},0);
}
phCom.deleteMessageYes = function() {
	Popups.makeConfirmWaiting();
	var map = new Hash();
	map.set('commentId', phCom.commentId);
	map.set('photoId', $('curr_photo_id').innerHTML);
	Helpers.rpc('/rpc/delete_comment/',map,phCom.deleteMessageSuccess,phCom.deleteMessageFail);
}
phCom.deleteMessageSuccess = function(result) {
	Popups.closeLast();
	Pagination.refresh();
}
phCom.deleteMessageFail = function(result) {
	Popups.closeLast();
	Popups.defaultError();
}
phCom.reply = function(commentId, isEdit) {
	var title = '';
	var buttonLabel = '';
	if (isEdit) {
		title=MSG.ME.REPLY_EDIT;
		buttonLabel=MSG.ME.SAVE;
	} else {
		title=MSG.ME.REPLY;
		buttonLabel=MSG.ME.POST;
	}
	me.create('postReply', 'me_reply_panel', title, buttonLabel, '', function(){phCom.addReply(commentId)}, 255);
	if (isEdit) {
		me.makeLoading('postReply');
	}
	Popups.showPopupW('message','me_reply',function(){return true;}, function() {$('me_reply_panel').update('');});
	if (isEdit) {
		var map = new Hash();
		map.set('photoId',$('curr_photo_id').innerHTML);
		map.set('commentId',commentId);
		Helpers.rpc('/rpc/get_reply/',map,phCom.getReplySuccess,phCom.getReplyFail);
	}
}

phCom.getReplySuccess = function(result) {
	me.stopLoading('postReply');
//	me.setValue('postReply', eval(result));
	me.setValue('postReply', result);
}
phCom.getReplyFail = function(result) {
	me.stopLoading('postReply');
	Popups.closeLast();
	Popups.defaultError();
}

phCom.addReply = function(commentId) {
	var map = new Hash();
	map.set('reply',me.getValue('postReply'));
	map.set('commentId',commentId);
	map.set('photoId',$('curr_photo_id').innerHTML);
	Helpers.rpc('/rpc/post_reply/',map,phCom.addReplySuccess,phCom.addReplyFail);
}
phCom.addReplySuccess = function(reply) {
//	Btn.wait('me_postReply_submit',false);
	Btns.enable('me_postReply_submit');
	Popups.closeLast();
	Pagination.refresh();
}
phCom.addReplyFail = function(result) {
//	Btn.wait('me_postReply_submit',false);
	Btns.enable('me_postReply_submit');
	if (result=='bad_words') {
		Popups.showMessage(MSG.ME.BAD_WORDS);
	} else if (result=='silent_mode') {
		Popups.showMessage(MSG.ME.FUNCTION_BLOCKED);
	} else {
		Popups.defaultError();
	}
}

var sympAll = new Object();
sympAll.display = function() {
	Popups.showPopupW('', 'common_wait');
	var map = new Hash();
//	alert($('symp_photo_id').innerHTML);
	map.set('photoId',$('symp_photo_id').innerHTML);
	Helpers.rpc('/rpc/get_all_symps/',map,sympAll.displaySuccess,sympAll.displayFail);
}
sympAll.displaySuccess = function(result) {
	Popups.closeLast();
	$('symps_to_image').width=$('symp_photo_w').innerHTML;
	$('symps_to_image').height=$('symp_photo_h').innerHTML;
	$('symps_to_image').src=$('symp_photo_url').innerHTML;
	$('all_symps_main_panel').update(result);
	$('all_symps_main_panel').setStyle({height:''+(Math.round(Helpers.getDocHeight()*0.95)-230)+'px'});
	Popups.showPopupW('','all_symps_pop');
}
sympAll.displayFail = function(result) {
	Popups.closeLast();
	Popups.defaultError();
}


var symp = new Object();
symp.pages=0;
symp.points=0;
symp.array=undefined;
symp.selectedSymp=0;
symp.source=null;
symp.perPage=10;
//symp.init = function(source) {
//	Btn.register('symp_btn',function() {symp.submit(symp.selectedSymp)});
//}
symp.display = function(source) {
	$('symp_form').reset();
	Btns.disable('symp_add','Не выбрана симпатия');
	symp.selectedSymp=0;
	Popups.showPopupW('', 'common_wait');
	symp.source=source;
	Helpers.rpc('/rpc/get_symps/',new Hash(),symp.displaySuccess,symp.displayFail);
}
symp.displaySuccess = function(result) {
	Popups.closeLast();
	var map = eval(result);
	symp.points=map.get('points');
	$('symp_balance').innerHTML=symp.points;
	symp.array = map.get('symps');
	$('symp_to_image').width=$('symp_photo_w').innerHTML;
	$('symp_to_image').height=$('symp_photo_h').innerHTML;
	$('symp_to_image').src=$('symp_photo_url').innerHTML;
	
	if (symp.array.length>0) {
		symp.pages = Math.ceil(symp.array.length/symp.perPage);
		Popups.showPopupW('','symp_picker');
		symp.showPage(1); 
	}
}
symp.displayFail = function(result) {
	Popups.closeLast();
	Popups.defaultError();
}
symp.showPage = function(page) {
	TableBuilder.init(5,4,4);
	var startIndex = (page-1)*symp.perPage;
	var endIndex = startIndex+symp.perPage;
	var blockArr = new Array();
	for (i=startIndex;(i<endIndex)&&(i<symp.array.length);i++) {
		var smp = symp.array[i];
		var id = smp[0];
		var points = smp[2];
		TableBuilder.addEl('<div id="symp-table-'+id+'" class="pada3" onClick="symp.selectSymp('+id+','+points+')"><div class="pada1" style="background:#dbdbdb"><table id="symp-img-'+id+'" bgcolor="#ffffff"><tr><td><img width="90" height="90" style="cursor:pointer;" src="'+SYSTEM.SYMP_HTTP+id+'.jpg"/></td></tr><tr height="5"><td></td></tr><tr><td align="center" class="t-11 c-g3">'+points+' баллов</td></tr><tr height="5"><td></td></tr></table></div></div>');
		if (symp.points<points) blockArr[blockArr.length]=id;
	}
	$('symp_main_panel').update(TableBuilder.getTable());
	
	//block expensive symps
	if (blockArr.length>0) {
		for (i=0;i<blockArr.length;i++) {
			var el = new Element('div',{'class':'symp_disabled','title':'Недостаточно баллов'});
			$('symp_main_panel').insert(el);
			el.absolutize();
			el.clonePosition($('symp-img-'+blockArr[i]));
		}
	}

	Pager.buildPager('symp_pager', 'symp_pager_panel', symp.showPage, symp.pages, page);	
}
symp.selectSymp = function(id, points) {
	if (symp.selectedSymp!=0) {
		var el = $('symp-table-'+symp.selectedSymp);
		if (el!=null) {
			el.className="pada3";
		}	
	} else {
		// first symp selected. update button
		Btns.enable('symp_add');
		$('symp_add').title='';
		$('symp_add1').className='gif bck82 pointer';
		$('symp_add2').className='t-12 t-b c-w padl5 padr5 pngh bck88 pointer';
		$('symp_add3').className='gif bck83 pointer';
	}
	$('symp-table-'+id).className="pada3 symp_selected";
	symp.selectedSymp=id;
}
symp.submit = function() {
//	$('symp_err').hide();
	var txt = $('symp_text').value;
//	if (txt.length<3) {
//		$('symp_err').show();
//		return;
//	}
	var map = new Hash();
	map.set('source',symp.source);
	map.set('sympId',symp.selectedSymp);
	map.set('photoId',$('symp_photo_id').innerHTML)
	map.set('private',$('symp_private').checked)
	map.set('message',txt);
	Btns.disable('symp_add');
	Helpers.rpc('/rpc/add_symp/',map,symp.submitSuccess,symp.submitFail);
}
symp.submitSuccess = function(result) {
	if ("user"==symp.source) {
		top.location='/user/'+$('symp_user_id').innerHTML+'/'+$('symp_photo_id').innerHTML;
	} else {
		Helpers.refresh();
	}
}
symp.submitFail = function(result) {
	Btns.enable('symp_add');
	Popups.defaultError();
}

var Btns = new Object();
Btns.btns = new Hash();
Btns.register = function(elName, fn) {
	var el = $(elName);
	if (el!=null) {
		var arr=new Array();
		arr[0]=fn;
		arr[1]=el.down().down().down();
		arr[2]=arr[1].next();
		arr[3]=arr[2].next();
		arr[4]=1; //enabled
		arr[6]=el;
		el.observe('click',fn);
//		arr[2].down().observe('click',fn);
		Btns.btns.set(elName,arr);
	}
}
Btns.disable = function(elName, title) {
	var arr = Btns.btns.get(elName);
	if (arr!=undefined && arr[4]==1) {
		arr[5]=arr[2].innerHTML;
		arr[4]=0; //disabled
		if (title!=undefined) {
			arr[6].title=title;
		} else {
			if (elName!='l_login')
				arr[2].innerHTML='<div class="t-12 t-b c-w padl5 padr5">Ожидайте...</div>';
		}
		arr[6].stopObserving('click',arr[0]);
		arr[1].addClassName('bck96');
		arr[2].addClassName('bck97');	
		arr[3].addClassName('bck98');
		arr[6].removeClassName('pointer');	
	}
} 
Btns.enable = function(elName) {
	var arr = Btns.btns.get(elName);
	if (arr!=undefined && arr[4]==0) {
		arr[2].innerHTML=arr[5];
		arr[4]=1; //disabled
		arr[6].observe('click',arr[0]);
		arr[1].removeClassName('bck96');
		arr[2].removeClassName('bck97');	
		arr[3].removeClassName('bck98');
		arr[6].addClassName('pointer');	
		arr[6].title='';
	}
} 
Btns.enableAll = function() {
	Btns.btns.each(function (pair) {
		Btns.enable(pair.key);
	});
} 

var Btn = new Object();
Btn.btns = new Hash();
Btn.disabled = new Hash();
Btn.animated = new Hash();
Btn.labels = new Hash();
Btn.animationId=1;
Btn.register = function(elName,fn) {
	var el = $(elName);
	if (el!=null) {
		el.observe('mouseover',Btn.mouseOver);
		el.observe('mouseout',Btn.mouseOut);
		el.observe('click',function() {Btn.click(this);});
		Btn.btns.set(elName,fn);
	}
}
Btn.click = function(el) {
	var fn = Btn.btns.get(el.id);
	if (fn!=undefined && Btn.disabled.get(el.id)!=1) fn();
}
Btn.wait = function(btnId, isWait) {
	var el = $(btnId);
	if (isWait) {
		Btn.disable(btnId);
		Btn.animated.set(btnId,1);
		if (Btn.labels.get(btnId)==undefined)
			Btn.labels.set(btnId,el.innerHTML);
		el.update(MSG.WAIT1);
		setTimeout("Btn.waitAnimation('"+btnId+"');",SYSTEM.ANIMATION_TIME);
	} else {
		Btn.animated.unset(btnId);
		Btn.enable(btnId);
		el.update(Btn.labels.get(btnId));
	}
}
Btn.waitAnimation = function(btnId) {
	if (Btn.animated.get(btnId)==1 && $(btnId)!=undefined) {
		Btn.animationId++;
		if (Btn.animationId>3) Btn.animationId=1;
		$(btnId).update(eval('MSG.WAIT'+Btn.animationId));
		setTimeout("Btn.waitAnimation('"+btnId+"');",SYSTEM.ANIMATION_TIME);
	}
}
Btn.disable = function(btnId) {
	var el = $(btnId);
	el.removeClassName('btnOver');
	el.addClassName('btnDisabled');
	el.stopObserving('mouseover',Btn.mouseOver);
	el.stopObserving('mouseout',Btn.mouseOut);
	Btn.disabled.set(btnId, 1);
}
Btn.enable = function(btnId) {
	var el = $(btnId);
	el.removeClassName('btnDisabled');
	el.observe('mouseover',Btn.mouseOver);
	el.observe('mouseout',Btn.mouseOut);
	Btn.disabled.unset(btnId);
}
Btn.mouseOver = function(ev) {
	var el = Helpers.getElementByEvent(ev);
	el.addClassName('btnOver')
}
Btn.mouseOut = function(ev) {
	var el = Helpers.getElementByEvent(ev);
	el.removeClassName('btnOver')
}

var tt = new Object();
tt.apendixHeight=11;
tt.template='<table id="tt_%elName%" border="0" align="center" style="display:none" class="abs">'+
		'	<tr height="'+tt.apendixHeight+'" id="tt_%elName%_top" style="display:none"><td class="padlr22"><img id="tt_%elName%_topImg" height="'+tt.apendixHeight+'" src="'+SYSTEM.SPACE+'"></td></tr>'+
		'	<tr height="9">'+
		'		<td><table width="100%" height="9"><tr><td width="9"><img width="9" height="9" src="'+SYSTEM.SPACE+'" class="gif bck26 fl"/></td><td class="col3" width="100%"></td><td width="9"><img src="'+SYSTEM.SPACE+'" width="9" height="9" class="gif bck27 fr"/></td></tr></table></td>'+
		'	</tr>'+
		'	<tr class="col3"><td id="tt_%elName%_body"></td></tr>'+
		'	<tr height="9">'+
		'		<td><table width="100%" height="9"><tr><td width="9"><img width="9" height="9" src="'+SYSTEM.SPACE+'" class="gif bck28 fl"/></td><td class="pngh bck30" width="100%"></td><td><img src="'+SYSTEM.SPACE+'" width="9" height="9" class="gif bck29 fr"/></td></tr></table></td>'+
		'	</tr>'+
		'	<tr height="'+tt.apendixHeight+'" id="tt_%elName%_bottom" style="display:none"><td class="padlr22" align="center"><img id="tt_%elName%_bottomImg" height="'+tt.apendixHeight+'" src="'+SYSTEM.SPACE+'"></td></tr>'+
		'</table>';
tt.activity = new Hash();
tt.tooltips = new Hash();
tt.currentTT = '';
tt.addText = function(elName, txt, width) {
	// crete tt
	if (width==undefined) width=SYSTEM.TOOLTIP_WIDTH;
	var ttEl = new Element('div', {'style':'width:'+width+'px'});
	ttEl.insert(txt);
	tt.addTT(elName,ttEl);
}
tt.addElement = function(elName, ttElName) {
	// crete tt
	if ($(elName)!=null) {
		var ttEl = new Element('div');
		ttEl.insert($(ttElName));
//	alert('start '+elName);
		tt.addTT(elName,ttEl);
//	alert('finish '+elName);
	}
}
tt.addTT = function(elName, ttEl) {
	var ttMainName = 'tt_'+elName;
	var template = tt.template;
	for (i=1;i<=6;i++) template=template.replace('%elName%',elName);
	$('body').insert(template);
	$('tt_'+elName+'_body').insert(ttEl);

	var ttMainEl = $(ttMainName);
	var el = $(elName);
//	alert (elName+','+el);
	el.observe('mouseover',function(){tt.over(elName)});
	el.observe('mouseout',function(){tt.out(elName)});
	ttMainEl.observe('mouseover',function(){tt.over(elName)});
	ttMainEl.observe('mouseout',function(){tt.out(elName)});
	
	tt.tooltips.set(elName,$(ttMainName));
}
tt.over = function(elName) {
	tt.activity.set(elName,1);
	tt.show(elName);	
}
tt.out = function(elName) {
	tt.activity.set(elName,0);
	setTimeout("tt.hide('"+elName+"')",SYSTEM.TOOLTIP_HIDE_DELAY);	
}
tt.show = function(elName) {
//	$('log').insert('show-'+elName+' ');
	if (tt.currentTT!='') {
		if (tt.currentTT==elName) return;
		tt.tooltips.get(tt.currentTT).hide();
	}
	tt.currentTT=elName;
	var el = $(elName);
	var elPositions = el.cumulativeOffset()
	var elLeft=elPositions[0]; 
	var elTop=elPositions[1];
	var elDim = el.getDimensions();
	var elWidth=el.getWidth();
	var elHeight=el.getHeight(); 

	$('tt_'+elName+'_top').hide();
	$('tt_'+elName+'_bottom').hide();

	var ttEl = tt.tooltips.get(elName);
	var ttTop = 0;
	var ttLeft = 0;
	var ttDim = ttEl.getDimensions();
	var ttWidth = ttEl.getWidth();
	var ttHeight = ttEl.getHeight()+tt.apendixHeight;
	
// 	alert(elName+', '+ttWidth+', '+ttHeight+', '+elLeft+', '+(elTop-scrollY));
	
	var scrollY=Helpers.getScrollY();
	var scrollX=Helpers.getScrollX();
	var screenWidth=$('body').getWidth();
	
	var hPosition='top';
	
	// можно ли разместить тултипу сверху?
	if (ttHeight<(elTop-scrollY)) {
		ttTop=elTop-ttHeight;
		$('tt_'+elName+'_bottom').show();
	} else {
		hPosition='bottom';
		ttTop=elTop+elHeight;
		$('tt_'+elName+'_top').show();
	}
	
	var vPosition='right';
	
	// можно ли разместить тултипу справа?
	var shift = elWidth*0.2;
	if (shift<25) shift=25;
	if ((screenWidth-elLeft-elWidth+scrollX)>ttWidth) {
		ttLeft=elLeft+elWidth-shift;
	} else if (ttWidth<elLeft-scrollX) {  // а слева?
		vPosition='left';
		ttLeft=elLeft-ttWidth+shift;
	} else {  // ну тогда все равно рисуем справа
		ttLeft=elLeft+shift;
	}
	
	if (hPosition=='top') {
		var img1 = $('tt_'+elName+'_bottomImg');
		var img2 = $('tt_'+elName+'_topImg');
		img2.className='';
		if (vPosition=='left') {
			img1.className='gif fr bck32 rel top1';
		} else {
			img1.className='gif fl bck31 rel top1';
		}
	} else {
		var img1 = $('tt_'+elName+'_topImg');
		var img2 = $('tt_'+elName+'_bottomImg');
		img2.className='';
		if (vPosition=='left') {
			img1.className='gif fr bck33 rel bot1';
		} else {
			img1.className='gif fl bck34 rel bot1';
		}
	}
	
	ttEl.setStyle({'left':ttLeft+'px','top':ttTop+'px'});
	ttEl.show();
	
}
tt.hide = function(elName, unconditional) {
//	$('log').insert('hide-'+elName+' ');
	if (tt.activity.get(elName)!=1) {
		tt.tooltips.get(elName).hide();
	}
	tt.currentTT='';
}
var user = new Object();
user.filter = "p";
user.lists = new Hash();
user.photosPerPage = 16;
user.mode = 'list';
user.currentPhotoId = 0;
user.cache = new Hash();
user.ccp = new Hash(); // comments current page
user.loadingPhotoId = 0;
user.userId = 0;
user.uiFilter = 'all';
user.init = function(arr,photoId, userId, filter) {
	user.userId = userId;
	user.uiFilter = filter;
	var curr=0;
	user.lists.set('all',arr);
	var p = new Array();
//	var a = new Array();
//	var k = new Array();
//	var o = new Array();
	for (i = 0; i < arr.length; i++) {
		var map = arr[i];
		if (photoId==map.get('id')) curr=photoId;
		p[p.length]=map;
//		switch (map.get('t')) {
//			case 'p':
//				p[p.length]=map;
//			break;
//			case 'k':
//				k[k.length]=map;
//			break;
//			case 'a':
//				a[a.length]=map;
//			break;
//			case 'o':
//				o[o.length]=map;
//			break;
//		}
	}
	user.lists.set('p',p);
//	user.lists.set('k',k);
//	user.lists.set('a',a);
//	user.lists.set('o',o);
	user.currentPhotoId=curr;

	// build filter
	if (curr!=0) {
//		user.filter='all';
		$('curr_photo_id').update(curr);
	}
//	user.buildFilter('ol_filterMain');
//	user.buildFilter('ol_filterDetails');
//	var def = 1;
//	if (user.filter=='p') def=2;
//	OptList.register('ol_filterMain',def,'olSelected2', user.filterChanged);
//	OptList.register('ol_filterDetails',def,'olSelected2', user.filterChanged);
//	user.filterChanged(user.filter);

	if (arr.length>=1) {
		user.updatePhotoList(1);
		var firstId = user.lists.get('p')[0].get('id');
		pSlider.init('userPhotoSlider', user.lists.get('p').clone(), firstId, user.updatePhotoPanel);
		if (user.mode=='details') {
			user.updatePhotoPanel(firstId);
		}
	
		if (curr!=0) {
			user.switchMode('details');
		} else {
			user.switchMode('list');
		}
		user.initPageElements(curr);
	} else {
		user.showEmptyPhotoList();
	}
}
user.showEmptyPhotoList = function() {
	$('userPhotoListPanel').hide();
	$('userPhotoListPanelEmpty').show();
};
user.getGoUrl = function(userId) {
	var url = '/user/'+userId;
	if (user.currentPhotoId!='' && user.currentPhotoId>0) {
		url+='/'+user.currentPhotoId;
	}
	return url;
}
user.initPageElements = function(photoId) {
	var pagesTotal = 1;
	var el = $('photo_comments_pages');
	if (el!=null) pagesTotal = el.innerHTML;
	var currentPage = 1;
	if (user.ccp.get(photoId)!=undefined)
		currentPage=user.ccp.get(photoId);
	if (photoId!=0) {
		Pagination.init('photoComments', 'photo_comments_panel', 'photo_comments_pagination', currentPage, pagesTotal, phCom.prepareMap);
		if ($('comment_post')!=null)
			me.create('postMain', 'comment_post', MSG.ME.COMMENT, MSG.ME.POST, '', phCom.addComment, 255);
		if ($('super_vote')!=null) {
			$('super_vote').observe('click', function(){uLog.actIfLogged(function(){symp.display('user')})});
		}
	}
}
user.updatePhotoPanel = function(photoId) {
//	Init.functions = new Array();
	if (user.currentPhotoId==photoId) return;
	// store page in cache 
	if (user.currentPhotoId!=0) {
		user.cache.set(user.currentPhotoId,$('details_panel').innerHTML);
	}
	// store page number
	user.ccp.set(user.currentPhotoId,Pagination.currentPage);
	
	user.currentPhotoId = photoId;
	$('curr_photo_id').update(photoId);
	// get page from cache (user.currentPhotoId)
	var cached = user.cache.get(user.currentPhotoId);
	if (cached!=undefined) {
		$('details_panel').update(cached);
		user.initPageElements(photoId);
	} else {
		user.loadPhotoDetails(photoId);
	}
	setTimeout("Init.all();",1000);// reinit tooltips
}
user.loadPhotoDetails = function(photoId) {
	user.loadingPhotoId = photoId;
	pSlider.disable();
	$('details_panel').update($('detail_wait'));
	$('details_wait').show();
	var map = new Hash();
	map.set('photoId',photoId);
	map.set('filter',user.uiFilter);
	Helpers.rpc('/rpc/photo_details/',map,user.loadPhotoDetailsSuccess,user.loadPhotoDetailsFail);
}
user.loadPhotoDetailsSuccess = function(result) {
	pSlider.enable();
	$('hiddenBlock').insert($('details_wait'));
	$('details_panel').update(result);
	user.initPageElements(user.loadingPhotoId);
}
user.loadPhotoDetailsFail = function(result) {
	pSlider.enable();
	$('hiddenBlock').insert($('details_wait'));
	Popups.defaultError();
}

user.switchMode = function(mode) {
	user.mode=mode;
	if (mode=='list') {
		$('userPhotoListPanel').show();
		$('userPhotoDetailedPanel').hide();
	} else {
//		pSlider.init('userPhotoSlider', user.lists.get(user.filter).clone(), user.currentPhotoId, user.updatePhotoPanel);
		$('userPhotoListPanel').hide();
		$('userPhotoDetailedPanel').show();
	}
}
//user.filterChanged = function(val) {
//	user.filter=val;
//	user.updatePhotoList(1);
//	var firstId = user.lists.get(val)[0].get('id');
//	pSlider.init('userPhotoSlider', user.lists.get(val).clone(), firstId, user.updatePhotoPanel);
//	if (user.mode=='details') {
//		user.updatePhotoPanel(firstId);
//	}
//	OptList.markOption('ol_filterMain',val);
//	OptList.markOption('ol_filterDetails',val);
//}
user.wrappers = new Hash();
user.updatePhotoList = function(page) {
	var arr = user.lists.get(user.filter);

	Pager.buildPager('photoList', 'photoListPager', user.updatePhotoList, Math.ceil(arr.length/user.photosPerPage), page);

	TableBuilder.init(4,-1,15);
	arr=arr.slice((page-1)*user.photosPerPage,page*user.photosPerPage);
	for (i=0;i<arr.length;i++) {
		var map = arr[i];
		var el = new Element('img',{border:0,'id':'psliderMain'+map.get('id'),'src':map.get('url'),'width':map.get('w'),'height':map.get('h'),'class':'pointer'});
		var ael = new Element('a',{'href':'/user/'+user.userId+'/'+map.get('id')+'/'+user.uiFilter});
		ael.insert(el);

//		var wrapped1 = TableBuilder.wrapWithTable(el,0,'col7',1); // gray
//		var wrapped2 = TableBuilder.wrapWithTable(el,0,'col2',5); // white
		var wrapped2 = TableBuilder.wrapWithTable(ael,0,'col2',5); // white
		var wrapped3 = TableBuilder.wrapWithTable(wrapped2,0,'col7',1); // gray
//		el.observe('click',function(){user.updatePhotoPanel(this.id.substr(11));user.switchMode('details');});
//		el.observe('click',function(){alert(''+i+' '+map.get('url'));});
//		user.wrappers.set(el.identify(),wrapped2.identify());

//		el.observe('mouseover', function(e) {
//			var tbl = $(user.wrappers.get(Helpers.getElementByEvent(e).identify()));
//			if (tbl!=null) tbl.className='col9'; // blue
//		});
//		el.observe('mouseout', function(e) {
//			var tbl = $(user.wrappers.get(Helpers.getElementByEvent(e).identify()));
//			if (tbl!=null) tbl.className='col2'; // white
//		});

		TableBuilder.addEl(wrapped3);
	}
	$('photoList').update('');
	$('photoList').insert(TableBuilder.getTable());
}

//user.buildFilter=function(filterName) {
//	var res = '<div class="ol" id="'+filterName+'_all">'+MSG.FILTER.ALL+'</div>';
//	if (user.lists.get('p').length>0) {
//		res+='<div class="ol" id="'+filterName+'_p">'+MSG.FILTER.PERSONAL+'</div>';
//	} else {
//		user.filter = 'all';
//	}
//	if (user.lists.get('k').length>0) res+='<div class="ol" id="'+filterName+'_k">'+MSG.FILTER.KID+'</div>';
//	if (user.lists.get('a').length>0) res+='<div class="ol" id="'+filterName+'_a">'+MSG.FILTER.ANIMAL+'</div>';
//	if (user.lists.get('o').length>0) res+='<div class="ol" id="'+filterName+'_o">'+MSG.FILTER.OTHER+'</div>';
//	$(filterName).insert(res);
//}


var pSlider = new Object();
pSlider.fn = null;
pSlider.body = null;
pSlider.left = null;
pSlider.right = null;
pSlider.rightActive=0;
pSlider.leftActive=0;
pSlider.active=1;
pSlider.maxHeight = 0;
pSlider.lenTotal = 0;
pSlider.lenPanel = 644;
pSlider.arr = null;
pSlider.initTime = 0;
pSlider.pos = 0;
pSlider.plannedPos = 0;
pSlider.border = 12;
pSlider.isMoving=false;
pSlider.selected = 0;
pSlider.init = function(elName, arr, photoId, fn) {
//	alert(elName+' '+photoId);
	pSlider.fn=fn;
	pSlider.initTime = Helpers.getTime();
	pSlider.arr = arr;
	var table = new Element('table',{'width':'100%'});
	var tbody = new Element('tbody');
	var row = new Element('tr');
//	var cellLeft = new Element('td',{'width':'22','class':'pointer'});
	var cellLeft = new Element('td',{'width':'22'});
	var spanCell1 = new Element('td');
	var cellBody = new Element('td', {'width':pSlider.lenPanel+'px'});
	var spanCell2 = new Element('td');
//	var cellRight = new Element('td',{'width':'22','class':'pointer'});
	var cellRight = new Element('td',{'width':'22'});
	row.insert(cellLeft).insert(spanCell1).insert(cellBody).insert(spanCell2).insert(cellRight);
	tbody.insert(row);
	table.insert(tbody);
	spanCell1.insert(new Element('img',{'src':SYSTEM.SPACE}));
	spanCell2.insert(new Element('img',{'src':SYSTEM.SPACE}));
	
	pSlider.left=new Element('img',{'class':'gif bck162','src':SYSTEM.SPACE});
	pSlider.right=new Element('img',{'class':'gif bck163','src':SYSTEM.SPACE});
	cellLeft.insert(pSlider.left);
	cellLeft.observe('click',function(){if(pSlider.leftActive==1)pSlider.click('left');});
	cellRight.insert(pSlider.right);
	cellRight.observe('click',function(){if(pSlider.rightActive==1)pSlider.click('right');});
	
	// init values
	var pos=0;
	var len=0;
	pSlider.maxHeight=0;
	pSlider.lenTotal=0;
	for (i=0;i<pSlider.arr.length;i++) {
		var map = pSlider.arr[i];
		pSlider.arr[i].set('left',len);
//		alert(map.get('h')+' '+pSlider.maxHeight);
		if ((1*map.get('h'))>pSlider.maxHeight) pSlider.maxHeight=1*map.get('h');
		if (map.get('id')==photoId) {
			if (len>=pSlider.lenPanel/2) {
				pos = len+(0.5*map.get('w'))-(0.5*pSlider.lenPanel);
			}
		}
		len+=(1*map.get('w'));
		len+=12; // border width
		len+=pSlider.border;
	}
	len-=pSlider.border;
	pSlider.lenTotal=len;
	
	var body = new Element('div');
	var bodyPanel = new Element('div');
//	body.setStyle({'overflow':'hidden','height':(1*pSlider.maxHeight+6)+'px','position':'relative'});
	body.setStyle({'overflow':'hidden','height':(1*pSlider.maxHeight+12)+'px','position':'relative'});
	bodyPanel.setStyle({'left':'-50px','width': (len*2)+'px','position':'absolute'});
	cellBody.insert(body);
	body.insert(bodyPanel);
	pSlider.body=bodyPanel;

	if (pSlider.lenPanel>=pSlider.lenTotal) {
		pos=0;
	}

	pSlider.updatePanel(pos);
	pSlider.plannedPos=pos;
	pSlider.move(pos);
	
	//$(elName).update('');
	$(elName).insert(table);

	pSlider.selectPhoto(photoId);
}
pSlider.disable = function() {
	pSlider.updateSlider('left',0);
	pSlider.updateSlider('right',0);
	pSlider.active=0;
}
pSlider.enable = function() {
	pSlider.updatePanel(pSlider.pos);
	pSlider.active=1;
}
pSlider.selectPhoto = function(photoId) {
	if (pSlider.selected!=0) {
		// clear prev
		var el = $('pslider'+pSlider.selected);
		if (el!=null) {
			$('ttable_'+pSlider.selected).removeClassName('pslider_img_selected');
			$('mtable_'+pSlider.selected).removeClassName('pslider_img_selected');
		}
	}
	pSlider.selected=photoId;
	// select new
	var el = $('pslider'+pSlider.selected);
	if (el!=null) {
		$('ttable_'+pSlider.selected).addClassName('pslider_img_selected');
		$('mtable_'+pSlider.selected).addClassName('pslider_img_selected');
	}
}
pSlider.click = function(direction) {
	// calculate planned pos
	var plannedPos=-1;
	if (direction=='right') {
		var max = pSlider.pos+pSlider.lenPanel+1;
		for (i = 0; i < pSlider.arr.length; i++) {
			var left = pSlider.arr[i].get('left');
			left-=pSlider.border;
			if (left>max) {
				plannedPos = left-pSlider.lenPanel;
				break;
			}
		}
		if (plannedPos==-1) {
			plannedPos = pSlider.lenTotal-pSlider.lenPanel;
		}
	} else {
		for (i = 0; i < pSlider.arr.length; i++) {
			var left = pSlider.arr[i].get('left');
			if (left<pSlider.pos) {
				plannedPos = left;
			} else {
				break;
			}
		}
		if (plannedPos==-1) plannedPos = 0;
	}
	// update visibility
	pSlider.updatePanel(plannedPos);
	
	// start movement
	pSlider.plannedPos=plannedPos;
	if (!pSlider.isMoving)
		pSlider.startMovement();
}
pSlider.startMovement = function() {
	pSlider.isMoving=true;
	if (pSlider.pos==pSlider.plannedPos) return;
	if (pSlider.pos>pSlider.plannedPos)
		pSlider.direction=-1;
	else 
		pSlider.direction=1;
	pSlider.updateSlider('left',false);
	pSlider.updateSlider('right',false);
	pSlider.startMovementContinious();
}
pSlider.startMovementContinious = function() {
	var speed=2;
	var diff = Math.abs(pSlider.pos-pSlider.plannedPos);
	if (diff>100) {
		speed=10;
	} else if (diff>60) {
		speed=8;
	} else if (diff>30) {
		speed=6;
	} else if (diff>10) {
		speed=4;
	}
	speed*=160;
	
	pos=pSlider.pos+pSlider.direction*(speed);
	if (pSlider.direction==1) {
		if (pos>=pSlider.plannedPos) {
			pos=pSlider.plannedPos;
			pSlider.isMoving=false;
		}
	} else {
		if (pos<=pSlider.plannedPos) {
			pos=pSlider.plannedPos;
			pSlider.isMoving=false;
		}
	}
	pSlider.move(pos);
	if (pSlider.isMoving) {
		setTimeout('pSlider.startMovementContinious();',1);
	} else {
		if (pos!=0) {
			pSlider.updateSlider('left',true);
		}
		if ((pSlider.lenTotal>pSlider.lenPanel)&&((Math.abs(pos)+pSlider.lenPanel)<pSlider.lenTotal)) {
			pSlider.updateSlider('right',true);
		}
	}
}
pSlider.updatePanel = function(pos) {
//	alert(pos);
	pos=pos*(-1);
	// check which images are not visible yet
	var min = Math.abs(pos)-700;
	var max = Math.abs(pos)+pSlider.lenPanel+150;
	for (i=0;i<pSlider.arr.length;i++) {
		var map = pSlider.arr[i];
		if (map.get('visible')!=pSlider.initTime) {
			var left = map.get('left'); 
			if (left>=min && left<=max) {
				var img = new Element('img',{'id':'pslider'+map.get('id'),'src':map.get('url'),'width':map.get('w'),'height':map.get('h'),'class':'pslider_img'});
				img.observe('mouseover',function(){this.addClassName('highlight')});
				img.observe('mouseout',function(){this.removeClassName('highlight')});
				img.observe('click',function(){if (pSlider.active==1){var photoId=this.id.substr(7);pSlider.selectPhoto(photoId);pSlider.fn(photoId)}});
				var imgTop = Math.round((pSlider.maxHeight - map.get('h'))/2); 
//				img.setStyle({'position':'absolute','left':map.get('left')+'px','top':imgTop+'px'});

				var wrapped1 = TableBuilder.wrapWithTable(img,0,'col2',5); // white
				var wrapped2 = TableBuilder.wrapWithTable(wrapped1,0,'col7',1); // gray
				wrapped2.setStyle({'position':'absolute','left':map.get('left')+'px','top':imgTop+'px'});
				wrapped2.id = 'ttable_'+map.get('id');
				wrapped1.id = 'mtable_'+map.get('id');

//				pSlider.body.insert(img);
				pSlider.body.insert(wrapped2);
				pSlider.arr[i].set('visible',pSlider.initTime);
			}
		}
	}
	if (pos==0) {
		pSlider.updateSlider('left',false);
	} else {
		pSlider.updateSlider('left',true);
	}
	if ((pSlider.lenTotal>pSlider.lenPanel)&&((Math.abs(pos)+pSlider.lenPanel)<pSlider.lenTotal)) {
		pSlider.updateSlider('right',true);
	} else {
		pSlider.updateSlider('right',false);
	}
}

pSlider.move = function(pos) {
	pos=pos*(-1);
	// validate position
	if (pos>0) pos=0;
	if ((pSlider.lenTotal>pSlider.lenPanel)&&((Math.abs(pos)+pSlider.lenPanel)>pSlider.lenTotal))
		pos = (-1)*(pSlider.lenTotal-pSlider.lenPanel);
	pSlider.body.setStyle({'left':pos+'px'});
	pSlider.pos=Math.abs(pos);
}
pSlider.updateSlider = function(slider,isActive) {
//	alert(pSlider.lenPanel+' '+pSlider.lenTotal);
	if ('left'==slider) {
		if (isActive) {
			pSlider.leftActive=1;
//			pSlider.left.update('<u><</u>');
			pSlider.left.className='gif bck160 pointer';
		} else {
			pSlider.leftActive=0;
//			pSlider.left.update('<');
			pSlider.left.className='gif bck162';
		}
	} else {
		if (isActive) {
			pSlider.rightActive=1;
//			pSlider.right.update('<u>></u>');
			pSlider.right.className='gif bck161 pointer';
		} else {
			pSlider.rightActive=0;
//			pSlider.right.update('>');
			pSlider.right.className='gif bck163';
		}
	}
}
var userStatHistory = new Object();
userStatHistory.getMap = function() {
	var map = new Hash();
//	map.set('photoId',$('curr_photo_id').innerHTML)
	return map;
}


var userEvents = new Object();
userEvents.selected = 0;
userEvents.cache = new Hash();
userEvents.opened = new Hash();
userEvents.getMap = function() {
	userEvents.opened = new Hash();
	var filter =OptList.getValue('ol_filter');
	var read =OptList.getValue('ol_read');
	var map = new Hash();
	map.set('filter',filter);
	map.set('read',read);
	return map;
}
userEvents.filterChanged = function() {
	userEvents.opened = new Hash();
	Pagination.goPage(1);
}
userEvents.click = function(el) {
	var id = el.id.substr(4);
	if (userEvents.opened.get(id)==undefined) {
		userEvents.getEventDetails(id);
	} else {
		userEvents.closeRow(id);
	}
}
userEvents.getEventDetails = function(id) {
	userEvents.selectRow(id);
	var cache = userEvents.cache.get(id);
	if (cache!=undefined) {
		userEvents.getEventDetailsShow(id, cache);
	} else {
		var map = new Hash();
		map.set('eventId',id);
//		userEvents.markLoading();
		Helpers.rpc('/rpc/get_event/', map, userEvents.getEventDetailsSuccess, userEvents.getEventDetailsFail)
	}
}
userEvents.getEventDetailsSuccess = function(result) {
//	userEvents.unmarkLoading();
	var id = userEvents.selected;
	var isFail = result.substring(4,5);
	if (isFail=='1') {
		userEvents.getEventDetailsFailShow(id,result);
	} else {
		userEvents.cache.set(id,result);
		userEvents.getEventDetailsShow(id,result);
	}
}
userEvents.getEventDetailsFailShow = function(id,result) {
	userEvents.opened.set(id,1);
	var el = $('row_'+id+'_panel');
	el.down().update(result);
	el.show();
	$('ttl_'+id).className = '';
}
userEvents.getEventDetailsShow = function(id,result) {
	userEvents.markReaded();
	userEvents.opened.set(id,1);
	var el = $('row_'+id+'_panel');
	el.down().update(result);
	el.show();
	$('ttl_'+id).className = '';
}
userEvents.getEventDetailsFail = function(fail) {
//	userEvents.unmarkLoading();
	Popups.defaultError();	
}
userEvents.selectRow = function(id) {
	if (userEvents.selected!=0) {
		userEvents.closeRow(userEvents.selected);
	}
	userEvents.selected=id;
	$('row_'+id+'_top').show();
	$('row_'+id+'_bottom').show();
	$('cell_'+id).addClassName('padlr13');
	$('cell_'+id).removeClassName('padlr15');
}
userEvents.closeRow = function(id) {
	userEvents.opened.unset(id);
	$('row_'+id+'_top').hide();
	$('row_'+id+'_bottom').hide();
	$('row_'+id+'_panel').hide();
	$('cell_'+id).addClassName('padlr15');
	$('cell_'+id).removeClassName('padlr13');
	$('ttl_'+id).className = 'nw oflow';
}
userEvents.markReaded = function() {
	var id = userEvents.selected;
	var cell = $('cell_'+id);

	if (cell.classNames().include('ev_closed') || cell.classNames().include('ev_closed_adm')) {
		var letter = $('letter_'+id);
		cell.addClassName('ev_opened');
		cell.removeClassName('ev_closed');
		if (cell.hasClassName('ev_closed_adm')) {
			cell.removeClassName('ev_closed_adm');
		}
		cell.addClassName('c-g2');
		cell.removeClassName('c-b');
		letter.className='gif bck182';
		userEvents.updateEventCount();		
	}
	
}
userEvents.updateEventCount = function() {
	var events = $('userEventsHidden').innerHTML;
	events--;
	$('userEventsHidden').innerHTML=events;
	$('userEventsDisplay').innerHTML=Helpers.numberToString(events);
	if (events==0) {
		$('userEventsDisplay').removeClassName('c-r');
		$('userEventsDisplay').addClassName('c-g1');
	}
}
//userEvents.markLoading = function() {
//	var id = userEvents.selected;
//	var el = $('row_'+id+'_panel');
//	el.update('<h2>Loading...</h2>');
//	el.show();
//}
//userEvents.unmarkLoading = function() {
//	var id = userEvents.selected;
//	var el = $('row_'+id+'_panel');
//	el.hide();
//	el.update('');
//}
//userEvents.refresh = function() {
//	Pagination.goPage(1);	
//}
userEvents.markAll = function() {
	Helpers.rpc('/rpc/mark_events/',new Hash(),userEvents.markAllSuccess, userEvents.markAllFail);
}
userEvents.markAllSuccess = function() {
//	Pagination.refresh();	
	top.location=window.location.href;
}
userEvents.markAllFail = function() {
	Popups.defaultError();
}
userEvents.reject = function(evId) {
	var map = new Hash();
	map.set('eventId',evId);
	Btns.disable('reject'+evId);
	Helpers.rpc('/rpc/reject_event/',map,Helpers.refresh,Helpers.refresh);
}
userEvents.approve = function(evId) {
	var map = new Hash();
	map.set('eventId',evId);
	Btns.disable('approve'+evId);
	Helpers.rpc('/rpc/approve_event/',map,Helpers.refresh,Helpers.refresh);
}
//userEvents.title = function(id) {
//	var max = SYSTEM.EVENT_TITLE_LENGTH;
//	var el = $('el_'+id);
//	var txt = el.innerHTML;
//	var len = el.getDimensions().width;
//	var pos = txt.lastIndexOf(' ');
//	while (len>max && pos>0) {
//		txt = txt.substr(0, pos-1);
//		pos = txt.lastIndexOf(' ');
//		el.update(txt);
//		len = el.getDimensions().width;
//		userEvents.kkk++;
//	}
//	$('ev_title_'+id).update(txt);
//}
//userEvents.updateTitles = function() {
//	var ids = $('ev_ids').innerHTML;
//	var arr = eval('Array('+ids+');');
//	if (arr.length>0) {
//		for (i=0; i<arr.length;i++) {
//			userEvents.title(arr[i]);
//		}
//	}
//}




var userMail = new Object();
userMail.selected = 0;
userMail.opened = new Hash();
userMail.click = function(el) {
	var id = el.id.substr(4);

	if (userMail.opened.get(id) == undefined) {

		// unmark & close previous
		if (userMail.selected!=0) {
			userMail.closeRow(userMail.selected);
		}
		
		// mark selected and read
		userMail.selected=id;
		var cell = $('cell_'+id);
		var sendRequest = false;
		if (!cell.hasClassName('ev_opened')) {
			sendRequest = true;
		}
		$('row_'+id+'_panel').show();
//		$('ttl_'+id).className = '';
		$('row_'+id+'_top').show();
		$('row_'+id+'_bottom').show();
		cell.addClassName('padlr13');
		cell.removeClassName('padlr15');
		cell.addClassName('ev_opened');
		cell.removeClassName('ev_closed');
		cell.addClassName('c-g2');
		cell.removeClassName('c-b');
		var letter = $('letter_'+id);
		letter.className='gif bck182';
	
		
		// open
		userMail.opened.set(id,1);
		var el = $('row_'+id+'_panel');
		el.show();
	
		// send rpc request to mark message as read
		if (sendRequest) {
			var map = new Hash();
			map.set('messageId',id);
			Helpers.rpc('/rpc/mark_message/', map, function(){},function(){});
			userMail.updateUserMessages();
		}
	} else {
		userMail.closeRow(id);
	}

}
userMail.updateUserMessages = function() {
	var messages = $('userMessagesHidden').innerHTML;
	messages--;
	$('userMessagesHidden').innerHTML=messages;
	$('userMessagesDisplay').innerHTML=Helpers.numberToString(messages);
	if (messages==0) {
		$('userMessagesDisplay').removeClassName('c-r');
		$('userMessagesDisplay').addClassName('c-g1');
	}
}
userMail.closeRow = function(id) {
	userMail.opened.unset(id);
	$('row_'+id+'_top').hide();
	$('row_'+id+'_bottom').hide();
	$('row_'+id+'_panel').hide();
	$('cell_'+id).addClassName('padlr15');
	$('cell_'+id).removeClassName('padlr13');
	$('ttl_'+id).className = 'nw oflow';

}
userMail.messageId=0;
userMail.delMessage = function(messageId) {
	userMail.messageId=messageId;
	Popups.showConfirm(MSG.CONFIRM.DEL_MESSAGE,userMail.delMessageConfirmed,function(){Popups.closeLast()},0);
}
userMail.delMessageConfirmed = function() {
	var map = new Hash();
	map.set('messageId',userMail.messageId);
	Helpers.rpc('/rpc/delete_message/', map, Helpers.refresh, userMail.delMessageFail);
}
userMail.delMessageFail = function(result) {
	Popups.defaultError();
}

var messages = new Object();
messages.reciever=0;
messages.refresh = 0;
messages.openEditor = function(userId, avatar, gender, name, age, location, refresh) {
	if (refresh == undefined) 
		messages.refresh = 0;
	else 
		messages.refresh = refresh;
	messages.reciever=userId;
	messages.initUserInfo(avatar, gender, name, age, location);
	me.create('postMessage', 'me_newMessage_panel', '', MSG.ME.SEND, '', messages.postMessage, 2000);
	Popups.showPopupW('message','me_newMessage');
}
messages.openAdminEditor = function(userId, avatar, name, refresh) {
	if (refresh == undefined) 
		messages.refresh = 0;
	else 
		messages.refresh = refresh;
	messages.reciever=userId;
	messages.initAdminInfo(avatar, 'Администрация');
	me.create('postMessage', 'me_newMessage_panel', '', MSG.ME.SEND, '', messages.postMessage, 2000);
	Popups.showPopupW('message','me_newMessage');
}
messages.avatarEl=null;
messages.genderEl=null;
messages.nameEl=null;
messages.ageEl=null;
messages.comaEl=null;
messages.locationEl=null;
messages.initSmElements = function() {
	if (messages.avatarEl==null) {
		messages.avatarEl=$('sm_img');
	}
	if (messages.comaEl==null) {
		messages.comaEl=$('sm_coma');
	}
	if (messages.genderEl==null) {
		messages.genderEl=$('sm_gender');
	}
	if (messages.nameEl==null) {
		messages.nameEl=$('sm_name');
	}
	if (messages.ageEl==null) {
		messages.ageEl=$('sm_age');
	}
	if (messages.locationEl==null) {
		messages.locationEl=$('sm_location');
	}
}
messages.initAdminInfo = function(avatar, name) {
	messages.initSmElements();
	messages.comaEl.hide();
	if (messages.avatarEl!=null)
		messages.avatarEl.src=avatar;
	if (messages.genderEl!=null) {
		messages.genderEl.className='gif bck42 fl';
	}
	if (messages.nameEl!=null)
		messages.nameEl.update(name);
}
messages.initUserInfo = function(avatar, gender, name, age, location) {
	messages.initSmElements();
	messages.comaEl.show();
	if (messages.avatarEl!=null)
		messages.avatarEl.src=avatar;
	if (messages.genderEl!=null) {
		if (gender=='m') {
			messages.genderEl.className='gif bck42 fl';
		} else {
			messages.genderEl.className='gif bck41 fl';
		}
	}
	if (messages.nameEl!=null)
		messages.nameEl.update(name);
	if (messages.ageEl!=null)		
		messages.ageEl.update(age);
	if (messages.locationEl!=null)
		messages.locationEl.update(location);
}
messages.postMessage = function() {
	var map = new Hash();
	map.set('userId',messages.reciever);
	map.set('message',me.getValue('postMessage'));
	Helpers.rpc('/rpc/send_message/',map,messages.postMessageSuccess,messages.postMessageFail);
}
messages.postMessageSuccess = function(result) {
	if (messages.refresh==0) {
		Popups.closeLast();
	} else {
		Helpers.refresh();		
	}
}
messages.postMessageFail = function(result) {
	Btns.enable('me_'+me.currentId+'_submit');
	if (result=='bad_words') {
		Popups.showMessage(MSG.ME.BAD_WORDS);
	} else if (result=='silent_mode') {
		Popups.showMessage(MSG.ME.FUNCTION_BLOCKED);
	} else {
		Popups.defaultError();
	}
}

var Vote = new Object();
Vote.over = function(position) {
	$(position+'1').className='bck35 pada1';
	$(position+'2').className='bck35 pada6';
	$('vote'+position+'L').addClassName('bck84');
	$('vote'+position+'M').addClassName('bck89');
	$('vote'+position+'R').addClassName('bck85');
}
Vote.out = function(position) {
	$(position+'1').className='bck36 pada1';
	$(position+'2').className='bck37 pada6';
	$('vote'+position+'L').removeClassName('bck84');
	$('vote'+position+'M').removeClassName('bck89');
	$('vote'+position+'R').removeClassName('bck85');
}

var Report = new Object();
Report.over = function(position) {
	$(position+'Rep').className='fr gif bck40 pointer';
}
Report.out = function(position) {
	$(position+'Rep').className='fr gif bck39';
}

// Init pages
var Init = new Object();
Init.functions = new Array();
Init.add = function(fn) {
	Init.functions[Init.functions.length]=fn;
}
Init.all = function() {
//	alert(Init.functions.inspect());
	Init.functions.each( function(f){f()} );
//	Init.functions = new Array(); // DO NOT UNCOMMENT!!!
//	var el = $('login_password');
//	if (el!=null) el.value='';
//	$('m_form').reset();
//	alert('-');
//	alert($('login_password').value);
//	setTimeout("alert($('login_password').value)",2000); 
}
Init.main = function(mainParam) {
	if (mainParam=='badLogin') {
		uLog.doNotRefreshPage=false;
		Popups.showPopup(MSG.TITLE.WRONG_LOGIN,'bad_login');
		Btns.register('b_login',function(){uLog.login('b')});
		Btns.register('b_send',uLog.sendPassword);
	}
	if (mainParam=='notLogged') {
		uLog.doNotRefreshPage=false;
		Popups.showPopup('','not_logged');
		Btns.register('b_login',function(){uLog.login('b')});
		Btns.register('b_send',uLog.sendPassword);
	}
	if (mainParam=='notLoggedRPC') {
		uLog.doNotRefreshPage=true;
		Popups.showPopup('','not_logged');
		Btns.register('b_login',function(){uLog.login('b')});
		Btns.register('b_send',uLog.sendPassword);
	}
}
Init.notLogged = function() {
	Btns.register('r_register',Reg.registration);
	Btns.register('r_login',function(){uLog.login('r')});
	Btns.register('l_login',function(){uLog.login('m')});
}
Init.inbox = function(pagesTotal) {
//	Pagination.init('mailInbox', 'inbox_panel', 'inbox_pagination', 1, pagesTotal);
}
Init.outbox = function(pagesTotal) {
//	Pagination.init('mailOutbox', 'outbox_panel', 'outbox_pagination', 1, pagesTotal);
}
Init.mailHistory = function(pagesTotal) {
//	Pagination.init('mailHistory', 'mailHistory_panel', 'mailHistory_pagination', 1, pagesTotal);
}
Init.event = function(pagesTotal) {
//	Pagination.init('userEvent', 'events_panel', 'events_pagination', 1, pagesTotal, userEvents.getMap, userEvents.updateTitles);
//	OptList.register('ol_filter',1,'olSelected2', userEvents.filterChanged);
//	OptList.register('ol_read',1,'olSelected2', userEvents.filterChanged);
//	userEvents.updateTitles();
}
Init.vote = function() {
	if ($('photo_comments_panel')!=null) {
		Pagination.init('photoCommentsLimited', 'photo_comments_panel', 'photo_comments_pagination', 1, 1, phCom.prepareMap);
		if ($('super_vote')!=null)
			$('super_vote').observe('click', function(){uLog.actIfLogged(function(){symp.display('vote')})});
	}
//	var el1=$('leftRep');
//	el1.observe('mouseover', function(el1,el2){Report.over('left')});
//	el1.observe('mouseout', function(){Report.out('left')});
//	var el2=$('rightRep');
//	el2.observe('mouseover', function(){Report.over('right')});
//	el2.observe('mouseout', function(){Report.out('right')});
//	tt.addElement('super_vote', 'tt');
//	tt.addText('supervote2','test test test test test test test test test test test test test',300);
}
Init.vote2 = function(disableCurrent, contestId) {
	$('filterAll').observe('click', function(event) {votesFilter.selectFilter('all',contestId);});
	$('filterFavorites').observe('click', function(event) {
		uLog.goIfLogged('/vote/favorites');
	});
	if (!disableCurrent) {
		$('filterCurrent').observe('click', function(event) {
			uLog.actIfLogged(function(){votesFilter.selectFilter('current',contestId)});
		})
	} else {
		votesFilter.disableCurrent = true;
	}
}
Init.stat = function(pagesTotal) {
//	Pagination.init('userStat', 'photo_stat_panel', 'photo_stat_pagination', 1, pagesTotal);
}
Init.statHistory = function(pagesTotal) {
//	Pagination.init('userStatHistory', 'photo_stat_history_panel', 'photo_stat_history_pagination', 1, pagesTotal, userStatHistory.getMap);
}
Init.photos = function(pagesTotal) {
//	Pagination.init('userPhoto', 'photo_main panel', 'photo_pagination', 1, pagesTotal);
//	OptList.register('ol_type',1,'olSelected2', UserPhotos.typeChanged);
	$('upl_erotic_cb').observe('click',UserPhotos.eroticChanged);
	$('photo_type').observe('change',UserPhotos.typeChanged);
	Btns.register('upl_submit',UserPhotos.upload);
//	$('upl_switcher').observe('click',UserPhotos.uploadSwitcher)
	$('uplTableMin').observe('click',function() {
		$('uplTableMin').hide();
		$('uplTableMax').show();
	})
	$('uplTableMaxSwitcher').observe('click',function() {
		$('uplTableMax').hide();
		$('uplTableMin').show();
	})
}
Init.userContests = function(pagesTotal) {
//	Pagination.init('userContests', 'user_contests panel', 'user_contests_pagination', 1, pagesTotal);

//	$('contest_switcher').observe('click',UserContests.contestSwitcher)
	$('contestTableMin').observe('click',function() {
		$('contestTableMin').hide();
		$('contestTableMax').show();
	})
	$('contestTableMaxSwitcher').observe('click',function() {
		$('contestTableMax').hide();
		$('contestTableMin').show();
	})

//	OptList.register('ol_type',1,'olSelected2', UserContests.typeChanged);
//	OptList.register('ol_subtype',1,'olSelected2');
	NOptList.register('ol_subtype',1,UserContests.typeChanged);
	
//	$('contest_create').observe('click',UserContests.contestCreate);
	Btns.register('contest_create',UserContests.contestCreate);
	$('contest_shared').observe('click',UserContests.locChange);
	$('contest_finish').observe('click',UserContests.endDateChange);
	Location.init('c_country','c_town','c_town_other_panel','c_town_other',LOC.CNTR_NOT_DEFINED,LOC.CITY_NOT_DEFINED);
	var d = new Date();
	var day = d.getDate(); if (day<10) day='0'+day;
	var month = d.getMonth()+1; if (month<10) month='0'+month;
	var startDate = day+'.'+month+'.'+d.getFullYear(); 
	$('contest_start').update(startDate);
}

Init.contests = function(pagesTotal,map,citiesHash) {
//	PhotoPicker.onSuccessCloseFn = function() {
//		Pagination.goPage(Pagination.currentPage);
//	}
	var filter = map.get('filter');
	Helpers.setSelection('ol_filter',filter);
	
	var type = map.get('type');
	Helpers.setSelection('ol_type',type);
	$('ol_type').observe('change',function(){ContestsMain.typeChanged(this.value)});
	
	var erotic = map.get('erotic');
	if ('on'==erotic) {
		$('ol_erotic').checked=true;
	}
	
	var state = map.get('state');
	Helpers.setSelection('ol_state',state);

	var status = map.get('status');
	Helpers.setSelection('ol_status',status);

	var count = map.get('count');
	if (count=='null') count=10;
	Helpers.setSelection('ol_count',count);

	ContestsMain.typeChanged(Helpers.getSelection('ol_type'));

	Location.init('c_country','c_town','c_town_other_panel','c_town_other',LOC.CNTR_NOT_DEFINED,LOC.CITY_NOT_DEFINED);
	Location.prevCountryValue=Helpers.getSelection('c_country');
	if (citiesHash!=null)
		Location.uploadTownsSuccessNoEval(citiesHash);
	var city = map.get('city');
	Helpers.setSelection('c_town',city);


	Helpers.restoreElements = function() {
		Location.init('c_country','c_town','c_town_other_panel','c_town_other',LOC.CNTR_NOT_DEFINED,LOC.CITY_NOT_DEFINED);
	}

	$('c_filter').observe('click', function() {
		if (Helpers.getSelection('ol_filter')!='all') {
			uLog.actIfLogged(ContestsMain.search);
		} else {
			ContestsMain.search();
		}
	});
	
	// update filter label
	var f = ''; var pref=', ';
	var el=Helpers.getSelectionLabel('ol_filter');
	if (el!='') {
		if (f!='') f+=pref;
		f+=el;
	} 
	el=Helpers.getSelectionLabel('ol_type');
	if (el!='') {
		if (f!='') f+=pref;
		f+=el;
	} 
	el=$('ol_erotic').checked;
	if (el) {
		if (f!='') f+=pref;
		f+='эротические';
	} 
	el=Helpers.getSelectionLabel('c_country');
	if (el!='') {
		if (f!='') f+=pref;
		f+=el;
	} 
	el=Helpers.getSelectionLabel('c_town');
	if (el!='') {
		if (f!='') f+=pref;
		f+=el;
	} 
	el=Helpers.getSelectionLabel('ol_state');
	if (el!='') {
		if (f!='') f+=pref;
		f+=el;
	} 
	el=Helpers.getSelectionLabel('ol_status');
	if (el!='') {
		if (f!='') f+=pref;
		f+=el;
	} 
	el=Helpers.getSelectionLabel('ol_count');
	if (el!='') {
		if (f!='') f+=pref;
		f+=el;
	} 
	if (f!='') $('currentFilter').update(f);
	
}
Init.contest = function() {
//	Popups.showMessage(PHOTO.META_A);
}
Init.userMain = function() {
//	UserMain.minAvatarId=minAvatarId;
//	UserMain.maxAvatarId=maxAvatarId;
	$('ud_main_edit_link').observe('click', function() {
		$('ud_main_display').hide();
		$('ud_main_edit').show();
	})
	$('ud_personal_edit_link').observe('click', function() {
		$('ud_personal_display').hide();
		$('ud_personal_edit').show();
	})
	$('ud_contact_edit_link').observe('click', function() {
		$('ud_contact_display').hide();
		$('ud_contact_edit').show();
	})
	$('ud_other_edit_link').observe('click', function() {
		$('ud_other_display').hide();
		$('ud_other_edit').show();
	})
	Location.init('r_country','r_town','r_other_panel','r_other',LOC.CNTR_MESSAGE,LOC.CITY_MESSAGE);
	Location.fillCntrCache('r_country','r_town');
	Location.prevCountryValue=Helpers.getSelection('r_country');
	$('av_change').observe('click', UserMain.openAvPicker);
	$('av_picker_custom').observe('click', UserMain.openAvPhotoPicker);
//	$('av_picker_apply').observe('click',AvatarPhotoPicker.apply);
	Btns.register('ud_main_save_link',UserMain.changeLoginData);
	Btns.register('ud_personal_save_link',UserMain.changePersonalData);
	Btns.register('ud_contact_save_link',UserMain.changeContactData);
	Btns.register('ud_other_save_link',UserMain.changeOtherData);
	Btns.register('av_editor_apply',AvatarPhotoPicker.applyCustomAvatar);
}	

// Pages
var UserPhotos = new Object();
UserPhotos.currentPage=1;
UserPhotos.pagesTotal=1;
UserPhotos.type='personal';
UserPhotos.erotic='false';
UserPhotos.uplPanel=0;
UserPhotos.selectedPhotoId=0;
UserPhotos.contestFilter = new Hash();
UserPhotos.deletePhoto = function(photoId) {
	UserPhotos.selectedPhotoId=photoId;
	UserPhotos.confirmId = Popups.showConfirm(MSG.CONFIRM.DELETE_PHOTO,UserPhotos.deletePhotoConfirmed,UserPhotos.closeConfirm,0);
	
}
UserPhotos.deletePhotoConfirmed = function() {
	Popups.makeConfirmWaiting();
	var map = new Hash();
	map.set('photoId',UserPhotos.selectedPhotoId);
	Helpers.rpc('/rpc/delete_photo/',map,UserPhotos.deletePhotoSuccess,UserPhotos.deletePhotoFail);
}
UserPhotos.closeConfirm = function() {
	Popups.closePopup(UserPhotos.confirmId);
}
UserPhotos.deletePhotoSuccess = function() {
//	UserPhotos.closeConfirm();
//	Pagination.refresh();
	top.location='/profile/photo';
}
UserPhotos.deletePhotoFail = function() {
	UserPhotos.closeConfirm();
	Popups.defaultError();
}
UserPhotos.uploadInProcess=0;
UserPhotos.upload = function() {
	if (UserPhotos.uploadInProcess!=0) return false;
	if ($('fakeFileName').value=='') {
		return false;
	}
	$('upl_err').up().hide();
	$('type_err').up().hide();
	var type = $('photo_type').value;
	if (type=='none') {
		$('type_err').up().show();
	} else {
		UserPhotos.uploadInProcess=1;
		Btns.disable('upl_submit');
		var form = $('upl_form');
		form.writeAttribute('action','/rpc/upload_image/'+UserPhotos.erotic+'/'+type);
		form.submit();
	}
}
UserPhotos.uploadSuccess=function() {
//	UserPhotos.uploadInProcess=0;
//	Btns.enable('upl_submit');
//	$('upl_form').reset();
	top.location='/profile/photo';
}
UserPhotos.uploadFail=function(result) {
	Btns.enable('upl_submit');
	UserPhotos.uploadInProcess=0;
	$('upl_err').update(eval(result));
	$('upl_err').up().show();
}
UserPhotos.typeChanged=function() {
	val = $('photo_type').value;
	if (val=='personal') {
		$('upl_show_erotic').show();
	} else {
		$('upl_show_erotic').hide();
		$('upl_erotic_cb').checked=false;
	};
	if (val=='personal') {
		$('personal_help').show();
		$('kid_help').hide();
		$('animals_help').hide();
		$('other_help').hide();
	} else if (val=='kid') {
		$('personal_help').hide();
		$('kid_help').show();
		$('animals_help').hide();
		$('other_help').hide();
	} else if (val=='other') {
		$('personal_help').hide();
		$('kid_help').hide();
		$('animals_help').hide();
		$('other_help').show();
	} else if (val=='animals') {
		$('personal_help').hide();
		$('kid_help').hide();
		$('animals_help').show();
		$('other_help').hide();
	} else {
		$('personal_help').hide();
		$('kid_help').hide();
		$('other_animals').hide();
		$('other_help').hide();
	}
	UserPhotos.type=val;
}
UserPhotos.eroticChanged=function(val) {
	UserPhotos.erotic=$('upl_erotic_cb').checked;
}
function getheight(){
	var d= document.documentElement;
	var b= document.body;
	var who= d.offsetHeight? d: b ;
	return Math.max(who.scrollHeight,who.offsetHeight);
}

UserPhotos.openContestPicker = function (photoId) {
	ContestPicker.photoId=photoId;
	Pagination.init('contestPicker', 'table_contests_content', 'contests_pager', 1, 1, UserPhotos.getContestPickerFilter);
	Pagination.waitEl = $('paginator_wait');

	UserPhotos.updateContestPickerFilter();
	Pagination.goPage(1);
	ContestPicker.wndId=Popups.showPopupW('','contest_picker');	
	
	Btns.register('c_filter',function() {
		UserPhotos.updateContestPickerFilter();
		Pagination.goPage(1);
	});
	
}
UserPhotos.getContestPickerFilter = function() {
	return UserPhotos.contestFilter;
}

UserPhotos.updateContestPickerFilter = function() {
	var res = new Hash();
	res.set('photoId',ContestPicker.photoId);
	res.set('filter',Helpers.getSelection('ol_filter'));
	res.set('location',Helpers.getSelection('ol_location'));
	res.set('state',Helpers.getSelection('ol_state'));
	res.set('count',Helpers.getSelection('ol_count'));
	UserPhotos.contestFilter = res;
}
//UserPhotos.saveMainPager = function() {
//	UserPhotos.currentPage=Pagination.currentPage;
//	UserPhotos.pagesTotal=Pagination.pagesTotal;
//	UserPhotos.beforePageSwitchFn=Pagination.beforePageSwitchFn;
//}
//UserPhotos.restoreMainPager = function() {
//	Pagination.init('userPhoto', 'photo_main panel', 'photo_pagination', UserPhotos.currentPage, UserPhotos.pagesTotal, UserPhotos.beforePageSwitchFn);
//}
UserPhotos.leaveContest = function(contestId, photoId) {
	UserPhotos.contestId=contestId;
	UserPhotos.photoId=photoId;
	Popups.showConfirm(MSG.CONFIRM.LEAVE_CONTEST,UserPhotos.leaveContestYes, function(){Popups.closeLast()},0);
}
UserPhotos.leaveContestYes = function() {
	Popups.makeConfirmWaiting();
	var map = new Hash();
	map.set('photoId',UserPhotos.photoId);
	map.set('contestId',UserPhotos.contestId);
	Helpers.rpc('/rpc/leave_contest/',map,UserPhotos.leaveContestSuccess,UserPhotos.leaveContestFail);
}
UserPhotos.leaveContestSuccess = function(result) {
	Popups.closeLast();
	$('pc_'+UserPhotos.photoId).update(result);
}
UserPhotos.leaveContestFail = function(result) {
	Popups.closeLast();
	Popups.defaultError();
}
UserPhotos.cancelRequest = function(contestId, photoId) {
	UserPhotos.contestId=contestId;
	UserPhotos.photoId=photoId;
	Popups.showConfirm(MSG.CONFIRM.CANCEL_REQUEST,UserPhotos.cancelRequestYes, function(){Popups.closeLast()},0);
}
UserPhotos.cancelRequestYes = function() {
	Popups.makeConfirmWaiting();
	var map = new Hash();
	map.set('photoId',UserPhotos.photoId);
	map.set('contestId',UserPhotos.contestId);
	Helpers.rpc('/rpc/cancel_request/',map,UserPhotos.cancelRequestSuccess,UserPhotos.cancelRequestFail);
}
UserPhotos.cancelRequestSuccess = function(result) {
	Popups.closeLast();
	$('pc_'+UserPhotos.photoId).update(result);
}
UserPhotos.cancelRequestFail = function(result) {
	Popups.closeLast();
	Popups.defaultError();
}


var ContestPicker = new Object();
ContestPicker.wndId = 0;
ContestPicker.photoId = 0;
ContestPicker.contestId = 0;
ContestPicker.isPublic = true;
ContestPicker.rowOver = function(val) {
	$('cp_row_'+val).addClassName('highlightRow');	
}
ContestPicker.rowOut = function(val) {
	$('cp_row_'+val).removeClassName('highlightRow');	
}
ContestPicker.rowClick = function(contestId,isPublic) {
	ContestPicker.contestId=contestId;
	ContestPicker.isPublic=isPublic;
	var msg=MSG.CONFIRM.SEND_REQUEST_TO_PHOTO;
	if (isPublic) {
		msg=MSG.CONFIRM.ADD_CONTEST_TO_PHOTO;
	}
	Popups.showConfirm(msg,ContestPicker.rowClickYes,function(){Popups.closeLast()},0);
}
ContestPicker.rowClickYes = function() {
	Popups.makeConfirmWaiting();
	var map = new Hash();
	map.set('photoId', ContestPicker.photoId);
	map.set('contestId', ContestPicker.contestId);
	Helpers.rpc('/rpc/contest_to_photo/', map, ContestPicker.rowClickSucces, ContestPicker.rowClickFail)
}
ContestPicker.rowClickSucces = function(result) {
	Popups.closeLast();
	Popups.closeLast();
	if (result.substring(0,5)=='cont:') {
		Popups.showMessage('Фотография не может быть добавлена, поскольку уже участвует в конкурсе "'+result.substring(5)+'"');
	} else if (result.substring(0,6)=='limit:') {
			Popups.showMessage('В одном конкурсе может участвовать не более "'+result.substring(6)+'" Ваших фотографий');
	} else {
		$('pc_'+ContestPicker.photoId).update(result);
		if (ContestPicker.isPublic) {
			Popups.showMessage(MSG.INF.CONTEST_ADDED_TO_PHOTO);
		} else {
			Popups.showMessage(MSG.INF.REQUEST_SENT_TO_PHOTO);
		}
	}
}
ContestPicker.rowClickFail = function(result) {
	Popups.closeLast();
	Popups.closeLast();
	Popups.defaultError();
}

var UserMain = new Object();
//UserMain.avPickerWndId = 0;

UserMain.changeOtherData = function() {
//	$('ud_other_wait').show();
	Btns.disable('ud_other_save_link');
	var map = new Hash();
	map.set('erotic',$('ud_erotic_edit').checked);
	map.set('sendEmail',$('ud_send_email_edit').checked);
	map.set('sendEmail2',$('ud_send_email2_edit').checked);
	Helpers.rpc('/rpc/update_other_data/',map,UserMain.changeOtherDataSuccess,UserMain.changeOtherDataFail);
}
UserMain.changeOtherDataSuccess = function(result) {
//	$('ud_other_wait').hide();
	Btns.enable('ud_other_save_link');

	var map = eval(result);
	if ('true'==map.get('erotic')) {
		$('ud_erotic_display').checked=true;
		$('ud_erotic_edit').checked=true;
	} else {
		$('ud_erotic_display').checked=false;
		$('ud_erotic_edit').checked=false;
	}
	if ('true'==map.get('sendEmail')) {
		$('ud_send_email_display').checked=true;
		$('ud_send_email_edit').checked=true;
	} else {
		$('ud_send_email_display').checked=false;
		$('ud_send_email_edit').checked=false;
	}
	if ('true'==map.get('sendEmail2')) {
		$('ud_send_email2_display').checked=true;
		$('ud_send_email2_edit').checked=true;
	} else {
		$('ud_send_email2_display').checked=false;
		$('ud_send_email2_edit').checked=false;
	}

	$('ud_other_edit').hide();
	$('ud_other_display').show();
}
UserMain.changeOtherDataFail = function(result) {
//	$('ud_other_wait').hide();
	Btns.enable('ud_other_save_link');
	Popups.defaultError();
}
UserMain.changeContactData = function() {
	Reg.validationResult=true;
	$('r_icq_err').up().hide();
	$('r_icq').removeClassName('cntrl-err');
	Reg.validateICQ();
	if (Reg.validationResult) {
//		$('ud_contact_wait').show();
		Btns.disable('ud_contact_save_link');
		var map = new Hash();
		map.set('icq',$('r_icq').value);
		map.set('skype',$('r_skype').value);
		map.set('pemail',$('r_pemail').value);
		map.set('show',$('ud_contact_show_edit').checked);
		Helpers.rpc('/rpc/update_contact_data/',map,UserMain.changeContactDataSuccess,UserMain.changeContactDataFail);
	}
}
UserMain.changeContactDataSuccess = function(result) {
//	$('ud_contact_wait').hide();
	Btns.enable('ud_contact_save_link');

	var map = eval(result);
	if ('true'==map.get('show')) {
		$('ud_contact_show_display').checked=true;
		$('ud_contact_show_edit').checked=true;
	} else {
		$('ud_contact_show_display').checked=false;
		$('ud_contact_show_edit').checked=false;
	}
	var icq = map.get('icq');
	if (icq=='0') icq = '';
	$('ud_contact_icq').update(icq);
	$('ud_contact_skype').update(map.get('skype'));
	$('ud_contact_pemail').update(map.get('pemail'));
	$('r_icq').value=icq;
	$('r_skype').value=map.get('skype');

	$('ud_contact_edit').hide();
	$('ud_contact_display').show();
}
UserMain.changeContactDataFail = function(result) {
//	$('ud_contact_wait').hide();
	Btns.enable('ud_contact_save_link');
	Popups.defaultError();
}

UserMain.changePersonalData = function() {
	
	// hide errors
	$('r_name_err').up().hide();
	$('r_country_err').up().hide();
	$('r_town_err').up().hide();
	$('r_date_err').up().hide();
	$('r_name').removeClassName('cntrl-err');
	$('r_country').removeClassName('cntrl-err');
	$('r_town').removeClassName('cntrl-err');
	$('r_day').removeClassName('cntrl-err');
	$('r_month').removeClassName('cntrl-err');
	$('r_year').removeClassName('cntrl-err');
	
	Reg.validationResult=true;
	Reg.validateName();
	Reg.validateDate();
	Reg.validateLocation();

	if (Reg.validationResult) {
//		$('ud_personal_wait').show();
		Btns.disable('ud_personal_save_link');
		var map = new Hash();
		map.set('name',$('r_name').value);
		map.set('country',$('r_country').value);
		map.set('city',$('r_town').value);
		map.set('day',$('r_day').value);
		map.set('month',$('r_month').value);
		map.set('year',$('r_year').value);
		Helpers.rpc('/rpc/update_personal_data/',map,UserMain.changePersonalDataSuccess,UserMain.changePersonalDataFail);
	}
}
UserMain.changePersonalDataSuccess = function(result) {
//	$('ud_personal_wait').hide();
	Btns.enable('ud_personal_save_link');

	var map = eval(result);
	$('ud_name').update(map.get('name'));
	$('r_name').value=$('r_name').value;

	$('ud_birth_date').update(map.get('birthDate'));
	// TODO: fill values
//	$('r_day').value='';
//	$('r_month').value='';
//	$('r_year').value='';

	// TODO: fill values
	$('ud_location').update(map.get('country')+', '+map.get('city'));
//	$('r_country').value='';
//	$('r_city').value='';

	$('ud_personal_edit').hide();
	$('ud_personal_display').show();
}
UserMain.changePersonalDataFail = function(result) {
//	$('ud_personal_wait').hide();
	Btns.enable('ud_personal_save_link');
	Popups.defaultError();
}

UserMain.changeLoginData = function() {
	Reg.validationResult=true;
	// hide errors
	$('r_email_err').up().hide();
	$('r_pass_err').up().hide();
	$('r_email').removeClassName('cntrl-err');
	$('r_pass1').removeClassName('cntrl-err');
	$('r_pass2').removeClassName('cntrl-err');
	
	Reg.validateEmail();
	Reg.validatePassword();
	if (Reg.validationResult) {
		//$('ud_main_wait').show();
		Btns.disable('ud_main_save_link');
		var map = new Hash();
		map.set('email',$('r_email').value);
		map.set('password',$('r_pass1').value);
		Helpers.rpc('/rpc/update_login_data/',map,UserMain.changeLoginDataSuccess,UserMain.changeLoginDataFail);
	}
}
UserMain.changeLoginDataSuccess = function(result) {
	var map = eval(result);
//	$('ud_main_wait').hide();
	Btns.enable('ud_main_save_link');
	$('ud_main_email').update(map.get('email'));
	$('r_email').value=map.get('email');
	$('r_pass1').value=map.get('password');
	$('r_pass2').value=map.get('password');
	$('ud_main_edit').hide();
	$('ud_main_display').show();
}
UserMain.changeLoginDataFail = function(result) {
//	$('ud_main_wait').hide();
	Btns.enable('ud_main_save_link');
	if (result=='email_exists') {
		Reg.showError('r_email_err',MSG.REG.DUPLICATE_EMAIL);
	} else {
		Popups.defaultError();
	}
}

UserMain.openAvPicker = function() {
//	var body = $('av_picker_content');
//	// clear
//	Helpers.clear(body);
	Popups.showPopupW('', 'av_picker');
}
UserMain.openAvPhotoPicker = function() {
	Popups.closeLast();
	AvatarPhotoPicker.open();
}

var ContestsMain = new Object();
ContestsMain.typeChanged = function(value) {
	if (value=='male' || value=='female' || value=='both') {
		$('ol_erotic').disabled=false;
	} else {
		$('ol_erotic').disabled=true;
		$('ol_erotic').checked=false;
	}
}
ContestsMain.search = function() {
//	var map = new Hash();
//	if (OptList.getValue('ol_filter')!='all')
//		map.set('filter',OptList.getValue('ol_filter'));
//	if (OptList.getValue('ol_type')!='all')
//		map.set('type',OptList.getValue('ol_type'));
//	if (OptList.getValue('ol_erotic')!='all')
//		map.set('erotic',OptList.getValue('ol_erotic'));
//	if ($('c_country').value!=0)
//		map.set('country',$('c_country').value);
//	if ($('c_town').value!=0)
//		map.set('city',$('c_town').value);
//	if (OptList.getValue('ol_state')!='all')
//		map.set('state',OptList.getValue('ol_state'));
//	if (OptList.getValue('ol_status')!='all')
//		map.set('status',OptList.getValue('ol_status'));
//	if (OptList.getValue('ol_count')!='all')
//		map.set('count',OptList.getValue('ol_count'));
	var form = $('submitForm');
	form.action='/contests/';
	form.submit();
}

var UserContests = new Object();
UserContests.uplPanel=0;
UserContests.contestId=0;
UserContests.contestSwitcher = function() {
	if (UserContests.uplPanel==0) {
		$('contest_panel').show();
		$('contest_switcher').update('- Создать конкурс');
		UserContests.uplPanel=1;
	} else {
		$('contest_panel').hide();
		$('contest_switcher').update('+ Создать конкурс');
		UserContests.uplPanel=0;
	}
}
UserContests.typeChanged = function(val) {
	if (val!='kid' && val!='animals' && val!='other') {
		$('contest_erotic_panel').show();
	} else {
		$('contest_erotic_panel').hide();
		$('contest_erotic').checked=false;
	}
}	
UserContests.locChange = function() {
	var val = $('contest_shared').checked;
	if (val==false) {
		$('contest_loc_panel').show();
	} else {
		$('contest_loc_panel').hide();
	}
}
UserContests.endDateChange = function() {
	var val = $('contest_finish').checked;
	if (val==false) {
		$('contest_date_panel').show();
	} else {
		$('contest_date_panel').hide();
	}
}
UserContests.contestCreate = function() {
	if (!UserContests.contestCreateValidate()) {
		Popups.showConfirm(MSG.CONFIRM.CONTEST_CREATE,UserContests.contestCreateYes,function(){Popups.closeLast()},0);
	}
}	
UserContests.contestCreateYes = function() {
//	Popups.makeConfirmWaiting();
	var map = new Hash();
	map.set('name',$('c_name').value);
	map.set('descr',$('c_descr').value);
//	map.set('type',NOptList.getValue('ol_type'));
	map.set('subType',NOptList.getValue('ol_subtype'));
	if ($('contest_shared').checked==false) {
		map.set('countryId',$('c_country').value);
		map.set('cityId',$('c_town').value);
	}
	map.set('erotic',$('contest_erotic').checked);
	var unlim = $('contest_finish').checked;
	if (unlim==false) {
		map.set('day',$('r_day').value);
		map.set('month',$('r_month').value);
		map.set('year',$('r_year').value);
	}
	map.set('unlim',unlim);
	map.set('private',$('contest_private').checked);
	Helpers.rpc('/rpc/contest_create/',map,UserContests.contestCreateSuccess,UserContests.contestCreateFail);
}	
UserContests.contestCreateSuccess = function(result) {
	top.location='/profile/contests';
//	Popups.closeLast();
//	OptList.register('ol_type',1,'olSelected2', UserContests.typeChanged);
//	OptList.register('ol_subtype',1,'olSelected2');
//	$('c_form').reset();
//	NOptList.register('ol_subtype',1);
//	Location.init('c_country','c_town','c_town_other_panel','c_town_other',LOC.CNTR_NOT_DEFINED,LOC.CITY_NOT_DEFINED);
//	$('contest_date_panel').hide();
//	$('contest_loc_panel').hide();
//	UserContests.contestSwitcher();
//	Pagination.goPage(1);
}
UserContests.contestCreateFail = function(result) {
	Popups.closeLast()
	Popups.defaultError();
}

UserContests.contestCreateValidate = function() {
	var result = false;
	$('c_name_err').hide();
	$('c_descr_err').hide();
	$('c_date_err').hide();
	// validate name
	var name=$('c_name').value;
	var name_err='';
	if (name=='') {
		name_err=MSG.CON.NO_NAME;
	} else if (name.length>100) {
		name_err=MSG.CON.LONG_NAME;
	} else if (name.length<10) {
		name_err=MSG.CON.SHORT_NAME;
	}
	if (name_err!='') {
		$('c_name_err').down().update(name_err);
		$('c_name_err').show();
		result = true;
	}
	// validate description
	var descr=$('c_descr').value;
	var descr_err='';
	if (descr=='') {
		descr_err=MSG.CON.NO_DESCR;
	} else if (descr.length>250) {
		descr_err=MSG.CON.LONG_DESCR;
	} else if (descr.length<10) {
		descr_err=MSG.CON.SHORT_DESCR;
	}
	if (descr_err!='') {
		$('c_descr_err').down().update(descr_err);
		$('c_descr_err').show();
		result = true;
	}
	// validate date
	var date_err='';
	if ($('contest_finish').checked==false) {
		var d = $('r_day').value;
		var m = $('r_month').value;
		var y = $('r_year').value;
		if (d==0 || m==0 || y==0) {
			date_err=MSG.CON.NO_DATE;
		} else {
			var tmp = new Date();
			var curr = new Date();
			tmp.setFullYear(y,(m-1),d);
			if (tmp.getDate()!=d) {
				date_err=MSG.CON.WRONG_DATE;
			} else if ((tmp.getTime()-curr.getTime())<(60*60*24*15*1000)) {
				date_err=MSG.CON.ERR_DATE;
			}
		}
		if (date_err!='') {
			$('c_date_err').down().update(date_err);
			$('c_date_err').show();
			result = true;
		}
	}
	return result;
}	
UserContests.deleteContest = function(contestId) {
	UserContests.contestId=contestId;
	Popups.showConfirm(MSG.CONFIRM.CONTEST_DELETE,UserContests.deleteContestYes,function() {Popups.closeLast()}, 0);
}
UserContests.deleteContestYes = function() {
	var map = new Hash();
	map.set('contestId',UserContests.contestId);
	Popups.makeConfirmWaiting();
	Helpers.rpc('/rpc/contest_delete/',map,UserContests.deleteContestSuccess,UserContests.deleteContestFail)
}
UserContests.deleteContestSuccess = function(result) {
	Popups.closeLast();
//	Pagination.refresh();
	top.location='/profile/contests';
}
UserContests.deleteContestFail = function(result) {
	Popups.closeLast();
	Popups.defaultError();
}
fUpload = new Object();
fUpload.type='';
fUpload.inProcess=0;
fUpload.validate=function() {
	if (fUpload.inProcess!=0) return false;
	if ($('fakeFileName').value=='') {
		return false;
	}
	return true;
}
fUpload.updateFileUpload=function() {
	var name=$('fileName').value;
	$('fakeFileName').value=name.substr(name.lastIndexOf('\\')+1);
	if (name!='') {
		$('upl1btn').className="gif bck82";
		$('upl2btn').className="pngh bck88 t-12 t-b c-w t-nu padl5 padr5 default";
		$('upl3btn').className="gif bck83";
	}
}
fUpload.upload=function(type) {
	fUpload.startUpload();
	fUpload.type=type;
	if (fUpload.type=='avatar') {
		$('fUpload').writeAttribute('action','/rpc/upload_avatar/?t='+Helpers.getTime());
	} else {
		
	}
	$('fUpload').submit();
}
fUpload.uploadDone=function(result) {
	fUpload.stopUpload();
	var el = $('av_err');
	el.up().hide();
	if (result.substr(0,7)=='success') {
		$('fUpload').reset();
		if (fUpload.type=='avatar') {
			$('ud_avatar').src=result.substr(8);
			$('av_pckr_avatar').src=result.substr(8);
			setTimeout('Popups.closeLast();',100); // opera fix
		} else if (fUpload.type=='avatar2') {
			Popups.closeLast();
		}
	} else {
		el.update(eval(result));
		el.up().show();
	}
}
fUpload.startUpload=function() {
	fUpload.inProcess=1;
	$('upl1btn').className="gif bck96";
	$('upl2btn').className="pngh bck97 t-12 t-b c-w t-nu padl5 padr5 default";
	$('upl2btn').update('Загрузка...');
	$('upl3btn').className="gif bck98";
}
fUpload.stopUpload=function() {
	fUpload.inProcess=0;
	$('upl1btn').className="gif bck82";
	$('upl2btn').className="pngh bck88 t-12 t-b c-w t-nu padl5 padr5 default";
	$('upl2btn').update('Загрузить');
	$('upl3btn').className="gif bck83";
}

/// POSTER

var me = new Object();
me.submitFns = new Hash();
me.groupsCount=5;
me.groupValues = new Hash({1:new Array(21,26,76,63, 18,20,70,31, 71,33,51,39, 75,68,69,77),
						   2:new Array(67,50,23,12, 55,32,30,34, 46,43,42,57, 45,44,56,53),
						   5:new Array(4,47,16,66,49,52,8,64,54),
						   3:new Array(1,3,6,9, 11,13,14,15, 17,19,22,24, 25,27,28,29),
						   4:new Array(35,65,61,60, 59,58,48,41, 40,36,37,38, 73,74,78,2)
						   });
me.groupSettings = new Hash({1:new Array(4,10,9),2:new Array(4,5,6),5:new Array(3,5,12),3:new Array(4,6,7),4:new Array(4,5,8)});
me.positions = new Hash();
me.disabled = new Hash();
me.maxLens = new Hash();
me.cElements = new Hash();
me.currentId = '';
me.create = function(id, elName, title, submitText, initialText, submitFn, maxLen) {
	me.currentId = id;
	me.submitFns.set(id, submitFn);
	me.positions.set(id, 1);
	me.maxLens.set(id,maxLen);
	var el = $(elName);
	var template = me.template;
	template = template.replace(':title:',title);
	template = template.replace(':maxLens:',maxLen);
	template = template.replace(/:id:/g,id);
	template = template.replace(':button_text:',submitText);
	template = template.replace(':init_text:',initialText);
	el.update('');
	el.insert(template);
	Btns.register('me_'+id+'_submit',function() {me.submit(id)});
	$('me_'+id+'_editor').observe('click',function(){me.switchPanel(id,true)});
	$('me_'+id+'_viewer').observe('click',function(){me.switchPanel(id,false)});
	$('me_'+id+'_ta').observe('keyup',function(){me.updateCounter(id)});
	me.cElements.set(id,$('me_'+id+'_counter'));
	me.renderGroup(id, 1);
}
me.updateCounter = function(id) {
	var max = me.maxLens.get(id)-me.getValue(id).length;
	if (max<0) max=0;
	me.cElements.get(id).update(max);
}
me.makeLoading = function(id) {
	Btns.disable('me_'+id+'_submit');
	me.disabled.set(id,1);
	$('me_'+id+'_ta').disabled=true;
	$('me_'+id+'_ta').value=MSG.ME.LOADING;
}
me.stopLoading = function(id) {
	Btns.enable('me_'+id+'_submit');
	me.disabled.unset(id);
	$('me_'+id+'_ta').disabled=false;
	$('me_'+id+'_ta').value='';
}
me.getValue = function(id) {
	return $('me_'+id+'_ta').value;
}
me.setValue = function(id, value) {
	$('me_'+id+'_ta').value=value;
}
me.reset = function(id) {
	$('me_'+id+'_ta').value='';
	me.positions.set(id, 1);
	me.renderGroup(id, 1);
}
me.submit = function(id) {
	// validate
	$('me_'+id+'_err').hide();
	var len = me.getValue(id).length;
	var err='';
	if (len<2) {
		err=MSG.ME.TXT_TO_SHORT;
	} else if (len>me.maxLens.get(id)) {
		err=MSG.ME.TXT_TO_LONG;
	}
	if (err!='') {
		$('me_'+id+'_err_msg').update(err);
		$('me_'+id+'_err').show();
	} else {
		// make waiting
//		Btn.wait('me_'+id+'_submit',true);
		Btns.disable('me_'+id+'_submit');
		// submit
		if (me.submitFns.get(id)!=undefined) me.submitFns.get(id)();
	}
}
me.prevGroup = function(id) {
	var val = me.positions.get(id);
	val--;
	if (val<1) val = me.groupsCount;
	me.positions.set(id,val);
	me.renderGroup(id, val);
}
me.nextGroup = function(id) {
	var val = me.positions.get(id);
	val++;
	if (val>me.groupsCount) val = 1;
	me.positions.set(id,val);
	me.renderGroup(id, val);
}
me.renderGroup = function(id, group) {
	var panel = $('me_'+id+'_panel');
	panel.update('');
	var list = me.groupValues.get(group);
	var settings = me.groupSettings.get(group);
	TableBuilder.init(settings[0],settings[1],settings[2]);
	for (i = 0; i < list.length; i++) {
		TableBuilder.addEl('<img class="pointer" src="'+SYSTEM.SMILES_HTTP+list[i]+'.gif" onClick="me.addSmile(\''+id+'\','+list[i]+')"/>');
	}
	panel.insert(TableBuilder.getTable());

}
me.addSmile = function(id, imgId) {
	me.switchPanel(id, true);
	if (1!=me.disabled.get(id)) {
		var el = $('me_'+id+'_ta');
		me.insertAtCursor(el,'{img:'+imgId+'}');
		el.focus();
	}
}

me.insertAtCursor = function(myField, myValue) {
//IE support
	if (document.selection) {
		myField.focus();
		sel = document.selection.createRange();
		sel.text = myValue;
 //MOZILLA/NETSCAPE support
 	} else if (myField.selectionStart || myField.selectionStart == '0') {
		var startPos = myField.selectionStart;
		var endPos = myField.selectionEnd;
		tmp = myField.value.substring(0, startPos)
		+ myValue
		+ myField.value.substring(endPos, myField.value.length);
		myField.value = '';
		myField.value = tmp;
	} else {
		myField.value += myValue;
	}
	myField. focus();
}
me.switchPanel = function(id,isEditor) {
	if (isEditor) {
		$('me_'+id+'_ta').show();
		$('me_'+id+'_div').hide();
		$('me_'+id+'_editor').className='png bck62 a-13 c-g1';
		$('me_'+id+'_viewer').className='png bck61 pointer a-13 c-g1';
	} else {
		$('me_'+id+'_ta').hide();
		$('me_'+id+'_div').show();
		$('me_'+id+'_editor').className='png bck61 pointer a-13 c-g1';
		$('me_'+id+'_viewer').className='png bck62 a-13 c-g1';
		var txt = me.getValue(id);
		$('me_'+id+'_div').update(txt.replace(/{img:([0-9]+)}/g,'<img src="'+SYSTEM.SMILES_HTTP+'$1'+'.gif" />').replace(/[\n\r]+/g, "<br>"));
	}
}

me.template = '<table width="100%">'+
	'<tr height="32">'+
		'<td><table width="100%"><tr>'+
			'<td class="a-18 c-g1 pngh bck64">:title:&nbsp;</td>'+
			'<td id="me_:id:_editor" class="png bck62 a-13 c-g1" align="center">редактор</td>'+
			'<td id="me_:id:_viewer" class="png bck61 pointer a-13 c-g1" align="center">просмотр</td>'+
			'<td width="1" class="png bck63"></td>'+
		'</tr></table></td>'+
		'<td width="6"></td>'+
		'<td></td>'+
	'</tr>'+
	'<tr height="166">'+
		'<td><table width="100%" height="166">'+
			'<tr height="165">'+
				'<td width="1" class="col6"></td>'+
				'<td class="pada3" valign="top"><textarea id="me_:id:_ta" class="ctrl-com-ta t-12 c-g1">:init_text:</textarea><div id="me_:id:_div" style="display:none" class="ctrl-com-view t-12 c-g1 pointer" onClick="me.switchPanel(\':id:\',true)"></div></td>'+
				'<td width="1" class="col6"></td>'+
			'</tr>'+
			'<tr height="1">'+
				'<td colspan="3" class="col6"></td>'+
			'</tr>'+
		'</table></td>'+
		'<td width="6"></td>'+
		'<td width="180"><table width="100%"><tr>'+
			'<td class="pointer" width="10"><table height="146" width="10" class="col6" onClick="me.prevGroup(\':id:\');">'+
				'<tr valign="top"><td><img class="png bck65" src="'+SYSTEM.SPACE+'"></td></tr>'+
				'<tr valign="middle"><td><img class="png bck66" src="'+SYSTEM.SPACE+'"></td></tr>'+
				'<tr valign="bottom"><td><img class="png bck67" src="'+SYSTEM.SPACE+'"></td></tr>'+
			'</table></td>'+
			'<td><table width="185" height="146">'+
				'<tr height="1" class="col6"><td></td></tr>'+
				'<tr height="144"><td align="center" valign="middle"><div id="me_:id:_panel" class="pada5"></div></td></tr>'+
				'<tr height="1" class="col6"><td></td></tr>'+
			'</table></td>'+
			'<td class="pointer" width="10"><table height="146" width="10" class="col6" onClick="me.nextGroup(\':id:\');">'+
				'<tr valign="top"><td><img class="png bck68" src="'+SYSTEM.SPACE+'"></td></tr>'+
				'<tr valign="middle"><td><img class="png bck69" src="'+SYSTEM.SPACE+'"></td></tr>'+
				'<tr valign="bottom"><td><img class="png bck70" src="'+SYSTEM.SPACE+'"></td></tr>'+
			'</table></td>'+
		'</tr>' +
		'<tr height="20"><td valign="bottom" align="center" colspan="3" class="t-12 c-g1">Доступно символов: <font id="me_:id:_counter" class="t-b">:maxLens:</font></td></tr>' +
		'</table></td>'+
	'</tr>'+
	'<tr id="me_:id:_err" style="display:none" height="16">'+
		'<td class="t-8 c-r" id="me_:id:_err_msg"></td>'+
	'</tr>'+
	'<tr height="5"><td></td></tr>'+
	'<tr>'+
		'<td align="center"><table id="me_:id:_submit" class="pointer"><tr>'+
			'<td class="gif bck82"></td>'+
			'<td class="pngh bck88"><a class="t-12 t-b c-w t-nu padl5 padr5" href="javascript:void(0);">:button_text:</a></td>'+
			'<td class="gif bck83"></td>'+
		'</tr></table></td>'+
	'</tr>'+
	'<tr height="15"><td colspan="3"></td></tr>'+
	'<tr height="5"><td colspan="3"><table width="100%"><tr>'+
				'<td><img class="png bck200" src="'+SYSTEM.SPACE+'"></td>'+
				'<td width="5"></td>'+
				'<td class="t-11 c-g3">Оскорбление других пользователей и использование ненормативной лексики категорически запрещено.</td>'+
			'</tr></table></td></tr>'+
	'<tr height="5"><td></td></tr>'+
'</table>';		

