/*
* JavaScript templayte ver. 0.0.1
* Copyright (c) 2007-2008 Sergey Voronkov(grey_asd@mail.ru)
* Пожалуста не удаляйте и не изменяйте эти коментарии.
* 
*   Dual licensed under the MIT (MIT-LICENSE.txt)
 * and GPL (GPL-LICENSE.txt) licenses.
 *
*/
var jsFW = function()
{
	return {
		version:'0.0.1',
		mail:''
	};
};
var userAgent = navigator.userAgent.toLowerCase();
jsFW.browser = {
	version: (userAgent.match( /.+(?:rv|it|ra|ie)[\/: ]([\d.]+)/ ) || [])[1],
	safari: /webkit/.test( userAgent ),
	opera: /opera/.test( userAgent ),
	msie: /msie/.test( userAgent ) && !/opera/.test( userAgent ),
	mozilla: /mozilla/.test( userAgent ) && !/(compatible|webkit)/.test( userAgent )
};

/**
* Расширение стандартных обьектов
*/
jsFW.extendPrototype = function(obj,proto)
{
	for(var i in proto)
		if(!obj.prototype[i]) obj.prototype[i] = proto[i];
};

jsFW.Prototype = function(obj,proto)
{
	for(var i in proto) if(!obj[i]) obj[i] =(function(proto){return function(){return proto.apply(this,[this].concat(Array.prototype.slice.apply(arguments)))}})(proto[i]);
	return obj;
};
/** Создание ленивой функции
* @param {Function} Функция которая будет вычеслина только один раз
* @param {Array} Мосив аргументов передаваемые в функцию при вычесление
* @return {Function} Ленивая функция
*/
jsFW.lazy = function(fun,arg)
{
	var res;
	return function() { return res || (res = fun.apply(this,arg || []))};
};
/** Лямбда вырожения
* @param {String} 
* @return {Function}  функция
*/
jsFW.lambda = function(lambda)
{
	var t = lambda.split('->');
	var params = t.length>1?t[0].split(','):[];
	var fun = t[1]||t[0];
	return new Function(params,'return ('+ fun +')');
}

/**
* Создает новый клас на основе базового
* @param {Class} Наследуемый класс
* @param {Function} Функция возврощающая прототип обьекта класса
* @return {Class} Новый класс
*/
jsFW.Class = function(proto,base)
{
	var _class = function(fun,arg)
	{
		if(this.constructor == _class)
		{
			if(this.__constructor) this.__constructor.apply(this,arguments)
		}
		else
		{
			if(typeof fun != 'string') {arg = fun;fun=false;}
			if(!fun) fun = '__constructor';
			this.__base = base;
			if(_class.prototype[fun]) return _class.prototype[fun].apply(this,arg||[]);
			this.__base = _class;
		}
	};
	if(base)
	{
		var instance = function(){};
		instance.prototype = base.prototype;
		_class.prototype = new instance();
	}
	_class.prototype.constructor = _class;
	if(proto instanceof Function) proto = proto(base);
	jsFW.hash.extend(_class.prototype,proto);
	_class.prototype.__base = base;
	return _class;
};

