/*
 * функции которые были в magazilla.js
 * ставим их в самое начало... критичны к загрузке
**/
function class_2_close(id){
	var el = $(id);
	if (el) el.className = el.className.replace(/-open/i, "-close");
}
function class_2_open(id){
	var el = $(id);
	if (el) el.className = el.className.replace(/-close/i, "-open");
}
function class_2_change(id, from, to, mode){   
  var ids = id.split(",");//тут id разделены запятыми
  //проходим по каждому id
  ids.map(function(id){
      //значения по умолчанию
      if (typeof from == "undefined") from = "-close";
      if (typeof to == "undefined") from = "-open";
      var el = $(id);
      if (el) {
        //здесь "(?=$| )" - для того, чтоб если оперируем "вложенными" классами
        //[такими как "aaa sort bbb" и "ccc sort-select ddd"], более-менее хорошо работало
        var from_r = new RegExp(from+"(?=$| )", "i"),
            to_r = new RegExp(to+"(?=$| )", "i");

        if (typeof mode != "undefined") {
            //меняем "в одностороннем порядке"
            el.className = from_r.test(el.className) ? el.className.replace(from_r, to) : el.className;
        }
        //переключаем классы
        else {
            el.className = from_r.test(el.className) ? el.className.replace(from_r, to) : el.className.replace(to_r, from);
        }
      }
  });
}

function stopEventPropagation(event){
    //запрещаем дальнейшее "всплывание" события
    if (event.stopPropagation)
        event.stopPropagation();
    event.cancelBubble = true;
}

//показывает элемент
function show_obj(id){
    var ids = id.split(",");//тут id разделены запятыми
    //проходим по каждому id
    ids.map(function(id){
        var el = $(id);
        if (el) el.style.display="";
    });
}
//скрывает элемент
function hide_obj(id){
    var ids = id.split(",");//тут id разделены запятыми
    //проходим по каждому id
    ids.map(function(id){
        var el = $(id);
        if (el) el.style.display="none";
    });
}

//отвечать в даннывй момент можно только на 1 пост
var opened_div = null;
var opened_answer_phrase = null;
function new_answer(div_id,answer_phrase_id){
	if (div_id != opened_div){
		hide_obj('did-'+opened_div);
		class_2_close('answer-'+opened_answer_phrase);
		opened_div = div_id;
		opened_answer_phrase=answer_phrase_id;
	}
}

/* функция ограничивает количество символов которые можно ввести в textarea или input type="text" */
function cutup(node, n){
	if (node.tagName == "TEXTAREA" || node.tagName == "INPUT"){
		if (node.value.length > n) node.value = node.value.substr(0, parseInt(n));
	}
}

//фнк производит эмуляцию клика на заданную ссылку
function clc(id){
    try {
        var node = $(id);
        if (typeof node != 'undefined' && node.nodeName.toUpperCase() == 'A'){
            if (node.click) node.click();
            else {
                location.href = node.href;
            }
        }
    } catch(e) {}
}

