// webnote.js.core.js v1.3.0

// Copyright (c) 2011 Кузнецов Алексей

/**
 *  Объединяющий класс.
 *  @author Кузнецов А.В.
 */
function $CWN(){
  //коки
	this.$cookie = new $CCOOKIE();
  //строки
  this.$string = new $CSTRING();
  //данные ключ=знач
  this.$kvd = new $CKEYVALUEDATA();
  //дата и время
  this.$datetime = new $CDATETIME();
  //кодирование
  this.$code = new $CCODE();
  //вектор
  this.$v = new $CVECTOR();
  //css
  this.$css = new $CCSS();
  //навигация по узлам
  this.$nn = new $CNODENAVIGATION(window);
}

/**
 *  Глобальный объект объединящего класса.
 *  @author Кузнецов А.В.
 */
var $wn = new $CWN();

/**
 *  Класс для работы с коками.
 *  @author Кузнецов А.В.
 */
function $CCOOKIE(){

	/**
	 *	Создает cookie, если такой уже существует, то он будет перезаписан.
   *	@param array $param Масссив параметров.
	 */
	this.$Set = function ($param) {
    if($param){
			var $name = $param['name']?$param['name']:"";
			var $value = $param['value']?$param['value']:"";
			var $expires = $param['expires']?(new Date($wn.$datetime.$TimeStamp($param['expires']))).toGMTString():"";
			var $path = $param['path']?$param['path']:"/";
			var $domain = $param['domain']?$param['domain']:"";
			var $secure = $param['secure']?$param['secure']:"";
		}
    document.cookie = $name + "=" + encodeURIComponent($value) +
      (($expires) ? "; expires=" + $expires : "") +
      (($path) ? "; path=" + $path : "") +
      (($domain) ? "; domain=" + $domain : "") +
      (($secure) ? "; secure" : "");
	}//$Set

	/**
	 *	Получение данных из кока.
	 *  @param string $name Имя искомого кока.
   *  @return string|false Данные искомого кока или false - если кок не найден.
	 */
	this.$Get = function ($name){
		var $cookies_arr = document.cookie.split(";");
		for(var $i=0; $i<$cookies_arr.length; $i++){
			var $key = $wn.$kvd.$GetKey($cookies_arr[$i]);
      if($key==$name) {
				return decodeURIComponent($wn.$kvd.$GetValue($cookies_arr[$i]));
			}
		}
    return false;
	}//$Get

	/**
	 *	Проверка наличия кока
	 *  @param string $name Имя искомого кока.
   *  @return bool true - если кок найден, иначе false.
	 */
	this.$Is = function ($name){
		var $cookies_arr = document.cookie.split(";");
		for(var $i=0; $i<$cookies_arr.length; $i++){
			var $key = $wn.$kvd.$GetKey($cookies_arr[$i]);
			if($key==$name) return true;
		}
		return false;
	}//$Is

  /**
	 *	Удаление кока.
	 *  @param string $name Имя искомого кока.
   *  @param string $path Путь кока ("/price/").
   *  @param string $domain Домен кока ("www.webnode.ru").
   *  @return bool true - если кок найден, иначе false.
	 */
	this.$Delete = function ($name, $path, $domain){
    $path = $path?$path:"/";
		$domain = $domain?$domain:"";
		this.$Set({name:$name, expires:"-1 day", path:$path, domain:$domain});
	}//$Delete

  /**
	 *	Количество коков.
   *  @return int Количество коков.
	 */
	this.$Count = function (){
		if(!document.cookie) return 0;
    var $cookies_arr = document.cookie.split(";");
    return $cookies_arr.length;
	}//$Count

  /**
	 *	Коки ввиде ассоциативного массива.
   *  @return array Ассоциативный массив.
	 */
	this.$AsArray = function (){
		var $cookies_arr = document.cookie.split(";");
		var $key, $val, $str="";
    for(var $i=0; $i<$cookies_arr.length; $i++){
			$key = $wn.$kvd.$GetKey($cookies_arr[$i]);
      $val = $wn.$kvd.$GetValue($cookies_arr[$i])
      if($key&&$val) $str += ",'"+$key+"':'"+$val+"'";
      if($str.length==0) return new Array();
		}
    eval("var $am = {"+$str.substring(1)+"}");
    return $am;
	}//$AsArray

}//$CCOOKIE

/**
 *  Обработка строк.
 *  @author Кузнецов А.В.
 */
function $CSTRING($string){
  /**
   *  Обрабатываемая строка по умолчанию.
   *  @var string
   */
  this.$string = $string;

  /**
   *  Урезание невидимых символов по краям строки.
   *  @param string $string Строка, которую нужно обработать.
   */
  this.$Trim = function ($string){
    if(!$string) $string = this.$string;
    return $string.replace(/(^\s+)|(\s+$)/g, "");
  }//$Trim
}//$CSTRING

/**
 *  Обработка составных строк типа ключ=знач;ключ=знач;
 *  @author Кузнецов А.В.
 */
function $CKEYVALUEDATA($data){

	/**
   *  Разделитель в строке между блоками ключ=значение.
   *  @var string
   */
	this.$separator = ";";
	/**
   *  Строка данных (ключ=знач;ключ=знач;)
   *  @var string
   */
  this.$data = $data;
  if(!this.$data) this.$data = new String("");

  /**
	 *	Получение значения из строки данных (ключ=знач;ключ=знач;)
	 *	@param string $key Ключ для поиска.
   *	@param string $data Строка данных (ключ=знач;ключ=знач;).
	 *	@return string|false Значение по ключу ввиде строки, иначе false если ключ не найден.
	 */
	this.$Get = function($key, $data){
		var $key_value = this.$GetKeyValue($key, $data);
		if($key_value===false) return false;
    return this.$Decode(this.$GetValue($key_value));
	}//$Get

  /**
   *  Установка нового значения в строку данных. Если ключ уже существует в
   *  строке данных, то значение по этому ключу будет заменено на $value.
   *  Если строка данных не сущестовала, то она будет содана.
   *	@param string $key Ключ.
   *	@param string $value Значение.
   *	@param string $data Строка данных (ключ=знач;ключ=знач;).
	 *	@return string Строку данных.
   */
  this.$Set = function($key, $value, $data){
    if(!$data) $data = this.$data;
    if($data) {
      if(this.$Is($key, $data)){
        return this.$Replace($key, this.$Encode($value), $data);
      }
      else{
        return $data+$key+"="+this.$Encode($value)+this.$separator;
      }
    }
    else{
      return $key+"="+this.$Encode($value)+this.$separator;
    }
	}//$Set

  /**
   *  Создание строки данных.
   *  @param string $array Ассоциативный массив.
   *  @return string Строку данных созданную на основе ассоциативного массива.
   */
  this.$Data = function($array){
    var $data = "";
    for(var $index in $array ){
      $data += $index+"="+$array[$index]+this.$separator;
    }
    return $data;
  }//$Data
  
  /**
	 *	Данные ввиде ассоциативного массива.
   *	@param string $data Строка данных (ключ=знач;ключ=знач;).
   *  @return array Ассоциативный массив.
	 */
	this.$AsArray = function ($data){
		var $data_arr = (new String($data)).split(";");
		var $key, $val, $str="";
    for(var $i=0; $i<$data_arr.length; $i++){
			$key = $wn.$kvd.$GetKey($data_arr[$i]);
      $val = $wn.$kvd.$GetValue($data_arr[$i])
      if($key&&$val) $str += ",'"+$key+"':'"+$val+"'";
      if($str.length==0) return new Array();
		}
    eval("var $am = {"+$str.substring(1)+"}");
    return $am;
	}//$AsArray

  /**
   *  Существует ли набор ключ=знач.
	 *	@param string key Ключ для поиска.
	 *	@param string data Строка данных (ключ=знач;ключ=знач;).
	 *	@return bool Возвращает true - если ключ найден в строке данных иначе false.
   */
  this.$Is = function($key, $data){
    if(!$data) $data = this.$data;
    if(!$key) return false;
    var $keyval_arr = $data.split(this.$separator);
		for(var $i=0; $i<$keyval_arr.length; $i++){
			var $cur_key = this.$GetKey($keyval_arr[$i]);
      if($cur_key==$key) return true;
		}
    return false;
  }//$Is

  /**
	 *	Удаление пары ключ=знач в строке данных.
	 *	@param string $key Ключ из изменяемой пары ключ=знач .
   *	@param string $data Строка данных, в которой происходят изменения.
	 *	@return string Изменённые данные.
	 */
	this.$Delete = function ($key, $data){
    if(!$data) $data = this.$data;
		var $data_arr = $data.split(this.$separator);
		for(var $i=0; $i<$data_arr.length; $i++){
			var $cur_key = this.$GetKey($data_arr[$i]);
			if($cur_key==$key) $data_arr[$i] = "";
		}
		var $newdata = "";
		for(var $i=0; $i<$data_arr.length; $i++){
			if($data_arr[$i].length>0) $newdata+=$data_arr[$i]+this.$separator;
		}
		return $newdata;
	}//$Delete

  /**
	 *	Изменение значения в паре ключ=знач в строке данных.
	 *	@param string $key Ключ из изменяемой пары ключ=знач .
	 *	@param string $new_value Новое значение для переданной пары.
   *	@param string $data Строка данных, в которой происходят изменения.
	 *	@return string Изменённые данные.
	 */
	this.$Replace = function ($key, $new_value, $data){
    if(!$data) $data = this.$data;
		var $data_arr = $data.split(this.$separator);
		for(var $i=0; $i<$data_arr.length; $i++){
			var $cur_key = this.$GetKey($data_arr[$i]);
			if($cur_key==$key) $data_arr[$i] = $key+"="+$new_value;
		}
		var $newdata = "";
		for(var $i=0; $i<$data_arr.length; $i++){
			if($data_arr[$i].length>0) $newdata+=$data_arr[$i]+this.$separator;
		}
		return $newdata;
	}//$Replace

  /**
 	 *	Количество пар ключ=знач в строке данных.
	 *	@param string data Строка данных (ключ=знач;ключ=знач;).
	 *	@return int
	 */
	this.$Count = function ($data){
    if(!$data) $data = this.$data;
    var $keyval_arr = $data.split(this.$separator);
    return $keyval_arr.length-1;
  }//$Count


  /**
   *  Функция декодирования данных.
   *  @param string $str Строка которую нужно декодировать.
   *  @return string Возвращает декодированную строку.
   */
  this.$Decode = function ($str){
    return decodeURIComponent($str);
  }//$Decode

  /**
   *  Функция кодирования данных.
   *  @param string $str Строка которую нужно кодировать.
   *  @return string Возвращает кодированную строку.
   */
  this.$Encode = function ($str){
    return encodeURIComponent($str);
  }//$Encode

  /**
 	 *	Получение ключ=знач из набора.
	 *	@param string data Строка данных (ключ=знач;ключ=знач;).
	 *	@param string key Ключ для поиска.
	 *	@return string Cтроку вида ключ=знач, иначе false если ключ ненайден.
	 */
	this.$GetKeyValue = function ($key, $data){
    if(!$data) $data = this.$data;
    var $keyval_arr = $data.split(this.$separator);
		for(var $i=0; $i<$keyval_arr.length; $i++){
			var $cur_key = this.$GetKey($keyval_arr[$i]);
      if($cur_key==$key) {
				return $cur_key+"="+this.$GetValue($keyval_arr[$i]);
			}
		}
    return false;
	}//$GetKeyValue

  /**
	 *	Получение ключа из набора ключ=знач.
	 *	@param string $key_value Строка состоящая из пары ключ=значение.
	 *	@return string Значение параметра (то что после равно).
	 */
	this.$GetKey = function ($key_value){
    if($key_value.indexOf("=")==-1) return "";
		return $wn.$string.$Trim(($key_value.split("="))[0]);
	}//$GetKey

	/**
	 *	Получение значения из набора ключ=значение.
	 *	@param string $key_value Строка состоящая из пары ключ=значение.
	 *	@return string Значение параметра (то что после равно).
	 */
	this.$GetValue = function ($key_value){
    if($key_value.indexOf("=")==-1) return "";
		var $value = ($key_value.split("="))[1];
		if($value[$value.length-1]==this.$separator) return $value.substring(0, $value.length-1);
		else return $value;
	}//$GetValue

  /**
	 *	Изменение значения в паре ключ=знач .
	 *	@param string $key_value Пара ключ=знач .
	 *	@param string $new_value Новое значение для переданной пары.
	 *	@return string Изменённую пару ключ=знач .
	 */
	this.$ReplaceValue = function ($key_value, $new_value){
    var $cur_key = this.$GetKey($key_value);
    return $cur_key+"="+$new_value;
	}//$ReplaceValue

  /**
	 *	Изменение ключа в паре ключ=знач .
	 *	@param string $key_value Пара ключ=знач .
	 *	@param string $new_key Новый ключ для переданной пары.
	 *	@return string Изменённую пару ключ=знач .
	 */
	this.$ReplaceKey = function ($key_value, $new_key){
    var $cur_val = this.$GetValue($key_value);
    return $new_key+"="+$cur_val;
	}//$ReplaceKey


  //----------------------------------------------------------
  //                       Старые функции
  //----------------------------------------------------------

	/*--*
	*	Добавляет новый параметр (ключ=значение) в строку $data, если такой уже существует, то он будет перезаписан
	*	Параметры:
	*		data - строка данных
	*		key - ключ
	*		value - значение
	--*/
	function $setDataOfKeyValue($data, $key, $value){
		if(this.$getKeyValue($data, $key)) {
			$data = this.$replaceValue($data, $key, encodeURIComponent($value));
		}
		else{
			$data += $key+"="+encodeURIComponent($value)+this.$separator;
		}
		return $data;
	}
	this.$setDataOfKeyValue = $setDataOfKeyValue;


	/*--*
	*	Получение данных из параметра (ключ=значение)
	*	Параметры:
	*		data - строка данных (ключ=знач;ключ=знач;)
	*		key - имя искомого параметра (ключ=значение)
	*	Возвращает:
	*		значение кока
	--*/
	function $getDataOfKeyValue($data, $key){
		var  $data_arr = $data.split(this.$separator);
		for(var $i=0; $i<$data_arr.length; $i++){
			var $cur_key = this.$getKey($data_arr[$i]);
			if($cur_key==$key) {
				return decodeURIComponent(this.$getValue($data_arr[$i]));
			}
		}
	}
	this.$getDataOfKeyValue = $getDataOfKeyValue;

	/*--*
	*	Получение ключа из набора
	*	Параметры:
	*		$key_value - ключ=значение
	*	Возвращает:
	*		значение ключа (то что до равно)
	--*/
	function $getKey($key_value){
		return ($key_value.split("="))[0];
	}
	this.$getKey = $getKey;

	/*--*
	*	Получение значения из набора
	*	Параметры:
	*		key_value - ключ=значение
	*	Возвращает:
	*		значение параметра (то что после равно)
	--*/
	function $getValue($key_value){
		var $value = ($key_value.split("="))[1];
		if($value[$value.length-1]==this.$separator) return $value.substring(0, $value.length-1);
		else return $value;
	}
	this.$getValue = $getValue;

	/*--*
	*	Получение значения из набора
	*	Параметры:
	*		data - строка данных (ключ=знач;ключ=знач;)
	*		key - ключ для поиска
	*	Возвращает:
	*		строку вида: ключ=значение
	--*/
	function $getKeyValue($data, $key){
		var $data_arr = $data.split(this.$separator);
		for(var $i=0; $i<$data_arr.length; $i++){
			var $dkey = this.$getKey($data_arr[$i]);
			if($dkey==$key) {
				return $data_arr[$i];
			}
		}
		return "";
	}
	this.$getKeyValue = $getKeyValue;

	/**
	 *	Список всех ключ=знач в $data
	 *	Возвращает:
	 *		массив.
	 */
	this.$KeyValueList = function ($data){
		return $data.split(this.$separator);
	}

	  /*--*
	*	Добавляет новый параметр (ключ=значение) в строку $data, если такой уже
  *	существует, то он будет перезаписан
	*	Параметры:
	*		data - строка данных (ключ=знач;ключ=знач;)
	*		key - ключ
	*		value - значение
	--*/
	this.$setKeyValue = function($data, $key, $value){
    if(this.$getKeyValue($data, $key)) {
			$data = this.$replaceValue($data, $key, $value);
		}
		else{
			$data += $key+"="+$value+this.$separator;
		}
		return $data;
	}

	/*--*
	*	Удаление параметра (ключ=значение)
	*		data - строка данных (ключ=знач;ключ=знач;)
	*		key - ключ для поиска
	*	Возвращает:
	*		true - если удаление было удачно, иначе false
	--*/
	function $deleteKeyValue($data, $key){
		if(!$data||!$key) return false;
		var $data_arr = $data.split(this.$separator);
		var $del_i=-1;
		for(var $i=0; $i<$data_arr.length; $i++){
			var $dkey = this.$getKey($data_arr[$i]);
			if($dkey==$key) {
				$del_i = $i;
				break;
			}
		}
		if($del_i==-1) return false;
		var $newdata = "";
		for(var $i=0; $i<$data_arr.length; $i++){
			if($data_arr[$i].length>0) if($i!=$del_i) $newdata+=$data_arr[$i]+this.$separator;
		}

		return $newdata;
	}
	this.$deleteKeyValue = $deleteKeyValue;

	/*--*
	*	Изменение значения из набора
	*	Параметры:
	*		data - строка данных (ключ=знач;ключ=знач;)
	*		key - ключ для поиска
	*		newvalue - новое значение
	*	Возвращает:
	*		измененную data
	--*/
	function $replaceValue($data, $key, $newvalue){
		var $data_arr = $data.split(this.$separator);
		for(var $i=0; $i<$data_arr.length; $i++){
			var $dkey = this.$getKey($data_arr[$i]);
			if($dkey==$key) {
				$data_arr[$i] = $dkey+"="+$newvalue;
			}
		}
		var $newdata = "";
		for(var $i=0; $i<$data_arr.length; $i++){
			if($data_arr[$i].length>0) $newdata+=$data_arr[$i]+this.$separator;
		}

		return $newdata;
	}
	this.$replaceValue = $replaceValue;
}//$CKEYVALUEDATA