/**
* Обьект для работы с кешем
*/
jsFW.hash = {
/**
	* Дополняет хеш свойствами других хешов 
	* @param {Object} Дополняемый хеш
	* @param {Object} Донор (Может быть несколько)
	* @return {Object} Измененый хеш
	*/
	extend:function(hash/*, ....*/)
	{
		for(var i=1,len = arguments.length;i<len;i++) for(var prop in arguments[i]) hash[prop] = arguments[i][prop];
		return hash;
	},
	unite:function(hash)
	{
		for(var i=1,len = arguments.length;i<len;i++)
		{
			var hash2 = arguments[i];
			for(var prop in hash2)
			{
				if(typeof hash2[prop] == 'object')
					jsFW.hash.unite(hash[prop],hash2[prop]);
				else
					hash[prop] = hash2[prop];
			}
		}
		return hash;
	},
	/** 
	* Осуществляет слияние двух и более хешов
	* @param {Object} Хеши более двух
	* @return {Object} Новый хеш
	*/
	merge:function()
	{
		var hash = {};
		for(var i=0,len = arguments.length;i<len;i++) for(var prop in arguments[i]) hash[prop] = arguments[i][prop];
		return hash;
	},
	/**
	* Поиск ключа по значению
	* @param {Object} hash Хеш где искать
	* @param {Object} value Значение которое искать
	* @return {String} Ключь
	*/
	indexOf:function(hash,value)
	{
		for(var i in hash) if(hash[i]==value) return i;
		return false;
	},
	/**
	* Выполняет функцию над всеми элиментами хеша
	* @param {Object}	Хеш
	* @param {Function}	выполняемая функция вида function(element,key,hash)
	* @param {Object}	Относительно ково будет выполнятся функция если не указана то относительно текущего елимента
	* @return {Object}
	*/
	each:function(hash,iterator,s)
	{
		var res = {};
		if(typeof iterator == 'function')
			for(var i in hash) res[i] = iterator.call(s || hash[i],hash[i],i,hash);
		else
			for(var i in hash) res[i] = (s[iterator] || hash[i][iterator])(hash[i],i,hash);
		return res;
	},
	/** Размер хеша *
	* @param {Object} 
	* @return {Number} 
	*/
	size:function(hash)
	{
		var size = 0;for(var i in hash) size++;
		return size;
	},
	/** Меняет местами ключь <-> значение *
	* @param {Object}
	* @return {Object}
	*/
	invert:function(hash)
	{
		var res = {};
		for(var i in hash) res[hash[i]] = i;
		return res;
	},
	/** Преобразует хеш в строку http запроса 
	*	@param {Object}
	*	@return {String}
	*/
	toHttpStr:function(hash)
	{
		if(typeof hash == 'string') return hash;
		var res = [];
		for(var i in hash)
		{
			if(hash[i] instanceof Array) res.push(hash[i].map(function(v){ return i+'='+encodeURIComponent(v);}).join('&'));
			else res.push(encodeURIComponent(i)+'='+encodeURIComponent(hash[i]));
			
		}
		return res.join('&').replace(/%20/g, "+");
	},
	/** Преобразовывает строку http запроса в хеш
	* @param {String}
	* @return {Object}
	*/
	fromHttpStr:function(http)
	{
		var param = decodeURIComponent(http).replace(/[\+]/g,' ').split('&');
		var res = {};
		for(var i=0,len=param.length;i<len;i++)
		{
			var t = param[i].split('=');
			if(!res[t[0]])
				res[t[0]] = t[1];
			else
			{
				if(!(res[t[0]] instanceof Array))
					res[t[0]] = [res[t[0]]];
				res[t[0]].push(t[1]);
			}
		}
		return res;
	}
};
/**
 * Возвращает случайное целое число в диапазоне от min до max *
 * @param {Object} min минимальное значение 
 * @param {Object} max максимальное значение 
 * @return {Integer} 
 */ 
Math.rand = function(min, max) { var res = Math.random(); return (min == undefined || max == undefined) ? res : Math.floor(res * (max - min + 1) + min)}; 
jsFW.extendPrototype(Array, 
{
	/**
	* Возврощает индекс в мосиве по значению
	* @param {Object}	Искомое значение
	*@return {Number}	Индекс значения в масиве
	*/
	indexOf:function(value)
	{
		for(var i=0,len=this.length;i<len;i++) if(this[i]===value) return i;
		return -1;
	},
	/**
	*
	* @param {Function}
	* @param {Object}
	* @return {Array}
	*/
	map:function(iterator,s)
	{
		var res = [];
		for(var i=0,len=this.length;i<len;i++)	res.push(iterator.call(s,this[i],i,this));
		return res;
	},
	/**
	* Выполняет функцию над всеми элиментами хеша
	* @param {Function}	выполняемая функция вида function(element,key,hash)
	* @param {Object}	Относительно ково будет выполнятся функция если не указана то относительно текущего елимента
	* @return {Array}
	*/
	each:function(iterator,s,arg)
	{
		var res = [];
		if(typeof iterator == 'function')
			for(var i=0,len=this.length;i<len;i++) res.push(iterator.call(s,this[i],i,this,arg));
		return res;
	},
	fun:function(iterator,arg)
	{
		var res = [];
		var arg = arg || [];
		for(var i=0,len=this.length;i<len;i++) if(typeof this[i][iterator] == 'function') res.push(this[i][iterator].apply(this[i],arg));
		return res;
	},
	/**
	*
	* @param {Function}
	* @param {Object}
	* @return {Array}
	*/
	filter:function(filter,s)
	{
		var ret = [];
		for(var i=0,len=this.length;i<len;i++) if(this[i] != undefined && filter.call(s,this[i],i,this)) ret.push(this[i]);
		return ret;
	},
	/**
	* Находит элимент и удаляет его
	* @param {Object}
	* @return {Object}
	*/
	removeElement:function(el)
	{
		var i = this.indexOf(el);
		if(i>=0) this.splice(i,1);
		return el;
	},
	toHash:function()
	{
		var res = {};
		for(var i=0,len=this.length;i<len;i++) res[this[i][0]] = this[i][1];
		return res;
	}
});
/**
* Работа с сабытиями
*/
/**
	* Создает делигата событий
	* @param {Object} 	Относительно ково запустится функция
	* @param {Function}	Функция
	* @param {Array}	Дополнительные параметры
	* @return {Function}	Функция вида function(s,e,param1,param2,...);
	*/