;(function(){
	
	//некоторые константы для работы с тегами (append, ...)
	var rleadingWhitespace = /^\s+/,
		rxhtmlTag = /(<([\w:]+)[^>]*?)\/>/g,
		rselfClosing = /^(?:area|br|col|embed|hr|img|input|link|meta|param)$/i,
		rtagName = /<([\w:]+)/,
		rtbody = /<tbody/i,
		rhtml = /<|&\w+;/,
		rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i,  // checked="checked" or checked (html5)
		fcloseTag = function( all, front, tag ) {
			return rselfClosing.test( tag ) ?
				all :
				front + "></" + tag + ">";
		},
		wrapMap = {
			option: [ 1, "<select multiple='multiple'>", "</select>" ],
			legend: [ 1, "<fieldset>", "</fieldset>" ],
			thead: [ 1, "<table>", "</table>" ],
			tr: [ 2, "<table><tbody>", "</tbody></table>" ],
			td: [ 3, "<table><tbody><tr>", "</tr></tbody></table>" ],
			col: [ 2, "<table><tbody></tbody><colgroup>", "</colgroup></table>" ],
			area: [ 1, "<map>", "</map>" ],
			_default: [ 0, "", "" ]
		};
	
		wrapMap.optgroup = wrapMap.option;
		wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
		wrapMap.th = wrapMap.td;
				  	
	//расширяем прототип Array методом map()
	//описание и код взят с: https://developer.mozilla.org/En/Core_JavaScript_1.5_Reference:Objects:Array:map
	if (!Array.prototype.map) {
		Array.prototype.map = function(fun /*, thisp*/){
			var len = this.length >>> 0;
			if (typeof fun != "function")
				throw new TypeError();
		
			var res = new Array(len);
			var thisp = arguments[1];
			for (var i = 0; i < len; i++){
				if (i in this)
					res[i] = fun.call(thisp, this[i], i, this);
			}
		
			return res;
		};
	}
        
    //расширяем прототип String методом capitalize()
	//описание и код взят с: https://ajax.googleapis.com/ajax/libs/prototype/1.7.0.0/prototype.js
	if (!String.prototype.capitalize) {
		String.prototype.capitalize = function(){
            return this.charAt(0).toUpperCase() + this.substring(1).toLowerCase();
		};
	}
	
	window.mui_confirm = function(event, str){
		var is_confirmed = confirm(str);
			
		if (!is_confirmed && event){
			//запрещаем дальнейшее "всплывание" события
			if (event.stopPropagation) 
				event.stopPropagation();
			event.cancelBubble = true;
				
			//отменяем действие по умолчанию
			if (event.preventDefault)//необходимо для addEventListener				
				event.preventDefault();
			event.returnValue = false;//необходимо для attachEvent
			return false;
		}
			
		return true;
	}
        
	//
	//глобальные переменные для mui.js
	var	toString = Object.prototype.toString;
	//флаг, добавлены ли обработчики на событие загрузки DOM
	var readyBound = false,
		//соответствие свойства display тегу
		elemdisplay = {};
	
	//
	//фнк. добавляет обработчики на загрузку DOM
	function bindReady(){
		if ( readyBound ) return;
		readyBound = true;
	
		// последние сборки Mozilla, Opera и webkit поддерживают это событие
		if ( document.addEventListener ) {
			document.addEventListener( "DOMContentLoaded", function(){
				document.removeEventListener( "DOMContentLoaded", arguments.callee, false );
				mui._ready();
			}, false );
	
		// если использована событийная модель IE
		} else if ( document.attachEvent ) {
			// для предотвращениея запуска перед onload,
			// может быть поздновато, но безопасно также для iframes
			document.attachEvent("onreadystatechange", function(){
				if ( document.readyState === "complete" ) {
					document.detachEvent( "onreadystatechange", arguments.callee );
					mui._ready();
				}
			});
	
			// если IE и не iframe
			// продолжаем проверять, чтобы увидеть что document is ready
			if ( document.documentElement.doScroll && window == window.top ) (function(){
				if ( mui.isReady ) return;
	
				try {
					// если используется IE, используем trick by Diego Perini
					// http://javascript.nwbox.com/IEContentLoaded/
					document.documentElement.doScroll("left");
				} catch( error ) {
					setTimeout( arguments.callee, 0 );
					return;
				}
	
				// and execute any waiting functions
				mui._ready();
			})();
		}
	
		// на всякий случай добавляем обработчик, который 100% запустится
		window.onload = mui._ready;
	};
			  
	var mui = window.mui = function() {
		return new mui.prototype.init();
	};		

	mui.prototype = {
		
		//конструктор объекта
		init : function(){},
		
		//добавляет фнк. в список на исполнение после загрузки DOM
		ready: function(fn) {
			// добавляем обработчики
			bindReady();
	
			// когда DOM уже готов
			if ( mui.isReady )
				// мгновенно запускаем если DOM уже готов
				fn.call( document, mui );
	
			// если нет, добавляем в список на запуск потом
			else
				mui.readyList.push( fn );
	
			return this;
		},
		
		//сокращенная форма для document.getElementById()
		$ : function $(id){
			var node = document.getElementById(id);
			return (node && node.id == id) ? node : undefined;
		},
		
		//делает запрос серверу с url == source, после ответа передает управление action_fnk(ответ, id элемента DOM для манипуляций)
		//param: [source] = адрес URL откуда взять данные (String)
		//param: [target] = id элемента DOM (String)
		//param: [action_fnk] = функция-обработчик данных (Function Object)
		//return: [] = void
		loadJSON : function (source, target, action_fnk){
			//для того чтобы использовать сокращенную запись вызова loadJSON
			var action_fnk = action_fnk || function(jdata, jtarget){
                try {
                    
                    var node = (jtarget.nodeType) ? jtarget: $(jtarget);
                    mui.evalScripts(jdata);
                    jdata = mui.stripScripts(jdata);

                    //если вставляем в элемент TR || TABLE
                    var nName = node.nodeName.toUpperCase();
                    if (nName == 'TR' || nName == 'TABLE'){
                        var context = node.ownerDocument || node[0] && node[0].ownerDocument || document;
                        // Fix "XHTML"-style tags in all browsers
                        jdata = jdata.replace(rxhtmlTag, fcloseTag);

                        // Trim whitespace, otherwise indexOf won't work as expected
                        var tag = (rtagName.exec( jdata ) || ["", ""])[1].toLowerCase(),
                            wrap = wrapMap[ tag ] || wrapMap._default,
                            depth = wrap[0],
                            div = context.createElement("div");

                        // Go to html and back, then peel off extra wrappers
                        div.innerHTML = wrap[1] + jdata + wrap[2];

                        // Move to the right depth
                        while ( depth-- ) {
                            div = div.lastChild;
                        }

                        //в msie нужно добавлять <tr в <tbody, а не к <table
                        if (mui.browser().msie){
                            if (node && node.firstChild && node.firstChild.nodeName.toUpperCase() == 'TBODY'){
                                node = node.firstChild;//node == <tbody
                            }
                        }

                        for (var i = 0, l = div.childNodes.length; i < l; i++) {
                            node.appendChild(div.childNodes[0]);
                        }
                    }
                    else
                        node.innerHTML = jdata;

                    mui.repaint(node);
                } catch (e) {}
			}
                        
			//получаем случайное название для функции callback
			var jsonh = 'jsonp'+(+new Date)+Math.round(Math.random()*100);
			var loader = this.loader;
			var self = this.srcElement;

			//создаем функцию callback в глобальном окружении
			window[ jsonh ] = function(data/*данные с сервера*/){                            
                //убираем прелоадер
                try{
                    if (loader && loader.nodeType) self.removeChild(loader);
                } catch(e){}
                action_fnk(data, target);
                //"собираем мусор" (Garbage collect)
                window[ jsonh ] = undefined;
                try{
                    delete window[ jsonh ];
                    if (head) head.removeChild(script);
                } catch(e){}
			};
			//стандартная загрузка данных через script include в head
			var head = document.getElementsByTagName("head")[0] || document.documentElement;
			var script = document.createElement("script");
			//передаем функцию callback как параметр URL
			script.src = source + (source.match(/\?/) ? "&" : "?") + 'callback='+jsonh;
			head.appendChild(script);
		},//end loadJSON()

		//extend object (в том числе можно расширять и саму библиотеку)
        //https://github.com/mootools/mootools-core/blob/1.2x/Source/Core/Core.js#L197
		extend : function(original, extended) {
			if (typeof extended == 'undefined') {
				extended = original;
				original = this;
			}
			for (var key in (extended || {})) original[key] = extended[key];
		    return original;
		}
	}
	
	//назначаем уже сформированный прототип как прототип для mui
	mui.prototype.init.prototype = mui.prototype;
	//выполняем конструктор
	mui = window.mui = mui.apply(this, arguments);
	//для сокращения записи
	window.$ = mui.$;
	
	mui.extend({
		isReady: false,
		readyList: [],
		// запускаем когда DOM уже готов
		_ready: function() {
			// проверяем, что эта фнк не запускалась (DOM еще не был загружен)
			if ( !mui.isReady ) {
				// запоминаем что DOM уже готов
				mui.isReady = true;
	
				// выполняем функции, которые ожидают загрузки DOM
				if ( mui.readyList ) {
					// выполняем список функций
					mui.readyList.map(function(fn){
						fn.call( document, mui );
					});
	
					// обнуляем список функций на выполнение
					mui.readyList = null;
				}
			}
		}
	});

    //see here https://jquerykeyboard.googlecode.com/hg/jquery.keyboard.js
    mui.meta_keys = [/*tab*/9,/*shift*/16,/*ctrl*/17,/*alt*/18,/*menu*/93,/*pause*/19,/*cmd*/91,/*insert*/45,/*home*/36,/*pageup*/33,/*end*/35,/*pagedown*/34]
       .concat([/*f1*/112,/*f2*/113,/*f3*/114,/*f4*/115,/*f5*/116,/*f6*/117,/*f7*/118,/*f8*/119,/*f9*/120,/*f10*/121,/*f11*/122,/*f12*/123])
       .concat([/*capslock*/20,/*numlock*/144,/*scrolllock*/145])
       .concat([/*npslash*/11,/*npstar*/106,/*nphyphen*/109,/*npplus*/107,/*npdot*/110]);
	
	mui.extend({
		//удаляет пробельные символы в начале и конце строки
		trim : function (str){
			//fastest [http://blog.stevenlevithan.com/archives/faster-trim-javascript]
			return str.replace(/^\s\s*/, '').replace(/\s\s*$/, '');
		},//end trim()
		
		//переопределяем window.escape для того чтобы на выходе имели windows-1251
		escape : function (str){
			//инициализируем таблицу перевода
			var trans = [];
			for (var i = 0x410; i <= 0x44F; i++){
				trans[i] = i - 0x350;//А-Яа-я	
			}
            
			trans[0x401] = 0xA8;//Ё
			trans[0x451] = 0xB8;//ё
            //украинские символы http://79.174.68.219/forums/programming/javascript/misc/thread/37933.xhtml
            trans[0x457] = 0xBF;//ї
            trans[0x407] = 0xAF;//Ї
            trans[0x456] = 0xB3;//і
            trans[0x406] = 0xB2;//І
            trans[0x404] = 0xBA;//є
            trans[0x454] = 0xAA;//Є

			var ret = [];
			//составляем массив кодов символов, попутно переводим кириллицу
			for (var i = 0; i < str.length; ++i){
				var code = str.charCodeAt(i);
				if (typeof trans[code] != 'undefined')
					code = trans[code];
				if (code <= 0xFF)
					ret.push(code);
			}
		  	return escape(String.fromCharCode.apply(null, ret));
		},
		
		//-- фнк. добавляет/меняет атрибут source на query string
		//образованную по виду: url?ids[1]=value1&ids[2]=value2
		//--пример использования:
		//
		//Your Nickname: <input type="text" id='id1' NaMe="nick" /><br />
		//<input type="submit" value="submit" onclick="mui.fill_source_attr(this, 'jsource', 'http://magazilla.ua/', ['id1'])">
		//
		//параметры:
		//obj: dom node - к какому элементу добавлять атрибут [часто будут указывать this]
		//source_attr: имя атрибута [например "jsource"]
		//url: к какому адресу будут добавляться параметры
		//ids - массив id input-ов [например ['id1', 'id2']]
		fill_source_attr : function(obj, source_attr, url, ids){
			source_attr = mui.trim(source_attr); 
			if (typeof source_attr === "string" && source_attr.length > 0){//какой атрибут установить
				if (typeof url === "string" && url.length > 0){//к какому url добавить query string
					var el = {}, name = '';
					
					ids.map(function(id){
						el = $(id);
						if (el){
							name = (el.nodeType) ? el.getAttribute('name') : null;
							if (name){//если у искомого элемента есть атрибут name								
								url += (url.match(/\?/) ? "&" : "?") + name + "=" + (escape(el.value) || "");
							}
						}
					});
					
					//ставим атрибут source
					if (obj.nodeType){
						obj.setAttribute(source_attr, url);
					}
				}
			}
		},//end fill_source_attr()
				
		//если elem содержится в массиве - то возвращаем номер, если нет - то -1
		//param: [elem] = untyped
		//param: [array] = Array
		//return: [] = Number
		inArray : function (elem, arr) {
			if (!arr) return -1;
			for (var i = 0, length = arr.length; i < length; i++)
				if (arr[i] == elem) return i;
			return -1;
		},//end inArray()
		
		//проверяем, является ли obj функцией
		isFunction: function( obj ) {
			return toString.call(obj) === "[object Function]";
		},
	
		//проверяем, является ли obj массивом
		isArray: function( obj ) {
			return toString.call(obj) === "[object Array]";
		},
		
		//фнк вырезает с content все теги <script />
		stripScripts : function(content) {
			if (!content) return "";
			var s_re = '<script[^>]*>([\\S\\s]*?)<\/script>';
			return content.replace(new RegExp(s_re, 'img'), '');
		},//end stripScripts()

        //фнк вырезает с content все теги
		stripTags : function(v) {
            return !v ? v : String(v).replace(/<\/?[^>]+>/gi, '');
		},//end stripTags()

		//фнк исполняет все скрипты находящиеся в строке content
		evalScripts : function(content) {
			if (!content) return "";
			return mui.extractScripts(content).map(function(script) { return mui.globalEval(script) });
		},//end evalScripts()
		
		//фнк выделяет скрипты со строки content в массив
		extractScripts : function(content) {
			var s_re = '<script[^>]*>([\\S\\s]*?)<\/script>',
				matchAll = new RegExp(s_re, 'img'),
				matchOne = new RegExp(s_re, 'im');
				
			return (content.match(matchAll) || []).map(function(scriptTag) {
				return (scriptTag.match(matchOne) || ['', ''])[1];
			});
		},//end extractScripts()
		
		// Evalulates a script in a global context
		// большинство кода взято с jquery v1.3.2
		globalEval: function( data ) {
			var root = document.documentElement,
				script = document.createElement("script"),
				id = "script" + (new Date).getTime(),
				scriptEval = false;
			
			script.type = "text/javascript";
			try {
				script.appendChild( document.createTextNode( "window." + id + "=1;" ) );
			} catch(e){}
			root.insertBefore( script, root.firstChild );
			// Make sure that the execution of code works by injecting a script
			// tag with appendChild/createTextNode
			// (IE doesn't support this, fails, and uses .text instead)
			if ( window[ id ] ) {
				scriptEval = true;
				delete window[ id ];
			}
			root.removeChild( script );
			
			if ( data && /\S/.test(data) ) {
				// Inspired by code by Andrea Giammarchi
				// http://webreflection.blogspot.com/2007/08/global-scope-evaluation-and-dom.html
				var head = document.getElementsByTagName("head")[0] || document.documentElement,
					script = document.createElement("script");
	
				script.type = "text/javascript";
				if (scriptEval){
					script.appendChild( document.createTextNode( data ) );
				}
				else 
					script.text = data;
	
				// Use insertBefore instead of appendChild  to circumvent an IE6 bug.
				// This arises when a base node is used (#2709).
				head.insertBefore( script, head.firstChild );
				head.removeChild( script );
			}
		},//end globalEval()
		
		//клонирует object
		//param: [object] = Object
		//return: [] = Object
		clone : function (object){
			return mui.extend({}, object);
		},//end clone
	
		//возвращает атрибуты элемента в виде объекта
		//param: [el] = DOM node
		//param: [prop] = String
		//return: [] = Object
		getAttr : function (el, prop){
			if (!el || !el.nodeType) return false;
			if (prop != undefined) return el.getAttribute(prop);
			var o = {},
				attr = el.attributes;
				
			for (var i = 0, length = attr.length; i < length; ++i){
				if (attr[i].specified){
					o[attr[i].nodeName] = attr[i].nodeValue;
				}
			}
			return o;
		},//end getAttr()
		
		//делает перерисовку DOM node elem для Opera
		repaint : function(elem){
			if (window.opera) {
				document.body.style.outline='1px solid transparent';
				elem.offsetHeight;// Force Opera redraw
				document.body.style.outline='0px';
			}
		},
	
		//проверяет, в данных момент элемент открыт или нет
		//param: [id] = (String)
		//return: [] = (true|false)
		isOpened : function (id){
			var el = $(id);
			return (el && el.style.display != 'none' && el.style.visibility != 'hidden');
		},
	
		//разворачивает/схлопывает елемент с заданным id
		//param: [id] = String
		//param: [flag] = true/false (flag === true - то разворачивает/схлопывает (по умолчанию только закрывает)) 
		//return: [] = void
		fclose : function (id, flag){
			var ids = id.split(",");//тут id разделены запятыми
			//проходим по каждому id
			ids.map(function(id){
				var el = $(mui.trim(id));
				if (el){
					if (flag === true) {
						if (mui.curCSS(el, 'display') == 'none') {
							//---
								var tagName = el.tagName, display;
								
								if ( elemdisplay[ tagName ] ) {
									display = elemdisplay[ tagName ];
								} else {
									var elem = document.createElement(tagName);
									elem = document.body.appendChild(elem);
									
									display = mui.curCSS(elem, "display");
									if ( display === "none" )
										display = "block";
									
									elem.parentNode.removeChild(elem);;
									
									elemdisplay[ tagName ] = display;
								}
							//---
							el.style.display = display;							
						}
						else {
							el.style.display = "none";
						}
					}
					else el.style.display = 'none';	
				}	
			});
		},//end fclose()
	
		//показывает (разворачивает) елемент с заданным id
		//param: [id] = String
		//return: [] = void
		fopen : function (id){
			var el = $(id);
			if (el) el.style.display = '';
		},//end fopen()
		
	   	//возвращает абсолютные координаты DOM node (el) относительно верхнего левого угла окна браузера
		//часть взято отсюда: http://code.google.com/p/doctype/wiki/ArticlePageOffset
		getCoordsXY : function(el) {
			if (el.parentNode === null || el.style.display == 'none') {
				return false;
			}
		  
			var parent = null, pos = [], box, browser = mui.browser(), doc = document.documentElement, b = document.body;
	
			if (el.getBoundingClientRect) {// IE && Opera 9.5+
				box = el.getBoundingClientRect();
				return [parseInt(box.left) + (doc.scrollLeft || b.scrollLeft), parseInt(box.top) + (doc.scrollTop || b.scrollTop)];
		  	}
		  	else if (document.getBoxObjectFor) { // gecko
				box = document.getBoxObjectFor(el);
				pos = [box.x, box.y];
			} else { // safari/opera
				pos = [el.offsetLeft, el.offsetTop];
				parent = el.offsetParent;
			if (parent != el) {
				while (parent) {
					pos[0] += parent.offsetLeft;
					pos[1] += parent.offsetTop;
					parent = parent.offsetParent;
				}
			}
		
			// opera & (safari absolute) incorrectly account for body offsetTop
			if (browser.opera || (browser.safari && el.style.position == 'absolute')) {
				pos[1] -= b.offsetTop;
			}
		
			// accumulate the scroll positions for everything but the body element
			parent = el.offsetParent;
			while (parent && parent != b) {
				pos[0] -= parent.scrollLeft;
				// see https://bugs.opera.com/show_bug.cgi?id=249965
				if (!browser.opera || parent.tagName != 'TR') {
					pos[1] -= parent.scrollTop;
				}
				parent = parent.offsetParent;
			}
		  }

	
		  return pos;
	   },

	    //возвращает абсолютьные координаты события на странице
		getEventXY : function(event) {
			var doc = document.documentElement, b = document.body;
			return [
						event.pageX || event.clientX + b.scrollLeft + doc.scrollLeft,
						event.pageY || event.clientY + b.scrollTop + doc.scrollTop
					];
		},//end getEventXY()
		
		//декодирует строку, которая была закодирована при помощи php фнк google_encode()
		google_decode : function(str){
			var result = "",
				ord = -1;				
				
			for (var i = 0, length = str.length; i < length; ++i){
				ord=str.charCodeAt(i);
				//сдвиг для кириллических символов
				if (ord >= 192) ord -= (975 /* сдвиг между кириллицей и латиницей */ - 127 /* 224 - 97 */);
				
				//кодируем только смысловые символы: 
				if ((ord == 90) || (ord == 122)){//границы диапазона латиницы
					result += String.fromCharCode(ord - 25/* длина eng алфавита */);
				}
				else if ((ord == 223) || (ord == 255)){//границы диапазона кирилицы
					ord += (975 - 127);
					result += String.fromCharCode(ord - 31/* длина rus алфавита */);
				}	
				//раскодируем только смысловые символы:
				else if (
						(ord >= 65 && ord <= 89) || /* [A-Z] == [65-90] (ASCII) */
						(ord >= 97 && ord <= 121) || /* [a-z] == [97-122] (ASCII) */
						(ord >= 192 && ord <= 222) || /* [А-Я] == [192-223] (ASCII) */
						(ord >= 224 && ord <= 254) /* [а-я] == [224-255] (ASCII) */
					)
				{
					if (ord >= 192) ord += (975 - 127);
					result += String.fromCharCode(ord + 1);//декодировка
				}
				else {
					result += str.charAt(i);// которые не кодируются
				}
			}
			return result;
		},//end google_decode()
	   
   		//возвращает width и height окна браузера (внутренняя область)
		//а также величину текущего скролла {scrollTop, scrollLeft}
   		getDocProps : function (){
			var doc = document.documentElement, b = document.body;
			return {
				width : b.clientWidth || window.innerWidth || doc.clientWidth,
				height : b.clientHeight || window.innerHeight || doc.clientHeight,				
				scrollTop : Math.max(doc.scrollTop, b.scrollTop),
				scrollLeft : Math.max(doc.scrollLeft, b.scrollLeft)
			};
		},
		//устанавливает cookie
		//взято с http://phpjs.org/functions/view/510
		setcookie : function (name, value, expires, path, domain, secure) {
			// http://kevin.vanzonneveld.net
			// +   original by: Jonas Raoni Soares Silva (http://www.jsfromhell.com)
			// *     example 1: setcookie('author_name', 'Kevin van Zonneveld');
			// *     returns 1: true
		
			expires instanceof Date ? expires = expires.toGMTString() : typeof(expires) == 'number' && (expires = (new Date(+(new Date) + expires * 1e3)).toGMTString());
			var r = [name + "=" + escape(value)], s, i;
			for(i in s = {expires: expires, path: path, domain: domain}){
				s[i] && r.push(i + "=" + s[i]);
			}
			return secure && r.push("secure"), document.cookie = r.join(";"), true;
		},//end setcookie()
		//читает cookies
		//нужно переместить в mui.js
		//взято с http://trac.dojotoolkit.org/browser/trunk/src/io/cookie.js?rev=2410
		getсookie : function(name) {
			var idx = document.cookie.indexOf(name+'=');
			if(idx == -1) { return null; }
			value = document.cookie.substring(idx+name.length+1);
			var end = value.indexOf(';');
			if(end == -1) { end = value.length; }
			value = value.substring(0, end);
			value = unescape(value);
			return value;
		},//end getcookie()
		
		//
		//-- работа с XMLHttpRequest()
		//ajax-параметры по умолчанию
		ajaxSettings : {
			type: "GET",
			target: null,//id элемента DOM, с которым будем манипулировать по окончании запроса
			cache: false,//запрещаем кеширование
			//стандартный тип формы, для получения доступа к глобальным массивам $_GET и $_POST
			contentType: "application/x-www-form-urlencoded",
			data: null,//данные, которые отсылаем на сервер
			xhr:function(){//фнк создания транспорта XMLHttpRequest()
				return window.ActiveXObject ? new ActiveXObject("Microsoft.XMLHTTP") : new XMLHttpRequest();
			}
		},
		
		//метод: GET (loadPOST делает то же самое, только по методу POST)
		//делает запрос серверу с url == source, после ответа передает управление action_fnk(ответ, id элемента DOM для манипуляций)
		//param: [source] = адрес URL откуда взять данные (String)
		//param: [data] = GET данные, которые отсылаем серверу (формат: '' или 'aa=11&bb=22' [query string])
		//param: [target] = id элемента DOM (String)
		//param: [action_fnk] = функция-обработчик данных (Function Object)
		//param: [response_type] = тип ответа (по умолчанию текст, могут быть также 'xml', 'json')
		//return: [] = XMLHttpRequest Object для дальнейшего контроля, например, для прекращения запроса
		loadGET : function(source, data, target, action_fnk, response_type) {
			return mui._ajax({
				type: "GET",
				source: source,
				data: data,
				target: target,
				success: action_fnk,
				dataType: response_type
			});
		},//end loadGET()

		//метод: POST (loadGET делает то же самое, только по методу GET)
		//делает запрос серверу с url == source, после ответа передает управление action_fnk(ответ, id элемента DOM для манипуляций)
		//param: [source] = адрес URL откуда взять данные (String)
		//param: [data] = POST данные, которые отсылаем серверу (формат: '' или 'aa=11&bb=22' [query string])
		//param: [target] = id элемента DOM (String)
		//param: [action_fnk] = функция-обработчик данных (Function Object)
		//param: [response_type] = тип ответа (по умолчанию текст, могут быть также 'xml', 'json')
		//return: [] = XMLHttpRequest Object для дальнейшего контроля, например, для прекращения запроса
		loadPOST : function(source, data, target, action_fnk, response_type) {
			return mui._ajax({
				type: "POST",
				source: source,
				data: data,
				target: target,
				success: action_fnk,
				dataType: response_type
			});
		},//end loadPOST()
		
		//фнк, управляющая ajax-запросом на основе XMLHttpRequest()
		//служит общей вспомогательной для loadPOST() и loadGET()
		//param: [s] = параметры ajax-запроса в форме ajaxSettings
		//return: [] = XMLHttpRequest Object для дальнейшего контроля, например, для прекращения запроса
		_ajax : function(s) {
	
			//расширяем пользовательские ajax настройки настройками по умолчанию
			s = mui.extend(mui.ajaxSettings, s);
			
			if (!s.source) return false;
			
			var status,//статус ответа ('success', 'error', 'parseerror', ...)
				data,//данные ответа сервера (формат: '' или 'aa=11&bb=22' [query string])
				type = s.type.toUpperCase(),//тип запроса (GET или POST) 
				requestDone = false;//индикатор окончания выполнения запроса
			
			//-- для GET запросов
			//запрещаем кеширование для GET запросов, если нужно
			if (type == "GET" && s.cache === false) {
				var ts = +new Date;
				// стараемся заменить _= если это уже есть в url
				var ret = s.source.replace(/(\?|&)_=.*?(&|$)/, "$1_=" + ts + "$2");
				// если ничего не было заменено, добавляем timestamp в конец
				s.source = ret + ((ret == s.source) ? (s.source.match(/\?/) ? "&" : "?") + "_=" + ts : "");
			}
			//если указана data для GET запроса, добавлем ее к url
			if (type == "GET" && s.data) {
				s.source += (s.source.match(/\?/) ? "&" : "?") + s.data;
				// IE отсылает data для GET и для POST запросов, отменяем это 
				s.data = null;
			}
			
			//создаем объект запроса (XMLHttpRequest())
			var xhr = s.xhr();
			
			//открываем асинхронное соединение
			xhr.open(type, s.source, true);

			//для того чтобы Content-Type был как у формы, таким образом получаем
			//доступ к массивам PHP $_GET и $_POST
			try {
				if ( s.data )
					//устанавливаем корректный header, если data будет отослана
					xhr.setRequestHeader("Content-Type", s.contentType);
			} catch (e) {}

			//-- ждем, когда вернется ответ
			var onreadystatechange = function(){
				//запрос был отклонен, очищаем интервал
				if (xhr.readyState == 0) {
					if (ival) {
						clearInterval(ival);
						ival = null;
					}
				//запрос завершен и ответ доступен
				} else if (!requestDone && xhr && xhr.readyState == 4) {
					requestDone = true;
					// очищаем интервал ожидания ответа
					if (ival) {
						clearInterval(ival);
						ival = null;
					}
					//смотрим, ответ сервера был успешным или нет
					if (!xhr.status && location.protocol == "file:" || ( xhr.status >= 200 && xhr.status < 300 ) || xhr.status == 304 || xhr.status == 1223){
						//контролируем ошибки парсинга XML
						try {
							//обрабатываем данные (в разных форматах ответа)
							data = httpData(xhr, s.dataType, s);
						} catch(e) {
							status = "parsererror";
						}
						if (s.success)
							s.success(data, s.target, status);
					}
					else 
						status = "error";
		
					xhr = null;
				}
			};

			//опрашиваем объект XMLHttpRequest() на изменение состояния ответа
			var ival = setInterval(onreadystatechange, 13);

			//отсылаем данные серверу
			try {
				xhr.send(s.data);
			} catch(e) {}
	
			//фнк, производящая парсинг ответа с сервера
			function httpData(xhr, type, s) {
				
				try{
					var ct = xhr.getResponseHeader("content-type"),
                            xml = type == "xml" || !type && ct && ct.indexOf("xml") >= 0,
                            //получаем ответ с сервера в виде XML или текста
                            data = xml ? xhr.responseXML : xhr.responseText;
				} catch (e){}
		
				if (xml && data.documentElement.tagName == "parsererror")
					throw "parsererror";
		
				//--если указан формат возврата в форме JSON объекта
				if( typeof data === "string" ){
					try{
						//получаем объект JavaScript, если использован JSON
						if ( type == "json" )
							data = window["eval"]("(" + data + ")");
					} catch (e){}
				}
				return data;
			}//end httpData
	
			//возвращаем XMLHttpRequest для возможности отмены запроса и т.д.
			return xhr;
		},//end _ajax()
		
		//--возвращает значение (value) элемента формы
		//param: [el] = элемент формы
		//return: [(String)] = значение элемента формы
		getFieldValue : function(el) {
			var n = el.name,
				t = el.type,
				tag = el.tagName.toLowerCase();
		
			if (!n || el.disabled || t == 'reset' || t == 'button' ||
				(t == 'checkbox' || t == 'radio') && !el.checked ||
				(t == 'submit' || t == 'image') && el.form && el.form.clk != el ||
				tag == 'select' && el.selectedIndex == -1)
					return null;
					
			//--обработка select
			if (tag == 'select') {
				var index = el.selectedIndex;
				if (index < 0) return null;
				var a = [], ops = el.options,
					one = (t == 'select-one'),
					max = (one ? index+1 : ops.length);
					
				for(var i=(one ? index : 0); i < max; i++) {
					var op = ops[i];
					if (op.selected) {
						var v = op.value;
						if (!v) // extra pain for IE...
							v = (op.attributes && op.attributes['value'] && !(op.attributes['value'].specified)) ? op.text : op.value;
						if (one) return v;
						a.push(v);
					}
				}
				return a;
			}
			
			return el.value;
		},//end fieldValue()
			
		//собирает данные с элементов формы в массив объектов (name => value),
		//который может быть передан, например, в функции mui.loadPOST и mui.loadGET
		//пример возвращаемого массива: [ { name: 'username', value: 'jresig' }, { name: 'password', value: 'secret' } ]
		//param: [form] = form element (DOM элемент формы)
		//return: [(Array)] = массив в форме [ { name: 'username', value: 'jresig' }, { name: 'password', value: 'secret' } ]
		formToArray : function(form) {
			var a = [],
				els = form.getElementsByTagName('*');
				
			if (!els) return a;
			
			for (var i = 0, length = els.length; i < length; ++i) {
				var el = els[i],
					n = el.name;	
				if (!n) continue;
		
				var v = mui.getFieldValue(el);
				if (v && mui.isArray(v)) {
					for(var j = 0, jmax = v.length; j < jmax; j++)
						a.push({name: n, value: v[j]});
				}
				else if (v !== null && typeof v != 'undefined')
					a.push({name: n, value: v});
			}
			return a;
		},//end formToArray

		//проводит сериализацию массива элементов формы или множества
		//пар типа key => values в query string
		//param: [a] = массив или объект
		//return: [(String)] = query string (формат: 'aa=11&bb=22')
		toQueryString: function(a) {
			var s = [];
	
			function add(key, value){
				s[s.length] = mui.escape(key) + '=' + mui.escape(value);
			};
	
			//--если передан массив, трактуем его как массив элементов формы
			if (mui.isArray(a))
				for (var i = 0, length = a.length; i < length; ++i ){
					add( a[i].name, a[i].value );
				}
			//--в другом случае, трактуем его как объект пар типа key=>value (key : value)
			else
				for ( var j in a )
					//--если значение - это массив, тогда ключи должны быть повторены
					if ( mui.isArray(a[j]) )
						for (var i = 0, length = a[j].length; i < length; ++i ){
							add( a[j][i].name, a[j][i].value );
						}
					else
						add( j, mui.isFunction(a[j]) ? a[j]() : a[j] );
	
			//--возвращаем результат сериализации
			return s.join("&").replace(/%20/g, "+");
		},//end toQueryString
		
		//фнк. проводящая submit формы на основе ajax
		//param: [(Evt)] = Event (тип зависит от события)
		//return: [false] = <- важно, для запрета submit по умолчанию
		submitForm : function(event, json) {
			
			//this - в данном случае это элемент формы.
			//этого можно добиться всегда, используя, например, submitForm.apply(obj, arguments)
			if (event && this.nodeType){
				
				var attr = mui.getAttr(this),//узнаем атрибуты формы
					xhr = {};//храним ссылку на объект XMLHttpRequest()

				try{
					//
					//компонуем объект с параметрами для будущего ajax запроса
					o = {
						source : attr.jsource || undefined,//url запроса
						data : mui.toQueryString(mui.formToArray(this)) || null,//GET или POST данные, отсылаемые серверу
						target : attr.jtarget || ''//id элемента, которым будем манипулировать
					};
				} catch (e){}
				
				//
				//добавление сабмита (если нажата кнопка) к списку параметров GET/POST
				if (event.type == 'click' && o.data){
					var target = event.target || event.srcElement;
					if (target.type == 'submit' && target.name && target.value){
						//тут не нужно проверять '?'
						o.data += "&" + mui.escape(target.name) +'='+ mui.escape(target.value);
					}
				}
				
				var action_fnk = function (data, target){
					var node = $(target);
					if (node && node.nodeType && typeof data === "string"){
						//в некоторых случаях нужно интерпретировать строку в html
						if (/^[\s]*\(/.test(data)){
							data = data.replace(/^[\s]*\(|\)$/g, "");
							try {
								data = window['eval'](data);
							} catch (e){}
						}
						node.innerHTML = mui.stripScripts(data);
						mui.evalScripts(data);
					}
				};
				
				if (o){
					//
					//в зависимости от указанного метода в форме, делаем GET или POST запрос (ajax)
					if (attr.method.toUpperCase() == 'POST'){
						xhr = mui.loadPOST(o.source, o.data, o.target, action_fnk);
					}
					else {
						if (json){
							o.source += (o.source.match(/\?/) ? "&" : "?")+o.data;
							mui.loadJSON(o.source, o.target, action_fnk);
						}
						else {
							xhr = mui.loadGET(o.source, o.data, o.target, action_fnk);	
						};		
					};
				}
				//
				//запрещаем submit формы по умолчанию
				if (event.preventDefault)//необходимо для addEventListener
				event.preventDefault();
				event.returnValue = false;//необходимо для attachEvent		
			}

			return false;
		},//end submitForm()
		
		//определение браузера
		browser : function(){
			var userAgent = navigator.userAgent.toLowerCase();
			return {	
				version: (userAgent.match( /.+(?:rv|it|ra|ie)[\/: ]([\d.]+)/ ) || [0,'0'])[1],
				safari : /webkit/.test( userAgent ),
				opera : /opera/.test( userAgent ),
				msie : /msie/.test( userAgent ) && !/opera/.test( userAgent ),
				mozilla : /mozilla/.test( userAgent ) && !/(compatible|webkit)/.test( userAgent )
			};
		},
	
		//добавляет обработчик handle() к елементу elem
		//может в дальнейшем стоит обратить внимание на http://dean.edwards.name/weblog/2005/12/js-tip1/
		//было полезно:
		//	http://trac.dojotoolkit.org/browser/dojo/trunk/_base/event.js?rev=15371
		//	http://blog.stchur.com/2007/03/15/mouseenter-and-mouseleave-events-for-firefox-and-other-non-ie-browsers/
		//	https://developer.mozilla.org/en/DOM/event.relatedTarget
		//param: [type] = тип события (String)
		//param: [handle] = String - функция-обработчик
		//param: [elem] = DOM node
		//return: [handle] = (Function)
		bind : function (type, handle, elem){
			elem = elem || ((window.addEventListener) ? window : document);
			//если это текстовый узел или комментарий [https://developer.mozilla.org/En/DOM/Node.nodeType]
			if ( elem.nodeType == 3 || elem.nodeType == 8 ) return;
				
			// Bind the global event handler to the element
			if (elem.addEventListener){//not IE
				if ((/^mouse(enter|leave)$/i).test(type)){//переобозначаем события mouse(enter|leave)
					var fp = handle;
					handle = function(event){
						// Check if mouse(over|out) are still within the same parent element
						var parent = event.relatedTarget;		
						//проходим вверх по дереву DOM
						while ( parent && parent != this )
							try { parent = parent.parentNode; }
							catch(e) { parent = this; }
		
						if( parent != this ){
							fp.call(this, event);
						}
					};
					type = ((/enter/i).test(type)) ? 'mouseover' : 'mouseout';
				}
				elem.addEventListener(type, handle, false);
                                return handle;
			}
                        else if (elem.attachEvent){
                                var f = function(){return handle.apply(elem, arguments);}
                                elem.attachEvent("on" + type, f);
                                return f;
                        }
		},//end bind()
	
		//убирает обработчик handle() с елемента elem
		//может в дальнейшем стоит обратить внимание на http://dean.edwards.name/weblog/2005/12/js-tip1/
		//param: [type] = тип события (String)
		//param: [handle] = String - функция-обработчик
		//param: [elem] = DOM node
		//return: [] = void
		unbind : function (type, handle, elem){
			elem = elem || ((window.removeEventListener) ? window : document);
			//отключаем глобальный обработчик событий от элемента
			if (elem.removeEventListener){
				if ((/^mouse(enter|leave)$/i).test(type)){//переобозначаем события mouse(enter|leave)
					type = ((/enter/i).test(type)) ? 'mouseover' : 'mouseout';
				}
				elem.removeEventListener(type, handle, false);
			}	
			else if (elem.detachEvent)
				elem.detachEvent("on" + type, handle);
		},//end unbind()
		
		//фнк возвращает свойства CSS 
		curCSS : function( elem, name ) {
			var defaultView = document.defaultView || {},
				ret, style = elem.style;

            //работа с opacity (полупрозрачность)
            if (name == 'opacity') {
                var ropacity = /opacity=([^)]*)/;
                if (style.opacity || style.opacity === 0)
                    return style.opacity;
                // IE uses filters for opacity
                return ropacity.test((elem.currentStyle ? elem.currentStyle.filter : style.filter) || "" )
                    ? ( parseFloat( RegExp.$1 ) / 100 ) + ""
                    : 1;
                return 1;
            }

			// Make sure we're using the right name for getting the float value
			if ( name.match( /float/i ) )
				name = styleFloat;
			//если стиль явно указан через style=""	
			if ( style && style[ name ] )
				ret = style[ name ];	
				
			else if ( defaultView.getComputedStyle ) {
	
				//только "float" здесь нужен
				if ( name.match( /float/i ) )
					name = "float";
					
				//переводим из camelCase в camel-case
				name = name.replace( /([A-Z])/g, "-$1" ).toLowerCase();
	
				var computedStyle = defaultView.getComputedStyle( elem, null );
	
				if ( computedStyle )
					ret = computedStyle.getPropertyValue( name );
	
				// We should always get a number back from opacity
				if ( name == "opacity" && ret == "" )
					ret = "1";
	
			} else if ( elem.currentStyle ) {
				var camelCase = mui.camelCase(name);

                 /*
                    name.replace(/\-(\w)/g, function(all, letter){
					return letter.toUpperCase();
				});
	            */

				ret = elem.currentStyle[ name ] || elem.currentStyle[ camelCase ];
	
				// From the awesome hack by Dean Edwards
				// http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291
	
				// If we're not dealing with a regular pixel number
				// but a number that has a weird ending, we need to convert it to pixels
				if ( !/^\d+(px)?$/i.test( ret ) && /^\d/.test( ret ) ) {
					// Remember the original values
					var left = style.left, rsLeft = elem.runtimeStyle.left;
	
					// Put in the new values to get a computed value out
					elem.runtimeStyle.left = elem.currentStyle.left;
					style.left = ret || 0;
					ret = style.pixelLeft + "px";
	
					// Revert the changed values
					style.left = left;
					elem.runtimeStyle.left = rsLeft;
				}
			}

            //code from https://ajax.googleapis.com/ajax/libs/prototype/1.7.0.0/prototype.js
            if (ret == 'auto') {
              if ((name == 'width' || name == 'height') && (elem.style.display != 'none')){
                 ret = elem['offset' + name.capitalize()] + 'px';

                 //code "LIKE" from https://ajax.googleapis.com/ajax/libs/prototype/1.7.0.0/prototype.js
                 if (name == 'width') {
                    ret = parseInt(ret)
                    + parseInt(mui.curCSS(elem, 'padding-left') || 0)
                    + parseInt(mui.curCSS(elem, 'padding-right') || 0)
                    + (!isNaN(parseInt(mui.curCSS(elem, 'border-left-width'))) ? parseInt(mui.curCSS(elem, 'border-left-width')) : 0)
                    + (!isNaN(parseInt(mui.curCSS(elem, 'border-right-width'))) ? parseInt(mui.curCSS(elem, 'border-right-width')) : 0)
                    + 'px';
                 }
                 if (name == 'height') {
                    ret = parseInt(ret)
                    + parseInt(mui.curCSS(elem, 'padding-top') || 0)
                    + parseInt(mui.curCSS(elem, 'padding-bottom') || 0)
                    + (!isNaN(parseInt(mui.curCSS(elem, 'bborder-top-width'))) ? parseInt(mui.curCSS(elem, 'border-top-width')) : 0)
                    + (!isNaN(parseInt(mui.curCSS(elem, 'border-bottom-width'))) ? parseInt(mui.curCSS(elem, 'border-bottom-width')) : 0)
                    + 'px';
                 }
              }
              else return 0;
            }

			return ret;
		},
		
		//создаем временный <iframe /> для загрузки файлов	   
		createUploadIframe: function(id){	
			if (mui.browser().msie) {//IE
				var io = document.createElement('<iframe id="'+id+'" name="'+id+'" />');
					io.src = 'javascript:false';
			}
			else {
				var io = document.createElement('iframe');
				io.id = id;
				io.name = id;
			}
			//чтобы не было визуально видно на странице
			io.style.cssText = "position:absolute; top:-10000px; left:-10000px;";
			document.body.appendChild(io);	
			return io;	
		}, 
		
		//загружаем файл кросс-доменно без перезагрузки страницы
		fileUpload: function(s){	
			function uploadCallback(){
				
				try{//это для opera > 10.
					if (mui.browser().opera && io.contentWindow.location.href == 'about:blank') 
						return false;
				}
				catch(e){}		
				
				var jsource = s.uploadform.getAttribute('jsource'),
					jtarget = s.uploadform.getAttribute('jtarget');
				if (jsource && jtarget){
					//вызываем фнк. success()
					mui.loadJSON(jsource, jtarget, (s.success) ? s.success : function(){});
				};
				//'подчищаем' <iframe />
				mui.unbind('load', uploadCallback, io);
                setTimeout(function(){
					try {io.parentNode.removeChild(io)} catch(e) {}
				}, 100);
			}
			//id и name для <iframe />
			var id = 'ifr' + (new Date().getTime());
			var io = mui.createUploadIframe(id);
	
			s.uploadform.method = 'POST';//методом GET файлы не загружаем
			s.uploadform.action = s.uploadform.getAttribute('jload');
			s.uploadform.target = id;//перенаправляем загрузку на <iframe />
			s.uploadform.submit();
			
			//по загрузке <iframe /> вызываем возврат
			(window.attachEvent) ? io.attachEvent('onload', uploadCallback) : io.addEventListener('load', uploadCallback, false);
			
			return false;
		},
		
		/* Добавляет окончание к соществительному в зависимости от числа:
		например, ending("телевизор", 5) = "телевизоров"
		К сожалению, подходи только для тех слов, которые в разном читсле не меняют свой формы
		*/
		add_ending : function(str, number, o1, o2, o5) {
			
			o1 = (o1 == undefined) ? "" : o1;
			o2 = (o2 == undefined) ? "а" : o2;
			o5 = (o5 == undefined) ? "ов" : o5;
		
		    if ((number >= 10) && (number <= 20)) result = o5;
		    else {
		        last_digit = (number+"").substring(-1, 1);
		        if (last_digit == 0) result = o5;
		        else if (last_digit == 1) result = o1;
		        else if (last_digit <= 4) result = o2;
		        else result = o5;
		    }
		    return str+result;
		},

        /**
         * Производит плавную анимацию свойства prop с параметрами params
         * @param node: DOM элемент
         * @param prop: анимируемый параметр (напр. marginLeft, left, width)
         * @param params: параметры анимации, формат:
         *
         * params = {
         *     start : начальное значение,
         *     finish : конечное значение,
         *     time : время анимации,
         *     n : к-во точек анимации
         *     wait : true|false ждать пока закончится предыдущая анимация или нет
         * }
         * @param cb: function(){ ... } фнк. которая выполнится по завершению анимации
         */
         /*
        animate_old : function(node, prop, params, cb){
            try {//в случае ошибки возвращаем false
                if (prop && params && node && node.nodeType) {
                    var temp = params.start;//промежуточное значение анимации
                    var finish = params.finish;
                    var d = (finish - temp) / params.n;
                    if (d == 0) return false;//нечего анимировать

                    if (!params.wait) mui.a_progress = false;
                    if (!mui.a_progress){//текущая анимация завершена
                        mui.a_progress = true;
                        var t_int = parseInt(params.time / params.n);
                        function fx() {
                            temp += d;
                            if ((d > 0 && temp < finish) || (d < 0 && temp > finish)){
                                setTimeout(function(){
                                    node.style[prop] = temp + 'px';
                                    setTimeout(fx, t_int);
                                }, 0);
                            } else {
                                //устанавливаем точное конечное значение
                                node.style[prop] = finish + "px";
                                mui.a_progress = false;
                                (cb || function(){})();
                            }
                        }
                        fx();
                    }
                }
                return true;
            } catch(e) {return false;}
        },//end of mui.animate_old()
        */

        /**
         * Производит плавную анимацию css свойства prop с параметрами options
         * @param node: DOM элемент
         * @param prop: объект с свойствами и границами анимации (например {height : [30, 50], left : 400, top : 500})
         * @param options: параметры анимации, формат:
         *
         * options = {
         *     duration : время анимации,
         *     fps : плавность анимации, по умолчанию 50 [frames per second]
         *     wait : true|false ждать пока закончится предыдущая анимация или нет
         *     unit : единицы в котором снимируется свойство, по умолчанию px
         *          (на самом деле это объект типа: {height : 'px', width : "%", opacity : ''})
         *     onStart : фнк. которую нужно выполнить перед анимацией
         *     onProcess : фнк., выполняющаяся на каждом шаге анимации
         *     onComplete : фнк. которую нужно выполнить по окончании анимации
         *     transition : закон, по которому протекает анимация.
         *          Одно из: 'Default', 'Pow', 'Expo', 'Circ', 'Sine', 'Back', 'Bounce', 'Elastic']
         * }
         */
        animate : function(node, prop, options){
            try {//в случае ошибки возвращаем false
                if (prop && node && node.nodeType) {
                    //могут передать отдельно параметры анимации и границы, а могут все в одном объекте
                    options = options || prop || {};

                    //переводим параметры анимации в вид camelCase [margin-left => marginLeft]
                    for ( p in prop ) {
                        var name = mui.camelCase( p );
                        if ( p !== name ) {
                            prop[ name ] = prop[ p ];
                            delete prop[ p ];
                        }
                    }

                    if (!options.wait) mui.a_progress = false;
                    //расширяем значениями по умолчанию
                    options = mui.extend({
                        fps : 50,
                        unit : 'px',
                        duration : 1000,
                        wait : true,
                        transition : 'Default'
                    }, options);
                    
                    var t0 = mui.timestamp();//начальная точка отсчета времени
                    var from = {}, to = {};

                    //управление для каждого свойства своя функция преобразования
                    var trans = {};
                    if (typeof options.transition != 'string') {
                        // transition name normalization
                        for ( var t in options.transition ) {
                            trans[t] = mui.transition[mui.camelCase(options.transition[t]) || 'Default'];
                        }
                    }
                    else
                        trans = mui.transition[mui.camelCase(options.transition) || 'Default'];

                    for ( p in prop ) {
                        //когда указано в таком формате {height : 100}
                        if (!mui.isArray(prop[p])) {
                            if (/scroll/i.test(p)) {
                                from[p] = parseInt(node[p]);
                            }
                            else {
                                from[p] = parseInt(mui.curCSS(node, p));
                            }
                            to[p] = parseInt(prop[p]);
                        }
                        //когда указано в таком формате {height : [20, 100]}
                        else if (typeof prop[p][1] != 'undefined') {
                            from[p] = parseInt(prop[p][0]);
                            to[p] = parseInt(prop[p][1]);
                        }
                    }

                    mui.a_i = null;
                    if (!mui.a_progress){//текущая анимация завершена
                        mui.a_progress = true;
                        (options.onStart || function(){})();//запуск фнк. перед началом анимации
                        mui.a_i = setInterval(function(){
                            setTimeout(function(){
                                var dt = mui.timestamp() - t0;
                                var delta = {};

                                for ( p in prop ) {
                                    trans = trans[p] || trans;
                                    if (!mui.isFunction(trans)) trans = mui.transition['Default'];
                                    //
                                    // delta - число от 0 до 1
                                    delta[p] = (dt < options.duration) ? trans(dt / options.duration) : 1;

                                    var val = parseFloat((to[p] - from[p]) * delta[p] + from[p]);

                                    unit = (typeof options.unit[p] != 'undefined') ? options.unit[p] : options.unit;
                                    if (typeof unit != 'string') unit = 'px';

                                    if (p == 'opacity')
                                        mui.setOpacity(node, val);
                                    else if (/scroll/i.test(p)) {
                                        node[p] = val;
                                    }
                                    else
                                        node.style[p] = val + unit;

                                    (options.onProcess || function(){})();//запуск фнк. на каждом шаге анимации
                                }
                                if (dt >= options.duration) {
                                    mui.a_progress = false;
                                    clearInterval(mui.a_i);
                                    (options.onComplete || function(){})();//запуск фнк. после окончания анимации
                                }
                            }, 0);
                        }, Math.round(1000 / options.fps));
                    }
                }
                return true;
            } catch(e) {return false;}
        },//end of mui.animate()

        //установка opacity кросс-браузерно
        setOpacity : function( elem, value ) {
            
            if (typeof elem.style.opacity != 'undefined'){
                elem.style.opacity = value;
            }
            else {
                var style = elem.style,
                    currentStyle = elem.currentStyle;

                // IE has trouble with opacity if it does not have layout
                // Force it by setting the zoom level
                style.zoom = 1;

                // Set the alpha filter to set the opacity
                var opacity = "alpha(opacity=" + value * 100 + ")",
                    filter = currentStyle && currentStyle.filter || style.filter || "";

                var ralpha = /alpha\([^)]*\)/i;
                style.filter = ralpha.test( filter ) ?
                    filter.replace( ralpha, opacity ) :
                    filter + " " + opacity;
            }
        },

        // Converts a dashed string to camelCased string;
	    // Used by both the css and data modules
	    camelCase : function( string ) {
		    return string.replace( /-([a-z])/ig, function( all, letter ) {
			    return letter.toUpperCase();
			});
		},

        //чтоб не было ошибки при написани console.log(var)
        log : function(v){
            if (typeof console != 'undefined') return console.log(v);
        },

        timestamp : Date.now || function(){return new Date().getTime()},

        transition : {
            Default : function(p){return -(Math.cos(Math.PI * p) - 1) / 2;},
            Pow: function(p, x){return Math.pow(p, x && x[0] || 6);},
            Expo: function(p){return Math.pow(2, 8 * (p - 1));},
            Circ: function(p){return 1 - Math.sin(Math.acos(p));},
            Sine: function(p){return 1 - Math.cos(p * Math.PI / 2);},
            Back: function(p, x){
                x = x && x[0] || 1.618;
                return Math.pow(p, 2) * ((x + 1) * p - x);
            },
            Bounce: function(p){
                var value;
                for (var a = 0, b = 1; 1; a += b, b /= 2){
                    if (p >= (7 - 4 * a) / 11){
                        value = b * b - Math.pow((11 - 6 * a - 11 * p) / 4, 2);
                        break;
                    }
                }
                return value;
            },
            Elastic: function(p, x){return Math.pow(2, 10 * --p) * Math.cos(20 * p * Math.PI * (x && x[0] || 1) / 3);}
        },

		confirm : function(event, str){
			var is_confirmed = confirm(str);
			
			if (!is_confirmed && event){
				//запрещаем дальнейшее "всплывание" события
				if (event.stopPropagation) 
					event.stopPropagation();
				event.cancelBubble = true;
				
				//отменяем действие по умолчанию
				if (event.preventDefault)//необходимо для addEventListener				
					event.preventDefault();
				event.returnValue = false;//необходимо для attachEvent
				return false;
			}
			
			return true;
		}
	});
})();

