/* Version 1.0.3 */

var HttpRequest = {

	get : function(url, params, callback) {
    url += '?charset='+(document.charset || document.characterSet);	
		var process = true,
			sid = 'sid' + parseInt(Math.random()*1000000),
			cb = 'cb=HttpRequest.callback.' + sid,
			script = document.createElement('script');
		script.type = 'text/javascript';
		script.charset = 'utf-8';
		if(params) {
			var sep = ''; url += '&';
			for(var name in params) {
				url += sep + name + '=' + params[name];
				sep = '&';
			}
		}
		if(url.indexOf('?') == -1) script.src = url + '?' + cb;
		else if(url.match(/\?[\w\d]+/)) script.src = url + '&' + cb;
		else script.src = url + cb;
		HttpRequest.callback[sid] = function(response) {
			process = false;
			callback(response);
		};
		script.onerror = script.onload = script.onreadystatechange = function() {
			if(!this.loaded && (!this.readyState
				|| this.readyState == 'loaded'
				|| this.readyState == 'complete'))
			{
				this.loaded = 1;
				this.onerror = this.onload = this.onreadystatechange = null;
				if(process) { callback(false); } else { /* Ответ пришел */ }
				this.parentNode.removeChild(this);
				delete script;
				delete HttpRequest.callback[sid];
			}
		}
		if(document.getElementsByTagName('head').length) {
			document.getElementsByTagName('head')[0].appendChild(script);
		} else { document.appendChild(script); }
	},

	post : function(url, params, callback) {
    url += '?charset='+(document.charset || document.characterSet);	
		function add2body(html) {
			var b = document.body;
			var div = document.createElement('div');        
			div.innerHTML = html.join ? html.join('') : html;    
			while (div.childNodes.length > 0) b.appendChild(div.childNodes[0]);
			return b.lastChild;
		}
		var form, input, doc = document, fid = 'fid' + parseInt(Math.random()*1000000),
  			html = '<iframe style="display:none" onload="HttpRequest._onLoad(this)"'
		  		+ ' src="javascript:true" id="' + fid + '" name="' + fid + '"></iframe>';
		var frame = add2body(html);
		HttpRequest.callback[fid] = callback;
		if(params) {
			if(params.nodeType) {
				form = params;
			} else {
				form = document.createElement('form');
				for(var name in params) {
					var value = params[name];
					input = document.createElement('textarea');
					input.name = name;
					input.value = value;			
					form.appendChild(input);
				}
			}
			if(form) {
				form.method = 'post';
				form.action = url;
				form.target = fid;
				//form.charset = form.acceptCharset = 'utf-8';
				form.style.display = 'none';
				document.body.appendChild(form);
				form.submit();
				form.parentNode.removeChild(form);
			}
		} else {
			frame.src = url;
			if(frame.contentWindow) {
				frame.contentWindow.location.replace(url);
			}	
		}
	},

	callback : {},

	_getData : function(frame) {
		if(frame.abort) return;
		var callback = HttpRequest.callback[frame.id];
		if(callback) {
			try {
				callback(eval("(" + frame.contentWindow.name + ")"));
			} catch (ex) {}
			delete HttpRequest.callback[frame.id];
		}
		setTimeout(function() { frame.parentNode.removeChild(frame); }, 0);				
	},

	_onLoad : function(frame) {
		var blank = 'about:blank',
			wnd = frame.contentWindow;
		try {
        	if (!frame.state && (wnd.location == blank
				|| wnd.location == 'javascript:true')) return;
		} catch (ex) {}
		if(frame.state) {
			return this._getData(frame);
		} else wnd.location = blank;
		frame.state = 1;
	}

}