jsFW.delegate = function(i, m, p){return function(e){if(m) return m.apply(i,[this,e!=undefined?e:window.event].concat(p||[]));}};
jsFW.event = 
{
	keys:{backspace:8,tab:9,enter:13,esc:27,left:37,up:38,right:39,down:40,del:46,home:36,end:35,pageup:33,pagedown:34,insert:45},
	fix:function(event)
	{
		var e = jsFW.hash.extend({},event);
		if ( !e.target && e.srcElement ) e.target = e.srcElement;
		// check if target is a textnode (safari)
		if (jsFW.browser.safari && e.target.nodeType == 3) e.target = event.target.parentNode;
		// Add relatedTarget, if necessary
		if ( !e.relatedTarget && e.fromElement )
			e.relatedTarget = e.fromElement == e.target ? e.toElement : e.fromElement;
		// Calculate pageX/Y if missing and clientX/Y available
		if ( e.pageX == null && e.clientX != null ) {
			var de = document.documentElement, b = document.body;
			e.pageX = e.clientX + (de && de.scrollLeft || b.scrollLeft || 0);
			e.pageY = e.clientY + (de && de.scrollTop || b.scrollTop || 0);
		}
		// Add which for key events
		if ( !e.which && (e.charCode || e.keyCode) )e.which = e.charCode || e.keyCode;
		
		// Add metaKey to non-Mac browsers (use ctrl for PC's and Meta for Macs)
		if ( !e.metaKey && e.ctrlKey ) e.metaKey = e.ctrlKey;
		// Add which for click: 1 == left; 2 == middle; 3 == right
		// Note: button is not normalized, so don't use it
		if ( !e.which && e.button )e.which = (e.button & 1 ? 1 : ( e.button & 2 ? 3 : ( e.button & 4 ? 2 : 0 ) ));
		return e;
	},
	/**
	*	Добавить событие к обьекту
	* @param {Object}	Обьект к которому привязывается событие
	* @param {String}	Тип события
	* @param {Function}	Функция выполняемая при событие
	* @return {Object}	Обьект к которому привязывается событие
	*/
	add:function(object,event,callback)
	{
		if(!callback) return object;
		if(!object.__events) object.__events = {};
		if(!object.__events[event])
		{
			object.__events[event] = object[event]?[object[event]]:[];
			object[event] = function(e)
			{
				var arg = arguments;
				if(e==undefined || (Event && e instanceof Event)) arg = [jsFW.event.fix(e || window.event)]
				return jsFW.event.call(object,event,arg);
			}
		}
		object.__events[event].push(callback);
		return object;
	},
	/**
	*	Удаление события
	*	@param {Object}	Обьект у которого удоляется событие
	*	@param {String}		Тип события
	*	@param {Function}	Удоляемая функция (может не быть)
	*	@return {Object}	Обьект у которого удоляется событие
	*/
	remove:function(object,event,fun)
	{
		if(event && fun)
			object.__events[event].removeElement(fun);
		else
		{
			for(var i in object.__events) delete object[i];
			delete object.__events;
		}
		return object;
	},
	/**
	*	Выполнение событий у обьекта
	*	@param {Object}	Обьект 
	*	@param {String}		Тип события
	*	@param {Array}		Аргументы
	*/
	call:function(object,event,arg)
	{
		var arg = arg || [];
		if(object.__events && object.__events[event])
		{
			var e = object.__events[event];
			for(var i=0,len=e.length;i<len;i++) if(e[i].apply(object,arg||[]) === false) return false;
		}
		else
			return object[event] && object[event].apply(object,arg||[]);
	},
	one:function(object,event,fun)
	{
		jsFW.event.add(object,event,function()
		{
			jsFW.event.remove(object,event,arguments.callee);
			return fun.apply(this,arguments);
		});
	},
	hover: function(object,fun) {
		function handleHover(e) {
			var p = e.relatedTarget;
			while ( p && p != this ) try { p = p.parentNode; } catch(e) { p = this; };
			if ( p == this ) return false;
			e.hover = e.type == "mouseover";
			return fun.apply(this, [e]);
		}
		jsFW.event.add(object,'onmouseover',handleHover);
		jsFW.event.add(object,'onmouseout',handleHover);
		return object;
	}
};
jsFW.Object = jsFW.Class({
	addEvent:function(type,callback){return jsFW.event.add(this,type,callback);},
	removeEvent:function(type,callback){return jsFW.event.remove(this,type,callback);},
	callEvent:function(type,arg){return jsFW.event.call(this,type,arg);}
});
/**
* Работа с DOM обьектами
*/
jsFW.element = function(arg)
{
	var res = [].concat(arg).map(function(id){return jsFW.element.get(id)});
	res.fun = function(iterator)
	{
		var res = [];
		var arg = Array.prototype.slice.apply(arguments);
		for(var i=0,len=this.length;i<len;i++)
		{
			arg[0] = this[i];
			res.push(iterator.apply(this,arg));
		}
		res.fun = arguments.callee;
		return res;
	};
	return res.length>1?res:res[0];
};
jsFW.hash.extend(jsFW.element,
{
	
	/**
	* Получение обьекта по id
	* @param {string} 		Id или сам обьект
	* @return {DOMObject}	Найденный обьект
	*/
	get:function(id)
	{
		if(typeof id == 'string') return document.getElementById(id);
		return id;
	},
	/**
	* Создание DOM елимента
	* @param {String} 		Название тега или html
	* @param {Object}		Параметры элимента - может не быть
	* @param {DOMObject}	Радительский элимент(куда добавить) - может не быть
	* @return {DOMObject}	Новый элимент
	*/
	create:function(tag,p,parent)
	{ 
		var el = null;
		try{el = document.createElement(tag);}
		catch(e){try{el = jsFW.element.create('div',{innerHTML:tag}).childNodes[0];}catch(e){return false;}}
		if(p && p.appendChild) parent = p;
		else el = jsFW.hash.unite(el,p);
		if(parent) parent.appendChild(el);
		return el; 
	},
	/**
	* Делает елимент пустым
	* @param {DOMObject}
	* @return {DOMObject}
	*/
	empty:function(element)
	{
		if(element)
		{
			var ch = element.childNodes;
			for(var i=ch.length;i>0;)
				jsFW.element.remove(ch[--i]);
		}
		return element;
	},
	/**
	* Удаляет элимент из dom
	* @param {DOMObject}
	* @return {DOMObject}
	*/
	remove:function(element)
	{
		if(element && element.parentNode) element.parentNode.removeChild(element);
		return element;
	},
	/**
	* Возращает или записывает в элимент текст зависит от второво аргумента
	* @param {DOMObject}
	* @param {String}
	* @return {DOMObject}
	*/
	text:function(element,txt)
	{
		if(element)
		{
			if(txt == undefined) return element.textContent || element.innerText;
			if(element.textContent!=undefined)
				element.textContent=txt;
			else
				element.innerText=txt;
		}
		return element;
	},
	/**
	* Добовляет класс к обьекту *
	* @param {DOMObject}
	* @param {String} 		Имя класса
	* @return {DOMObject}
	*/
	addClass:function(element,cName)
	{
		if(element && !((new RegExp("\\b"+cName+"\\b","i")).test(element.className))) element.className += ' '+cName;
		return element;
	},
	/**
	* Удаляет класс  обьекта *
	* @param {DOMObject}
	* @param {String} 		Имя класса
	* @return {DOMObject}
	*/
	removeClass:function(element,cName)
	{
		if(element) element.className = element.className.replace((new RegExp("\\b"+cName+"\\b","i")),'');
		return element;
	},
	opacity:function(element, nOpacity)
	{
		var opacity = (function()
		{
			if (!jsFW.browser.opera && typeof document.body.style.opacity == 'string') // CSS3 compliant 
				return function(element, nOpacity) {element.style['opacity'] = nOpacity}
			else if (jsFW.browser.mozilla)return function(element, nOpacity) {element.style['MozOpacity'] = nOpacity}
			else if (jsFW.browser.safari) return function(element, nOpacity) {element.style['KhtmlOpacity'] = nOpacity}
			else if (jsFW.browser.msie && jsFW.browser.version >5.5) // Internet Exploder 5.5+
			{
				return function(element, nOpacity) {
					nOpacity *= 100;
					// Если уже установлена прозрачность, то меняем её через коллекцию filters, иначе добавляем прозрачность через style.filter
					var oAlpha = element.filters['DXImageTransform.Microsoft.alpha'] || element.filters.alpha;
					if (oAlpha) oAlpha.opacity = nOpacity;
					else element.style.filter += "progid:DXImageTransform.Microsoft.Alpha(opacity="+nOpacity+")"; // Для того чтобы не затереть другие фильтры используем "+="
				}
			}
			else
				return function(){}; //нет прозрачности
		})();
		jsFW.element.opacity = opacity;
		opacity.call(this,element, nOpacity);
	}
});