/* добавим пока что временно кусочек для оценки отзывов */
//глобальные настройки
var voting_settings = {
	'Reviews' : {
		'label' : 'Отзыв полезен?',
		'answerY' : 'Да',
		'answerN' : 'Нет' 
	},
	'Links' : {
		'label' : 'Ссылка полезна?',
		'answerY' : 'Да',
		'answerN' : 'Нет' 
	},
    'Questions' : {
		'label' : 'Вопрос полезен?',
		'answerY' : 'Да',
		'answerN' : 'Нет'
	}
}

/*
	функция, проводящая голосование
	
	id: id отзыва в базе
	voteY: количество положительных отзывов
	voteN: количество отрицательных отзывов
	vote: {+1|-1} как проголосовали
	key: служебный ключъ
	url_prefix: префиксная часть url (разные сервера, необязательный параметр)
*/
function vote(id, tn, voteY, voteN, vote, key, url_prefix, mode){
	var pref = "yn-";
	var node = $(pref+id).getElementsByTagName('span')[0];
	
	//alert(url + ' _state=' + node.getAttribute('_state') + node.tagName);

	//сначала проверяем состояние ссылки
	if (typeof node.getAttribute !== "undefined" && node.getAttribute('_state') != undefined){
		return false;
	}
	else if (typeof node.setAttribute !== "undefined"){
		node.setAttribute('_state', 'wait');
	}
	
	//находим результирующие значения количества голосов
	(vote > 0) ? ++voteY : ++voteN;
	//пытаемся поставить куки на текущие значения	
	mui.setcookie('vote_'+tn+'_'+id+'_y', voteY, 10*366*60*60*24/* 10 лет */, "/");
	mui.setcookie('vote_'+tn+'_'+id+'_n', voteN, 10*366*60*60*24/* 10 лет */, "/");
	//url запроса к серверу
	var url = (url_prefix ? url_prefix : '') + 'mui_vote.php?tn_=' + tn + '&id_=' + id + '&vote_=' + vote + '&key_=' + key;
	
	
	//обрабатываем результаты на сервере
	mui.loadJSON(url, id, function(data){
		//обновляем форму 
		if (data.KeyError == 1) {print_vote_form(1/*выводим Активную форму*/, tn, id, data.MarksY, data.MarksN, data.key, url_prefix, mode);}
		else {print_vote_form(0/*выводим неактивную форму*/, tn, id, data.MarksY, data.MarksN, data.key, url_prefix, mode);}
	});
}//end vote()