/**
 *  Обработка дат.
 *  @author Кузнецов А.В.
 */
function $CDATETIME(){

  /**
   *  Трансформирует строку с датой в timpstamp строку.
   *  @param string $str Строка с датой.
   *  @return timestamp Строку времени в милисекундах (timpstamp).
   */
  this.$TimeStamp = function($str){
		//
		if(!$str) return this.$Now();
		//
		var $match;

    //2010
		$match = $str.match(/^([0-9]{4})$/);
		if($match)
			return Date.parse(new Date( $match[1], 0, 1 ));

		//201012
		$match = $str.match(/^([0-9]{4})(0[1-9]{1}|1{1}[0-2]{1})$/);
		if($match)
			return Date.parse(new Date( $match[1], parseInt($match[2])-1, 1 ));
		//20101204
		$match = $str.match(/^([0-9]{4})(0[1-9]{1}|1{1}[0-2]{1})(0[1-9]{1}|[1-2]{1}[0-9]{1}|3[0-1]{1})$/);
		if($match)
			return Date.parse(new Date( $match[1], parseInt($match[2])-1, $match[3] ));
		//2010120412
		$match = $str.match(/^([0-9]{4})(0[1-9]{1}|1{1}[0-2]{1})(0[1-9]{1}|[1-2]{1}[0-9]{1}|3[0-1]{1})([0-1]{1}[0-9]{1}|2[0-3]{1})$/);
		if($match)
			return Date.parse(new Date( $match[1], parseInt($match[2])-1, $match[3], $match[4] ));
    //201012041212
		$match = $str.match(/^([0-9]{4})(0[1-9]{1}|1{1}[0-2]{1})(0[1-9]{1}|[1-2]{1}[0-9]{1}|3[0-1]{1})([0-1]{1}[0-9]{1}|2[0-3]{1})([0-5]{1}[0-9]{1})$/);
		if($match)
			return Date.parse(new Date( $match[1], parseInt($match[2])-1, $match[3], $match[4], $match[5] ));
    //20101204121212
		$match = $str.match(/^([0-9]{4})(0[1-9]{1}|1{1}[0-2]{1})(0[1-9]{1}|[1-2]{1}[0-9]{1}|3[0-1]{1})([0-1]{1}[0-9]{1}|2[0-3]{1})([0-5]{1}[0-9]{1})([0-5]{1}[0-9]{1})$/);
		if($match)
			return Date.parse(new Date( $match[1], parseInt($match[2])-1, $match[3], $match[4], $match[5], $match[6] ));

		//2010-12 | 2010.12 | 2010 12 | 2010/12 | 2010-9 | 2010.9 | 2010 9 | 2010/9
		$match = $str.match(/^([0-9]{4})[\-\. \/]{1}([1-9]{1}|0[1-9]{1}|1{1}[0-2]{1})$/);
		if($match)
			return Date.parse(new Date( $match[1], parseInt($match[2])-1, 1 ));
		//2010-12-04 | 2010.12.04 | 2010 12 04 | 2010/12/04 | 2010-9-04 | 2010.9.04 | 2010 9 04 | 2010/9/04
		$match = $str.match(/^([0-9]{4})[\-\. \/]{1}([1-9]{1}|0[1-9]{1}|1{1}[0-2]{1})[\-\. \/]{1}([1-9]{1}|0[1-9]{1}|[1-2]{1}[0-9]{1}|3[0-1]{1})$/);
		if($match)
			return Date.parse(new Date( $match[1], parseInt($match[2])-1, $match[3] ));
    //2010-12-04T12 | 2010.2.4 12
		$match = $str.match(/^([0-9]{4})[\-\. \/]{1}([1-9]{1}|0[1-9]{1}|1{1}[0-2]{1})[\-\. \/]{1}([1-9]{1}|0[1-9]{1}|[1-2]{1}[0-9]{1}|3[0-1]{1})[ T]{1}([0-1]{1}[0-9]{1}|2[0-3]{1}|[0-9]{1})$/);
		if($match)
			return Date.parse(new Date( $match[1], parseInt($match[2])-1, $match[3], $match[4] ));
    //2010-12-04T12:12 | 2010.2.4 12:12
		$match = $str.match(/^([0-9]{4})[\-\. \/]{1}([1-9]{1}|0[1-9]{1}|1{1}[0-2]{1})[\-\. \/]{1}([1-9]{1}|0[1-9]{1}|[1-2]{1}[0-9]{1}|3[0-1]{1})[ T]{1}([0-1]{1}[0-9]{1}|2[0-3]{1}|[0-9]{1}):([0-5]{1}[0-9]{1}|[0-9]{1})$/);
		if($match)
			return Date.parse(new Date( $match[1], parseInt($match[2])-1, $match[3], $match[4], $match[5] ));
    //2010-12-04T12:12:12 | 2010.2.4 12:12:12
		$match = $str.match(/^([0-9]{4})[\-\. \/]{1}([1-9]{1}|0[1-9]{1}|1{1}[0-2]{1})[\-\. \/]{1}([1-9]{1}|0[1-9]{1}|[1-2]{1}[0-9]{1}|3[0-1]{1})[ T]{1}([0-1]{1}[0-9]{1}|2[0-3]{1}|[0-9]{1}):([0-5]{1}[0-9]{1}|[0-9]{1}):([0-5]{1}[0-9]{1}|[0-9]{1})$/);
    if($match)
			return Date.parse(new Date( $match[1], parseInt($match[2])-1, $match[3], $match[4], $match[5], $match[6] ));

    //12-2010 | 12.2010 | 12 2010 | 12/2010 | 9-2010 | 9.2010 | 9 2010 | 9/2010
		$match = $str.match(/^([1-9]{1}|0[1-9]{1}|1{1}[0-2]{1})[\-\. \/]{1}([0-9]{4})$/);
		if($match)
			return Date.parse(new Date( $match[2], parseInt($match[1])-1, 1 ));
    //04-12-2010 | 04.12.2010 | 04 12 2010 | 04/12/2010 | 4-9-2010 | 4.9.2010 | 4 9 2010 | 4/9/2010
		$match = $str.match(/^([1-9]{1}|0[1-9]{1}|[1-2]{1}[0-9]{1}|3[0-1]{1})[\-\. \/]{1}([1-9]{1}|0[1-9]{1}|1{1}[0-2]{1})[\-\. \/]{1}([0-9]{4})$/);
		if($match)
			return Date.parse(new Date( $match[3], parseInt($match[2])-1, $match[1] ));
    //4.2.2010 12
		$match = $str.match(/^([1-9]{1}|0[1-9]{1}|[1-2]{1}[0-9]{1}|3[0-1]{1})[\-\. \/]{1}([1-9]{1}|0[1-9]{1}|1{1}[0-2]{1})[\-\. \/]{1}([0-9]{4}) ([0-1]{1}[0-9]{1}|2[0-3]{1}|[0-9]{1})$/);
		if($match)
			return Date.parse(new Date( $match[3], parseInt($match[2])-1, $match[1], $match[4] ));
    //4.2.2010 12:12
		$match = $str.match(/^([1-9]{1}|0[1-9]{1}|[1-2]{1}[0-9]{1}|3[0-1]{1})[\-\. \/]{1}([1-9]{1}|0[1-9]{1}|1{1}[0-2]{1})[\-\. \/]{1}([0-9]{4}) ([0-1]{1}[0-9]{1}|2[0-3]{1}|[0-9]{1}):([0-5]{1}[0-9]{1}|[0-9]{1})$/);
		if($match)
			return Date.parse(new Date( $match[3], parseInt($match[2])-1, $match[1], $match[4], $match[5] ));
    //4.2.2010 12:12:12
		$match = $str.match(/^([1-9]{1}|0[1-9]{1}|[1-2]{1}[0-9]{1}|3[0-1]{1})[\-\. \/]{1}([1-9]{1}|0[1-9]{1}|1{1}[0-2]{1})[\-\. \/]{1}([0-9]{4}) ([0-1]{1}[0-9]{1}|2[0-3]{1}|[0-9]{1}):([0-5]{1}[0-9]{1}|[0-9]{1}):([0-5]{1}[0-9]{1}|[0-9]{1})$/);
		if($match)
			return Date.parse(new Date( $match[3], parseInt($match[2])-1, $match[1], $match[4], $match[5], $match[6] ));

    // +/-N second|minute|hour|day|month|year|week
		$match = $str.match(/^(\-|\+)([0-9]{1,10}) (second|minute|hour|day|week)$/i);
    var $factor = 1;
    if($match){
      switch($match[3]){
      case "second":$factor = 1000;/* 1 s */break;
      case "minute":$factor = 60000;/* 1 m */break;
      case "hour":$factor = 3600000;/* 1 h */break;
      case "day":$factor = 86400000;/* 24 h */break;
      case "week":$factor = 604800000;/* 24*7 h */break;
      }
      var $now_ts = this.$Now();
      eval('var $fts = '+$now_ts+$match[1]+$match[2]+"*"+$factor);
			return $fts;
    }
    return this.$Now();
	}//$TimeStamp

  /**
   *  Форматированный вывод даты.
   *  @param string $format Формат даты.
   *  @param string $timestamp Время в милисекундах (timestamp).
   *  @return string Человеко подобную строку означающую какую-либо дату.
   */
	this.$Date = function ($format, $timestamp){
		if(!$format) $format = '';
		if(!$timestamp) $timestamp = Date.parse(new Date());

    var $datestr = "";
    for(var $i=0; $i<$format.length; $i++){
      switch($format.charAt($i)){
      case "Y":$datestr += this.$Year($timestamp);break;
      case "y":$datestr += this.$WYear($timestamp);break;
      case "L":$datestr += this.$isLeapYear($timestamp);break;
      //month
      case "F":$datestr += this.$MonthWord($timestamp);break;
      case "m":$datestr += this.$WRMonth($timestamp);break;
      case "M":$datestr += this.$MonthWor($timestamp);break;
      case "n":$datestr += this.$RMonth($timestamp);break;
      case "t":$datestr += this.$MonthDayCount($timestamp);break;
      //day
      case "d":$datestr += this.$WDayOfMonth($timestamp);break;
      case "D":$datestr += this.$DayOfWeekWor($timestamp);break;
      case "j":$datestr += this.$DayOfMonth($timestamp);break;
      case "l":$datestr += this.$DayOfWeekWord($timestamp);break;
      case "N":$datestr += this.$RDayOfWeek($timestamp);break;
      case "w":$datestr += this.$DayOfWeek($timestamp);break;
      case "z":$datestr += this.$DayOfYear($timestamp);break;
      //time
      case "g":$datestr += this.$Hours12($timestamp);break;
      case "G":$datestr += this.$Hours24($timestamp);break;
      case "h":$datestr += this.$WHours12($timestamp);break;
      case "H":$datestr += this.$WHours24($timestamp);break;
      case "i":$datestr += this.$Minutes($timestamp);break;
      case "s":$datestr += this.$Seconds($timestamp);break;
      //week
      case "W":$datestr += this.$WeekOfYear($timestamp);break;
      default:
        $datestr += $format.charAt($i);
      }
    }

    return $datestr;
	}//$Date

	/**
   *  Получение текущего времени в милисекундах.
   *  @return timestamp Строку времени в милисекундах (timpstamp).
   */
	this.$Now = function (){
		var $now_time = 0;
		try{
			$now_time = Date.now();
		}catch($e){
			$now_time = Date.parse(new Date());
		}
		return $now_time;
	}//$Now

	/**
   *  Получение текущего времени в милисекундах.
   *  @return timestamp Строку времени в милисекундах (timpstamp).
   */
	this.$Time = function (){
		return this.$Now();
	}//$Time

//-- Year --------------------------------

	/**
	 *	Определение високосности года.
	 *	@param timestamp $timestamp Время и дата в милисекундах, получаемое с
   *    помощью метода Time(). Если $timestamp не указан, то берется текущее
   *    время и дата. Так же можно указать просто год (4 цифры).
	 *	@return bool Возвращает true - год високосный, иначе false - не високосный.
	 */
	this.$isLeapYear = function ($timestamp){
		if(!$timestamp) $timestamp = Date.parse(new Date());
		if((new String($timestamp)).length==4) $timestamp = new Date($timestamp, 0, 1);
		var $y = (new Date($timestamp)).getFullYear();
		if ( ($y%4==0&&$y%100!=0)||$y%400==0)return true; else return false;
	}//$isLeapYear

  /**
   *  Номер года ввиде 4 цифр.
	 *	@param timestamp $timestamp Время и дата в милисекундах, получаемое с
   *    помощью метода Time(). Если $timestamp не указан, то берется текущее
   *    время и дата.
   *  @return string Номер года. Пример: "2008".
   */
  this.$Year = function ($timestamp){
    if(!$timestamp) $timestamp = Date.parse(new Date());
    return (new Date($timestamp)).getFullYear();
  }//$Year

  /**
   *  Номер года ввиде 2 цифр.
	 *	@param timestamp $timestamp Время и дата в милисекундах, получаемое с
   *    помощью метода Time(). Если $timestamp не указан, то берется текущее
   *    время и дата.
   *  @return string Номер года. Пример: "08".
   */
  this.$WYear = function ($timestamp){
    var $fy = new String(this.$Year($timestamp));
    return $fy.substring($fy.length-2);
  }//$WYear

//-- Month ------------------------------

	/*--*
	*	Получение номера месяца в году
	*	Параметры:
	*		$timestamp - время и дата в милисекундах, получаемое с помощью метода Time()
	*			Если $timestamp не указан, то берется текущее время и дата.
	*	Возвращает:
	*		номер месяца в году, от 0 до 11
	--*/
	this.$Month = function ($timestamp){
		if(!$timestamp) $timestamp = Date.parse(new Date());
		return (new Date($timestamp)).getMonth();
	}

	/*--*
	*	Получение номера месяца в году
	*	Параметры:
	*		$timestamp - время и дата в милисекундах, получаемое с помощью метода Time()
	*			Если $timestamp не указан, то берется текущее время и дата.
	*	Возвращает:
	*		номер месяца в году, от 1 до 12
	--*/
	this.$RMonth = function ($timestamp){
		if(!$timestamp) $timestamp = Date.parse(new Date());
		return ( (new Date($timestamp)).getMonth() )+1;
	}

	/*--*
	*	Получение номера месяца в году с ведущим нулем
	*	Параметры:
	*		$timestamp - время и дата в милисекундах, получаемое с помощью метода Time()
	*			Если $timestamp не указан, то берется текущее время и дата.
	*	Возвращает:
	*		номер месяца в году, от 00 до 11
	--*/
	this.$WMonth = function ($timestamp){
		if(!$timestamp) $timestamp = Date.parse(new Date());
		var $m = new String(this.$Month($timestamp));
		return $m.length==2?$m:('0'+$m);
	}

	/*--*
	*	Получение номера месяца в году с ведущим нулем
	*	Параметры:
	*		$timestamp - время и дата в милисекундах, получаемое с помощью метода Time()
	*			Если $timestamp не указан, то берется текущее время и дата.
	*	Возвращает:
	*		номер месяца в году, от 01 до 12
	--*/
	this.$WRMonth = function ($timestamp){
		if(!$timestamp) $timestamp = Date.parse(new Date());
		var $m = new String(this.$RMonth($timestamp));
		return $m.length==2?$m:('0'+$m);
	}

  /**
   *  Массив полных названий месяцев.
   *  @var array
   */
  this.$MonthWordArray = {1:'January', 2:'February', 3:'March', 4:'April', 5:'May', 6:'June', 7:'July', 8:'August', 9:'September', 10:'October', 11:'November', 12:'December'};

  /**
   *  Массив сокращенных названий месяцев.
   *  @var array
   */
  this.$MonthWorArray = {1:'Jan', 2:'Feb', 3:'Mar', 4:'Apr', 5:'May', 6:'Jun', 7:'Jul', 8:'Aug', 9:'Sep', 10:'Oct', 11:'Nov', 12:'Dec'};

	/*--*
	*	Получение названия месяца в году по английски
	*	Параметры:
	*		$timestamp - время и дата в милисекундах, получаемое с помощью метода Time()
	*			Если $timestamp не указан, то берется текущее время и дата.
	*			Так же в $timestamp можно указать номер месяца от 1 до 12.
	*	Возвращает:
	*		номер название месяца в году по английски
	--*/
	this.$MonthWord = function ($timestamp){
		if(!$timestamp) $timestamp = Date.parse(new Date());
		var $m = null;
		var $ttlen = (new String($timestamp)).length;
		if($timestamp&&$ttlen>=1&&$ttlen<=2) $m = parseInt($timestamp);
		if($m==null) $m = this.$RMonth($timestamp);
		var $mname = null;
		return this.$MonthWordArray[$m];
	}//$MonthWord

	/*--*
	*	Получение названия месяца в году по английски в сокращенном варианте
	*	Параметры:
	*		$timestamp - время и дата в милисекундах, получаемое с помощью метода Time()
	*			Если $timestamp не указан, то берется текущее время и дата.
	*			Так же в $timestamp можно указать номер месяца от 1 до 12.
	*	Возвращает:
	*		номер название месяца в году по английски в сокращенном варианте
	--*/
	this.$MonthWor = function $MonthWor($timestamp){
		if(!$timestamp) $timestamp = Date.parse(new Date());
		var $m = null;
		var $ttlen = (new String($timestamp)).length;
		if($timestamp&&$ttlen>=1&&$ttlen<=2) $m = parseInt($timestamp);
		if($m==null) $m = this.$RMonth($timestamp);
		return this.$MonthWorArray[$m];
	}

	/*--*
	*	Получение количества дней в месяце
	*	Параметры:
	*		$timestamp - время и дата в милисекундах, получаемое с помощью метода Time()
	*			Если $timestamp не указан, то берется текущее время и дата.
	*	Возвращает:
	*		количество дней в месяце
	--*/
	this.$MonthDayCount = function ($timestamp){
		if(!$timestamp)	$timestamp = Date.parse(new Date());
		var $m = this.$RMonth($timestamp);
		var $mdc = null;
		switch($m){
			case 1:$mdc = 31;break;
			case 2:this.$isLeapYear($timestamp)?$mdc=29:$mdc=28;break;
			case 3:$mdc = 31;break;
			case 4:$mdc = 30;break;
			case 5:$mdc = 31;break;
			case 6:$mdc = 30;break;
			case 7:$mdc = 31;break;
			case 8:$mdc = 31;break;
			case 9:$mdc = 30;break;
			case 10:$mdc = 31;break;
			case 11:$mdc = 30;break;
			case 12:$mdc = 31;break;
		}
		return $mdc;
	}
  
//-- Week -------------------------------

	/*--*
	*	Получение номера недели в году
	*	Параметры:
	*		$timestamp - время и дата в милисекундах, получаемое с помощью метода Time()
	*			Если $timestamp не указан, то берется текущее время и дата.
	*	Возвращает:
	*		номер недели в году, от 1 до 52(53)
	--*/
	this.$WeekOfYear = function ($timestamp){
		if(!$timestamp) $timestamp = Date.parse(new Date());

		var $y = (new Date($timestamp)).getFullYear();
		var $jan1day = this.$RJan1DayOfWeek($timestamp);
		var $dayofweek = this.$RDayOfWeek($timestamp);
		var $dayofyear = this.$RDayOfYear($timestamp);
		var $yearnumber = 0;
		var $weeknumber = 0;

		//-- 1
		if (this.$RDayOfYear($timestamp)<=(8-$jan1day)&&$jan1day>4){
			$yearnumber = $y-1;
			if(($jan1day==5)||($jan1day==6&&this.$isLeapYear($y-1))){
               $weeknumber = 53;
			}
            else{
               $weeknumber = 52;
			}
		}
		else
			$yearnumber = $y;

		//-- 2
		if ($yearnumber==$y){
			var $i;
			if (this.$isLeapYear($y))
               $i = 366;
            else
               $i = 365;
			if (($i-$dayofyear)<(4-$dayofweek)){
               $yearnumber = $y+1;
               $weeknumber = 1;
			}
		}

		//-- 3
		if ($yearnumber==$y){
			var $j = this.$RDayOfYear($timestamp)+(7-this.$RDayOfWeek($timestamp))+($jan1day-1)
			$weeknumber = this.$Div($j,7);
			if($jan1day>4) $weeknumber-=1;
		}

		//-- 4
		return $weeknumber;
	}//$WeekOfYear


//-- Day --------------------------------

	/*--*
	*	Получение дня недели из timestamp в виде цифры.
	*	Параметры:
	*		$timestamp - время и дата в милисекундах, получаемое с помощью метода Time()
	*			Если $timestamp не указан, то берется текущее время и дата.
	*	Возвращает:
	*		значения с 0 (воскресение) по 6 (суббота)
	--*/
	this.$DayOfWeek = function ($timestamp){
		if(!$timestamp) $timestamp = Date.parse(new Date());
		return (new Date($timestamp)).getDay();
	}

	/*--*
	*	Получение дня недели из timestamp в виде цифры.
	*	Параметры:
	*		$timestamp - время и дата в милисекундах, получаемое с помощью метода Time()
	*			Если $timestamp не указан, то берется текущее время и дата.
	*	Возвращает:
	*		значения с 1 (воскресение) по 7 (суббота)
	--*/
	this.$RDayOfWeek = function ($timestamp){
		if(!$timestamp) $timestamp = Date.parse(new Date());
		var $day_of_week = (new Date($timestamp)).getDay();
		return $day_of_week==0?7:$day_of_week;
	}

  /**
   *  Полное название дней в неделе.
   *  @var array
   */
  this.$DayOfWeekWordArray = {1:'Monday',2:'Tuesday',3:'Wednesday',4:'Thursday',5:'Friday',6:'Saturday',0:'Sunday'};
  /**
   *  Сокращённое название дней в неделе.
   *  @var array
   */
  this.$DayOfWeekWorArray = {1:'Mon',2:'Tue',3:'Wed',4:'Thu',5:'Fri',6:'Sat',0:'Sun'};

	/*--*
	*	Получение дня недели из timestamp ввиде слова.
	*	Параметры:
	*		$timestamp - время и дата в милисекундах, получаемое с помощью метода Time()
	*			Если $timestamp не указан, то берется текущее время и дата.
	*	Возвращает:
	*		слово, обозначающее день недели
	--*/
	this.$DayOfWeekWord = function ($timestamp){
		if(!$timestamp) $timestamp = Date.parse(new Date());
		var $ndw = this.$DayOfWeek($timestamp);
		return this.$DayOfWeekWordArray[$ndw];
	}//$DayOfWeekWord


	/*--*
	*	Получение дня недели из timestamp ввиде сокращенного слова.
	*	Параметры:
	*		$timestamp - время и дата в милисекундах, получаемое с помощью метода Time()
	*			Если $timestamp не указан, то берется текущее время и дата.
	*	Возвращает:
	*		слово, обозначающее день недели
	--*/
	this.$DayOfWeekWor = function ($timestamp){
		if(!$timestamp) $timestamp = Date.parse(new Date());
		var $ndw = this.$DayOfWeek($timestamp);
		return this.$DayOfWeekWorArray[$ndw];
	}

	/*--*
	*	Получение дня недели из timestamp ввиде русского слова.
	*	Параметры:
	*		$timestamp - время и дата в милисекундах, получаемое с помощью метода Time()
	*			Если $timestamp не указан, то берется текущее время и дата.
	*	Возвращает:
	*		русское слово, обозначающее день недели
	--*/
	function $RusDayOfWeekWord($timestamp){
		if(!$timestamp) $timestamp = Date.parse(new Date());
		var $ndw = this.$DayOfWeek($timestamp);
		if($ndw==1) return 'Понедельник';
		if($ndw==2) return 'Вторник';
		if($ndw==3) return 'Среда';
		if($ndw==4) return 'Четверг';
		if($ndw==5) return 'Пятница';
		if($ndw==6) return 'Суббота';
		if($ndw==0) return 'Воскресенье';
	}
	this.$RusDayOfWeekWord = $RusDayOfWeekWord;

	/*--*
	*	Получение номера дня месяца из timestamp.
	*	Параметры:
	*		$timestamp - время и дата в милисекундах, получаемое с помощью метода Time()
	*			Если $timestamp не указан, то берется текущее время и дата.
	*	Возвращает:
	*		номер дня месяца, от 1 до 31
	--*/
	function $DayOfMonth($timestamp){
		if(!$timestamp) $timestamp = Date.parse(new Date());
		return (new Date($timestamp)).getDate();
	}
	this.$DayOfMonth = $DayOfMonth;

	/*--*
	*	Получение номера дня месяца из timestamp с ведущим нулем.
	*	Параметры:
	*		$timestamp - время и дата в милисекундах, получаемое с помощью метода Time()
	*			Если $timestamp не указан, то берется текущее время и дата.
	*	Возвращает:
	*		номер дня месяца ввиде строки, от 01 до 31
	--*/
	function $WDayOfMonth($timestamp){
		if(!$timestamp) $timestamp = Date.parse(new Date());
		var $ndm = new String((new Date($timestamp)).getDate());
		return $ndm.length==1?("0"+$ndm):$ndm;
	}
	this.$WDayOfMonth = $WDayOfMonth;

	/*--*
	*	Получение номера дня года из timestamp.
	*	Параметры:
	*		$timestamp - время и дата в милисекундах, получаемое с помощью метода Time()
	*			Если $timestamp не указан, то берется текущее время и дата.
	*	Возвращает:
	*		номер дня в году, от 0 до 365
	--*/
	function $DayOfYear($timestamp){
		if(!$timestamp) $timestamp = Date.parse(new Date());
		var $mnth = new Array(0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334);
		var $m = this.$Month($timestamp);
		var $day_of_year_number = this.$DayOfMonth($timestamp) + $mnth[$m];
		if(this.$isLeapYear()&&$m>1){
			$day_of_year_number += 1;
		}
		return $day_of_year_number-1;
	}
	this.$DayOfYear = $DayOfYear;

	/*--*
	*	Получение номера дня года из timestamp.
	*	Параметры:
	*		$timestamp - время и дата в милисекундах, получаемое с помощью метода Time()
	*			Если $timestamp не указан, то берется текущее время и дата.
	*	Возвращает:
	*		номер дня в году, от 1 до 366
	--*/
	function $RDayOfYear($timestamp){
		if(!$timestamp) $timestamp = Date.parse(new Date());
		var $mnth = new Array(0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334);
		var $m = this.$Month($timestamp);
		var $day_of_year_number = this.$DayOfMonth($timestamp) + $mnth[$m];
		if(this.$isLeapYear()&&$m>1){
			$day_of_year_number += 1;
		}
		return $day_of_year_number;
	}
	this.$RDayOfYear = $RDayOfYear;

	/*--*
	*	Получение номера дня в недели для первого января года из timestamp.
	*	Параметры:
	*		$timestamp - время и дата в милисекундах, получаемое с помощью метода Time()
	*			Если $timestamp не указан, то берется текущее время и дата.
	*	Возвращает:
	*		номер дня в году, от 0 (воскресенье) до 6(суббота)
	--*/
	function $Jan1DayOfWeek($timestamp){
		var $h = this.$RJan1DayOfWeek();
		return $h==7?0:$h;
	}
	this.$Jan1DayOfWeek = $Jan1DayOfWeek;

	/*--*
	*	Получение номера дня в недели для первого января года из timestamp.
	*	Параметры:
	*		$timestamp - время и дата в милисекундах, получаемое с помощью метода Time()
	*			Если $timestamp не указан, то берется текущее время и дата.
	*	Возвращает:
	*		номер дня в году, от 1 (понедельник) до 7(воскресенье)
	--*/
	function $RJan1DayOfWeek($timestamp){
		if(!$timestamp) $timestamp = Date.parse(new Date());
		var $y = (new Date($timestamp)).getFullYear();
		var $yy = ($y-1)%100;
		var $c = ($y-1)-$yy;
		var $g = $yy+this.$Div($yy, 4);
		var $jan1weekday = 1+(((((this.$Div($c, 100))%4)*5)+$g)%7);
		return $jan1weekday;
	}
	this.$RJan1DayOfWeek = $RJan1DayOfWeek;

  //-- Time --------------------------------

  /**
   *  Получение часов.
   *  @return string Возвращает часы, от 0 до 23.
   */
  this.$Hours24 = function($timestamp){
    if(!$timestamp) $timestamp = Date.parse(new Date());
    var $wh = new String((new Date($timestamp)).getHours());
    return $wh;
  }//$Hours24

  /**
   *  Получение часов с ведущим нулем.
   *  @return string Возвращает часы, от 00 до 23.
   */
  this.$WHours24 = function($timestamp){
    if(!$timestamp) $timestamp = Date.parse(new Date());
    var $wh = new String((new Date($timestamp)).getHours());
    return $wh.length==1?("0"+$wh):$wh;
  }//$WHours24

  /**
   *  Получение часов.
   *  @return string Возвращает часы, от 1 до 12.
   */
  this.$Hours12 = function($timestamp){
    if(!$timestamp) $timestamp = Date.parse(new Date());
    var $wh = parseInt((new Date($timestamp)).getHours());
    if($wh==0) $wh = 12;
    if($wh>12) $wh = $wh-12;
    return new String($wh);
  }//$Hours12

  /**
   *  Получение часов c ведущим нулем.
   *  @return string Возвращает часы, от 01 до 12.
   */
  this.$WHours12 = function($timestamp){
    if(!$timestamp) $timestamp = Date.parse(new Date());
    var $wh = parseInt((new Date($timestamp)).getHours());
    if($wh==0) $wh = 12;
    if($wh>12) $wh = $wh-12;
    $wh = new String($wh);
    return $wh.length==1?("0"+$wh):$wh;
  }//$Hours12

  /**
   *  Получение секунд с ведущим нулем.
   *  @return string Возвращает часы, от 00 до 59.
   */
  this.$Seconds = function($timestamp){
    if(!$timestamp) $timestamp = Date.parse(new Date());
    var $wh = new String((new Date($timestamp)).getSeconds());
    return $wh.length==1?("0"+$wh):$wh;
  }//$Minutes

  /**
   *  Получение минут с ведущим нулем.
   *  @return string Возвращает часы, от 00 до 59.
   */
  this.$Minutes = function($timestamp){
    if(!$timestamp) $timestamp = Date.parse(new Date());
    var $wh = new String((new Date($timestamp)).getMinutes());
    return $wh.length==1?("0"+$wh):$wh;
  }//$Minutes

  //-- Math --------------------------------

	/*--*
	*	Деление целых. Реализация операции div
	--*/
	function $Div($a, $b){
		return ($a-$a%$b)/$b;
	}
	this.$Div = $Div;
}