jsFW.HttpRequest = jsFW.Class({
	__constructor:function(o)
	{
		this.async = true;
		this.method = 'get';
		this.type = 'text';
		this.timeout = 0;
		jsFW.hash.extend(this,o);
		this.createRequest();
	},
	createRequest:function()
	{
		if (window.XMLHttpRequest) {
			try {
				this.req = new XMLHttpRequest();
			} catch (e){}
		} else if (window.ActiveXObject) {
			try {
				this.req = new ActiveXObject('Msxml2.XMLHTTP');
			} catch (e){
				try {
					this.req = new ActiveXObject('Microsoft.XMLHTTP');
				} catch (e){return ;}
			}
		}
		function processReqChange()
		{
			try {if (this.req.readyState == 4) {
					if (this.req.status == 200) this.success();
					else this.faled();
				}}
			catch(e) {
				this.faled(e);
				throw e;
			}
		}
		if(this.req)
		{
			this.req.onreadystatechange = jsFW.delegate(this,processReqChange);
			this.dFaled = jsFW.delegate(this,this.faled);
		}
	},
	faled:function(error)
	{
		console.log('HttpRequest: '+error);
		this.callEvent('onfaled',[error]);
	},
	success:function()
	{
		var data = null;
		function toXml(s, doc) {
			if (window.ActiveXObject) {
				doc = new ActiveXObject('Microsoft.XMLDOM');
				doc.async = 'false';
				doc.loadXML(s);
			}
			else
				doc = (new DOMParser()).parseFromString(s, 'text/xml');
			return (doc && doc.documentElement && doc.documentElement.tagName != 'parsererror') ? doc : null;
		};
		try
		{
			if(this.type == 'xml')
			{
				data = this.req.responseXML;
				if (!data && this.req.responseText != null) data = toXml(this.req.responseText);
			}
			else if(this.type == 'json')
				data = eval('('+this.req.responseText+')');
			else
				data = this.req.responseText;
		}catch(e)
		{
			this.faled(e);
			return;
		}
		this.callEvent('onsuccess',[data]);
	},
	send:function(url,param)
	{
		var a = url.split('?');
		url = a[0];
		if(a[1]) param = jsFW.hash.extend(jsFW.hash.fromHttpStr(a[1]),param);
		param = jsFW.hash.toHttpStr(param) || null;
		if(param && this.method.toLowerCase()=='get'){
			url += '?'+param;
			param = null;
		}
		var method = param?this.method:'get';
		this.req.open(method,url,this.async);
		if(param) this.req.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
		this.req.setRequestHeader("X-Requested-With", "XMLHttpRequest");
		this.req.setRequestHeader("If-Modified-Since", "Sat, 1 Jan 2000 00:00:00 GMT");
		this.req.send(param);
	}
},jsFW.Object);
jsFW.FormHttpRequest = jsFW.Class({
	createRequest:function()
	{
		this.req = {
		responseText: null,
		responseXML: null,
		status: 0,
		statusText: 'n/a',
		getAllResponseHeaders: function() {},
		getResponseHeader: function() {},
		setRequestHeader: function() {}
		};
	},
	send:function(url,form)
	{
		
		var id = 'jqFormIO' + jsFW.FormHttpRequest.id++;
		var io = jsFW.element.create('<iframe id="' + id + '" name="' + id + '" />',{style:{position:'absolute',top: '-1000px',left: '-1000px'}},document.body);
		var op8 = jsFW.browser.opera && window.opera.version() < 9;
		if (jsFW.browser.msie || op8) io.src = 'javascript:false;document.write("");';
		var cbInvoked = 0;
		var _this = this;
		jsFW.event.add(io,'onload',function()
		{
			if (cbInvoked++) return;
			jsFW.event.remove(io,'onload',arguments.callee);
			try
			{
				var doc = io.contentWindow ? io.contentWindow.document : io.contentDocument ? io.contentDocument : io.document;
				_this.req.responseText = doc.body ? doc.body.innerHTML : null;
				_this.req.responseXML = doc.XMLDocument ? doc.XMLDocument : doc;
				_this.success();
			}
			catch(e)
			{
				_this.faled(e);
				throw e;
			}
			setTimeout(function() {
				jsFW.element.remove(io);
			}, 100);
		});
		
		var encAttr = form.encoding ? 'encoding' : 'enctype';
		var t = form.target;
		form.target = id;
		form.method = 'POST';
		if(url) form.action = url;
		form[encAttr] = 'multipart/form-data';
		form.submit();
		form.target = t; // reset target
	}
},jsFW.HttpRequest);
jsFW.FormHttpRequest.id = 0;
/**
* Выполняет функцию после полной загрузки страницы
* @param {Function}		Функция которую нужно выполнить
*/
jsFW.ready = function(fun)
{
	if(jsFW.ready.is_ready) fun.call();
	else jsFW.event.add(jsFW.ready,'onready',fun);
};
jsFW.ready.onloading = function()
{
	jsFW.event.call(jsFW.ready,'onready');
	jsFW.event.remove(jsFW.ready);
	jsFW.ready.is_ready = true;
};
(function(){
	if (jsFW.browser.msie && window == top )
	{
		try {document.documentElement.doScroll("left");
		} catch(e){setTimeout( arguments.callee, 0 );return;}
		jsFW.ready.onloading();
	}
	if (document.addEventListener)document.addEventListener("DOMContentLoaded",jsFW.ready.onloading, false );
})();