/*
	печатает форму для голосования

	is_active: {0|1} - какую форму голосования выводить: активную (можно голосовать) или неактивную
	id: {String} - id элемента, где произошло событие
	current_voteY: к-тво положительных оценок
	current_voteN: к-тво отрицательных оценок
	key: служебный ключъ
	url_prefix: префиксная часть url (разные сервера, необязательный параметр)
*/
function print_vote_form(is_active, tn, id, current_voteY, current_voteN, key, url_prefix, mode){

	var pref = "yn-";
	url_prefix = url_prefix || '';
	//возвращает активную форму для голосования с данными data
	//в этой фнк подстраивается дизайн активной формы
	function print_active_form(data, mode){
            try{
		var settings = voting_settings[tn],
			html = '';
            var persent = parseInt((parseInt(data.voteY) / (parseInt(data.voteY) + parseInt(data.voteN))) * 100);

		    if (mode == 'color-bar') {
                var opacity = (parseInt(data.voteY) + parseInt(data.voteN)) / 100;
                if (opacity > 1) opacity = 1;
                if (opacity < 0.2) opacity = 0.2;
                var bg_style = (persent) ? "" : "background:#ccc;";
                var op_style = "-moz-opacity:"+opacity+"; filter:alpha(opacity="+parseInt(opacity*100)+"); opacity:"+opacity+"; }";
                html += '<div style="text-align: center;">'+settings.label+'</div>';
                html += '<div class="helpful-bar" style="'+bg_style+" "+op_style+'"><div style="width: '+persent+'%" class="helpful-likes"></div><div style="width: '+(100-persent)+'%" class="helpful-dislikes"></div></div>';
                html += '<div style="float: left"><em class="yes" onclick="vote(\''+id+'\', \''+tn+'\', '+ data.voteY +', '+ data.voteN +', 1, \''+ key +'\', \''+ url_prefix +'\', \''+mode+'\'); return false">'+settings.answerY+'</em>' + '<sub>'+data.voteY+'</sub></div>';
                html += '<div style="float: right"><em class="no" onclick="vote(\''+id+'\', \''+tn+'\', '+ data.voteY +', '+ data.voteN +', -1, \''+ key +'\', \''+ url_prefix +'\', \''+mode+'\'); return false">'+settings.answerN+'</em>' + '<sub>'+data.voteN+'</sub></div>';
            }
            else {
                html += settings.label + ' ';
                html += '<a href="javascript:void(0)" class="yes" onclick="vote(\''+ id +'\', \''+ tn +'\', '+ data.voteY +', '+ data.voteN +', 1, \''+ key +'\', \''+ url_prefix +'\', \''+mode+'\'); return false">' + settings.answerY + '</a>' + '<sub>' + data.voteY + '</sub> <span class="votes-slash">/</span> ';
                html += '<a href="javascript:void(0)" class="no" onclick="vote(\''+ id +'\', \''+ tn +'\', '+ data.voteY +', '+ data.voteN +', -1, \''+ key +'\', \''+ url_prefix +'\', \''+mode+'\'); return false">' + settings.answerN + '</a>' + '<sub>'+ data.voteN +'</sub>';
            }
		
		return html;
            } catch (e){}
	}
	
	//возвращает неактивную форму для голосования с данными data
	//в этой фнк подстраивается дизайн неактивной формы
	function print_passive_form(data, mode){
		var settings = voting_settings[tn],
			html = '';

        var persent = parseInt((parseInt(data.voteY) / (parseInt(data.voteY) + parseInt(data.voteN))) * 100);

		if (mode == 'color-bar') {
            var opacity = (parseInt(data.voteY) + parseInt(data.voteN)) / 100;
            if (opacity > 1) opacity = 1;
            if (opacity < 0.2) opacity = 0.2;
            var bg_style = (persent) ? "" : "background:#ccc;";
            var op_style = "-moz-opacity:"+opacity+"; filter:alpha(opacity="+parseInt(opacity*100)+"); opacity:"+opacity+"; }";
            html += '<div style="text-align: center;">'+settings.label+'</div>';
            html += '<div class="helpful-bar" style="'+bg_style+'"><div style="width: '+persent+'%" class="helpful-likes"></div><div style="width: '+(100-persent)+'%" class="helpful-dislikes"></div></div>';
            html += '<div style="float: left"><span class="yes">'+settings.answerY+'</span>' + '<sub>'+data.voteY+'</sub></div>';
            html += '<div style="float: right"><span class="no">'+settings.answerN+'</span>' + '<sub>'+data.voteN+'</sub></div>';
        }
        else {
            html += settings.label + ' ';
            html += settings.answerY + '<sub>' + data.voteY + '</sub> / ';
            html += settings.answerN + '<sub>'+ data.voteN +'</sub>';
        }
		
		return html;
	}
	
	var vote_form_html = '',//храним HTML код формы голосования
		vote_form_data = {//храним данные для вывода в форму голосования
			'voteY' : (current_voteY >= 0) ? current_voteY : '',
			'voteN' : (current_voteN >= 0) ? current_voteN : ''
		},
		settings = voting_settings;
		
	//если пользователь проголосовал в течение какого-то времени (нескольких суток)	
	if (is_active == 1 || (!mui.getсookie('vote_'+tn+'_'+id+'_y') && !mui.getсookie('vote_'+tn+'_'+id+'_n'))){
		vote_form_html = print_active_form(vote_form_data, mode);
	}
	else {//пользователь не голосовал или перегрузил страницу
		vote_form_html = print_passive_form(vote_form_data, mode);
	}
	var s = document.createElement('span');
	try{
		$(pref+id).innerHTML = "";
		s.innerHTML = vote_form_html;
		$(pref+id).appendChild(s);
	} catch (e){}
}//end print_vote_form()