/**
 *  Кодирование строк.
 *  @author Кузнецов А.В.
 */
function $CCODE(){
  /**
   *  Однонаправленное кодирование строки SHA1 алгоритмом.
   *  @param string $str Кодируемая строка.
   *  @return string Hash кодируемой строки.
   */
  this.$Sha1 = function ($str){

    var msg = $str;

    function rotate_left(n,s) {
      var t4 = ( n<<s ) | (n>>>(32-s));
      return t4;
    };

    function lsb_hex(val) {
      var str="";
      var i;
      var vh;
      var vl;

      for( i=0; i<=6; i+=2 ) {
        vh = (val>>>(i*4+4))&0x0f;
        vl = (val>>>(i*4))&0x0f;
        str += vh.toString(16) + vl.toString(16);
      }
      return str;
    };

    function cvt_hex(val) {
      var str="";
      var i;
      var v;

      for( i=7; i>=0; i-- ) {
        v = (val>>>(i*4))&0x0f;
        str += v.toString(16);
      }
      return str;
    };


    function Utf8Encode(string) {
      string = string.replace(/\r\n/g,"\n");
      var utftext = "";

      for (var n = 0; n < string.length; n++) {

        var c = string.charCodeAt(n);

        if (c < 128) {
          utftext += String.fromCharCode(c);
        }
        else if((c > 127) && (c < 2048)) {
          utftext += String.fromCharCode((c >> 6) | 192);
          utftext += String.fromCharCode((c & 63) | 128);
        }
        else {
          utftext += String.fromCharCode((c >> 12) | 224);
          utftext += String.fromCharCode(((c >> 6) & 63) | 128);
          utftext += String.fromCharCode((c & 63) | 128);
        }

      }

      return utftext;
    };

    var blockstart;
    var i, j;
    var W = new Array(80);
    var H0 = 0x67452301;
    var H1 = 0xEFCDAB89;
    var H2 = 0x98BADCFE;
    var H3 = 0x10325476;
    var H4 = 0xC3D2E1F0;
    var A, B, C, D, E;
    var temp;

    msg = Utf8Encode(msg);

    var msg_len = msg.length;

    var word_array = new Array();
    for( i=0; i<msg_len-3; i+=4 ) {
      j = msg.charCodeAt(i)<<24 | msg.charCodeAt(i+1)<<16 |
        msg.charCodeAt(i+2)<<8 | msg.charCodeAt(i+3);
      word_array.push( j );
    }

    switch( msg_len % 4 ) {
      case 0:
        i = 0x080000000;
        break;
      case 1:
        i = msg.charCodeAt(msg_len-1)<<24 | 0x0800000;
        break;

      case 2:
        i = msg.charCodeAt(msg_len-2)<<24 | msg.charCodeAt(msg_len-1)<<16 | 0x08000;
        break;

      case 3:
        i = msg.charCodeAt(msg_len-3)<<24 | msg.charCodeAt(msg_len-2)<<16 | msg.charCodeAt(msg_len-1)<<8	| 0x80;
        break;
    }

    word_array.push( i );

    while( (word_array.length % 16) != 14 ) word_array.push( 0 );

    word_array.push( msg_len>>>29 );
    word_array.push( (msg_len<<3)&0x0ffffffff );


    for ( blockstart=0; blockstart<word_array.length; blockstart+=16 ) {

      for( i=0; i<16; i++ ) W[i] = word_array[blockstart+i];
      for( i=16; i<=79; i++ ) W[i] = rotate_left(W[i-3] ^ W[i-8] ^ W[i-14] ^ W[i-16], 1);

      A = H0;
      B = H1;
      C = H2;
      D = H3;
      E = H4;

      for( i= 0; i<=19; i++ ) {
        temp = (rotate_left(A,5) + ((B&C) | (~B&D)) + E + W[i] + 0x5A827999) & 0x0ffffffff;
        E = D;
        D = C;
        C = rotate_left(B,30);
        B = A;
        A = temp;
      }

      for( i=20; i<=39; i++ ) {
        temp = (rotate_left(A,5) + (B ^ C ^ D) + E + W[i] + 0x6ED9EBA1) & 0x0ffffffff;
        E = D;
        D = C;
        C = rotate_left(B,30);
        B = A;
        A = temp;
      }

      for( i=40; i<=59; i++ ) {
        temp = (rotate_left(A,5) + ((B&C) | (B&D) | (C&D)) + E + W[i] + 0x8F1BBCDC) & 0x0ffffffff;
        E = D;
        D = C;
        C = rotate_left(B,30);
        B = A;
        A = temp;
      }

      for( i=60; i<=79; i++ ) {
        temp = (rotate_left(A,5) + (B ^ C ^ D) + E + W[i] + 0xCA62C1D6) & 0x0ffffffff;
        E = D;
        D = C;
        C = rotate_left(B,30);
        B = A;
        A = temp;
      }

      H0 = (H0 + A) & 0x0ffffffff;
      H1 = (H1 + B) & 0x0ffffffff;
      H2 = (H2 + C) & 0x0ffffffff;
      H3 = (H3 + D) & 0x0ffffffff;
      H4 = (H4 + E) & 0x0ffffffff;

    }

    var temp = cvt_hex(H0) + cvt_hex(H1) + cvt_hex(H2) + cvt_hex(H3) + cvt_hex(H4);

    return temp.toLowerCase();

  }//$Sha1

  /**
   *  Работа со строками в кодировке utf-8
   */
  this.$utf8 = {
    /**
     *  Перекодировка в шестнадцатиричные цифры и обратно.
     */
    $UTFtoHEXstr: function ($utfstr, $func) {
      var $result = "";
      var $b = "";
      for(var $i=0; $i<$utfstr.length; $i++){
        if($func)
          $result += $func($utfstr.charCodeAt($i));
        else{
          $b = "0000"+$wn.$code.$hex.$d2h($utfstr.charCodeAt($i));
          $result += "\\u"+$b.substring($b.length-4);
        }
      }
      return $result;
    }//$UTFtoHEXstr
  }//utf8

  this.$hex = {
    $d2h: function(d){return d.toString(16);},
    $h2d: function(h){return parseInt(h,16);}
  }//hex



}//$CCODE