function FeedbackWidget(sComplexId, oProperty) {

	var sVersion = "1_0_3",
		sAppid = sComplexId.split(":")[0],
		sClientId = sComplexId.split(":")[1],
		sLanguage = oProperty ? (oProperty.sLanguage || "ru") : "ru",
		sDeviceSignature,
		sSession,
		aSuggestionObjects,
		oSuggestion,
		nCurrentContent,
		sCurrentList,
		sSuggestionTemplate,
		sCommentTemplate,
		oClientLocalization,
		GOut,
		GCache = {};

	//
	// DOM utils.
	//

	function id(sId, bRefresh) {
		if(bRefresh && GCache[sId]) {
			if(GCache[sId].parentNode) GCache[sId].parentNode.removeChild(GCache[sId]);
			delete GCache[sId];
		}
		return GCache[sId] || (GCache[sId] = document.getElementById(sId));
	}
	function ce(sTag) { return document.createElement(sTag); }
	function Add2Body(sHtml) {
		var b = document.body;
		var div = document.createElement('div');
		div.innerHTML = sHtml.join ? sHtml.join('') : sHtml;
		while (div.childNodes.length > 0) b.appendChild(div.childNodes[0]);
		return b.lastChild;
	}

	function AddStyle(sText) {
    	var oStyle = ce("style");
    	oStyle.type = "text/css";
    	if(oStyle.styleSheet) oStyle.styleSheet.cssText = sText;
        else {
			if(oBrowser.bIsMozilla || oBrowser.bIsOpera) oStyle.innerHTML = sText;
            else {
            	var oCssText = document.createTextNode(sText);
            	oStyle.appendChild(oCssText);
        	}
        }
        var oHead = document.getElementsByTagName('head')[0];
        oHead.appendChild(oStyle);
	}

	function GetTarget(oEvent) {
		var oTarg;
		if (!oEvent) var oEvent = window.event;
		if (oEvent.target) oTarg = oEvent.target;
		else if (oEvent.srcElement) oTarg = oEvent.srcElement;
		if (oTarg.nodeType == 3) oTarg = oTarg.parentNode;
		return oTarg;
	}

	//
	// Common utils.
	//

	var sAgent = navigator.userAgent.toLowerCase();
    oBrowser = { 
        bIsOpera: /opera/.test(sAgent), 
        bIsSafari: /safari/.test(sAgent),
        bIsMsie: /msie/.test(sAgent) && !/opera/.test(sAgent),
        bIsMozilla: /mozilla/.test(sAgent) && !/(compatible|webkit)/.test(sAgent) 
    };

	String.prototype.replaceAll = function(s1, s2) { return this.split(s1).join(s2); }

	function toJSON(obj) {
    	switch(typeof obj) {
        	case "function" : return obj.toString();
        	case "string" : return "\"" + obj.replaceAll('\n', '\\\\n').replaceAll('\r', '\\\\r').replaceAll("\\\"", "\\\\\"").replaceAll("\"", "\\\"") + "\"";
        	case "object" : 
        	var str = "";
        	if(obj == null) return "null";
        	if(obj instanceof Array) {
            	for (var i = 0, l = obj.length; i < l; i++) str += ", " + toJSON(obj[i]);
            	if (str.length > 0) str = str.substring(1);
            	return "[ " + str + " ]";
        	}
        	for (var i in obj) str += ", " + i + " : " + toJSON(obj[i]);
        	return "{ " + (str.length > 0 ? str.substring(1) : str) + " }";
    	}
    	return obj;
	}

	function FormatDate(nDate) {
		var oDate = new Date(nDate);
		function fn(str) { str += ""; if(str.length == 1) str = "0" + str; return str; }
		return fn(oDate.getDate()) + "." + fn(oDate.getMonth() + 1) + "." + (oDate.getFullYear() + "").substr(2)
			+ "&nbsp;&nbsp;" + fn(oDate.getHours()) + ":" + fn(oDate.getMinutes());
	}

	function SafeEscape(sData) {
		if(typeof sData == "string")
			sData = sData.replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/\n/g, "<br />");
		return sData;
	}

	function XTemplate(sTemplate, oData) {
		var fn = function(t, p) { return (oData[p] != undefined) ? SafeEscape(oData[p]) : t; }
		return sTemplate.replace(/%\(([A-Za-z0-9_|.]*)\)/g, fn);
	}

	function FindSuggestion(nId) {
		for(var i=0, n=aSuggestionObjects.length; i<n; i++)
			if(aSuggestionObjects[i].id == nId)
				return aSuggestionObjects[i];
	}

	function MessageOutput(sMessageId) {
		// Constructor.
		var nTimeout, oMessage = id(sMessageId);
		oMessage.style.className = "message-output"; 

		this.Notify = function(sText, bDisableTimer) {
			oMessage.innerHTML = sText;
			oMessage.style.display = "block";
			if(bDisableTimer) return;
			if(nTimeout) clearTimeout(nTimeout);
			nTimeout = setTimeout(function() { oMessage.style.display = "none"; nTimeout = 0; }, 2000);
		}
		this.Hide = function() { oMessage.style.display = "none"; nTimeout = 0; }
		this.LazyHide = function() { if(nTimeout) return; oMessage.style.display = "none"; nTimeout = 0; }
		oMessage.onclick = function() { this.style.display = "none"; nTimeout = 0; }


		return this;
	}

	//
	// Content function. 
	//

	function GetContent(nType, sCriteria, nFrom) {
		var nCount, sDataType, sTemplate, sContentEmpty;
		nCurrentContent = nType;
		sCurrentList = sCriteria;
		nFrom = nFrom || 0;
		if(nType == 0) { // Suggestion.
			nCount = oProperty.nSuggestionsOnPage || 5; // Max on page.
			sContentType = "SuggestionList_";
			sTemplate = sSuggestionTemplate;
			sContentEmpty = "LT_SuggestionEmpty";
			id("content-list").className = "suggestion-list";
		} else if(nType == 1) { // Comments.
			nCount = oProperty.nCommentsOnPage || 4; // Max on page.
			sContentType = "CommentList_";
			sTemplate = sCommentTemplate;
			sContentEmpty = "LT_CommentEmpty";
			id("content-list").className = "comment-list";
		} else {
			return;
		}
		sContentType += sClientId;
		id("content-list").innerHTML = "<div class='content-loading'>" + oClientLocalization["LT_Loading"] + "</div>";
		var sBatchRequest = "{version:'1.0',global:{session:'" + sSession + "',type:'" + sContentType + "',criteria:\"" + sCriteria + "\"},methods:["
			+ "{'Data.Base.GetObjectsCount':{}},{'Data.Base.GetObjectsByCriteria':{from:" + (nFrom ? nFrom : 0) + ",count:" + nCount + "}}]}";
		HttpRequest.get("http://api.hivext.ru/1.0/utils/batch/cross/call", { appid : sAppid, request : sBatchRequest, sync : "true" }, function(oResponse) {
			if(oResponse.result == 0) {
				var nContentCount = oResponse.response[0].count || 0;
				if(!nContentCount) {
					id("content-list").innerHTML = "<div class='content-empty'>" + oClientLocalization[sContentEmpty] + "</div>";				
					return;
				}
				aContentObjects = oResponse.response[1].objects;
				if(nType == 0) aSuggestionObjects = aContentObjects;
				// Output data.
				var sContentListHtml = "", sPageHtml = "";
				for(var i=0, n=aContentObjects.length; i<n; i++) {
					if(nType == 0) {
						i % 2 ? aContentObjects[i].sClassName = "suggestion dark" : aContentObjects[i].sClassName = "suggestion";
						aContentObjects[i].sStatusText = oClientLocalization[aContentObjects[i].sStatus];
					}
					aContentObjects[i].sFormatDate = FormatDate(aContentObjects[i].nDate);
					sContentListHtml += XTemplate(sTemplate, aContentObjects[i]);
				}
				if(nContentCount > nCount) {
					sPageHtml += "<div id='list-select' align='right'>";
					var n = parseInt(nContentCount/nCount) + (nContentCount%nCount ? 1 : 0);
					for(var i=0; i<n; i++) {			
						sPageHtml += "<span id='" + i + "' class='" + (nFrom == (i*nCount) ? "page" : "page-select") + "'><a id='" + i + "' href='javascript:void(0);'>" + (i+1) + "</a></span>";
					}
					sPageHtml += "</div>";
				}
				id("content-list").innerHTML = sContentListHtml + sPageHtml;
				if(nContentCount > nCount) {
					id("list-select", true).onclick = function(oEvent) {
						var oElement = GetTarget(oEvent);
						if(oElement == this) return;
						if(oElement.id) GetContent(nType, sCriteria, parseInt(oElement.id)*nCount);
					}
				}
			}
		});
	}

	function ClientInit() {
		
		var sCurrentHQL = "";

		var oContentHQL = {
			LT_MenuPopular 		: "sStatus <> 'LT_Moderate' ORDER BY nScore DESC, id DESC",
			LT_MenuNew 			: "sStatus = 'LT_New' ORDER BY id DESC",
			LT_MenuComplited 	: "sStatus = 'LT_Complited' ORDER BY id DESC",
			LT_MenuAll 			: "sStatus <> 'LT_Moderate' ORDER BY id DESC",
			LT_MenuUnderReview 	: "sStatus = 'LT_UnderReview' ORDER BY id DESC",
			LT_MenuInProcess 	: "sStatus = 'LT_InProcess' ORDER BY id DESC",
			LT_MenuDenied 		: "sStatus = 'LT_Denied' ORDER BY id DESC"
		};

		GOut = new MessageOutput("feedback-message");

		var oMenuItems = id("feedback-menu").getElementsByTagName("a");

		var sAddValue = "";
		
		if((id("suggestion-add").tagName + "").toLowerCase() == "a") sAddValue = id("suggestion-add").innerHTML;
		else sAddValue = id("suggestion-add").value;

		function _menuSettings(oElement) {
			if((id("suggestion-add").tagName + "").toLowerCase() == "a")
				id("suggestion-add").title = id("suggestion-add").innerHTML = sAddValue; //oClientLocalization["LT_ActionAdd"];
			else id("suggestion-add").value = sAddValue; //oClientLocalization["LT_ActionAdd"];
			id("suggestion-add").bCancel = false;
			id("suggestion-edit").style.display = "none";
			id("suggestion-one").style.display = id("comment-edit").style.display = "none";
			id("content-list").style.display = "block";
			for(var i=0; i<oMenuItems.length; oMenuItems[i++].parentNode.className = "");
			GOut.LazyHide();
		}
		
		id("feedback-menu").onclick = function(oEvent) {
			var oElement = GetTarget(oEvent);
			if(oContentHQL[oElement.id]) {
				_menuSettings();
				oElement.parentNode.className = "fb_active";
				GetContent(0, oContentHQL[oElement.id]);
				sCurrentHQL = oElement.id;
			}
		}

		id("fbclient-content").onclick = function(oEvent) {
			var oElement = GetTarget(oEvent);
			if(oElement.id) {
				var aId = oElement.id.split("-");
				if(aId[0] == "title" || aId[0] == "comments") {
					oSuggestion = FindSuggestion(aId[1]);
					id("suggestion-one").innerHTML = XTemplate(sSuggestionTemplate, oSuggestion); 
					id("comment-text").value = oClientLocalization["LT_CommentText"];
					id("comment-text").className = "virgin-input";
					id("comment-text").onclick = function() { this.value = ""; this.className = ""; this.onclick = function() {} }
					id("suggestion-one").style.display = id("comment-edit").style.display = "block";
					GetContent(1, "nSuggestion=" + aId[1] + " ORDER BY id ASC");

					if((id("suggestion-add").tagName + "").toLowerCase() == "a")
						id("suggestion-add").title = id("suggestion-add").innerHTML = sAddValue; //oClientLocalization["LT_EditCancel"]; 
					else id("suggestion-add").value = sAddValue; //oClientLocalization["LT_EditCancel"];
					id("suggestion-add").bCancel = true;

				} else if(aId[0] == "vote") { // Vote action.
					sBatchRequest = "{version:'1.0',alias:{m1:'Data.Base.GetObjectsCount',m2:'Data.Base.GetObjectsByCriteria'},"
						+ "global:{session:'" + sSession + "',type:'VoteList_" + sClientId + "'},methods:["
						+ "{m1:{criteria:'nSuggestion=" + aId[2] + " AND nVote=1'}},{m1:{criteria:'nSuggestion=" + aId[2] + " AND nVote=0'}},"
						+ "{m2:{criteria:'nSuggestion=" + aId[2] + " AND sSignature=\"" + sDeviceSignature + "\"',count:1}}]}";
					HttpRequest.get("http://api.hivext.ru/1.0/utils/batch/cross/call", { appid : sAppid, request : sBatchRequest, sync : "true" }, function(oResponse) {
						if(oResponse.result == 0) {
							var nScore = oResponse.response[0].count - oResponse.response[1].count;		
							if(oResponse.response[2].objects && oResponse.response[2].objects.length) {
								var oVote = oResponse.response[2].objects[0];
								var sBatchTemplate = "{version:'1.0',alias:{m:'Data.Base.SetProperty'},global:{session:'%(sSession)'},methods:["
									+ "{m:{type:'VoteList_" + sClientId + "',id:%(nVoteId),field :'nVote',value:%(nVote)}},{m:{type:'SuggestionList_" + sClientId + "',"
									+ "id:%(nSuggestionId),field:'nScore',value:%(nScore)}}]}";
								var oParams = { sSession: sSession, nVoteId : oVote.id, nVote : aId[1]== "up" ? 1 : 0, nSuggestionId : aId[2],
									nScore : (function() { if(aId[1] == "up" && oVote.nVote == 0) { oVote.nVote = 1; return nScore += 2;
									} else if(aId[1] == "down" && oVote.nVote == 1) { oVote.nVote = 0; return nScore -= 2;
									} else return nScore; })() };
								id("score-" + aId[2]).innerHTML = oParams.nScore;
								HttpRequest.get("http://api.hivext.ru/1.0/utils/batch/cross/call",
									{ appid : sAppid, request : XTemplate(sBatchTemplate, oParams), sync : "true" }, function(oResponse) {
									if(oResponse.result == 0) {}
								});
							} else {
								var sBatchTemplate = "{version:'1.0',global:{session:'%(sSession)'},methods:["
									+ "{'Data.Base.CreateObject':{type:'VoteList_" + sClientId + "',data:'{nSuggestion:%(nSuggestionId),nVote:%(nVote)}'}},"
									+ "{'Data.Base.SetProperty':{type:'SuggestionList_" + sClientId + "',id:%(nSuggestionId),field:'nScore',value:%(nScore)}}]}";							
								var oParams = { sSession : sSession, sSignature : sDeviceSignature, nSuggestionId : aId[2], nVote : aId[1]== "up" ? 1 : 0,
									nScore : (function() { if(aId[1] == "up") return nScore += 1; else return nScore -= 1; })() };
								id("score-" + aId[2]).innerHTML = oParams.nScore;
								HttpRequest.get("http://api.hivext.ru/1.0/utils/batch/cross/call",
									{ appid : sAppid, request : XTemplate(sBatchTemplate, oParams), sync : "true" }, function(oResponse) {
									if(oResponse.result == 0) {}
								});
							}
						}
					});
				}
			}
		}

		id("suggestion-add").onclick = function() {
			if(this.bCancel) {
				if((this.tagName + "").toLowerCase() == "a") this.title = this.innerHTML = sAddValue; //oClientLocalization["LT_ActionAdd"];
				else this.value = sAddValue; //oClientLocalization["LT_ActionAdd"];
				id("suggestion-edit").style.display = "none";
				id("suggestion-one").style.display = id("comment-edit").style.display = "none";
				id("content-list").style.display = "block";
				GetContent(0, oContentHQL[sCurrentHQL]);
				GOut.Hide();
				this.bCancel = false;
			} else {
				if((this.tagName + "").toLowerCase() == "a") {
					//sAddValue = this.innerHTML;
					this.title = this.innerHTML = oClientLocalization["LT_EditCancel"];
				} else {
					//sAddValue = this.value;
					this.value = oClientLocalization["LT_EditCancel"];
				}
				this.bCancel = true;
				id("suggestion-title").value = oClientLocalization["LT_EditTitle"];
				id("suggestion-title").className = "virgin-input";
				id("suggestion-title").onfocus = function() { this.value = ""; this.className = ""; this.onfocus = function() {} }
				id("suggestion-description").value = oClientLocalization["LT_EditDescription"];
				id("suggestion-description").className = "virgin-input";
				id("suggestion-description").onfocus = function() { this.value = ""; this.className = ""; this.onfocus = function() {} }
				id("suggestion-one").style.display = id("comment-edit").style.display = "none";
				id("content-list").style.display = "none";
				id("suggestion-edit").style.display = "block";

				if(oClient.nModerateMode) GOut.Notify(oClientLocalization["LT_N_ModerateMode"], true);
			}

		}

		id("suggestion-send").onclick = function() {
			if(id("suggestion-title").className || !id("suggestion-title").value || !id("suggestion-author").value) return;
			id("suggestion-send").disabled = true;
			var oParams = {
				appid : sAppid,
				session : sSession,
				type: "SuggestionList_" + sClientId,
				data : toJSON({
					sTitle : id("suggestion-title").className ? "" : id("suggestion-title").value,
					sDescription : id("suggestion-description").className ? "" : id("suggestion-description").value,
					sAuthor : id("suggestion-author").value,
					sStatus : oClient.nModerateMode ? "LT_Moderate" : "LT_New"
				})
			};

			HttpRequest.post("http://api.hivext.ru/1.0/data/base/cross/createobject", oParams, function(oResponse) {
				if(oResponse.result == 0) { 
					id("suggestion-edit").style.display = "none";
					id("content-list").style.display = "block";

					GOut.Notify(oClientLocalization["LT_N_SuggestionSend"]);

					// Call menu item.
					if(id("LT_MenuNew")) {
						_menuSettings();
						id("LT_MenuNew").parentNode.className = "fb_active";
						GetContent(0, oContentHQL["LT_MenuNew"]);
						sCurrentHQL = "LT_MenuNew";
					}

					if((id("suggestion-add").tagName + "").toLowerCase() == "a")
						id("suggestion-add").title = id("suggestion-add").innerHTML = sAddValue; //oClientLocalization["LT_ActionAdd"];
					else id("suggestion-add").value = sAddValue; //oClientLocalization["LT_ActionAdd"];
					id("suggestion-add").bCancel = false;
				}
				id("suggestion-send").disabled = false;
			});
		}

		id("comment-send").onclick = function() {
			if(id("comment-text").className || !id("comment-text").value || !id("comment-author").value) return;
			id("comment-send").disabled = true;
			var sBatchParams = "{version:'1.0',global:{session:'" + sSession + "',type:'CommentList_" + sClientId + "'},methods:["
				+ "{'Data.Base.CreateObject':{data:'{nSuggestion: " + oSuggestion.id + ",sComment:\"" + id("comment-text").value.replaceAll('\n', '\\\\n').replaceAll('\r', '\\\\r') + "\",sAuthor:\"" + id("comment-author").value + "\"}'}},"
				+ "{'Data.Base.GetObjectsCount':{criteria:'nSuggestion=" + oSuggestion.id + "'}}]}";
			HttpRequest.post("http://api.hivext.ru/1.0/utils/batch/cross/call", { appid : sAppid, request : sBatchParams, sync : "true" }, function(oResponse) {
				if(oResponse.result == 0) {
					id("comment-text").value = oClientLocalization["LT_CommentText"];
					id("comment-text").className = "virgin-input";
					id("comment-text").onclick = function() { this.value = ""; this.className = ""; this.onclick = function() {} }
					var nCount = oResponse.response[1].count;
					GetContent(1, "nSuggestion=" + oSuggestion.id + " ORDER BY id DESC");
					HttpRequest.get("http://api.hivext.ru/1.0/data/base/cross/setproperty", { appid : sAppid, session : sSession,
						type : "SuggestionList_" + sClientId, id : oSuggestion.id, field : "nComments", value : nCount }, function(oResponse) {
						if(oResponse.result == 0) {}
					});
				} else {
					GOut.Notify("LT_E_CommentSave");
				}
				id("comment-send").disabled = false;
			});
		}

		GetContent(0, oContentHQL["LT_MenuPopular"]);
		sCurrentHQL = "LT_MenuPopular";

	}

	function ExpandWidget(oClient, nHField, nVField) {
		var oStyle = oClient.style;
		oStyle.position = "relative";
		oStyle.marginLeft = "0";
		oStyle.left = nHField + "px";
		oStyle.top = nVField + "px";
		oStyle.right = nHField + "px";
		oStyle.bottom = nVField + "px";
		oStyle.width = "auto"; //parseInt(GetClientWidth() - 2 * nHField) + "px";
		oStyle.height = "auto"; //parseInt(GetClientHeight() - 2 * nVField) + "px";
		id("fbclient-close").style.display = "none";
		if(id("fb_actions")) id("fb_actions").style.position = "absolute";
	}

	function ClientConstruct() {
		var sBatchRequest = "{version:'1.0',alias:{m:'Data.Base.GetObject'},global:{session:'" + sSession + "',id:1},methods:["
			+ "{'Data.Base.GetObjectsByCriteria':{appid:'a42b0a83276602f9883e2e3ffa183650',type:'GLocalizeList',criteria:'sLanguage=\"" + sLanguage + "\"'}},"
			+ "{m:{type:'ClientInfo_" + sClientId + "'}},{m:{type:'ClientTheme_" + sClientId + "'}}]}";			
		HttpRequest.get("http://api.hivext.ru/1.0/utils/batch/cross/call", { appid : sAppid, request : sBatchRequest, sync : "true" },
			function(oResponse) {
			if(oResponse.result == 0) {
				if(oResponse.response[0].objects && oResponse.response[0].objects.length) {
					oClientLocalization = eval("(" + oResponse.response[0].objects[0].sLocalizeData + ")"); // Construct localization object.
					if(oResponse.response[1].object && oResponse.response[2].object) {
						oClient = oResponse.response[1].object;
						oTheme = oResponse.response[2].object;
				   		if(oTheme && oTheme.sMainTemplate && oTheme.sSuggestionTemplate && oTheme.sCommentTemplate && oTheme.sMainCSS) {

							if(!oProperty) oProperty = {}

							oProperty.sImagesPath = "http://code.hivext.ru/applications/feedback/images/";
							oProperty.sButtonSideImage = oProperty.sButtonSideImage || oClientLocalization["LT_R_ButtonImage"] || oProperty.sImagesPath + "sidebutton20.png";
							oProperty.sButtonCloseImage = oProperty.sButtonCloseImage || oProperty.sImagesPath + "close20.png";

							oTheme.sMainCSS = XTemplate(oTheme.sMainCSS, oProperty);
				    		AddStyle(oTheme.sMainCSS);

							if(oResponse.response[1].object.sHeaderTitle)
								oClientLocalization["LT_Header"] = oResponse.response[1].object.sHeaderTitle;
							var sWidgetHTML = XTemplate(oTheme.sMainTemplate, oClientLocalization);
							Add2Body(sWidgetHTML);

							if(oProperty && oProperty.oInline) {
								oRoot = id(oProperty.oInline);
								if(!oRoot) { /* Error */ }
								//oRoot.innerHTML = sWidgetHTML;
								oRoot.appendChild(id("fbclient"));
							} else {
								bIsPopup = true;
								oRoot = id("fbclient");
								oProperty.nWidth = oProperty.nWidth || 600;
								oProperty.nHeight = oProperty.nHeight || 420;
								oRoot.style.width = oProperty.nWidth + "px";
							}

							function Slide(s0, s1, fCallback) {
								var fT = 0, nIID = setInterval(function() {
									fT += 0.10;
									if(fT >= 1.0) {
										fCallback();
										clearInterval(nIID);
									} else {
										id("fbclient-main").style.top = parseInt(s0 + fT * (s1 - s0)) + "%";
									}
								}, 10);
							}

							if(bIsPopup) {
								id("fbclient-button").onclick = function() {
									/*id("fbclient-main").style.top = "35%";*/
									id("fbclient-main").style.display = "block";
									//id("fbclient-background").style.display = "none";
									
									/*Slide(0, 37, function() {
										id("fbclient-main").style.top = "37%";
										id("fbclient-background").style.display = "block";
									});*/
								}
								id("fbclient-close").onclick = function() {
									//id("fbclient-background").style.display = "none";
									id("fbclient-main").style.display = "none";
									/*Slide(37, 100, function() { id("fbclient-main").style.display = "none"; });*/
								}
								var style = id("fbclient-button").style, propStyle = oProperty.oButtonStyle || {};
                				if(oProperty.sButtonSide == "right") style.right = '0px'; else style.left = '0px';
                				for (var i in propStyle) style[i] = propStyle[i];
								id("fbclient-button").style.display = "block"; // Show the side button.
								oRoot.style.marginLeft = -parseInt(oProperty.nWidth/2) + "px";
								id("fbclient-content").style.minHeight = (oProperty.nHeight - 100) + "px";
								oRoot.style.top = -parseInt(oProperty.nHeight/2) + "px";
							} else {
								//id("fbclient").style.width = oProperty.nWidth ? oProperty.nWidth + "px" : "100%";
								//id("fbclient").style.height = oProperty.nHeight ? oProperty.nHeight + "px" : "100%";							
								ExpandWidget(id("fbclient"), 0, 0);
							}
							sSuggestionTemplate = XTemplate(oTheme.sSuggestionTemplate, oClientLocalization);
							sCommentTemplate = XTemplate(oTheme.sCommentTemplate, oClientLocalization);
							ClientInit();
                		}
                	} else if(!oResponse.response[1].object) { alert(oClientLocalization["LT_E_ClientNotFound"]); }
            		else { alert(oClientLocalization["LT_E_TemplatesNotFound"]); }
				} else alert("Localization object not found.");
			}
		});
	}

	//
  	// Document OnReady
  	//

	var isReadyInited = 0, safariTimer, isReady = window.isReady, readyHndlr = [];
	
  	function onReady(handler) {
    	if (isReady) {
        	handler();
    	} else {
        	readyHndlr.push(handler);        
        	initOnReady();
    	}
  	}

  	function ready() {
    	if (isReady) return;
      	isReady = 1;
      	for (var i = 0, len = readyHndlr.length; i < len; i++) {
        	readyHndlr[i]();
      	}
      	readyHndlr = null;
  	}

  	function addEvent (obj, name, handler) {
		if (obj.attachEvent) obj.attachEvent('on' + name, handler);
	    else obj.addEventListener(name, handler, false);
	}

  	function initOnReady() {
    	if (isReadyInited) return;
        isReadyInited = 1;
	    if (oBrowser.bIsMozilla || oBrowser.bIsOpera) {
           	addEvent(document, 'DOMContentLoaded', ready);
        } else 
        	if (oBrowser.bIsMsie) {
        		(function () {
           			try {
                   		document.documentElement.doScroll('left');
               		} catch (e) {
                   		setTimeout(arguments.callee, 50);
                   		return;
               		}
               		ready();
         		})();
      		} else
           		if (oBrowser.bIsSafari) {
           			safariTimer = setInterval(function() {
           				if (document.readyState == "loaded" || 
           					document.readyState == "complete") {
           					clearInterval(safariTimer);
           					safariTimer = null;
           					ready();
           				}
           			}, 10);
           		}
       	addEvent(window, 'load', ready);
  	}

	//
	// Constructor.
	//

	var bIsPopup = false, oRoot;

	onReady(function() {

		HttpRequest.get("http://api.hivext.ru/1.0/users/authentication/cross/getdevicesignature", { appid : sAppid }, function(oResponse) {
			if(oResponse.result == 0) {
				sSession = sDeviceSignature = oResponse.signature;
				ClientConstruct(oProperty);
			}
		});

	});

}