//загрузка файлов и изображений
function j_submit_file (event){
	if (typeof mui != "undefined"){
		mui.fileUpload({
			uploadform: this.form,
			type: 'POST',
			dataType: 'html',
			success: function (data, target) {$(target).innerHTML = data;},
			error: function (status) {}
		});
	}
	return false;
}


function unselect_opis(node){
	if (typeof node != undefined && typeof node.parentNode != undefined){
		var arr = node.parentNode.getElementsByTagName('a');
		for (var i = 0, length = arr.length; i < length; ++i){
			if (arr[i].className == "sort-select") arr[i].className = "sort";
		}
	}
}
function show_short_opis(event, id_short, id_full){
	if (typeof $(id_short) != "undefined" && typeof $(id_short) != "undefined"){
		unselect_opis(this);//остальные неактивными
		this.className = "sort-select";//эту делаю активной
		show_obj(id_short);
		hide_obj(id_full);
	}
}
function show_full_opis(event, id_short, id_full){
	if (typeof $(id_short) != "undefined" && typeof $(id_short) != "undefined"){
		unselect_opis(this);//остальные неактивными
		this.className = "sort-select";//эту делаю активной
		hide_obj(id_short);
		if ($(id_full).innerHTML.replace(/^\s\s*/, '').replace(/\s\s*$/, '') != '') {
			show_obj(id_full);
			if (event.stopPropagation)
				event.stopPropagation();
			event.cancelBubble = true;
		}
	}
}