/**
 *  Класс для работы с массивом.
 *  @author Кузнецов А.В.
 */
function $CVECTOR($array){

  //связанный с классом массив
  this.$array = new Array();
  if($array) this.$array = $array;

  //Функции преобразования внутреннего массива this.$array

  /**
   *	Добавление в конец вектора переменной $var
   *	@param $var - переменная добавляемая в вектор
   *	@param array $arr Массив в котором происходит поиск. Если данный параметр
   *    не был передан, то поиск будет вестить по внутреннему массиву.
   *  @return array Массив с добавленным в конце элементом.
   */
  this.$Add = function($var, $arr){
    if(!$arr) $arr = this.$array;
    $arr[$arr.length] = $var;
    this.$array = $arr;
    return $arr;
  }//$Add

  /**
   *	Получение вектора ввиде массива или одного элемента
   *	@param int $idx - индекс элемента вектора.
   *	@param array $arr Массив в котором происходит поиск. Если данный параметр
   *    не был передан, то поиск будет вестить по внутреннему массиву.
   *	@return mixed Возвращает элемент вектора, если $index определен,
   *		иначе будет возвращены все элементы вектора ввиде масива.
   */
  this.$Get = function($idx, $arr){
    var $index;
    if(!$arr) $arr = this.$array;
    if($idx=='last') return $arr[$arr.length-1];
    if($idx=='first') return $arr[0];
    if($idx==='undefined') return $arr;
    return $arr[$idx];
  }//$Get

  /**
   *	Получение количества элементов вектора.
   *	@param array $arr Массив в котором происходит поиск. Если данный параметр
   *    не был передан, то поиск будет вестить по внутреннему массиву.
   *  @return int Длинну вектора.
   */
  this.$Length = function($arr){
    if(!$arr) $arr = this.$array;
    return $arr.length;
  }//$Length

  /**
   *	Входит ли $var в элемент вектора
   *	@param mixed $var Переменная искомая в элементах массива.
   *	@param array $arr Массив в котором происходит поиск. Если данный параметр
   *    не был передан, то поиск будет вестить по внутреннему массиву.
   *	@return bool Возвращает true если $var является элементом массива, иначе false.
   */
  this.$In = function($var, $arr){
    if(!$arr) $arr = this.$array;
    for(var $i in $arr){
      if(	$var==$arr[$i] ){
        return true;
      }
    }
    return false;
  }//$In

  /**
   *	Удаление элемента массива $arr с индексом $idx.
   *	@param int $idx - индекс элемента вектора.
   *	@param array $arr Массив в котором происходит поиск. Если данный параметр
   *    не был передан, то поиск будет вестить по внутреннему массиву.
   *	@return array Возвращает исходный массив с удаленным элементом.
   */
  this.$Del = function($idx, $arr){
    if(!$arr) $arr = this.$array;
    if($idx=='last') $idx = $arr.length-1;
    if($idx=='first') $idx = 0;
    var $res_arr = new Array();
    for(var $i=0; $i<$arr.length; $i++){
      if(	$idx!=$i ){
        $res_arr[$res_arr.length] = $arr[$i];
      }
    }
    this.$array = $res_arr;
    return $res_arr;
  }//$Del

  /**
   *	Объединение двух массивов $arr и $add_arr.
   *	@param array $add_arr Добавляемый массив.
   *	@param array $arr Массив,  к которому добавляют.
   *	@return array Возвращает объединенный массив.
   */
  this.$Merge = function($add_arr, $arr){
    //--Проверка
    if(!$arr) $arr = this.$array;
    //--Операции
    var $merge_arr = $arr;
    for (var $i in $add_arr){
       $merge_arr[$merge_arr.length] = $add_arr[$i];
    }
    //--Результат
    this.$array = $merge_arr;
    return $merge_arr;
  }//$Merge

  /**
   *	Изменнеие индексов массива наоборот.
   *	@param array $arr Массив в котором происходит поиск. Если данный параметр
   *    не был передан, то поиск будет вестить по внутреннему массиву.
   *  @return array Перевернутый массив.
   */
  this.$Revers = function($arr){
    //--Проверка
    if(!$arr) $arr = this.$array;
    //--Операции
    var $new_arr = new Array();;
    for (var $i=$arr.length-1; $i>=0; $i--){
       $new_arr[$new_arr.length]=$arr[$i];
    }
    //--Результат
    this.$array = $new_arr;
    return $new_arr;
  }//$Revers

  /**
   *	Применение к элементам массива $arr функции $func
   *	Параметры:
   *	@param array $arr Массив в котором происходит поиск. Если данный параметр
   *    не был передан, то поиск будет вестить по внутреннему массиву.
   *	@param function $func Функция, которая применяется к каждому элементу массива.
   *			Функция принимает 2 параметра индекс элемента и его значение.
   *			Если функция $func что-то вернет, то цикл остановиться и данные
   *			результаты будут возвращены функцией $Each.
   *	$return mixed Возвращает какое-либо значение, либо undefined.
   */
  this.$Each = function($func, $arr){
    //--Проверка
    if(!$arr) $arr = this.$array;
    //--Операции
    var $hRet;
    for(var $i=0; $i<$arr.length; $i++){
      $hRet = $func($i, $arr[$i]);
      if($hRet) break;
    }
    return $hRet;
  }//$Each

  /**
   *	Входит ли $var в элемент вектора
   *	@param mixed $var Переменная исковая в элементах вектора.
   *	@param array $arr Массив в котором происходит поиск. Если данный параметр
   *    не был передан, то поиск будет вестить по внутреннему массиву.
   *	@return Возвращает индекс $var если $var является элементом вектора, иначе false.
   */
  this.$Index = function($var, $arr){
    if(!$arr) $arr = this.$array;
    for(var $i=0; $i<$arr.length; $i++){
      if(	$var==$arr[$i] ){
        return $i;
      }
    }
    return false;
  }//$Index

  /**
   *	Определение является ли переменная $var массивом.
   *	@param mixed $var Любая переманная.
   *	@return Возвращает true если $var есть массив, иначе false.
   */
  this.$IsArray = function($var){
    var g = $var.constructor.toString();
    if(g.match(/function Array()/)){
      return true;
    }
    else{
      return false;
    }
  }//$IsArray

  /**
   *  Преобразование массива в JSON строку валидную для парсинга php скриптом.
   *  @param object|array $obj Объект (пример: {a:1, d:"2"}) или массив (пример: [1,2,"eee"]).
   *  @return Возвращает строку в json формате валидную для парсинга в PHP.
   */
  this.$ToJSON = function($obj){
    if(!$obj) $obj = this.$array;
    if(typeof $obj!='object') return false; 
    var $json_str = "{";
    var $i, $counter=-1;
    for($i in $obj){
      $counter++;
      //
      $json_str+='"'+$i+'":';
      //
      if(typeof $obj[$i]=='object'){
        $json_str += this.$ToJSON($obj[$i])+",";
      }
      else{
        if($obj[$i]||$obj[$i]===0){
          var $obj_str = new String($obj[$i]);
          $json_str += '"'+$obj_str.replace('\\','\\\\').replace('"','\\"').replace(/\n/g,'\\n').replace(/\t/g,'\\t')+'",';
        }
        else
          $json_str += '"",';
      }
    }
    if($counter>-1)
      return $json_str.substr(0,$json_str.length-1)+"}";
    else
      return '""';
  }//$ToJSON

  //Функции в стиле PHP

  /**
   *	Определение является ли переменная $input массивом
   *	@param mixed $var Любая переманная.
   *	@return Возвращает true если $var есть массив, иначе false.
   */
  this.$is_array = function($var){
    return this.$IsArray($var);
  }//$is_array

  /**
   *	Входит ли $var в элемент вектора
   *	@param mixed $var Переменная искомая в элементах массива.
   *	@param array $arr Массив в котором происходит поиск. Если данный параметр
   *    не был передан, то поиск будет вестить по внутреннему массиву.
   *	@return Возвращает true если $var является элементом массива, иначе false.
   */
  this.$in_array = function($var, $arr){
    for(var $i=0; $i<$arr.length; $i++){
      if(	$var==$arr[$i] ){
        return true;
      }
    }
    return false;
  }//$in_array

}//$CVECTOR