/** Simple JavaScript Templating *
*  John Resig - http://ejohn.org/ - MIT Licensed *
* @exsample 
*	<script type="text/html" id="item_tmpl">
*	  <div id="<%=id%>" class="<%=(i % 2 == 1 ? " even" : "")%>">
*		<div class="grid_1 alpha right">
*		  <img class="righted" src="<%=profile_image_url%>"/>
*		</div>
*		<div class="grid_6 omega contents">
*		  <p><b><a href="/<%=from_user%>"><%=from_user%></a>:</b> <%=text%></p>
*		</div>
*	  </div>
*	</script>
*	var results = document.getElementById("results");
*	results.innerHTML = tmpl("item_tmpl", dataObject);
*	var show_user = tmpl("item_tmpl"), html = "";
*	for ( var i = 0; i < users.length; i++ ) {
*		 html += show_user( users[i] );
*	}
*/
(function(){
	var cache = {};
	jsFW.tmpl = function tmpl(str, data){
	// Выяснить, мы получаем шаблон или нам нужно его загрузить
	// обязательно закешировать результат
	var fn = !/\W/.test(str) ?
	  cache[str] = cache[str] ||
		tmpl(document.getElementById(str).innerHTML) :
 
	  // Сгенерировать (и закешировать) функцию, 
	  // которая будет служить генератором шаблонов
	  new Function("obj",
		"var p=[],print=function(){p.push.apply(p,arguments);};" +
 
		// Сделать данные доступными локально при помощи with(){}
		"with(obj){p.push('" +
 
		// Превратить шаблон в чистый JavaScript
		str
			.replace(/[\r\t\n]/g, " ")
			.split("<%").join("\t")
			.replace(/((^|%>)[^\t]*)'/g, "$1\r")
			.replace(/\t=(.*?)%>/g, "',$1,'")
			.split("\t").join("');")
			.split("%>").join("p.push('")
			.split("\r").join("\\'")
		+ "');}return p.join('');");
	return data ? fn( data ) : fn;
  };
})();
String.prototype.lambda = function(){	return jsFW.lambda(this);}
/**
*  Сокращения *
*/
$ = jsFW.element;
$C = jsFW.Class;
$e = jsFW.event;