function slide_menu_show_hide(pref, height){
    try {
        var content = $(pref+'_content');
        var currh = parseInt(mui.curCSS(content, 'height'));
        var o = {duration : 100};
        o.onStart = function(){
            class_2_change('notes_ek_toggle', 'notes-ek-toggle-open', 'notes-ek-toggle-close');
        }

        setTimeout(function(){
            mui.animate(content, {height : (currh ? 0 : (height || content.scrollHeight))}, o);
        }, 0);
    } catch (e) {}

    return false;
};



mui.ready(function () {
    guide_id = ['guide_1', 'guide_2', 'guide_6', 'guide_7'];
    guide_offset = {
        'guide_1' : [135, 55],
        'guide_2' : [15, 10],
        'guide_6' : [30, 28],
        'guide_7' : [270, 10]
    };
    function get_points(num) {
        var str = (num+1)+' из '+guide_len;
        return "<span style='font-size:12px'>"+str+"</span>";
    }
    guide_len = guide_id.length;
    guide_ms = [
        'MagaZilla — крупнейший каталог описаний и цен на бытовую технику, электронику и компьютеры. Мы помогаем найти нужную модель и выбрать магазин с лучшей ценой и оптимальной доставкой.<div class="divt"><table width="100%"><tr><td><div class="leftt" style="visibility: hidden;">&larr;&nbsp;<em>назад</em></div></td><td class="sim-guide">'+get_points(0)+'</td><td><div class="rightt"><em onclick="show_help_tip(1)">вперед</em>&nbsp;&rarr;</div></td></tr></table></div>',
        'В строке поиска можно указывать название модели (<em onclick="if ($(\'search\')) $(\'search\').value = this.innerHTML">iphone 4</em>, <em onclick="if ($(\'search\')) $(\'search\').value = this.innerHTML">Canon 500D</em> и др.) или название группы товаров (<em onclick="if ($(\'search\')) $(\'search\').value = this.innerHTML">карты памяти</em>, <em onclick="if ($(\'search\')) $(\'search\').value = this.innerHTML">сумки для ноутбуков</em>)<div class="divt"><table width="100%"><tr><td><div class="leftt">&larr;&nbsp;<em onclick="show_help_tip(0)">назад</em></div></td><td class="sim-guide">'+get_points(1)+'</td><td><div class="rightt"><em onclick="show_help_tip(2)">вперед</em>&nbsp;&rarr;</div></td></tr></table></div>',
        'Добавьте нас в Facebook и следите за новостями сайта и новинками IT рынка на нашей странице.<div class="divt"><table width="100%"><tr><td><div class="leftt">&larr;&nbsp;<em onclick="show_help_tip(1)">назад</em></div></td><td class="sim-guide">'+get_points(2)+'</td><td><div class="rightt"><em onclick="show_help_tip(3)">вперед</em>&nbsp;&rarr;</div></td></tr></table></div>',
        'Мы ценим наших посетителей и ваше мнение для нас важно. Если у вас есть вопросы или замечания по работе сайта, с радостью рассмотрим их.<div class="divt"><table width="100%"><tr><td><div class="leftt">&larr;&nbsp;<em onclick="show_help_tip(2)">назад</em></div></td><td class="sim-guide">'+get_points(3)+'</td><td><div class="rightt" style="visibility: hidden;"><em>вперед</em>&nbsp;&rarr;</div></td></tr></table></div>'
    ];
});