/**
 *	Класс по работе с объектами CSS.
 *	@author Кузнецов А.В.
 */
function $CCSS(){

	//--объект фрэйма
	this.window = window;

	/*--*
	*	Получение объекта css по имени файла
	*	Параметры:
	*		$filename - имя файла таблицы стилей (название с расширением)
	*	Возвращает:
	*		объект css таблицы, либо null если возникли ошибки
	--*/
	function $getCSSObj($filename){
		//--перебор всех таблиц стилей
		var $ssh;
		for(var $i=0; $i<this.window.document.styleSheets.length; $i++){
			$ssh = this.window.document.styleSheets[$i];
			if($ssh.href.indexOf($filename)!=-1){
				return $ssh;
			}
		}
	}
	this.$getCSSObj = $getCSSObj;

	/*--*
	*	Получение индекса css таблицы по имени файла
	*	Параметры:
	*		$filename - имя файла таблицы стилей (название с расширением)
	*	Возвращает:
	*		индекс css таблицы, либо null если возникли ошибки
	--*/
	function $getCSSIndex($filename){
		//--перебор всех таблиц стилей
		var $ssh;
		for(var $i=0; $i<this.window.document.styleSheets.length; $i++){
			$ssh = this.window.document.styleSheets[$i];
			if($ssh.href.indexOf($filename)!=-1){
				return $i;
			}
		}
	}
	this.$getCSSIndex = $getCSSIndex;

	/*--*
	*	Получение объекта правила css таблицы
	*	Параметры:
	*		$filename - имя файла таблицы стилей (название с расширением)
	*		$rulename - название правила (все что до фигурных скобок)
	*	Возвращает:
	*		объект правила css таблицы, либо null если возникли ошибки
	--*/
	function $getCSSRuleObj($filename, $rulename){
		//--перебор всех таблиц стилей
		var $ssh;
		for(var $i=0; $i<this.window.document.styleSheets.length; $i++){
			$ssh = this.window.document.styleSheets[$i];
			if($ssh.href.indexOf($filename)!=-1){
				for(var $ii=0; $ii<$ssh.cssRules.length; $ii++){
					if($ssh.cssRules[$ii].selectorText==$rulename){
						return $ssh.cssRules[$ii];
					}
				}
			}
		}
	}
	this.$getCSSRuleObj = $getCSSRuleObj;

	/*--*
	*	Добавление стиля к документу
	*	Параметры:
	*		$url - адрес ксс файла
	--*/
	function $AddStyleSheet($url){
		var $style;
		$style = this.window.document.createElement('link');
		$style.rel = 'stylesheet';
		$style.type = 'text/css';
		$style.href = $url;
		this.window.document.getElementsByTagName('head')[0].appendChild($style);
	}
	this.$AddStyleSheet = $AddStyleSheet;

}//$CCSS

/**
 *	Класс обеспечивающий навигацию по узлам DOM-структуры.
 *	@author Кузнецов А.В.
 */
