var U={

	////////////////////////////////////////////////////////////////////
	// unsorted
	////////////////////////////////////////////////////////////////////
	newin: function(link){
		if(link && link.href){
			var newin=window.open(link.href);
			return false;
		}
	},

	popup: function(url,w,h,hash){
		var hash=(hash || {});
		var name=(hash.name || '_blank');
		if(!(window.screen 
			&& window.screen.height 
			&& window.screen.height > (h+50) 
			&& window.screen.width 
			&& window.screen.width > (w+50)
		)){
			w=(window.screen.width>(w+50))?(w+25):(window.screen.width-50);
			h=(window.screen.height>(h+50))?(h+25):(window.screen.height-50);
			hash.s=1;
		}
		var left=(U.getCookie('lastPopupLeft') || 75);
		left=parseInt(left)+ 25;
		if(window.screen && window.screen.width && left+parseInt(w)>window.screen.width)left=50;
		U.setCookie('lastPopupLeft',left);
		var top=(U.getCookie('lastPopupTop') || 75);
		top=parseInt(top)+ 25;
		if(window.screen && window.screen.height && top+parseInt(w)>window.screen.height)top=50;
		U.setCookie('lastPopupTop',top);
		var params='';
		params+='left='+ parseInt(left)+ ',';
		params+='top='+ parseInt(top)+ ',';
		params+='width='+ parseInt(w)+ ',';
		params+='height='+ parseInt(h)+ ',';
		params+='scrollbars='+ (hash.s || hash.scroll || hash.scrollbars || '0')+ ',';
		params+='resizable='+ (hash.r || hash.resize || hash.resizable || '0')+ ',';
		params+='menubar='+ (hash.m || hash.menu || hash.menubar || '0')+ ',';
		//params+='titlebar='+ (hash.titlebar || '0')+ ',';
		params+='toolbar='+ (hash.toolbar || '0')+ ',';
		params+='location='+ (hash.location || '0')+ ',';
		//params+='directories='+ (hash.directories || '0')+ ',';
		//params+='hotkeys='+ (hash.hotkeys || '0')+ ',';
		params+='status='+ (hash.status || '0')+ ',';
		//params+='dependent='+ (hash.dependent || '0')+ ',';
		//if(hash.fullscreen){params+='fullscreen='+ hash.fullscreen+ ',';}
		//params+='channelmode='+ (hash.channelmode || '0');
		//alert(params);
		var win=window.open(url,name,params);
		try{
			win.focus();
			return win;
		}catch(e){}
	},

	popimg: function(im,w,h,hash){
		var alt=(hash.a || hash.alt || '');
		var p=(hash.p==1 || hash.print==1)?'onload="window.print()"':'';
		var cc=(hash.cc==1 || hash.clickclose==1)?'onclick="self.close();"':'';
		var bc=(hash.bc==1 || hash.blurclose==1)?'onBlur="self.close()"':'';
		var popimgwin = U.popup('',w,h,hash);
		popimgwin.document.open("text/html");
		popimgwin.document.writeln('<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 //EN" "http://www.w3.org/TR/html4/strict.dtd"><html><head><title>'+alt+'<\/title><style type="text/css" title="">* {padding:0;margin:0;background:#fff;}<\/style><\/head>');
		popimgwin.document.writeln('<body '+bc+' '+p+'><div '+cc+'><img src="'+im+'" width="'+w+'" height="'+h+'" alt="'+alt+'" border="0" align="left" \/><\/div><\/body><\/html>');
		popimgwin.document.close();
		popimgwin.focus();
	},

	props: function(hash){
		var result='';
		for(var i in hash){
			result+=''+ i+ ': '+ hash[i]+ '\n';
		}
		return result;
	},

	defvar: function(def,data){//возвращает дефолтное значение, если отсутствуют данные
		return (data)?data:def;
	},

	hashToStr: function(hash){//эта функция получает хэш и превращает его в строку
		//если тип параметра object
		if(typeof hash=='object'){
			//инициализируем результат
			var result='hash={};';
			//пробегаем по свойствам
			for(var i in hash){
				//собираем результат
				result+='hash.'+ i+ '="'+ hash[i]+ '";';
			}
		}
		//делаем escape
		result=escape(result);
		//возвращаем результат
		return result;
	},

	hashFromStr: function(str){//эта функция получает строку и выполняет unescape и eval; используется в паре с hashToStr()
		eval(unescape(str));
		return hash;
	},

	loadBigImage: function(hash){//загружает большое изображение и на время загрузки отображает анимированный гиф процесса загрузки
		//проверяем все ли данные переданы
		if(hash.bigImgBoxId && hash.bigImgSrc && hash.previewId && hash.loaderBgcolor && hash.loaderSrc){
			//проверяем существуют ли на странице переданные id
			if(U.gbi(hash.bigImgBoxId) && U.gbi(hash.previewId)){
				//проверяем загружена ли в браузер картинка анимированного лоадера
				//если нижеупомянутое действие еще не производилось
				if(!U.loadBigImage_loaderImage){
					//создаем объект Image для лоадера
					U.loadBigImage_loaderImage=new Image();
					//назначаем src
					U.loadBigImage_loaderImage.src=hash.loaderSrc;
				}
				//запускаем проверку загрузки лоадера
				U.loadBigImageTestLoader(U.hashToStr(hash))
			}
		}
	},

	loadBigImageTestLoader: function(hash){//эта функция нужна для ожидания загрузки картинки лоадера (вызывается из loadBigImage())
		//если загрузка лоадера закончена
		if(U.loadBigImage_loaderImage.complete){
			//вызываем loadBigImageEnd()
			U.loadBigImageEnd(hash);
		}else{
			//иначе еще раз вызываем loadBigImageTestLoader()
			setTimeout('U.loadBigImageTestLoader("'+ hash+ '")', 100);
		}
	},

	loadBigImageEnd: function(hash){//эта функция запускается после загрузки картинки лоадера и ждет загрузки большого изображения
		//распаковываем наш hash
		var hash=U.hashFromStr(hash);
		//если нижеописанное действие не производилось
		if(!U.loadBigImage_bigImage){
			//впервые создаем хэш с объектами Image, которые будут хранить все запрошенные загрузки
			U.loadBigImage_bigImage={};
		}
		//если нижеописанное действие не производилось
		if(!U.loadBigImage_bigImage[hash.previewId]){
			//создаем новый объект Image для текущей большой картинки (ассоциатором должен быть hash.previewId, поскольку hash.bigImgBoxId может быть общим для многих)
			U.loadBigImage_bigImage[hash.previewId]=new Image();
			//определяем ему src
			U.loadBigImage_bigImage[hash.previewId].src=hash.bigImgSrc;
		}
		//если загрузка большого изображения закончена
		if(U.loadBigImage_bigImage[hash.previewId].complete){
			//помещаем новое изображение в приготовленное место
			U.gbi(hash.bigImgBoxId).innerHTML='<img src="'+ U.loadBigImage_bigImage[hash.previewId].src+ '" width="'+ U.loadBigImage_bigImage[hash.previewId].width+ '" height="'+ U.loadBigImage_bigImage[hash.previewId].height+ '" alt="">';
			//если превьюшка была заменена на лоадер
			if(U.loadBigImage_bigImage[hash.previewId].loaderElement){
				//делаем на лоадер ссылку для упрощения кода
				var loader=U.loadBigImage_bigImage[hash.previewId].loaderElement;
				//заменяем лоадер на превьюшку
				loader.parentNode.replaceChild(U.loadBigImage_bigImage[hash.previewId].previewElement, loader);
				//удаляем объект лоадера, он больше не понадобится, поскольку изображение есть в кэше
				U.loadBigImage_bigImage[hash.previewId].loaderElement=null;
			}
			//если был передан код на исполнение, исполняем его
			if(hash.functionToRun){eval(hash.functionToRun);}
			//завершаем работу
			return;
		}else{
			//иначе 
			if(!preview){
				//делаем ссылку на превьюшку
				var preview=U.gbi(hash.previewId);
			}
			//если нижеописанное действие не производилось
			if(!U.loadBigImage_bigImage[hash.previewId].loaderElement){
				//создаем элемент картинки загрузчика
				U.loadBigImage_bigImage[hash.previewId].loaderElement=document.createElement('IMG');
				//делаем на этот элемент ссылку для упрощения кода
				var loader=U.loadBigImage_bigImage[hash.previewId].loaderElement;
				//устанавливаем загрузчику основные атрибуты
				loader.setAttribute('src',U.loadBigImage_loaderImage.src);
				loader.setAttribute('width',U.loadBigImage_loaderImage.width);
				loader.setAttribute('height',U.loadBigImage_loaderImage.height);
				//определяем его будущие позицию, родителя и отступы (которые будут сделаны с помощью бордеров с нужным цветом)
				var borderLeft=parseInt((preview.offsetWidth-loader.width)/2);
				var borderRight=preview.offsetWidth-loader.width-borderLeft;
				var borderTop=parseInt((preview.offsetHeight-loader.height)/2);
				var borderBottom=preview.offsetHeight-loader.height-borderTop;
				var top=preview.offsetTop;
				var left=preview.offsetLeft;
				//устанавливаем стили
				loader.style.position='relative';
				loader.style.zIndex=999;
				loader.style.borderColor=hash.loaderBgcolor;
				loader.style.borderTopWidth=borderTop+ 'px';
				loader.style.borderRightWidth=borderRight+ 'px';
				loader.style.borderBottomWidth=borderBottom+ 'px';
				loader.style.borderLeftWidth=borderLeft+ 'px';
				//дублируем старую певьюшку перед тем как удалить ее из кода страницы
				U.loadBigImage_bigImage[hash.previewId].previewElement=preview;
				//заменяем превьюшку на лоадер
				preview.parentNode.replaceChild(loader, preview);
			}
			//еще раз вызываем loadBigImageEnd()
			setTimeout('U.loadBigImageTestLoader("'+ U.hashToStr(hash)+ '")', 100);
		}
	},

	scrollBottom: function(node){
		node.scrollTop=node.scrollHeight;
	},

	sboxSelect: function(sbox,value){
		if(sbox && sbox.options){
			var ops=sbox.options;
			for(var i=0; i<ops.length; i++){
				if(ops[i].value==value){
					ops.selectedIndex=i;
					break;
				}
			}
		}
	},

	sboxValue: function(sbox){
		var index=sbox.options.selectedIndex;
		var current=sbox.options[index].value;
		return current;
	},

	sboxText: function(sbox){
		var index=sbox.options.selectedIndex;
		var text=sbox.options[index].text;
		return text;
	},

	playFLV: function(flv,w,h,eI){//четвертым параметром может быть id элемента, 
		//в который нужно установить проигрыватель, иначе будет открыто новое окно
		if(eI){
			var FO = { movie:'/admin/fw/js/flvplayer.swf', width:w, height:h, majorversion:7, build:0, bgcolor:'#ffffff', flashvars:'file='+flv+'&showdigits=true&autostart=true&showfsbutton=false' };
			UFO.create(FO, eI);
		}else{
			var flvwin = U.popup('',w,h);
			flvwin.document.open("text/html");
			flvwin.document.writeln('<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 //EN" "http://www.w3.org/TR/html4/strict.dtd">');
			flvwin.document.writeln('<html><head><title>'+flv+'<\/title>');
			flvwin.document.writeln('<script type="text/javascript" src="/admin/fw/js/ufo.js"><\/script>');
			flvwin.document.writeln('<style type="text/css" title="">* {padding:0;margin:0;background:#fff;}<\/style><\/head>');
			flvwin.document.writeln('<body><div id="flvDiv"><\/div>');
			flvwin.document.writeln('<script language="javascript" type="text/javascript">');
			flvwin.document.writeln('var FO = { movie:"/admin/fw/js/flvplayer.swf", width:'+w+', height:'+h+', majorversion:7, build:0, bgcolor:"#ffffff", flashvars:"file='+flv+'&showdigits=true&autostart=true&showfsbutton=false" };');
			flvwin.document.writeln('UFO.create(FO, "flvDiv");<\/script>');
			flvwin.document.writeln('<\/body><\/html>');
			flvwin.document.close();
			flvwin.focus();
		}
	},

	aclocal: function(form_id,elem_name,values_arr,regexp_arr){//autocomplete
		var form=U.gbi(form_id);
		var elem=form.elements[elem_name];
		elem.setAttribute('autocomplete','off');
		U.addEvent(elem,'keyup',function(event){return U.aclocalCatchKeyUp(event,form_id,elem_name)});
		U.addEvent(elem,'keydown',function(event){return U.aclocalCatchKeyDown(event,form_id,elem_name)});
		U['aclocal#'+form_id+'~'+elem_name]={
			'values_arr': values_arr,
			//если массив regexp_arr не был передан, определяем свой массив из двух регулярок,
			//позволяющих найти строку, которая содержит набираемое слово (независимо от порядкового номера слова)
			'regexp_arr': (regexp_arr || [function(str){return new RegExp('^'+str,'i')},function(str){return new RegExp('\\s'+str,'i')}]),
			'start_str': null,
			'likes': null,
			'current_link': 0
		};
	},

	aclocalCatchKeyUp: function(event,form_id,elem_name){
		if(event.keyCode==38 || event.keyCode==40 || event.keyCode==13){return;}
		var str=U.gbi(form_id).elements[elem_name].value;
		U['aclocal#'+form_id+'~'+elem_name].start_str=str;//запоминаем исходное напечатанное
		
		var likes=U.aclocalLikes(str,form_id,elem_name);
		
		var ac=U.gbi(form_id+'AutoComplete');
		if(!ac){alert('на странице не определен элемент #'+form_id+'AutoComplete, в котором будут выводится совпадения');}
		
		if(likes && likes.length){
			ac.style.width=U.gbi(form_id).elements[elem_name].clientWidth + 'px';
			ac.innerHTML=U.aclocalLikesCode(likes,form_id,elem_name);
			U['aclocal#'+form_id+'~'+elem_name].likes=likes;
			ac.style.display='block';
		}else{
			ac.style.display='none';
		}

		var current_link=U['aclocal#'+form_id+'~'+elem_name].current_link;
		U.doOutAclocalLink(form_id+'~'+elem_name+'~link'+current_link,true);
	},

	aclocalLikes: function(str,form_id,elem_name){
		var result=[];
		var values_arr=U['aclocal#'+form_id+'~'+elem_name].values_arr;
		if(str!=''){
			if(values_arr && values_arr.length){
				for(var i in values_arr){
					if(U.aclocalCheckEq(str,form_id,elem_name,values_arr[i])){
						result.push(values_arr[i]);
					}
				}
			}
		}

		return result;
	},

	aclocalCheckEq: function(str,form_id,elem_name,value_to_check){
		var regexp_arr=U['aclocal#'+form_id+'~'+elem_name].regexp_arr;
		var result=false;
		for(var i in regexp_arr){
			var re=regexp_arr[i](str);
			if(value_to_check.search(re)>=0){
				result=true;
				break;
			}
		}
		return result;
	},

	aclocalLikesCode: function(likes,form_id,elem_name){
		var result='';
		for(var i in likes){
			var num=1+parseInt(i);
			result+='<a id="'+form_id+'~'+elem_name+'~link'+num+'" onmouseover="U.doOverAclocalLink(this.id)" onmouseout="U.doOutAclocalLink(this.id)" href="javascript:U.doSelectAclocalLink(\''+form_id+'~'+elem_name+'~link'+num+'\')">'+likes[i]+'<br></a>';
		}

		return result;
	},

	doOverAclocalLink: function(id,replaceValue){
		var form_id=id.split('~')[0];
		var elem_name=id.split('~')[1];
		var link=U.gbi(id);
		if(link){
			var current_link=id.split('~')[2].substr(4);
			U['aclocal#'+form_id+'~'+elem_name].current_link=current_link;
			link.className='ho';
			if(replaceValue){
				U.gbi(form_id).elements[elem_name].value=U['aclocal#'+form_id+'~'+elem_name].likes[current_link-1];
			}
		}else{
			U['aclocal#'+form_id+'~'+elem_name].current_link=0;
		}
	},

	doOutAclocalLink: function(id,replaceValue){
		var link=U.gbi(id);
		var form_id=id.split('~')[0];
		var elem_name=id.split('~')[1];
		if(link){
			U.gbi(id).className='';
			U['aclocal#'+form_id+'~'+elem_name].current_link=0;
			if(replaceValue){
				U.gbi(form_id).elements[elem_name].value=U['aclocal#'+form_id+'~'+elem_name].start_str;
			}
		}
	},

	doSelectAclocalLink: function(id){
		var form_id=id.split('~')[0];
		U.gbi(form_id+'AutoComplete').style.display='none';
		var elem_name=id.split('~')[1];
		var likes=U['aclocal#'+form_id+'~'+elem_name].likes;
		var current_link=parseInt(U['aclocal#'+form_id+'~'+elem_name].current_link);
		var value=likes[current_link-1];
		console.log('value is '+value);
		U.gbi(form_id).elements[elem_name].value=value;
		U.gbi(form_id).submit();
	},

	aclocalCatchKeyDown: function(event,form_id,elem_name){
		if(U['aclocal#'+form_id+'~'+elem_name].current_link > 0){
			var current_link=parseInt(U['aclocal#'+form_id+'~'+elem_name].current_link);
		}

		if(event.ctrlKey==13 && current_link){
			U.doSelectAclocalLink(form_id+'~'+elem_name+'~link'+current_link);
			U.stopEvent(event);
		}//else if(event.ctrlKey || event.altKey || event.shiftKey){return;}

		if(event.keyCode==40 || event.keyCode==38){
			var likes=U['aclocal#'+form_id+'~'+elem_name].likes;
			
			if( !current_link ){
				var current_link=(event.keyCode==40) ? 1 : likes.length;
			}else{
				U.doOutAclocalLink(form_id+'~'+elem_name+'~link'+current_link,true);
				if(event.keyCode==40 && (current_link < likes.length)){
					current_link+=1;
				}else if(event.keyCode==38 && (current_link > 1)){
					current_link-=1;
				}else{
					current_link=0;
				}
			}
			
			U.doOverAclocalLink(form_id+'~'+elem_name+'~link'+current_link,true);
			U.stopEvent(event);
		}
	},

	////////////////////////////////////////////////////////////////////
	// tests
	////////////////////////////////////////////////////////////////////
	isfirst: function(){//
		return (location.pathname=='/' || location.pathname=='/index.html');
	},

	ispda: function(){
		if(window.top && window.top.screen && window.top.screen.width){
			return window.top.screen.width<640;
		}else{
			return true;
		}
	},

	isajax: function(){
		var result=false;
		try{
			var req=new JsHttpRequest();
			result=(typeof req=='object');
		}catch(e){}
		return result;
	},

	////////////////////////////////////////////////////////////////////
	// cookies
	////////////////////////////////////////////////////////////////////
	setCookie: function(cookieName,cookieContent,cookieExpireTime){
		if(cookieExpireTime>0){
			var expDate=new Date();
			expDate.setTime(expDate.getTime()+cookieExpireTime*1000*60*60);
			var expires=expDate.toGMTString();
			document.cookie=cookieName+"="+escape(cookieContent)+"; path="+escape('/')+"; expires="+expires;
		}else{
			document.cookie=cookieName+"="+escape(cookieContent)+"; path="+escape('/')+"";
		}
	},

	getCookie: function(cookieName){
		var ourCookie=document.cookie;
		if(!ourCookie || ourCookie=="")return "";
			ourCookie=ourCookie.split(";");
		var i=0;
		var Cookie;
		while(i<ourCookie.length){
			Cookie=ourCookie[i].split("=")[0];
			if(Cookie.charAt(0)==" ")
				Cookie=Cookie.substring(1);
			if(Cookie==cookieName){
				return unescape(ourCookie[i].split("=")[1]);
			}
			i++;
		}
		return ""
	},

	
	////////////////////////////////////////////////////////////////////
	// events
	////////////////////////////////////////////////////////////////////
	addEvent: function(node,event,func){
		if(!node)return;
		if(node.addEventListener){
			node.addEventListener(event,func,false);
		}else{
			if(node.attachEvent){
				event='on'+event;
				node.attachEvent(event,func);
			}
		}
	},

	removeEvent: function(node,event,func){
		if(!node)return;
		if(node.addEventListener){
			node.removeEventListener(event,func,false);
		}else{
			if(node.detachEvent){
				event='on'+event;
				node.detachEvent(event,func);
			}
		}
	},

	stopEvent: function(event){
		event.cancelBubble = true; //отключить бег события выше для ИЕ
		event.returnValue = false; //отключить стандартное действие
		//то же самое для Мозиллы
		if(event.preventDefault) event.preventDefault(); 
		if(event.stopPropagation) event.stopPropagation();
	},

	tryUntil: function(function2run,testCondition){
		var testCondition=unescape(testCondition);
		var function2run=unescape(function2run);
		if(eval(testCondition)){
			try{
				eval(function2run);
			}catch(e){/*поскольку событие было отложено, возможно что к моменту реализации функция уже перестанет существовать*/}
		}else{
			var date=new Date();
			var mls=parseInt(arguments[2] || 100);
			setTimeout('U.tryUntil("'+ escape(function2run)+ '","'+ escape(testCondition)+ '",'+ mls+ ')',mls);
		}
	},

	clientX: function(){//определяем координату мыши по X
		return U.clientXY()[0];
	},

	clientY: function(){//определяем координату мыши по Y
		return U.clientXY()[1];
	},

	clientTarget: function(){//определяем элемент под мышью
		return U.clientXY()[2];
	},

	clientXY: function(evt){//возвращает координаты мыши
		if(evt){//автовызов, инициированный обработчиком событий
			U.clientXY_x=evt.clientX;
			U.clientXY_y=evt.clientY;
			U.clientXY_target=(evt.target)?evt.target:evt.srcElement;
		}else{//вызвал программист
			if(typeof U.clientXY_x=='undefined'){
				U.clientXY_x=0;
				U.clientXY_y=0;
				U.clientXY_target=null;
				U.addEvent(document,'mousemove',U.clientXY);
			}
			return [U.clientXY_x,U.clientXY_y,U.clientXY_target];
		}
	},

	ctrlEnter: function(event){//отслеживает нажатие ctrl Enter
		if(event.keyCode==13 && event.ctrlKey){
			return true;
		}
		return false;
	},

	////////////////////////////////////////////////////////////////////
	// string
	////////////////////////////////////////////////////////////////////

	splitText: function(str,step){
		var step=step||1;
		var tmpArr=[];
		var result=[];
		var tmp, symb;
		for(var i=0; i<str.length; i++){
			symb=str.substr(i,1);
			if(symb=='&' && str.substr(i).indexOf(';')){
				tmp='&';
				do{
					i++;
					symb=str.substr(i,1);
					tmp+=symb;
				}while(symb && symb!=';');
				tmpArr.push(tmp);
			}else{
				if(symb=='<' && str.substr(i).indexOf('>')){
					tmp='<';
					do{
						i++;
						symb=str.substr(i,1);
						tmp+=symb;
					}while(symb && symb!='>');
					tmpArr.push(tmp);
				}else{
					tmpArr.push(symb);
				}
			}
		}
		if(step==1)return tmpArr;
		for(var i=0; i<tmpArr.length; i+=step){
			tmp='';
			for(var j=0; j<step; j++){
				tmp+=tmpArr[i+j]||'';
			}
			result.push(tmp);
		}
		return result;
	},

	trim: function(str){
		var result=str;
		result=result.replace(/^[\s]+/,'');
		result=result.replace(/[\s]+$/,'');
		return result;
	},

	validateEmail: function(email){
		var result=email.search(/^[^@\s]+@[^@\s]+\.[^@\s]{2,}$/);
		result=(result==0)?true:false;
		return result;
	},
	
	////////////////////////////////////////////////////////////////////
	// DOM
	////////////////////////////////////////////////////////////////////

	append: function(parent_or_id,child){
		try{
			var parent=(typeof parent_or_id=='string')?U.gbi(parent_or_id):parent_or_id;
			parent.appendChild(child);
			if(navigator.appName=='Microsoft Internet Explorer'){
				parent.innerHTML+='';
			}
		}
		catch(e){/*alert(e)*/}
	},

	insert: function(parent_or_id,child,ref_or_id){
		try{
			var parent=(typeof parent_or_id=='string')?U.gbi(parent_or_id):parent_or_id;
			var ref=(typeof ref_or_id=='string')?U.gbi(ref_or_id):ref_or_id;
			parent.insertBefore(child,ref);
			if(navigator.appName=='Microsoft Internet Explorer'){
				parent.innerHTML+='';
			}
		}
		catch(e){/*alert(e)*/}
	},

	rmv: function(elem_or_id){
		try{
			if(typeof elem_or_id=='string'){
				var elem=U.gbi(elem_or_id);
			}else{
				var elem=elem_or_id;
			}
			var parent=elem.parentNode;
			parent.removeChild(elem);

			return true;
 		}
		catch(e){alert('cant remove element: '+elem_or_id);}
	},

	gbi: function(id){
		return document.getElementById(id);
	},

	gbt: function(tagname,elem_or_id){
		var parent=(elem_or_id)?
			(typeof elem_or_id=='string')?U.gbi(elem_or_id):elem_or_id
			:document;
		var result=parent.getElementsByTagName(tagname);
		if(result && result.length){
			return result;
		}
	},

	gbtr: function(tagname,elem_or_id){
		var parent=(elem_or_id)?
			(typeof elem_or_id=='string')?U.gbi(elem_or_id):elem_or_id
			:document;
		var elem=(typeof elem_or_id=='string')?U.gbi(elem_or_id):elem_or_id;
		U.tags=new Array();
		U.gbtRecursive(tagname,parent);
		var result=U.tags;
		U.tags=null;
		if(result && result.length){
			return result;
		}
	},

	gbtc: function(tagname,classname,elem_or_id){
		var result=[];
		var parent=(elem_or_id)?
			(typeof elem_or_id=='string')?U.gbi(elem_or_id):elem_or_id
			:document;
		var tags=U.gbt(tagname,parent);
		if(tags){
			for(var i=0; i<tags.length; i++){
				if(tags[i].className==classname){
					result.push(tags[i]);
				}
			}
		}
		if(result && result.length){
			return result;
		}
	},

	gbtcr: function(tagname,classname,elem_or_id){
		var result=[];
		var parent=(elem_or_id)?
			(typeof elem_or_id=='string')?U.gbi(elem_or_id):elem_or_id
			:document;
		var tags=U.gbtr(tagname,parent);
		if(tags){
			for(var i in tags){
				if(tags[i].className==classname){
					result.push(tags[i]);
				}
			}
		}
		if(result && result.length){
			return result;
		}
	},

	gbtRecursive: function(tagname,parent){
		for(var i=0; i<parent.childNodes.length; i++){
			if(parent.childNodes[i].nodeType==1){
				if(parent.childNodes[i].tagName==tagname){
					U.tags.push(parent.childNodes[i]);
				}
				U.gbtRecursive(tagname,parent.childNodes[i]);
			}
		}
	},

	layerX: function(elem_or_id){//определяем левую координату слоя
		var elem=(typeof elem_or_id=='string')?U.gbi(elem_or_id):elem_or_id; 
		return U.layerXY(elem)[0];
	},

	layerY: function(elem_or_id){//определяем верхнюю координату слоя
		var elem=(typeof elem_or_id=='string')?U.gbi(elem_or_id):elem_or_id; 
		return U.layerXY(elem)[1];
	},

	layerXY: function(elem_or_id){//определяем обе координаты слоя
		var x=0;
		var y=0;
		var elem=(typeof elem_or_id=='string')?U.gbi(elem_or_id):elem_or_id; 
		while(elem){
			x+=elem.offsetLeft-elem.scrollLeft;
			y+=elem.offsetTop-elem.scrollTop;
			if(elem.tagName=='BODY'){
				elem=U.htmlTag();
			}else{
				elem=elem.offsetParent;
			}
		}
		return [x,y];
	},

	showhide: function(id){
		if(U.gbi(id)){
			if(U.gbi(id).offsetHeight>0){
				U.gbi(id).style.display='none';
			}else{
				U.gbi(id).style.display='block';
			}
		}
	},

	sh: function(id){
		U.showhide(id);
	},

	bodyTag: function(){
		if(!U.bodyTagElement){
			U.bodyTagElement=document.getElementsByTagName('BODY')[0];
		}
		return U.bodyTagElement;
	},
	
	htmlTag: function(){
		if(!U.htmlTagElement){
			U.htmlTagElement=document.getElementsByTagName('HTML')[0];
		}
		return U.htmlTagElement;
	},
	
	////////////////////////////////////////////////////////////////////
	// array
	////////////////////////////////////////////////////////////////////
	array: {
		find: function(array,value){
			for(var i=0; i<array.length; i++){
				if(array[i]==value){
					return i;
				}
			}
			return -1;
		},

		remove: function(array,index){
			array.splice(index,1);
			return array;
		},

		fr: function(array,value){//fiend then remove
			var index=U.array.find(array,value);
			if(index>=0){
				U.array.remove(array,index);
			}
		}
	},

	////////////////////////////////////////////////////////////////////
	// object
	////////////////////////////////////////////////////////////////////
	object: {
		af: function(obj,hash){//apply fields
			var fieldsArr=obj._af.split(',');
			var fieldName='';
			for(var i in fieldsArr){
				fieldName=fieldsArr[i];
				obj[fieldName]=(hash[fieldName]||null);
			}
		},

		join2str: function(obj){//join fields to a string
			var fieldsArr=obj._af.split(',');
			var fieldName='';
			var result='';
			for(var i in fieldsArr){
				fieldName=fieldsArr[i];
				if(obj[fieldName]!=null){
					result+=fieldName+ ':"'+ obj[fieldName]+ '",';
				}
			}
			if(result)result=result.substr(0,result.length-1);
			return result;
		}
	},

	////////////////////////////////////////////////////////////////////
	// animation
	////////////////////////////////////////////////////////////////////
	mouseScroll: function(hash){//осуществляет скроллирование слоя, контролируемое движением мыши
		/*
			hash имеет следующие поля
			id - id элемента для скроллирования
			repeat - способ прокрутки (xy, x, y, no), по умолчанию без прокрутки
			zone - ограничение зоны чувствительности мыши (xy, x, y, no), по умолчанию без ограничения
			methodX (methodY) - матем.метод (пока только sin, он же по умолчанию), описывающий движение слоя //kx (ky) - коэфициент ускорения (от 0 до ...) по оси X (Y), по умолчанию 0,  поэтому если не передан, движение не будет осуществляться по данной оси
		*/
		this._af='id,repeat,methodX,methodY,presets';
		U.object.af(this,hash);

		var layerid='layer'+ this.id;

		//находим слой для прокрутки 
		var layer=U.gbi(this.id);
		//находим родителя
		var parentLayer=layer.parentNode;

		//если это первый вызов
		if(this[layerid]!='object'){
			this[layerid]={};
			this._af='id,repeat,methodX,methodY,layer'+ this.id;
			//у родителя фиксируем ширину, высоту, position и overflow
			parentLayer.style.width=parentLayer.offsetWidth+ 'px';
			parentLayer.style.height=parentLayer.offsetHeight+ 'px';
			parentLayer.style.position='relative';
			parentLayer.style.overflow='hidden';
			//теперь у слоя для прокрутки фиксируем position
			layer.style.position='absolute';
			//запоминаем некоторые величины
			this[layerid].layerWidth=layer.offsetWidth;
			this[layerid].layerHeight=layer.offsetHeight;
			this[layerid].parentWidth=parentLayer.offsetWidth;
			this[layerid].parentHeight=parentLayer.offsetHeight;
			this[layerid].parentLeft=parentLayer.offsetLeft;
			this[layerid].parentTop=parentLayer.offsetTop;
		}
		//вычисляем смещение
			//определяем центр родителя
			var bodyWidth=document.getElementsByTagName('body')[0].offsetWidth;
			if(this[layerid].centerCoords && this[layerid].bodyWidth && this.bodyWidth==bodyWidth){
			}else{
				this[layerid].bodyWidth=bodyWidth;
				this[layerid].centerCoords=U.layerXY(parentLayer);
				this[layerid].centerCoords[0]+=parentLayer.offsetWidth/2;
				this[layerid].centerCoords[1]+=parentLayer.offsetHeight/2;
			}
			//определяем шаг
			var step=[0,0];
			if(this.methodX!=null)
				step[0]=-50*Math.sin((U.clientX()/this[layerid].centerCoords[0]-1)*Math.PI/2);
			if(this.methodY!=null)
				step[1]=-50*Math.sin((U.clientY()/this[layerid].centerCoords[1]-1)*Math.PI/2);
		//перерисовываем слой
		if(step[0]){
			var layerLeft=layer.offsetLeft + step[0];
			if(this.repeat!='x' && this.repeat!='xy'){
				if(layerLeft+this[layerid].layerWidth < this[layerid].parentWidth)
					layerLeft=this[layerid].parentWidth - this[layerid].layerWidth;
				if(layerLeft > 0)layerLeft=0;
			}
			layer.style.left=layerLeft+ 'px';
		}
		if(step[1])
			var layerTop=layer.offsetTop + step[1];
			if(this.repeat!='y' && this.repeat!='xy'){
				if(layerTop+this[layerid].layerHeight < this[layerid].parentHeight)
					layerTop=this[layerid].parentHeight - this[layerid].layerHeight;
				if(layerTop > 0)layerTop=0;
			}
			layer.style.top=(layer.offsetTop + step[1])+ 'px';
		//рекурсивно вызываем функцию
		setTimeout('U.mouseScroll({'+ U.object.join2str(this)+ '})',20);
	},

	typewriter: function(id,text,speed,endfunc){//эффект печатной машинки
		/*
			id - id элемента для применения эффекта
			text - сам текст, может содержать конечные теги, типа <br>
			speed - скорость вывода (необязательный параметр)
			endfunc - строка кода, который будет выполнен по окончании вывода текста
		*/

		//получаем текст в виде массива
		var step=U.defvar(1,parseInt(speed));
		var textArr=U.splitText(text,step);
		var arrStr=textArr.join('¬');
		var endfunc=(endfunc!='')?escape(endfunc):'';
		//создаем хэш для таймеров
		if(!U.typewriterTimer){U.typewriterTimer={};}
		//формируем функцию для рекурсивного вызова и запускаем ее
		U.typewriterRec(id,arrStr,endfunc);
	},

	typewriterRec: function(id,arrStr,endfunc,position){
		var textArr=arrStr.split('¬');
		var position=position||0;
		if(position==0){U.gbi(id).innerHTML='';}
		if(position<textArr.length && U.gbi(id)){
			//определяем очередную порцию текста
			var textPortion=textArr[position];
			//меняем пробелы на табуляцию, чтобы пробелы не проглатывались маками
			textPortion=textPortion.replace(/ /g, '&#9;');
			//в уже напечатанном тексте делаем обратную замену
			var textExisted=U.gbi(id).innerHTML
			textExisted=textExisted.replace(/&#9;/g, ' ');
			//добавляем очередную порцию текста
			U.gbi(id).innerHTML=textExisted+ textPortion;
			position++;
			U.typewriterTimer[id]=setTimeout('U.typewriterRec("'+ id+ '","'+ arrStr+ '","'+ endfunc+ '","'+ position+ '")',25);
		}else{
			var endfunc=unescape(endfunc);
			eval(endfunc);
		}
	}
}