function show_help_tip(i) {
    try {
    //скрываем все тултипы
    guide_id.map(function(id){hide_obj('guide_'+id+'-outer');});

    //показываем нужный
    var id = 'guide_'+guide_id[i],
        node_outer = $(id+"-outer");

    if (node_outer) {
        node_outer.parentNode.removeChild(node_outer);
    }

    $(guide_id[i]).appendChild(tooltip._template(id, tooltip.settings));
    $(id).innerHTML = guide_ms[i];

    //скроллим к нужному тултипу
    var coords = mui.getCoordsXY($(id+"-outer"));
    coords[0] += guide_offset[guide_id[i]][0];
    coords[1] += guide_offset[guide_id[i]][1];
    tooltip.fposition(coords, id+"-outer", null, tooltip.getInnerDiv(id+"-outer", 'arrow'), {"right" : "right", "bottom" : "bottom"});//позиционируем подсказку

    var o = {'duration' : 700, 'fps' : 100};
    o.onComplete = function() {
        tooltip.fposition(coords, id+"-outer", null, tooltip.getInnerDiv(id+"-outer", 'arrow'), {"right" : "right", "bottom" : "bottom"});//позиционируем подсказку
    };
    mui.animate(document.body, {scrollTop: coords[1]-100}, o);
    } catch (e) {}
}