function $CNODENAVIGATION($win){

	//--Фрэйм в котором происходит обработка
	if($win)
		this.$window = $win;
	else
		this.$window = window;

	//константы
	this.$TEXTNODE = 3;
	this.$NODE = 1;
	this.$COMMENT = 8;

	//объект для работы с массивами
	this.$v = new $CVECTOR();

	/*--*
	*	Поиск узлов по заданном шаблону
	*	Параметры:
	*		$exp - шаблон поиска
	*		$start_node - узел, в рамках которого роисходит поиск
	*		$deep - глубина поиска относительно узла $start_node
	*	Возвращает:
	*		массив узлов удовлетворяющих шаблону $exp.
	*
	*	Шаблон $exp задается ввиде тега с атрибутами(<a href="">).
	*	Если имя тега или перечень трибутов отсутсвуют, то это означает,
	*	что возможно любое значение. Имена атибутов и их значения можно отрицать.
	*	Пример: <a> - найти все теги "а".
	*	<a name> - найти все теги "а" с атрибутом name, в котором содержиться любое значене.
	*	<a !name> - найти все теги "а", в которых нет атрибута name.
	*	<a name="1"> - найти теги "а", где имеется атрибут name равный 1.
	*	<a name!="1"> - найти все теги "а", где имеетс атрибут name не равный 1.
	*	< name> - нати любой тег с атрибутом name, содержащим любое значение.
	*   < > - найти все теги.
	--*/
	this.$find = function ($exp, $start_node, $deep){
		if(!$start_node) $start_node = this.$window.document.body;
		var $found = $exp.match(/<([a-z0-9]+)? ?([^>]*)>/i);
		var $tag_name = $found[1]?$found[1]:null;
		var $tag_attributes_string = $found[2]?$found[2]:null;
		var $att_isnot = new Array();
		var $att_name = new Array();
		var $att_value_isnot = new Array();
		var $att_value = new Array();
		if($tag_attributes_string!=null){
			$found = $tag_attributes_string.match(/([\!]{0,1}([_\-a-z0-9]+))([\!\=]{0,2}"([^"]*)")?/ig);
			var $valueparam = null;
			for($i=0; $i<$found.length; $i++){
				$valueparam = (/([\!]{0,1}([_\-a-z0-9]+))([\!\=]{0,2}"([^"]*)")?/i).exec($found[$i]);
				$l = $att_isnot.length;
				$att_isnot[$l] = $valueparam[1]&&$valueparam[1][0]=="!"?true:false;
				$att_name[$l] = $valueparam[2]?$valueparam[2]:null;
				$att_value_isnot[$l] = $valueparam[3]&&$valueparam[3][0]=="!"?true:false;
				$att_value[$l] = $valueparam[4]?$valueparam[4]:null;
			}
		}

		var $findNodesInTree = function ($start_node, $tag_name, $att_name, $att_isnot, $att_value, $att_value_isnot, $deep, $find_node_arr){
			if($deep!=null) if($deep==0) return; else $deep--;
			var $flag_att_name;
			var $flag_att_value;
			var $c = $start_node;
			for(var $i=0; $i<$start_node.childNodes.length; $i++){
				$flag_att_name = true;
				$flag_att_value = true;
				var $child = $start_node.childNodes[$i];
				if($child.nodeType==1){
					if($tag_name==null||$child.nodeName.toLowerCase() == $tag_name.toLowerCase()){
						//--
						if($att_name!=null){
							for($ii=0; $ii<$att_name.length; $ii++){
								if($child.getAttribute($att_name[$ii])){
									if($att_isnot[$ii])
										$flag_att_name = false;
								}
								else{
									if(!$att_isnot[$ii])
										$flag_att_name = false;
								}
							}
						}
						//--
						if($att_value!=null){
							for($ii=0; $ii<$att_value.length; $ii++){
								if($att_value[$ii]==null) continue;
								if($child.getAttribute($att_name[$ii])&&$child.getAttribute($att_name[$ii])==$att_value[$ii]){
									if($att_value_isnot[$ii])
										$flag_att_value = false;
								}
								else{
									if(!$att_value_isnot[$ii])
										$flag_att_value = false;
								}
							}
						}

						if($flag_att_name&&$flag_att_value) $find_node_arr[$find_node_arr.length]=$child;
					}
					if ($child.childNodes.length) {
						$findNodesInTree($child, $tag_name, $att_name, $att_isnot, $att_value, $att_value_isnot, $deep, $find_node_arr);
					}
				}
			}
		}
		var $find_node_arr = new Array();
		$findNodesInTree($start_node, $tag_name, $att_name, $att_isnot, $att_value, $att_value_isnot, $deep, $find_node_arr)

		return $find_node_arr;
	}

	/*--*
	*	Получение узла по иду $id
	*	Параметры:
	*		$id - ид искомого узла
	*	Возвращает:
	*		объект узла
	--*/
	this.$ = function($id){
		return this.$window.document.getElementById($id);
	}

	/*--*
	*	Получение потомков узла $c ввиде массива
	*	Параметры:
	*		$param - ассоциативный массив с параметрами:
	*			c - узел, в котором происходит поиск, обязательно должен иметь тип 1.
	*			type - тип узлов, которые необходимо получить
	*			deep - глубина поиска
	*			excluded - исключенные из обхода узел или массив узлов
	*			distinct - вывод только уникальных значений (true||false)
	*			start_offset - начальный узел-смещение, после которого найденные узлы начинают заноситься в итоговый массив
	*			$end_offset - конечный узел-смещение, после которого найденные узлы перестают заноситься в итоговый массив
	*			limit - число, ограничение по количеству возвращаемых узлов
	*	Возвращает:
	*		массив дочерных узлов, отвечающих параметрам.
	*
	*	Пример передачи параметров:
	*
	*	var $nn = new $CNODENAVIGATION();
	*	$nn.$ChildNodes({ 'c':$nn.$('container'), 'type':$nn.$NODE, 'deep':1})
	*
	*	var $nn = new $CNODENAVIGATION();
	*	var $excluded = new Array($nn.$('innernode'), $nn.$('container').lastChild);
	*	var $res = $nn.$ChildNodes({ 'c':$nn.$('container'), 'type':3, 'excluded':$excluded });
	*
	*	var $nn = new $CNODENAVIGATION();
	*	var $res = $nn.$ChildNodes({ 'c':$nn.$('container'), 'type':3, 'excluded':$nn.$('innernode') });
	*
	*	var $nn = new $CNODENAVIGATION();
	*	var $res = $nn.$ChildNodes({ 'c':(new Array($nn.$('innernode'), $nn.$('p2'))) });
	*
	*	var $nn = new $CNODENAVIGATION();
	*	var $res = $nn.$ChildNodes({ 'c':$nn.$('container'), 'start_offset':$nn.$('dd'), 'type':$nn.$TEXTNODE, 'limit':2, 'deep':3 });
	*
	*	var $nn = new $CNODENAVIGATION();
	*	var $res = $nn.$ChildNodes({ 'c':$nn.$('container'), 'start_offset':$nn.$('p2'), 'end_offset':$nn.$('p3'), 'type':$nn.$TEXTNODE, 'limit':1 })
	*
	*	Любой из параметров может отсутсвовать. Если отсутсвует 'c', то поиск
	*	будет происходить внутри тега body.
	*	Если отсутсвует 'type', то будут находиться узлы с любым типом.
	*	Если отсутсвует 'deep', то поиск будет происходить на любую глубину.
	*	Если отсутсвует 'excluded', то исключенных из обхода узлов нет. Этот
	*   параметр может принимать как массив узлов так и один узел.
	*	Если параметр 'distinct' отсутвует, то по умолчанию выбирается значение true.
	*	Граничные узлы, удовлетворяющие условиям, будут включены в итоговый массив.
	--*/
	this.$ChildNodes = function($param){
		//получение параметров
		var $c = this.$window.document.body;
		var $node_type = null;
		var $deep = null;
		var $excluded_tags = null;
		var $distinct = true;
		var $start_offset = null;
		var $end_offset = null;
		var $limit = null;
		if($param){
			$c = $param['c']?$param['c']:this.$window.document.body;
			$node_type = $param['type']?$param['type']:null;
			$deep = $param['deep']?$param['deep']:null;
			$excluded_tags = $param['excluded']?$param['excluded']:null;
			if($param['distinct']==undefined) $distinct = true;
			else
				if($param['distinct']===false) $distinct = false;
			$start_offset = $param['start_offset']?$param['start_offset']:null;
			$end_offset = $param['end_offset']?$param['end_offset']:null;
			$limit = $param['limit']?$param['limit']:null;
		}
		//функция определения массива
		var $is_array = this.$v.$is_array;
		//Фнкция обхода одного узла
		var $BypassNode = function ($c, $childs, $node_type, $deep, $excluded_tags, $start_offset, $end_offset, $limit){
			if($limit!=null) if($limit==0) return {'start_offset':$start_offset, 'end_offset':$end_offset, 'limit':$limit};
			if($deep!=null) if($deep==0) return {'start_offset':$start_offset, 'end_offset':$end_offset, 'limit':$limit}; else $deep--;
			var $is_excluded_tag = false;
			for(var $i=0; $i<$c.childNodes.length; $i++){
				//пропуск исключенных тегов
				$is_excluded_tag = false;
				if($excluded_tags!=null)
					if($is_array($excluded_tags))
						for(var $ii=0; $ii<$excluded_tags.length; $ii++){
							if($excluded_tags[$ii] == $c.childNodes[$i]) $is_excluded_tag = true;
						}
					else
						if($excluded_tags == $c.childNodes[$i]) $is_excluded_tag = true;
				if($is_excluded_tag) continue;
				//обработка смещения ($start_offset)
				if( $start_offset===null || $start_offset===true || $start_offset==$c.childNodes[$i] || $start_offset==$c ) $start_offset = true;
				//формирование результирующего массива узлов
				if($node_type==null){
					if(($start_offset===null || $start_offset===true) && ($limit==null || $limit>0) ) {
						$childs[$childs.length] = $c.childNodes[$i];
						if($limit!=null) $limit--;
					}
					if ($c.childNodes[$i].nodeType==1&&$c.childNodes[$i].childNodes.length) {
						$metodata = $BypassNode($c.childNodes[$i], $childs, $node_type, $deep, $excluded_tags, $start_offset, $end_offset, $limit);
						$start_offset = $metodata['start_offset'];
						$end_offset = $metodata['end_offset'];
						$limit = $metodata['limit'];
					}
				}
				else{
					if($c.childNodes[$i].nodeType == $node_type){
						if(($start_offset===null || $start_offset===true) && ($limit==null || $limit>0) ) {
							$childs[$childs.length] = $c.childNodes[$i];
							if($limit!=null) $limit--;
						}
						if ($c.childNodes[$i].childNodes.length) {
							$metodata = $BypassNode($c.childNodes[$i], $childs, $node_type, $deep, $excluded_tags, $start_offset, $end_offset, $limit);
							$start_offset = $metodata['start_offset'];
							$end_offset = $metodata['end_offset'];
							$limit = $metodata['limit'];
						}
					}
					else{
						if ($c.childNodes[$i].nodeType==1&&$c.childNodes[$i].childNodes.length) {
							$metodata = $BypassNode($c.childNodes[$i], $childs, $node_type, $deep, $excluded_tags, $start_offset, $end_offset, $limit);
							$start_offset = $metodata['start_offset'];
							$end_offset = $metodata['end_offset'];
							$limit = $metodata['limit'];
						}
					}
				}
				//обработка смещения ($end_offset)
				if(($start_offset===null || $start_offset===true) && $end_offset!=null && ($end_offset==$c.childNodes[$i] || $end_offset===true) )
					return {'start_offset':$start_offset, 'end_offset':true, 'limit':$limit};
			}
			return {'start_offset':$start_offset, 'end_offset':$end_offset, 'limit':$limit};
		}
		//фнкция обхода нескольких узлов
		var $BypassNodes = function ($c_array, $return_childs, $node_type, $deep, $excluded_tags, $start_offset, $end_offset, $limit){
			//функци объекдинения массивов
			var $AssociationArrays = function ($array1, $array2){
				for(var $i=0; $i<$array2.length; $i++){
					$array1[$array1.length] = $array2[$i];
				}
				return $array1;
			}
			//выполнение обхода
			var $childs = new Array();
			for(var $i=0; $i<$c_array.length; $i++){
				$childs = new Array();
				$metodata = $BypassNode($c_array[$i], $childs, $node_type, $deep, $excluded_tags, $start_offset, $end_offset, $limit);
				$start_offset = $metodata['start_offset'];
				$end_offset = $metodata['end_offset'];
				$limit = $metodata['limit'];

				$return_childs = $AssociationArrays($return_childs, $childs);
			}
		}
		//функция фильтрации
		var $FiltrationNodes = function ($node_array, $distinct){
			var $v = new $CVECTOR();
			if($distinct == true){
				var $flt_arr = new Array();
				for(var $i=0; $i<$node_array.length; $i++){
					if( !$v.$in_array($node_array[$i], $flt_arr) ){
						$flt_arr[$flt_arr.length] = $node_array[$i];
					}
				}
				$node_array = $flt_arr;
			}

			return $node_array;
		}
		//поиск узлов
		var $childs = new Array();
		if(this.$v.$is_array($c)) $BypassNodes($c, $childs, $node_type, $deep, $excluded_tags, $start_offset, $end_offset, $limit);
		else $BypassNode($c, $childs, $node_type, $deep, $excluded_tags, $start_offset, $end_offset, $limit);
		//фильтрация узлов
		$childs = $FiltrationNodes($childs, $distinct);

		return $childs;
	}

	/*--*
	*	Получение всех родителей узла $c ввиде массива до узла body (включительно)
	*	Параметры:
	*		$param - ассоциативный массив с параметрами:
	*			c - узел, для которого ищется родитель
	*			deep - глубина поиска
	*			stop_node - родительский узел, до которого делается поиск.
	*	Возвращает:
	*		массив всех родителей (узлов типа 1) до узла body (включительно)
	*
	*	Параметр 'c' обязателен для работы функции. Он должен в себе содержать узел.
	*	Параметр 'deep' для поиска не обязателен. Если его не задать, то поиск будет
	*	происходить пока не бдет достигнут тег body.
	*	Стоповый узел входит в результирующий массив.
	--*/
	this.$ParentNodes = function($param){
		//получение параметров
		var $c = null;
		var $deep = null;
		var $stop_node = null;
		if($param){
			$c = $param['c']?$param['c']:null;
			if($c==null||!$c.nodeType) return new Array();
			$deep = $param['deep']?$param['deep']:null;
			$stop_node = $param['stop_node']?$param['stop_node']:null;
		}
		else
			return new Array();
		//
		var $parent;
		if($c) $parent = $c.parentNode; else return new Array();
		var $parents = new Array();
		while($parent&&($parent.nodeName!="BODY")){
			if($deep!=null) if($deep==0) break; else $deep--;
			$parents[$parents.length] = $parent;
			$parent = $parent.parentNode;
			if($stop_node==$parent) break;
		}
		if($parent&&($parent.nodeName=="BODY")){
			if($deep!=null){
				if($deep==0) {}
				else {
					$parents[$parents.length] = $parent;
				}
			}
			else{
				$parents[$parents.length] = $parent;
			}
		}
		return $parents
	}

	/*--*
	*	Применение к элементам массива $arr функции $func
	*	Параметры:
	*		$arr - массив узлов
	*		$func - функция, которая применяется к каждому элементу массива.
	*			Функция принимает 2 параметра индекс элемента и его значение.
	--*/
	this.$Each = function($arr, $func){
		for(var $i=0; $i<$arr.length; $i++){
			$func($i, $arr[$i]);
		}
	}


	/*--*
	*	Поиск элементов формы.
	*	Параметры:
	*		$param - ассоциативный массив с параметрами:
	*			c - узел, в котором происходит поиск
	*			deep - глубина поиска
	*			excluded - исключенные из обхода узел или массив узлов
	*	Возвращает:
	*		массив элементов формы, отвечающих параметрам.
	--*/
	this.$FormElements = function($param){
		//получение параметров
		var $c = this.$window.document.body;
		var $deep = null;
		var $excluded_tags = null;
		if($param){
			$c = $param['c']?$param['c']:this.$window.document.body;
			$deep = $param['deep']?$param['deep']:null;
			$excluded_tags = $param['excluded']?$param['excluded']:null;
		}
		//поиск и формирование массива элементов
		var $child_nodes = this.$ChildNodes({'c':$c, 'type':this.$NODE, 'deep':$deep, 'excluded':$excluded_tags});
		var $form_elements = new Array();
		this.$Each($child_nodes, function($i, $child){

			if(	$child.nodeName=="SELECT"||
				($child.nodeName=="INPUT"&&$child.getAttribute('type')=="text")||
				($child.nodeName=="INPUT"&&$child.getAttribute('type')=="checkbox")||
				($child.nodeName=="INPUT"&&$child.getAttribute('type')=="radio")||
				$child.nodeName=="TEXTAREA"
			)
			{
				$form_elements[$form_elements.length] = $child;
			}
		});
		return $form_elements;
	}

	/*--*
	*	Получение индекса узла среди узлов его родителя
	*	Параметры:
	*		$node - узел
	*	Возвращает:
	*		int порядковый номер, если узел не найден или вообще не существовал, вернет false
	--*/
	this.$Index = function($node){
		if(!$node) return false;
		if($node.nodeType=='undefined') return false;
		var $parent = $node.parentNode;
		var $i = false;
		for($i=0; $i<$parent.childNodes.length; $i++){
			if($parent.childNodes[$i]==$node) break;
		}
		return $i;
	}



	//--Старые
	/*--*
	*	Получение всех потомков узла $c ввиде массива $childs
	--*/
	function $getAllChildsOfNode($c, $childs){
		for(var $i=0; $i<$c.childNodes.length; $i++){
			$childs[$childs.length] = $c.childNodes[$i];
			if ($c.childNodes[$i].childNodes.length) {
				this.$getAllChildsOfNode($c.childNodes[$i], $childs);
			}
		}
	}
	this.$getAllChildsOfNode = $getAllChildsOfNode;

	/*--*
	*	Обработка строки атрибутов и превращение их в 2 массива
	*	Параметры:
	*		$nodeAttributs - строка с атрибутами (name=value&name=value)
	*		$names - массив имен, который будет возвращен после обработки строки $nodeAttributs
	*		$values - массив значений
	--*/
	function $AttributesAsArrays($nodeAttributs, $names, $values){
		if($nodeAttributs==null) return;
		var $st1 = $nodeAttributs.split("&");
		var $st2;
		for(var $i=0; $i<$st1.length; $i++){
			$st2 = $st1[$i].split("=");
			if($st2.length==2){
				$names[$i]=$st2[0];
				$values[$i]=$st2[1];
			}
			else{
				$names[$i]="";
				$values[$i]="";
			}
		}
	}
	this.$AttributesAsArrays = $AttributesAsArrays;

	/*--*
	*	Получение всех узлов с именем $nodeName дочерних узлу $startNode ввиде массива $textNodeArr
	*	Параметры:
	*		$startNode - узел родитель
	*		$nodeName - имя искомых узлов
	*		$nodeAttributs - атрибуты, которые должны присутствовать у найденного элемента (name=value&name=value)
	*		$excludingAttributes - атрибуты, которые не должны присутствовать у найденного элемента (name=value&name=value)
	*		$deep - глубина (число)
	*		$textNodeArr - массив текстовых узлов, в который записываются все найденные #text узлы
	--*/
	function $findNodesByName($startNode, $nodeName, $nodeAttributs, $excludingAttributes,  $deep, $textNodeArr){
		if($deep!=null) if($deep==0) return; else $deep--;
		var $isattr = true;
		var $names = new Array();
		var $values = new Array();
		if($nodeAttributs!=null){
			this.$AttributesAsArrays($nodeAttributs, $names, $values);
		}
		var $ex_names = new Array();
		var $ex_values = new Array();
		if($excludingAttributes!=null){
			this.$AttributesAsArrays($excludingAttributes, $ex_names, $ex_values);
		}
		var $c = $startNode;
		var $parents;
		for(var $i=0; $i<$c.childNodes.length; $i++){
			var $child = $c.childNodes[$i];
			if($child.nodeType==1){
				if($child.nodeName.toLowerCase() == $nodeName.toLowerCase()){
					$isattr = true;
					if($nodeAttributs!=null){
						for($ii=0; $ii<$names.length; $ii++){
							if($child.getAttribute($names[$ii])&&$child.getAttribute($names[$ii])==$values[$ii]){}
							else{$isattr=false;}
						}
					}
					if($excludingAttributes!=null){
						for($ii=0; $ii<$ex_names.length; $ii++){
							if($child.getAttribute($ex_names[$ii])&&$child.getAttribute($ex_names[$ii])==$ex_values[$ii]){$isattr=false;}
						}
					}
					if($isattr)	$textNodeArr[$textNodeArr.length]=$child;
				}
				if ($child.childNodes.length) {
					this.$findNodesByName($child, $nodeName, $nodeAttributs, $excludingAttributes, $deep, $textNodeArr);
				}
			}
		}
	}
	this.$findNodesByName = $findNodesByName;

	/*--*
	*	Обнаружение родителей узла $c
	*	Возвращает:
	*		массив ссылко на узлы родителей
	--*/
	function $getParentsForNode($c){
		var $parent;
		if($c) $parent = $c.parentNode;
		else return new Array();
		var $parents = new Array();
		var $count = 0;
		while($parent&&($parent.nodeName!="BODY"||$parent.getAttribute('id')!='content')){
			$parents[$count] = $parent;
			$count++;
			$parent = $parent.parentNode
		}
		if($parent&&($parent.nodeName!="BODY"||$parent.getAttribute('id')!='content')){
			$parents[$count] = $parent;
		}
		return $parents
	}
	this.$getParentsForNode = $getParentsForNode;

}//$CNODENAVIGATION

/**
 *  Класспо работе с ренжами.
 *  @author Кузнецов А.В.
 */
function $CRANGE($range, $window){

  //объект окна, к которому принадлежит ренж
  this.$window = window;
  if($window&&$window.document){
    this.$window = $window;
  }

  //объект ренжа
  this.$range = null;
  if($range&&$range.insertNode){
    this.$range = $range;
  }

  //объект навигации по узлам
  this.$nn = new $CNODENAVIGATION(this.$window);

  /**
   *  Получение общего родителя для начального и конечного узлов ренж.
   */
  this.$CA = function(){
    return this.$range.commonAncestorContainer;
  }

  /**
   *  Получить контейнер, с которого начинается ренж.
   *  С этого узла и включая его начинается выделение.
   *  Возвращает:
   *    узел (типа 1 или 3) или null если произошли ошибки
   */
  this.$SC = function(){
    if(this.$range==null) return null;
    var $sc = null;
    if(this.$range.startContainer.nodeType==3){
			$sc = this.$range.startContainer;
		}
		else{
			if(this.$range.startContainer.nodeType==1){
        $sc = this.$range.startContainer.childNodes[this.$range.startOffset];
      }
		}
    return $sc;
  }

  /**
   *  Получить контейнер, на котором заканчивается ренж (т.е. последний в ренже).
   *  Возвращает:
   *    узел (типа 1 или 3) или null если произошли ошибки
   */
  this.$EC = function(){
    if(this.$range==null) return null;
    var $ec = null;
    if(this.$range.endContainer.nodeType==3){
			if(this.$range.endOffset>0)
        $ec = this.$range.endContainer;
      else{
        if(this.$range.endContainer.previousSibling) return this.$range.endContainer.previousSibling;
        else return this.$range.endContainer.parentNode;
      }
		}
		else{
			if(this.$range.endContainer.nodeType==1){
        $ec = this.$range.endContainer.childNodes[this.$range.endOffset-1];
      }
		}
    return $ec;

    /*if(this.$range==null) return null;
    var $ec = null;
    if(this.$range.endContainer.nodeType==3){
			$ec = this.$range.endContainer;
		}
		else{
			if(this.$range.endContainer.nodeType==1){
        $ec = this.$range.endContainer.childNodes[this.$range.endOffset-1];
      }
		}
    return $ec;*/
  }

  /**
   *  Получение текстовых узлов ренжа.
	 *	Возвращает:
	 *		массив текстовых узлов (типа 3), входящих в ренж
   *
   */
  this.$TextNodes = function(){
    if(this.$range==null) return null;
    var $first_node = this.$SC();
    var $last_node = this.$EC();
    if(this.$range.commonAncestorContainer==$first_node&&$first_node==$last_node){
			return new Array($first_node);
		}
		else{
      return this.$nn.$ChildNodes({'c':this.$range.commonAncestorContainer, 'start_offset':this.$SC(), 'end_offset':this.$EC(), 'type':this.$nn.$TEXTNODE});
    }
  }

  /**
   *	Получение узлов (типа 1) частично или полностью входящих ввыделение
	 *	Возвращает:
	 *		массив узлов (типа 1), входящих в ренж
	 */
	this.$Nodes = function(){
		if(this.$range==null) return null;
    return this.$nn.$ChildNodes({'c':this.$range.commonAncestorContainer, 'start_offset':this.$SC(), 'end_offset':this.$EC(), 'type':this.$nn.$NODE});
	}

  /**
   *	Получение любых узлов частично или полностью входящих ввыделение
	 *	Возвращает:
	 *		массив узлов, входящих в ренж
	 */
	this.$AllNodes = function(){
		if(this.$range==null) return null;
    var $first_node = this.$SC();
    var $last_node = this.$EC();
    if(this.$range.commonAncestorContainer==$first_node&&$first_node==$last_node){
			return new Array($first_node);
		}
		else{
      return this.$nn.$ChildNodes({'c':this.$range.commonAncestorContainer, 'start_offset':$first_node, 'end_offset':$last_node});
    }
  }

  /**
   *  Первый текстовый узел
   *  Возвращает:
   *    текстовый узел или null если произошли ошибки или узел не найден.
   */
  this.$STN = function(){
    var $sc = this.$SC();
    if($sc==null) return null;
    if($sc.nodeType==1) {
      var $textnodes = this.$TextNodes();
      if($textnodes==null) return null;
      if($textnodes.length>0)
        return $textnodes[0];
      else
        return null;
    }
    if($sc.nodeType==3) return $sc;
  }


  /**
   *  Получить смещение в стартовом текстовом узле.
   *  Смещение возможно получить только если стартовый контейнер текстовый узел.
   *  Возвращает:
   *    смещение (колличество символов с начала строки) или null если произошли ошибки.
   */
  this.$STNO = function(){
    var $sc = this.$SC();
    if($sc==null) return null;
    if($sc.nodeType==1) return 0;
    if($sc.nodeType==3) return this.$range.startOffset;
  }

  /**
   *  Конечный текстовый узел
   *  Возвращает:
   *    текстовый узел или null если произошли ошибки или узел не найден.
   */
  this.$ETN = function(){
    var $ec = this.$EC();
    if($ec==null) return null;
    if($ec.nodeType==1) {
      var $textnodes = this.$TextNodes();
      if($textnodes==null) return null;
      if($textnodes.length>0)
        return $textnodes[$textnodes.length-1];
      else
        return null;
    }
    if($ec.nodeType==3) return $ec;
  }

  /**
   *  Получить смещение в конечном текстовом узле.
   *  Смещение возможно получить только если конечный контейнер текстовый узел.
   *  Возвращает:
   *    смещение (колличество символов с начала строки) или null если произошли ошибки.
   */
  this.$ETNO = function(){
    var $ec = this.$EC();
    if(!$ec) return null;
    if($ec.nodeType==1) {
      var $etn = this.$ETN();
      if($etn===null) return null;
      return $etn.textContent.length
    }
    if($ec.nodeType==3) {
      if(this.$range.endContainer!=$ec)
        return this.$ETN().length;
      else
        return this.$range.endOffset;
    }

    /*var $ec = this.$range.endContainer;
    if(!$ec) return null;
    if($ec.nodeType==1) {
      var $etn = this.$ETN();
      if($etn===null) return null;
      return $etn.textContent.length
    }
    if($ec.nodeType==3) {
      return this.$range.endOffset;
    }*/
  }

  /**
   *	Определение попадания узла $node в ренж
   *	Параметры:
   *    $node - узел, для которого необходимо определить попадание
	 */
	this.$RangeIntersectsNode = function($node) {
		try{
			var nodeRange = $node.ownerDocument.createRange();
			try {
				nodeRange.selectNode($node);
			}
			catch (e) {
				nodeRange.selectNodeContents($node);
			}
			return this.$range.compareBoundaryPoints(Range.END_TO_START, nodeRange) == -1 &&
				 this.$range.compareBoundaryPoints(Range.START_TO_END, nodeRange) == 1;
		}
		catch (ee) {
			return false;
		}
	}

}//$CRANGE


/**
 *	Работа с запросами на сервер.
 *	@author Кузнецов А.В.
 */
function $getXmlHttp(){
	var $xmlhttp;
	try{
		$xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
	}
	catch(e){
		try{
			$xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
		}
		catch(E){
			$xmlhttp = false;
		}
	}
	if (!$xmlhttp && typeof XMLHttpRequest!='undefined'){
		$xmlhttp = new XMLHttpRequest();
	}
	return $xmlhttp;
}

function $CSERVER(){
	//--имя экземпляра класса
	this.$class_name;
	//--объект для связи с сервером
	this.$xmlhttp;
	//--домен
	this.$domen;
	//--гл файл
	this.$MSName;
	//--параметр
	this.$param;

	/*--*
	*	Инициализация
	*	Параемтры:
	*		$cn - имя экзепляра класса
	*		$domen - домен
	*		$MSName - имя гл файла
	--*/
	function $Init($cn, $domen, $MSName){
		this.$class_name = $cn;
		this.$is_upload = false;
		this.$domen = $domen;
		this.$MSName = $MSName;
	}
	this.$Init = $Init;

	/*--*
	*	Получение данных с сервера
	*	Параметры:
	*		$query - запрос
	--*/
	function $execute($query, $sucuploadfunc, $erruploadfunc){
		//--проверка на присутсвие запроса
		if($query&&$query.length==0) return;
		//--получаем источник данных
		var $xmlhttp = $getXmlHttp();
		var $param = this.$param;

		$xmlhttp.open('GET', this.$domen+"/"+this.$MSName+$query, true);
		$xmlhttp.onreadystatechange = function(){
			if ($xmlhttp.readyState == 4) {
				// readyState==4, выключаем таймер
				if($xmlhttp.status == 200) {
					if($sucuploadfunc) $sucuploadfunc($xmlhttp.responseText, $param);
				}
				else{
					if($erruploadfunc) $erruploadfunc($xmlhttp.status, $xmlhttp.responseText, $param);
				}
			}
		}
		$xmlhttp.send(null);

	}
	this.$execute = $execute;

	/*--*
	*	Отправка данных на сервер
	--*/
	function $post($params, $sucuploadfunc, $erruploadfunc){
		if($params&&$params.length==0) return;
		var $xmlhttp = $getXmlHttp();
		var $param = this.$param;
		$xmlhttp.open('POST', this.$domen+"/"+this.$MSName, true);
		$xmlhttp.onreadystatechange = function(){
			if ($xmlhttp.readyState == 4) {
				if($xmlhttp.status == 200) {
					if($sucuploadfunc) $sucuploadfunc($xmlhttp.responseText, $param);
				}
				else{
					if($erruploadfunc) $erruploadfunc($xmlhttp.status, $xmlhttp.responseText, $param);
				}
			}
		}
		$xmlhttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
		$xmlhttp.send($params);
	}
	this.$post = $post;

}//$CSERVER


var Base64 = {

	// private property
	_keyStr : "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",

	// public method for encoding
	encode : function (input) {
		var output = "";
		var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
		var i = 0;

		input = Base64._utf8_encode(input);

		while (i < input.length) {

			chr1 = input.charCodeAt(i++);
			chr2 = input.charCodeAt(i++);
			chr3 = input.charCodeAt(i++);

			enc1 = chr1 >> 2;
			enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
			enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
			enc4 = chr3 & 63;

			if (isNaN(chr2)) {
				enc3 = enc4 = 64;
			} else if (isNaN(chr3)) {
				enc4 = 64;
			}

			output = output +
			this._keyStr.charAt(enc1) + this._keyStr.charAt(enc2) +
			this._keyStr.charAt(enc3) + this._keyStr.charAt(enc4);

		}

		return output;
	},

	// public method for decoding
	decode : function (input) {
		var output = "";
		var chr1, chr2, chr3;
		var enc1, enc2, enc3, enc4;
		var i = 0;

		input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");

		while (i < input.length) {

			enc1 = this._keyStr.indexOf(input.charAt(i++));
			enc2 = this._keyStr.indexOf(input.charAt(i++));
			enc3 = this._keyStr.indexOf(input.charAt(i++));
			enc4 = this._keyStr.indexOf(input.charAt(i++));

			chr1 = (enc1 << 2) | (enc2 >> 4);
			chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
			chr3 = ((enc3 & 3) << 6) | enc4;

			output = output + String.fromCharCode(chr1);

			if (enc3 != 64) {
				output = output + String.fromCharCode(chr2);
			}
			if (enc4 != 64) {
				output = output + String.fromCharCode(chr3);
			}

		}

		output = Base64._utf8_decode(output);

		return output;

	},

	// private method for UTF-8 encoding
	_utf8_encode : function (string) {
		string = string.replace(/\r\n/g,"\n");
		var utftext = "";

		for (var n = 0; n < string.length; n++) {

			var c = string.charCodeAt(n);

			if (c < 128) {
				utftext += String.fromCharCode(c);
			}
			else if((c > 127) && (c < 2048)) {
				utftext += String.fromCharCode((c >> 6) | 192);
				utftext += String.fromCharCode((c & 63) | 128);
			}
			else {
				utftext += String.fromCharCode((c >> 12) | 224);
				utftext += String.fromCharCode(((c >> 6) & 63) | 128);
				utftext += String.fromCharCode((c & 63) | 128);
			}

		}

		return utftext;
	},

	// private method for UTF-8 decoding
	_utf8_decode : function (utftext) {
		var string = "";
		var i = 0;
		var c = c1 = c2 = 0;

		while ( i < utftext.length ) {

			c = utftext.charCodeAt(i);

			if (c < 128) {
				string += String.fromCharCode(c);
				i++;
			}
			else if((c > 191) && (c < 224)) {
				c2 = utftext.charCodeAt(i+1);
				string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
				i += 2;
			}
			else {
				c2 = utftext.charCodeAt(i+1);
				c3 = utftext.charCodeAt(i+2);
				string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
				i += 3;
			}

		}

		return string;
	}

}

//--------------------------------
//  Ядро корзины товаров.
//--------------------------------

function $CBASKET(){
  
  //формирование хранилища
  $(function(){
    if(!$wn.$cookie.$Is('basket')){
      $wn.$cookie.$Set({name:'basket', expires:'+1 day'});
    }
  });
  
  /**
   *	Добавление элемента.
   *	@param int $id Ид товара.
   *	@param int $count Количество единиц добавляемого элемента.
   *	@param string $params Параметры элемента.
   *	@param func $callback Функция, выполняемая после добавления элемента.
   *    Данная функция получает 3 параметра: ид изменяемого элемента, количество, и параметры элемента.
   *	@return bool Возвращает true если все операторы выполнились успешно, иначе false.
   */
  this.$AddItem = function($id, $count, $params, $callback){
    //проверка входящих параметров
    if($id===undefined) return false;
    if($count===undefined) $count=1;
    if(!$params) $params="";
    //получение данных корзины товаров
    var $coocie_data = $wn.$cookie.$Get('basket');
    var $tovar_count = $wn.$kvd.$Count($coocie_data);
    var $new_coocie_data = "";
    var $new_item_data = "";
    //поиск товара по иду и параметрам
    var $key_found_item = this.$FindItemKey($id, $params);
    if($key_found_item===false) {
      //добавление товара
      $new_item_data = $wn.$kvd.$Set("id", $id, "");
      $new_item_data = $wn.$kvd.$Set("count", $count, $new_item_data);
      $new_item_data = $wn.$kvd.$Set("params", $params, $new_item_data);
      $new_coocie_data = $wn.$kvd.$Set($wn.$datetime.$Now(), $new_item_data, $coocie_data);
    }
    else{
      //добавление количества у существующего товара
      var $found_item_data = $wn.$kvd.$Get($key_found_item, $coocie_data);
      var $current_item_count = $wn.$kvd.$Get('count', $found_item_data);
      $new_item_data = $wn.$kvd.$Set('count', parseInt($current_item_count)+parseInt($count), $found_item_data);
      $new_coocie_data = $wn.$kvd.$Set($key_found_item, $new_item_data, $coocie_data);
    }     
    $wn.$cookie.$Set({name:'basket', value:$new_coocie_data, expires:'+1 day'});
    if($callback) $callback($wn.$kvd.$Get('id', $new_item_data), $wn.$kvd.$Get('count', $new_item_data), $wn.$kvd.$Get('params', $new_item_data));
    return true;
  }//$AddItem

  /**
   *	Удаление элемента.
   *	@param int $id Ид элемента.
   *	@param int $count Количество единиц удаляемого элемента.
   *	@param string $params Параметры элемента.
   *	@param func $callback Функция, выполняемая после добавления элемента.
   *    Данная функция получает 3 параметра: ид изменяемого элемента, количество, и параметры элемента.
   *	@return bool Возвращает true если все операторы выполнились успешно, иначе false.
   */
  this.$DelItem = function($id, $count, $params, $callback){
    //проверка входящих параметров
    if($id===undefined) return false;
    if($count===undefined) $count=1;
    if(!$params) $params="";
    //получение данных корзины товаров
    var $coocie_data = $wn.$cookie.$Get('basket');
    var $tovar_count = $wn.$kvd.$Count($coocie_data);
    var $new_coocie_data = "";
    //поиск товара по иду и параметрам
    var $key_found_item = this.$FindItemKey($id, $params);
    if($key_found_item===false) {
      //товара нет = выход из функции
      return true;
    }
    else{
      //удаление количества у существующего товара
      var $found_item_data = $wn.$kvd.$Get($key_found_item, $coocie_data);
      var $current_item_count = parseInt($wn.$kvd.$Get('count', $found_item_data));
      var $new_found_item_data = "";
      if($current_item_count!=0&&$current_item_count>$count)
        $new_found_item_data = $wn.$kvd.$Set('count', parseInt($current_item_count)-parseInt($count), $found_item_data);
      else
        $new_found_item_data = $wn.$kvd.$Set('count', 0, $found_item_data);
      $new_coocie_data = $wn.$kvd.$Set($key_found_item, $new_found_item_data, $coocie_data);
      //
      $wn.$cookie.$Set({name:'basket', value:$new_coocie_data, expires:'+1 day'});
      if($callback) $callback($wn.$kvd.$Get('id', $new_found_item_data), $wn.$kvd.$Get('count', $new_found_item_data), $wn.$kvd.$Get('params', $new_found_item_data)); 
      return true;
    }     
  }//$DelItem

  /**
   *	Подсчет количества элементов в корзине.
   */
  this.$CountItem = function(){
    var $coocie_data = $wn.$cookie.$Get('basket');
    return $wn.$kvd.$Count($coocie_data);
  }//CountItem

  /**
   *	Наличие товара с определенным идом и параметрами.
   *	@param int $id Ид элемента.
   *	@param string $params Параметры элемента.
   *	@return string Возвращает, уникальный ид товара иначе false.
   */
  this.$FindItemKey = function($id, $params){
    var $cookie_data = $wn.$cookie.$Get('basket');
    var $tovar_arr = $wn.$kvd.$AsArray($cookie_data);
    var $tovar_data_arr;
    for(var $key in $tovar_arr){
      $tovar_data_arr = $wn.$kvd.$AsArray($wn.$kvd.$Decode($tovar_arr[$key]));
      if(
        ($tovar_data_arr.id==$id&&$wn.$kvd.$Decode($tovar_data_arr.params)==$params)||
        ($tovar_data_arr.id==$id&&!$tovar_data_arr.params&&!$params)
      ) return $key;
    }
    return false;
  }//$FindItemKey
  
  /**
   *	Получение параметров товара ввиде массива.
   *	@param int $id Ид элемента.
   *	@param string $params Параметры элемента.
   *	@return string Возвращает, о товаре ввиде массива иначе false.
   */  
  this.$ItemData = function($id, $params){
    var $cookie_data = $wn.$cookie.$Get('basket');
    var $key_found_item = this.$FindItemKey($id, $params);
    if($key_found_item===false) return false;
    var $item_data = $wn.$kvd.$Get($key_found_item, $cookie_data);
    var $id = parseInt($wn.$kvd.$Get('id', $item_data));
    var $count = parseInt($wn.$kvd.$Get('count', $item_data));
    var $params = $wn.$kvd.$Get('params', $item_data);
    return {'id':$id, 'count':$count, 'params':$params};
  }//$ItemData

  /*this.$Look = function(){
    var $cookie_data = $wn.$cookie.$Get('basket');
    var $tovar_arr = $wn.$kvd.$AsArray($cookie_data);
    var $tovar_data_arr;
    for(var $key in $tovar_arr){
      $tovar_data_arr = $wn.$kvd.$AsArray($wn.$kvd.$Decode($tovar_arr[$key]));
      console.log($tovar_data_arr['id']+", "+$tovar_data_arr['count']+", "+$tovar_data_arr['params']+";");
    }
  }*///$Look

}//$CBASKET

//--------------------------------
//  Интерфейс "Карточка товара".
//--------------------------------

function $CCARDPRODUCT($tovar_id){
  
  //ид товара
  this.$tovar_id = $tovar_id;
  
  //объект корзины
  this.$basket = new $CBASKET();
  
  this.$UpdateBasketTable = function(){
    var $bi = new $CBASKETINTERFACE();
    $bi.$UpdateBasketTable();
  }

  /**
   * Добавление товара по штучно.
   */
  this.$AddItem = function (){  
    this.$basket.$AddItem(this.$tovar_id, 1, this.$ItemParams()); 
    this.$UpdateBasketTable();
  }//$AddItem

  /**
   * Удаление товара из корзины по штучно.
   */
  this.$DelItem = function(){
    this.$basket.$DelItem(this.$tovar_id, 1, this.$ItemParams());     
    this.$UpdateBasketTable(); 
  }//$DelItem
  
  /**
   * Полное удаление товара из корзины.
   */
  this.$ReleaseItem = function(){
    var $params = this.$ItemParams();
    var $item_params = this.$basket.$ItemData(this.$tovar_id, $params);
    this.$basket.$DelItem(this.$tovar_id, $item_params.count, $params); 
    this.$UpdateBasketTable();
  }//$ReleaseItem
  
  /**
   * Количество данного товара в корзине товаров.
   */
  this.$ItemCount = function(){
    var $params = this.$ItemParams();
    var $item_params = this.$basket.$ItemData(this.$tovar_id, $params);
    return $item_params.count; 
  }//$ItemCount

  /**
   * Параметры товара.
   */
  this.$ItemParams = function(){
    var $params = "";
    $('select[properties_id]').each(function($i,$el){
      $params+=$el.options[$el.selectedIndex].getAttribute('properties_values_id')+",";
    });
    $params = $params.substring(0, $params.length-1);
    return $params;
  }//$ItemParams
}//$CCARDPRODUCT

//--------------------------------
//  Интерфейс "Корзина товаров".
//--------------------------------

function $CBASKETINTERFACE(){
  
  /**
   * Обновление списка товаров в корзине.
   */
  this.$UpdateBasketTable = function (){
    $("#basket_content").load($domen+"/"+$mfn+"?o=shp&p="+$p+"&cmd=basket_table&e=price_basket");
  }//$UpdateBasketTable

  /**
   * Загрузка формы заказа.
   */
  this.$ShowOrderForm = function (){
    $("#basket_content").load($domen+"/"+$mfn+"?o=shp&p="+$p+"&cmd=order_form&e=price_basket");
  }//$UpdateBasketTable
  
  /**
   * Закрытие корзины товаров.
   */ 
  this.$CloseBasket = function (){
    $('#propC').attr("style", "display:none;");
    this.$UpdateBasketTable();
  }//$CloseBasket
  
  /**
   * Открытие корзины товаров.
   */
  this.$OpenBasket = function (){
    $('#propC').attr("style", "display:block;");
  }//$OpenBasket
  
  //--
  
  this.$AddEd = function ($ths){
    var $n = 1;
    this.$AddTovarCount($n, $ths);
    this.$AddTovarPrice($n,$ths)
    this.$UpdateCountAll($ths);
    this.$UpdatePriceAll($ths);
    var $basket = new $CBASKET();
    var $tovar_uid = this.$TovarIdParams($ths);
    $basket.$AddItem($tovar_uid.id, $n, $tovar_uid.params);
  }//$AddEd
  
  this.$RemoveEd = function ($ths){
    var $n = 1;
    this.$RemoveTovarCount($n, $ths);
    this.$RemoveTovarPrice($n,$ths)
    this.$UpdateCountAll($ths);
    this.$UpdatePriceAll($ths);
    var $basket = new $CBASKET();
    var $tovar_uid = this.$TovarIdParams($ths);
    $basket.$DelItem($tovar_uid.id, $n, $tovar_uid.params);
  }//$RemoveEd
  
  //--
  
  /**
   * Объект таблицы корзины товаров.
   */
  this.$GetTableObj = function($ths){
    return $ths.parentNode.parentNode.parentNode.parentNode.parentNode;
  }
  
  /**
   * Общее колличество товаров в корзине.
   */
  this.$UpdateCountAll = function($ths){
    var $count = 0;
    $('tr > td:nth-child(4) > p > span:nth-child(1)', this.$GetTableObj($ths)).each(function($i, $el){
      $count += parseInt($el.innerHTML);
    });
    this.$SetCountAll($count);
  }
  this.$GetCountAll = function(){
    return parseInt( $('#count_sum_all').html() );
  }
  this.$SetCountAll = function($count){
    $('#count_sum_all').html( parseInt($count) );
  }  
  
  /**
   * Общяя стоимость всех товаров в корзине.
   */
  this.$UpdatePriceAll = function($ths){
    var $sum = 0.0;
    $('tr > td:last-child > p > span', this.$GetTableObj($ths)).each(function($i, $el){
      $sum += parseFloat($el.innerHTML);
    });
    this.$SetPriceAll($sum);
  }
  this.$SetPriceAll = function($price){
    $('#price_sum_all').html(parseFloat($price));
  }  
  this.$GetPriceAll = function(){
    return parseFloat($('#price_sum_all').html());
  } 
  
  /**
   * Колличество конкретного товара.
   */
  this.$AddTovarCount = function ($count, $ths){
    this.$SetTovarCount(this.$GetTovarCount($ths)+parseInt($count), $ths);
  } 
  this.$RemoveTovarCount = function ($count, $ths){
    $count = parseInt($count);  
    this.$AddTovarCount($count>0?$count*(-1):$count, $ths);
  } 
  this.$SetTovarCount = function ($count, $ths){
    $count = parseInt($count);
    $ths.parentNode.childNodes[0].innerHTML = $count<0?0:$count;
  } 
  this.$GetTovarCount = function ($ths){
    return parseInt($ths.parentNode.childNodes[0].innerHTML);
  }
  
  /**
   * Стоимость единицы конкретного товара.
   */  
  this.$GetTovarPriceEd = function ($ths){
    return parseFloat($ths.parentNode.parentNode.parentNode.lastChild.childNodes[0].childNodes[0].getAttribute('ed'));
  }  
  
  /**
   * Стоимость конкретного товара в зависимости от его колличества.
   */
  this.$AddTovarPrice = function ($count, $ths){
    this.$SetTovarPrice(this.$GetTovarPrice($ths)+(parseInt($count)*this.$GetTovarPriceEd($ths)), $ths);
  } 
  this.$RemoveTovarPrice = function ($count, $ths){
    $count = parseInt($count);  
    this.$AddTovarPrice($count>0?$count*(-1):$count, $ths);
  } 
  this.$SetTovarPrice = function ($price, $ths){
    $price = parseFloat($price);
    $ths.parentNode.parentNode.parentNode.lastChild.childNodes[0].childNodes[0].innerHTML = $price<0?0.0:$price;
  } 
  this.$GetTovarPrice = function ($ths){
    return parseFloat($ths.parentNode.parentNode.parentNode.lastChild.childNodes[0].childNodes[0].innerHTML);
  } 
  
  /**
   * Ид товара и его параметры ввиде массива.
   */
  this.$TovarIdParams = function($ths){
    var $val = $('td:first-child > p', $ths.parentNode.parentNode.parentNode)[0].innerHTML.split('|');
    return {"id":$val[0], "params":$val[1]};
  }
  
}//$CBASKETINTERFACE

//--------------------------------
//  Интерфейс каталога товаров
//--------------------------------

/**
 * Кнопка показать еще товаров.
 */
function $ShowMore($selector){  
  var $tovars = $($selector);
  //подсчет количества отображаемых товаров
  $offset = parseInt($tovars.size());
  // 
  $.ajax({
    url: $domen+'/'+$mfn+'?o=shp&cmd=showmore&e=price_catalog&p='+$p+'&catalog='+$catalog_id+'&offset='+$offset,
    success: function($data){
      $tovars[0].parentNode.innerHTML = $tovars[0].parentNode.innerHTML+$data;
      //
      $('a[rel=lightbox]').lightBox({
        'noMoreScreen':true,
        'imageLoading': $domen+'/script/lightbox/images/lightbox-ico-loading.gif',
        'imageBtnClose': $domen+'/script/lightbox/images/lightbox-btn-close.gif',
        'imageBtnPrev': $domen+'/script/lightbox/images/lightbox-btn-prev.gif',
        'imageBtnNext': $domen+'/script/lightbox/images/lightbox-btn-next.gif',
        'imageBlank':$domen+'/script/lightbox/images/lightbox-blank.gif',
        'txtImage':'Изображение',
        'txtOf':'из',
        'noNavigation':true
      });

    },
    error:function($data){

    }
  });
};//
  

//--------------------------------
//  
//--------------------------------

function $UpdateButtonsAdd(){
  var $basket = new $CBASKET();
  //изменение кнопок у уже добавленных в корзину товаров
  var $item_id;    
  $("button[but_add_tovar_id]").each(function($i, $el){
    $item_id = $el.getAttribute("but_add_tovar_id");
    if($item_id){
      if($basket.$IsItem($item_id)){
        $el.setAttribute("class", "add_yet"); 
        $el.setAttribute("title", "Этот товар уже добавлен в корзину. Добавить еще?");         
      }
      else{
       $el.setAttribute("class", "but_add_tovar"); 
       $el.setAttribute("title", "Добавить в корзину."); 
      }      
    }    
  });
}

function $UpdateMinibasket(){
  var $basket = new $CBASKET();
  var $tovar_count = $basket.$CountItem();
  var $word = "";
  if($tovar_count==1) $word = "товар";
  if($tovar_count==0) $word = "товаров";
  if($tovar_count>1&&$tovar_count<5) $word = "товара";
  if($tovar_count>4) $word = "товаров";
  $('#minibasket-tovar-count').html($tovar_count+" "+$word);
  setTimeout(function(){
    $UpdateMinibasket();
  }, 2000);
}

