--[[/*
--*--*--*--*--*--*--*--*--*--*--*--*--*--*--*--*--*--*--*--*--*--*--*--*--*--*
--* PRAdmin v2.13, a small utility which helps you to easily set up Your PtokaX hub.
--* Copyright (C) 2006-2009 Thor ( ejjeliorjarat [on] gmail [dot] com )
--*
--* This program is free software; you can redistribute it and/or modify
--* it under the terms of the GNU General Public License as published by
--* the Free Software Foundation; either version 2 of the License, or
--* (at your option) any later version.
--*
--* This program is distributed in the hope that it will be useful,
--* but WITHOUT ANY WARRANTY; without even the implied warranty of
--* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
--* GNU General Public License for more details.
--*
--* You should have received a copy of the GNU General Public License
--* along with this program; if not, write to the Free Software
--* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
--*
--*--*--*--*--*--*--*--*--*--*--*--*--*--*--*--*--*--*--*--*--*--*--*--*--*--*
--*
--* NEW!!
--* From v2.10 the GUI is designed with DialogBlocks 2oo8
--* and loaded from the generated XRC file.
--* You can download it from: http://www.anthemion.co.uk/dialogblocks
--* From v2.13 the xrc and images are zip compressed to xrs file
--* GUI settings ID's follow PtokaX's LUA interface numbers
--* wxCheckBox - chk ; wxSpinCtrl - num ; wxTextCtrl - txt
--* Others for translation:
--* wxStaticBox - stb ; wxStaticText - stt
--*
--*/]]
--[[ IMPORT ]]--
local io,math,os,package,string,table = io,math,os,package,string,table;
local setmetatable,rawget,rawset = setmetatable,rawget,rawset;
local ipairs,pairs,next = ipairs,pairs,next;
local package,require = package,require;
local tonumber,tostring = tonumber,tostring;
local assert,loadstring,collectgarbage = assert,loadstring,collectgarbage;

--[[ GLOBALS ]]--
_APPNAME = 'PtokaX Remote Admin'
_APPVER = 'v2.13'
package.cpath = package.cpath..';./lib/?.so;./lib/?.dll;./lib/?.dylib;'
require 'wx'     -- GUI drawing
require 'socket' -- Sockets
_DEBUG = true;
os.setlocale("")

-- iconv start
require 'iconv'

local local_encoding = 'utf-8'
local remote_encoding = 'windows-1251'  -- Hub encoding

local input_converter = iconv.new(local_encoding .. '//IGNORE', remote_encoding)
local output_converter = iconv.new(remote_encoding  .. '//IGNORE', local_encoding)
if not input_converter or not output_converter then
	error('cannot create iconv descriptor')
end

local function convert(converter, string)
	converted_string, error_code = converter:iconv(string)
	if error_code then
		error("iconv cannot convert '" .. string .. "'")
	end
	return converted_string
end

local function convert_input(string)
	return convert(input_converter, string)
end

local function convert_output(string)
	return convert(output_converter, string)
end
-- iconv end

if _DEBUG then
	tCounters = {}
	tNames = {}
	tDebugArray = {}
	hook = function()
		local f = debug.getinfo(2,"f").func
		if not tNames[f] then
			if #tDebugArray > 50 then table.remove(tDebugArray,1) end
			table.insert(tDebugArray,f) -- Order the stack called by time - first call
			tNames[f] = debug.getinfo(2, "Snl")
		end
	end
	debug.sethook(hook,"c") -- Set the hook
	DBGFILE = io.open("debug.log","a")
	function DEBUG(str)
		local f = io.open("debug.txt","a")
		f:write(os.date("[%H:%M:%S] ")..str.."\n")
		f:close()
	end
end

function OnError(errorstr)
	if _DEBUG then debug.sethook() end -- We don't need the following things...
	local file = io.open("./exceptioninfo.txt","a+")
	if file then
		local tUptime = os.date("!*t",os.clock())
		local m_PlatformInfo = wx.wxPlatformInfo.Get()
		file:write("System informations: \n"..
		"               Time: "..os.date("%x %X").."\n"..
		"                 OS: "..wx.wxGetOsDescription().." ("..m_PlatformInfo.GetArchName(m_PlatformInfo:GetArchitecture())..")\n"..
		"        Free memory: "..(tFuncs and tFuncs:ConvertShare(wx.wxGetFreeMemory():ToDouble()) or (wx.wxGetFreeMemory():ToDouble().." B")).."\n"..
		"       Startup path: "..wx.wxGetCwd().."\n"..
		"         Resolution: "..wx.wxGetDisplaySize():GetWidth().."x"..wx.wxGetDisplaySize():GetHeight().."\n"..
		"             Uptime: "..string.format("%02i:%02i:%02i",tUptime.hour,tUptime.min,tUptime.sec).."\n"..
		"    Program version: ".._APPVER.."\n"..
		"        LUA version: ".._VERSION.."\n"..
		"  wxWidgets version: "..wx.wxVERSION_STRING.."\n"..
		"      wxLUA version: "..wxlua.wxLUA_VERSION_STRING.."\n"..
		string.rep("-",60).."\nError message description:\n"..tostring(errorstr).."\n"..
		"Lua "..debug.traceback().."\n")
		file:write(string.rep("=",60).."\n")
		if _DEBUG then
			local getname = function(func)
				local n = tNames[func]
				if n.what == "C" then return n.name or "<?>" end
				local loc = string.format("[%s]:%s",n.short_src, n.linedefined)
				if n.namewhat ~= "" then return string.format("%s [%s] (%s)", loc, n.currentline,n.name)
				else return string.format("%s", loc) end
			end
			for i,arr in ipairs(tDebugArray) do
				file:write(tostring(getname(arr)).."\n")
			end
			file:write(string.rep("=",60).."\n")
			DBGFILE:close()
		end
		file:close()
		wx.wxMessageBox("An error occured in the application, some information about it has been generated. \n"..
		"Please send the exceptioninfo.txt file to: ejjeliorjarat@gmail.com","ERROR",wx.wxICON_ERROR)
	else
		wx.wxMessageBox("An error occured in the application, but the program can't write into the debug file. \n"..
		"Hence, I can't find out why it crashed, so don't report this as a bug unless you find a solution...","ERROR",wx.wxICON_ERROR)
	end
	wx.wxGetApp():ExitMainLoop()
	wx.wxExit(0)
end

tFuncs = {}

function tFuncs.GetCtrl(self,sid,owner)
	if not owner then owner = tCtrls["app"] end
	local ctrl = owner:FindWindow(m_XmlResource.GetXRCID(sid))
	if not ctrl then OnError("Missing control in self:GetCtrl() "..tostring(sid)) return end
	return ctrl:DynamicCast(ctrl:GetClassInfo():GetClassName())
end

function tFuncs.SetStatusText(self,sText,iField)
	if not statuslog then statuslog = {} end
	table.insert(statuslog,os.date("[%H:%M:%S] ")..sText)
	if #statuslog > 10 then table.remove(statuslog,1) end
	if not iField then
		tCtrls["statusbar"]:SetToolTip(wx.wxToolTip(table.concat(statuslog,"\n")))
		tCtrls["statusbar"]:SetStatusText(os.date("[%H:%M:%S] ")..sText,0)
	else
		tCtrls["statusbar"]:SetStatusText(sText,iField)
	end
end

function tFuncs.UDPEnableHideCtrls(self,sPage)
	local sPageText = sPage:sub(1,1):upper()..sPage:sub(2):lower()
	self:GetCtrl("wxID_STT_UDPMSG"):SetLabel(sPageText.." messages")
	self:GetCtrl("wxID_CHK_UDP"..tCtrls["shown_page"]):Hide()
	self:GetCtrl("wxID_TXT_UDP"..tCtrls["shown_page"]):Hide()
	self:GetCtrl("wxID_TXT_UDP"..sPage):Show(true)
	self:GetCtrl("wxID_CHK_UDP"..sPage):Show(true)
	tCtrls["shown_page"] = sPage
	local font = tCtrls["app"]:GetFont()
	font:SetWeight(wx.wxFONTWEIGHT_NORMAL)
	self:GetCtrl("wxID_CMD_UDP"..sPage):SetFont(font)
	self:GetCtrl("ID_PNL_UDPDBG"):Layout()
end

function tFuncs.CreateUDPDebugFrame(self)
	local udpport = wx.wxGetNumberFromUser("Enter the UDP port what you want to listen on:","Enter a portnumber:","Enter a portnumber",422,1,65535)
	if udpport == -1 then return end -- cancelled.
	tCtrls["udp_client"],err = socket.udp()
	if not tCtrls["udp_client"] then
		wx.wxMessageBox("Can't make UDP port, because:\n "..tostring(err))
		return
	end
	tCtrls["udp_client"]:setsockname("*",udpport)
	if tCtrls["iStatus"] == 1 then
		self:Send("<"..self:GetCtrl("txt_login_nick"):GetValue().."> !debug "..udpport)
	else
		wx.wxMessageBox("You are not connected to the hub.\nIf you want to get debug messages, "..
		"write !debug "..udpport.." in the main chat!",_APPNAME)
	end
	table.insert(tCtrls["tDeadThreads"],ThreadCreate(tFuncs.UDPListen,{}))
	self:GetCtrl("wxID_CMD_UDPCLOSE"):SetBitmapLabel(self:GetImage("close"))
	tCtrls["tab"]:AddPage(self:GetCtrl("ID_PNL_UDPDBG"),"UDP debug",false,10)
	tCtrls["wxID_TXT_UDPSYS"] = self:GetCtrl("wxID_TXT_UDPSYS")
	tCtrls["wxID_TXT_UDPERR"] = self:GetCtrl("wxID_TXT_UDPERR")
	tCtrls["wxID_TXT_UDPCHAT"] = self:GetCtrl("wxID_TXT_UDPCHAT")
	tCtrls["wxID_TXT_UDPLUA"] = self:GetCtrl("wxID_TXT_UDPLUA")
	tCtrls["wxID_TXT_UDPREG"] = self:GetCtrl("wxID_TXT_UDPREG")
	tCtrls["wxID_TXT_UDPLOG"] = self:GetCtrl("wxID_TXT_UDPLOG")
	self:GetCtrl("ID_PNL_UDPDBG"):Layout()
	tCtrls["cmd_udpdbg"]:Enable(false)
end

function tFuncs.ConvertShare(self,iBytes)
	if not iBytes then return 0 end
	local i,tUnits = 1, {"B","Kb","Mb","Gb","Tb","Pb","Eb","Yb"}
	while iBytes > 1024 do iBytes = iBytes / 1024 i = i + 1 end
	return string.format("%.2f",iBytes).." "..(tUnits[i] or "??")
end

function tFuncs.IsIP(self,str)
	return iff(str:find("^[12]?[%d]?%d%.[12]?[%d]?%d%.[12]?[%d]?%d%.[12]?[%d]?%d$"),true,false)
end

function tFuncs.IP2DEC(self,sIP)
    local iDec,iNum = 0,0
	for num in sIP:gmatch("(%d+)") do
		iNum = iNum + 1
		if tonumber(num) < 0 or tonumber(num) > 255 then return -1 end
		iDec = iDec + num*256^(4-iNum)
	end
	if iNum ~= 4 then return -1 end
	return iDec
end

function tFuncs.SortListItems(self,col,lst)
	-- This function is stripped and converted from bindings.wx.lua (c) John Labenski (5/7/2007)
	local sorted = false
	local tLst2Table = {["lst_bans"] = "tBans",["lst_rangebans"] = "tRangeBans",["lst_regs"] = "tRegs"}
	if tCtrls["tSortedLists"][lst] then
		sorted = true
	end
	local function SortListItems(item1,item2,col) -- The first two parameters automatically comes. Read the manual.
		local i1,i2 = "",""
		i1 = tCtrls[tLst2Table[lst]][item1+1][col]:lower()
		i2 = tCtrls[tLst2Table[lst]][item2+1][col]:lower()
		-- sort on the real numbers, but treat "" as lower
		if (i1 == "") and (i2 == "") then
			i1, i2 = 0, 0
		elseif (i1 == "") then
			i1, i2 = 0, 1
		elseif (i2 == "") then
			i1, i2 = 1, 0
		end
		if sorted then
			if i1 < i2 then return	1 end
			if i1 > i2 then return -1 end
		else
			if i1 < i2 then return -1 end
			if i1 > i2 then return	1 end
		end
		return 0
	end
	tCtrls[lst]:SortItems(SortListItems, col+1)
	if sorted then
		tCtrls["tSortedLists"][lst] = nil
	else
		tCtrls["tSortedLists"][lst] = 1
	end
	--[[for c = 1, tCtrls[lst]:GetColumnCount() do
		if c ~= col+1 then
			tCtrls[lst]:SetColumnImage(c-1,-1)
		elseif not sorted then
			tCtrls[lst]:SetColumnImage(col,2)
		else
			tCtrls[lst]:SetColumnImage(col,3)
		end
	end]]
end

function tFuncs.CleanUp(self)
    tCtrls["iStatus"] = 0
	tCtrls["tcp_client"]:shutdown()
	if tCtrls["udp_client"] then
		tCtrls["udp_client"]:close()
	end
	wx.wxEndBusyCursor() -- Maybe some operations were in progress
	self:SetStatusText("Connection closed...")
	self:GetCtrl("wxID_CMD_LOGIN"):SetLabel(self:Translate("Connect") or "Connect")
	self:GetCtrl("txt_login_nick"):Enable(true)
	self:GetCtrl("wxID_CMD_STAT"):Enable(false)
	tCtrls["lst_scripts"]:Clear()
	tCtrls["lst_scripts"]:SetToolTip("")
	tCtrls["tab"]:SetSelection(0)
	tCtrls["lst_bans"]:DeleteAllItems()
	tCtrls["lst_rangebans"]:DeleteAllItems()
	tCtrls["lst_regs"]:DeleteAllItems()
	tCtrls["lst_profiles"]:Clear()
	for i=0,54 do
	    tCtrls["lst_permissions"]:Check(i,false)
	end
	for i=0,55 do
		tCtrls["chk"]["chk_"..i]:SetValue(false)
	end
	for i=0,113 do
		if tCtrls["num"]["num_"..i]:GetClassInfo():GetClassName() == "wxSpinCtrl" then
			tCtrls["num"]["num_"..i]:SetValue(0)
		else
			tCtrls["num"]["num_"..i]:SetSelection(0)
		end
	end
	for i=0,34 do
		if tCtrls["txt"]["txt_"..i]:GetClassInfo():GetClassName() == "wxTextCtrl" then
			tCtrls["txt"]["txt_"..i]:SetValue("")
		else
			tCtrls["txt"]["txt_"..i]:SetSelection(0)
		end
	end
	bitmap = self:GetImage("spider")
	local icon = wx.wxIcon()
	icon:CopyFromBitmap(bitmap)
	tCtrls["app"]:SetIcon(icon)
	tCtrls["taskbar"]:SetIcon(icon,_APPNAME.." ".._APPVER)
	tCtrls["app"]:SetTitle(_APPNAME.." ".._APPVER)
	tCtrls["lst_texts"]:Clear()
	for index,thread in ipairs(tCtrls["tDeadThreads"]) do
		ThreadDestroy(thread)
	end
	tCtrls["tab"]:SetSelection(0)
	e = nil -- Destroy the last TCP connection error [if any]
end

function tFuncs.LoadPermissions(self,iProfileNumber)
	local sProf = tCtrls["tProfiles"][tonumber(iProfileNumber)][2]
	for i = 1,#sProf do
		tCtrls["lst_permissions"]:Check(i-1,iff(sProf:sub(i,i) == "1",true,false))
	end
end

-- No self here, diff. thread!
function tFuncs.FileAction(sFile,iMode)
	while true do
		if tCtrls["tFiles"][sFile] == 1 then
			local evt = wx.wxCommandEvent(wx.wxEVT_NULL,tCtrls["wxID_EVENT_TEXTFILE"])
			evt:SetString(sFile)
			evt:SetInt(iMode)
			tCtrls["app"]:AddPendingEvent(evt)
			tCtrls["tFiles"][sFile] = nil
			break
		end
	end
end

function tFuncs.DownloadFile(self,type,file)
	self:Send("$GET "..type.." \""..file.."\"")
	tCtrls["tFiles"][file] = 0
end

function tFuncs.ReloadScripts(self)
	tCtrls["lst_scripts"]:Clear()
	tCtrls["lst_scripts"]:SetToolTip(wx.wxToolTip((self:Translate("ScriptsMemory") or "Memory used by scripts [kB]")..":\n"))
	self:Send("$GET 4")
end

function tFuncs.ReloadRegs(self)
	tCtrls["tRegs"] = {}
	tCtrls["lst_regs"]:DeleteAllItems()
	self:Send("$GET 6")
end

function tFuncs.ReloadBans(self)
	tCtrls["tBans"] = {}
	tCtrls["lst_bans"]:DeleteAllItems()
	self:Send("$GET 3 0")
end

function tFuncs.ReloadRangeBans(self)
	tCtrls["tRangeBans"] = {}
	tCtrls["lst_rangebans"]:DeleteAllItems()
	self:Send("$GET 3 1")
end

function tFuncs.ReloadTexts(self)
	if tCtrls["iStatus"] == 1 then
		tCtrls["lst_texts"]:Clear()
		self:Send("$GET 7")
	end
end

function tFuncs.ReIndex(self,lstView,iFrom)
	for j=0,tCtrls[lstView]:GetItemCount()-1 do
		local item = tCtrls[lstView]:GetItemData(j)
		if item >= iFrom then
			tCtrls[lstView]:SetItemData(j,item-1)
		end
	end
end

function tFuncs.CreateBan(self,t)
	-- Sent as string, easier than tons of string.finds which might be wrong...
	local sTemp = "t = {"..tostring(t[1])..","..tostring(t[2])..","..tostring(t[3])..",\""..t[4].."\","..
	"\""..t[5].."\",\""..t[6].."\",\""..t[7].."\","..tostring(t[8])..",}"
	self:Send("$SET 3 6 "..sTemp)
end

function tFuncs.CreateRangeBan(self,t)
	local sTemp = "t = {\""..t[1].."\",\""..t[2].."\","..tostring(t[3])..",\""..t[4].."\",\""..t[5].."\","..t[6].."}"
	self:Send("$SET 3 7 "..sTemp)
end

function tFuncs.Unban(self,item)
	local selitem = tCtrls["lst_bans"]:GetItemData(item)+1
	if tCtrls["tBans"][selitem][2]:find("<"..tCtrls["tLangs"][292]..">") then -- just IP ban
		self:Send("$SET 3 0 "..item.." "..tCtrls["tBans"][selitem][1])
	else -- nick [and maybe also an IP] ban
		self:Send("$SET 3 0 "..item.." "..iff(tCtrls["tBans"][selitem][1] == "<"..tCtrls["tLangs"][291]..">",
		tCtrls["tBans"][selitem][2],tCtrls["tBans"][selitem][2].." "..tCtrls["tBans"][selitem][1]))
	end
end

function tFuncs.ShowBanDialog(self,t)
	local bandialog = wx.wxDialog()
	if m_XmlResource:LoadDialog(bandialog,wx.NULL,"ID_DLG_BANS") then
		-- Translations --
		bandialog:SetTitle(tCtrls["tLangs"][290])
		self:GetCtrl("ID_CHK_NICKBAN",bandialog):SetLabel(tCtrls["tLangs"][291])
		self:GetCtrl("ID_CHK_IPBAN",bandialog):SetLabel(tCtrls["tLangs"][292])
		self:GetCtrl("ID_CHK_FULLBAN",bandialog):SetLabel(tCtrls["tLangs"][293])
		self:GetCtrl("ID_CHK_FULLBAN",bandialog):SetToolTip(tCtrls["tLangs"][294])
		self:GetCtrl("ID_STT_BANNICK",bandialog):SetLabel(tCtrls["tLangs"][3])
		self:GetCtrl("ID_STT_BANIP",bandialog):SetLabel(tCtrls["tLangs"][295])
		self:GetCtrl("ID_STT_BANREASON",bandialog):SetLabel(tCtrls["tLangs"][296])
		self:GetCtrl("ID_STT_BANCREATEDBY",bandialog):SetLabel(tCtrls["tLangs"][297])
		self:GetCtrl("ID_CHK_BANTEMPORARY",bandialog):SetLabel(tCtrls["tLangs"][298])
		self:GetCtrl("ID_STT_BANDAY",bandialog):SetLabel(tCtrls["tLangs"][299])
		self:GetCtrl("ID_STT_BANMONTH",bandialog):SetLabel(tCtrls["tLangs"][300])
		self:GetCtrl("ID_STT_BANYEAR",bandialog):SetLabel(tCtrls["tLangs"][301])
		self:GetCtrl("ID_STT_BANHOUR",bandialog):SetLabel(tCtrls["tLangs"][302])
		self:GetCtrl("ID_STT_BANMINUTE",bandialog):SetLabel(tCtrls["tLangs"][303])
		self:GetCtrl("ID_STT_BANEXPIRATION",bandialog):SetLabel(tCtrls["tLangs"][304])
		local tMonths = { -- Localization, PPK?
		tCtrls["tLangs"][305],tCtrls["tLangs"][306],tCtrls["tLangs"][307],tCtrls["tLangs"][308],
		tCtrls["tLangs"][309],tCtrls["tLangs"][310],tCtrls["tLangs"][311],tCtrls["tLangs"][312],
		tCtrls["tLangs"][313],tCtrls["tLangs"][314],tCtrls["tLangs"][315],tCtrls["tLangs"][316],
		}
		self:GetCtrl("ID_NUM_BANMONTH",bandialog):Clear(); self:GetCtrl("ID_NUM_BANMONTH",bandialog):Append(tMonths)
		self:GetCtrl("ID_CHK_BANPERMANENT",bandialog):SetLabel(tCtrls["tLangs"][317])
		-- Translations end --
		local IPValidator = wx.wxTextValidator(wx.wxFILTER_INCLUDE_CHAR_LIST)
		IPValidator:SetIncludes({"0","1","2","3","4","5","6","7","8","9","."})
		self:GetCtrl("ID_TXT_BANIP",bandialog):SetValidator(IPValidator)
		self:GetCtrl("ID_TXT_BANREASON",bandialog):SetValidator(tCtrls["NoP"])
		self:GetCtrl("ID_TXT_BANNICK",bandialog):SetValidator(tCtrls["Nick"])
		self:GetCtrl("ID_TXT_BANCREATEDBY",bandialog):SetValidator(tCtrls["Nick"])
		self:GetCtrl("ID_CHK_IPBAN",bandialog):Connect(wx.wxEVT_COMMAND_CHECKBOX_CLICKED,function(event)
			self:GetCtrl("ID_CHK_FULLBAN",bandialog):Enable(event:IsChecked())
		end)
		self:GetCtrl("ID_CHK_BANTEMPORARY",bandialog):Connect(wx.wxEVT_COMMAND_CHECKBOX_CLICKED,function(event)
			if event:IsChecked() == true then 
				self:GetCtrl("ID_CHK_BANPERMANENT",bandialog):SetValue(false)
				self:GetCtrl("ID_STT_BANDAY",bandialog):Enable(true)
				self:GetCtrl("ID_STT_BANMONTH",bandialog):Enable(true)
				self:GetCtrl("ID_STT_BANYEAR",bandialog):Enable(true)
				self:GetCtrl("ID_STT_BANHOUR",bandialog):Enable(true)
				self:GetCtrl("ID_STT_BANMINUTE",bandialog):Enable(true)
				self:GetCtrl("ID_STT_BANEXPIRATION",bandialog):Enable(true)
				self:GetCtrl("ID_NUM_BANDAY",bandialog):Enable(true)
				self:GetCtrl("ID_NUM_BANMONTH",bandialog):Enable(true)
				self:GetCtrl("ID_NUM_BANYEAR",bandialog):Enable(true)
				self:GetCtrl("ID_NUM_BANHOUR",bandialog):Enable(true)
				self:GetCtrl("ID_NUM_BANMINUTE",bandialog):Enable(true)
			else
				self:GetCtrl("ID_CHK_BANPERMANENT",bandialog):SetValue(true)
				self:GetCtrl("ID_STT_BANDAY",bandialog):Enable(false)
				self:GetCtrl("ID_STT_BANMONTH",bandialog):Enable(false)
				self:GetCtrl("ID_STT_BANYEAR",bandialog):Enable(false)
				self:GetCtrl("ID_STT_BANHOUR",bandialog):Enable(false)
				self:GetCtrl("ID_STT_BANMINUTE",bandialog):Enable(false)
				self:GetCtrl("ID_STT_BANEXPIRATION",bandialog):Enable(false)
				self:GetCtrl("ID_NUM_BANDAY",bandialog):Enable(false)
				self:GetCtrl("ID_NUM_BANMONTH",bandialog):Enable(false)
				self:GetCtrl("ID_NUM_BANYEAR",bandialog):Enable(false)
				self:GetCtrl("ID_NUM_BANHOUR",bandialog):Enable(false)
				self:GetCtrl("ID_NUM_BANMINUTE",bandialog):Enable(false)
			end
		end)
		self:GetCtrl("ID_CHK_BANPERMANENT",bandialog):Connect(wx.wxEVT_COMMAND_CHECKBOX_CLICKED,function(event)
			if event:IsChecked() == true then 
				self:GetCtrl("ID_CHK_BANTEMPORARY",bandialog):SetValue(false)
				self:GetCtrl("ID_STT_BANDAY",bandialog):Enable(false)
				self:GetCtrl("ID_STT_BANMONTH",bandialog):Enable(false)
				self:GetCtrl("ID_STT_BANYEAR",bandialog):Enable(false)
				self:GetCtrl("ID_STT_BANHOUR",bandialog):Enable(false)
				self:GetCtrl("ID_STT_BANMINUTE",bandialog):Enable(false)
				self:GetCtrl("ID_STT_BANEXPIRATION",bandialog):Enable(false)
				self:GetCtrl("ID_NUM_BANDAY",bandialog):Enable(false)
				self:GetCtrl("ID_NUM_BANMONTH",bandialog):Enable(false)
				self:GetCtrl("ID_NUM_BANYEAR",bandialog):Enable(false)
				self:GetCtrl("ID_NUM_BANHOUR",bandialog):Enable(false)
				self:GetCtrl("ID_NUM_BANMINUTE",bandialog):Enable(false)
			else
				self:GetCtrl("ID_CHK_BANTEMPORARY",bandialog):SetValue(true)
				self:GetCtrl("ID_STT_BANDAY",bandialog):Enable(true)
				self:GetCtrl("ID_STT_BANMONTH",bandialog):Enable(true)
				self:GetCtrl("ID_STT_BANYEAR",bandialog):Enable(true)
				self:GetCtrl("ID_STT_BANHOUR",bandialog):Enable(true)
				self:GetCtrl("ID_STT_BANMINUTE",bandialog):Enable(true)
				self:GetCtrl("ID_STT_BANEXPIRATION",bandialog):Enable(true)
				self:GetCtrl("ID_NUM_BANDAY",bandialog):Enable(true)
				self:GetCtrl("ID_NUM_BANMONTH",bandialog):Enable(true)
				self:GetCtrl("ID_NUM_BANYEAR",bandialog):Enable(true)
				self:GetCtrl("ID_NUM_BANHOUR",bandialog):Enable(true)
				self:GetCtrl("ID_NUM_BANMINUTE",bandialog):Enable(true)
			end
		end)
		if t and #t == 6 then
			if t[1]:find("<"..tCtrls["tLangs"][291]..">") then
				self:GetCtrl("ID_TXT_BANNICK",bandialog):SetValue(t[2])
				self:GetCtrl("ID_CHK_NICKBAN",bandialog):SetValue(true)
			elseif t[2]:find("<"..tCtrls["tLangs"][292]..">") then
				self:GetCtrl("ID_TXT_BANIP",bandialog):SetValue(t[1])
				self:GetCtrl("ID_CHK_IPBAN",bandialog):SetValue(true)
				self:GetCtrl("ID_CHK_FULLBAN",bandialog):Enable(true)
			else
				self:GetCtrl("ID_TXT_BANNICK",bandialog):SetValue(t[2])
				self:GetCtrl("ID_CHK_NICKBAN",bandialog):SetValue(true)
				self:GetCtrl("ID_TXT_BANIP",bandialog):SetValue(t[1])
				self:GetCtrl("ID_CHK_IPBAN",bandialog):SetValue(true)
				self:GetCtrl("ID_CHK_FULLBAN",bandialog):Enable(true)
			end
			self:GetCtrl("ID_CHK_FULLBAN",bandialog):SetValue(iff(t[6] == "1",true,false))
			self:GetCtrl("ID_TXT_BANREASON",bandialog):SetValue(t[4])
			self:GetCtrl("ID_TXT_BANCREATEDBY",bandialog):SetValue(t[3])
			self:GetCtrl("ID_CHK_BANPERMANENT",bandialog):SetValue(iff(t[5]:find("%b<>"),true,false))
			self:GetCtrl("ID_CHK_BANTEMPORARY",bandialog):SetValue(iff(t[5]:find("%d"),true,false))
			if self:GetCtrl("ID_CHK_BANPERMANENT",bandialog):IsChecked() == true then
				self:GetCtrl("ID_STT_BANDAY",bandialog):Enable(false)
				self:GetCtrl("ID_STT_BANMONTH",bandialog):Enable(false)
				self:GetCtrl("ID_STT_BANYEAR",bandialog):Enable(false)
				self:GetCtrl("ID_STT_BANHOUR",bandialog):Enable(false)
				self:GetCtrl("ID_STT_BANMINUTE",bandialog):Enable(false)
				self:GetCtrl("ID_STT_BANEXPIRATION",bandialog):Enable(false)
				self:GetCtrl("ID_NUM_BANDAY",bandialog):Enable(false)
				self:GetCtrl("ID_NUM_BANMONTH",bandialog):Enable(false)
				self:GetCtrl("ID_NUM_BANYEAR",bandialog):Enable(false)
				self:GetCtrl("ID_NUM_BANHOUR",bandialog):Enable(false)
				self:GetCtrl("ID_NUM_BANMINUTE",bandialog):Enable(false)
			end
			local tExp = os.date("*t",(tonumber(t[5]) or os.time()))
			self:GetCtrl("ID_NUM_BANDAY",bandialog):SetValue(tExp["day"])
			self:GetCtrl("ID_NUM_BANMONTH",bandialog):SetSelection(tExp["month"]-1)
			self:GetCtrl("ID_NUM_BANYEAR",bandialog):SetValue(tExp["year"])
			self:GetCtrl("ID_NUM_BANHOUR",bandialog):SetValue(tExp["hour"])
			self:GetCtrl("ID_NUM_BANMINUTE",bandialog):SetValue(tExp["min"])
		else
			-- Maybe we got the settings: add the default tempban time to the current date (if not then 0)
			local iBanTime = tCtrls["num"]["num_16"]:GetValue()*60
			local tExp = os.date("*t",os.time()+iBanTime)
			self:GetCtrl("ID_NUM_BANDAY",bandialog):SetValue(tExp["day"])
			self:GetCtrl("ID_NUM_BANMONTH",bandialog):SetSelection(tExp["month"]-1)
			self:GetCtrl("ID_NUM_BANYEAR",bandialog):SetValue(tExp["year"])
			self:GetCtrl("ID_NUM_BANHOUR",bandialog):SetValue(tExp["hour"])
			self:GetCtrl("ID_NUM_BANMINUTE",bandialog):SetValue(tExp["min"])
			self:GetCtrl("ID_TXT_BANCREATEDBY",bandialog):SetValue(self:GetCtrl("txt_login_nick"):GetValue())
		end
		bandialog:Connect(wx.wxEVT_CLOSE_WINDOW,function(event)
			-- Checking
			local bNickban = self:GetCtrl("ID_CHK_NICKBAN",bandialog):GetValue()
			local bIPban = self:GetCtrl("ID_CHK_IPBAN",bandialog):GetValue()
			local bFullban = self:GetCtrl("ID_CHK_FULLBAN",bandialog):GetValue()
			local bPermban = self:GetCtrl("ID_CHK_BANPERMANENT",bandialog):GetValue()
			local bTempban = self:GetCtrl("ID_CHK_BANTEMPORARY",bandialog):GetValue()
			local sIP = self:GetCtrl("ID_TXT_BANIP",bandialog):GetValue()
			local sNick = self:GetCtrl("ID_TXT_BANNICK",bandialog):GetValue()
			local sReason = self:GetCtrl("ID_TXT_BANREASON",bandialog):GetValue()
			local sCreatedBy = self:GetCtrl("ID_TXT_BANCREATEDBY",bandialog):GetValue()
			local tExp = {}
			if bTempban then
				tExp["day"] = self:GetCtrl("ID_NUM_BANDAY",bandialog):GetValue()
				tExp["month"] = self:GetCtrl("ID_NUM_BANMONTH",bandialog):GetSelection()+1
				tExp["year"] = self:GetCtrl("ID_NUM_BANYEAR",bandialog):GetValue()
				tExp["hour"] = self:GetCtrl("ID_NUM_BANHOUR",bandialog):GetValue()
				tExp["min"] = self:GetCtrl("ID_NUM_BANMINUTE",bandialog):GetValue()
				if os.time(tExp) < os.time() then
					wx.wxMessageBox((self:Translate("BadTimeSpecifiedBanExpired") or "Bad time specified. With that time, the ban would already have expired!"),_APPNAME,wx.wxICON_EXCLAMATION)
					return
				end
			end
			if ((not bNickban) and (not bIPban)) then
				wx.wxMessageBox((self:Translate("YouCantCreateBanWithoutNickOrIP") or "You can't create ban if you don't ban nick or IP!"),_APPNAME,wx.wxICON_EXCLAMATION)
				return
			end
			if bIPban then
				if sIP == "" then
					wx.wxMessageBox((self:Translate("ForIPBanSpecifyIP") or "For IP ban must be IP specified!"),_APPNAME,wx.wxICON_EXCLAMATION)
					return
				elseif (not self:IsIP(sIP)) then
					wx.wxMessageBox(sIP.." "..(self:Translate("IsNotValidIPAddress") or "is not valid IP address!"),_APPNAME,wx.wxICON_EXCLAMATION)
					return
				end
			end
			if bNickban then
				if sNick == "" then
					wx.wxMessageBox((self:Translate("ForNickBanSpecifyNick") or "For nick ban must be nick specified!"),_APPNAME,wx.wxICON_EXCLAMATION)
					return
				end
			end
			if not t then
				for i,v in ipairs(tCtrls["tBans"]) do
					if v[1] == sIP or v[2] == sNick then
						wx.wxMessageBox((self:Translate("SimilarBanExist") or "Similar ban already exist!"),_APPNAME,wx.wxICON_EXCLAMATION)
						return
					end
				end
			end
			event:Skip()
		end)
		bandialog:Centre()
		if bandialog:ShowModal() == wx.wxID_CANCEL then return end -- cancelled
		local bNickban = self:GetCtrl("ID_CHK_NICKBAN",bandialog):GetValue()
		local bIPban = self:GetCtrl("ID_CHK_IPBAN",bandialog):GetValue()
		local bFullban = self:GetCtrl("ID_CHK_FULLBAN",bandialog):GetValue()
		local bTempban = self:GetCtrl("ID_CHK_BANTEMPORARY",bandialog):GetValue()
		local sIP = self:GetCtrl("ID_TXT_BANIP",bandialog):GetValue()
		local sNick = self:GetCtrl("ID_TXT_BANNICK",bandialog):GetValue()
		local sReason = self:GetCtrl("ID_TXT_BANREASON",bandialog):GetValue():gsub("\"","\\\"")
		local sCreatedBy = self:GetCtrl("ID_TXT_BANCREATEDBY",bandialog):GetValue():gsub("\"","\\\"")
		local tExp = {}
		tExp["day"] = self:GetCtrl("ID_NUM_BANDAY",bandialog):GetValue()
		tExp["month"] = self:GetCtrl("ID_NUM_BANMONTH",bandialog):GetSelection()+1
		tExp["year"] = self:GetCtrl("ID_NUM_BANYEAR",bandialog):GetValue()
		tExp["hour"] = self:GetCtrl("ID_NUM_BANHOUR",bandialog):GetValue()
		tExp["min"] = self:GetCtrl("ID_NUM_BANMINUTE",bandialog):GetValue()
		return {{t or ""},{bIPban,bFullban,bNickban,sIP,sNick,sReason,sCreatedBy,iff(bTempban,os.time(tExp),0)}}
	else
		wx.wxMessageBox("Failed to load the ban dialog form from the XML resource. Please re-download the application",_APPNAME,wx.wxICON_EXCLAMATION)
	end
end

function tFuncs.ShowRangeBanDialog(self,t)
	local rangebandialog = wx.wxDialog()
	if m_XmlResource:LoadDialog(rangebandialog,wx.NULL,"ID_DLG_RANGEBANS") then
		-- Translations --
		rangebandialog:SetTitle(tCtrls["tLangs"][322])
		self:GetCtrl("ID_CHK_RANGEFULLBAN",rangebandialog):SetLabel(tCtrls["tLangs"][293])
		self:GetCtrl("ID_STT_RANGEBANFROMIP",rangebandialog):SetLabel(tCtrls["tLangs"][323])
		self:GetCtrl("ID_STT_RANGEBANTOIP",rangebandialog):SetLabel(tCtrls["tLangs"][324])
		self:GetCtrl("ID_STT_RANGEBANREASON",rangebandialog):SetLabel(tCtrls["tLangs"][296])
		self:GetCtrl("ID_STT_RANGEBANCREATEDBY",rangebandialog):SetLabel(tCtrls["tLangs"][297])
		self:GetCtrl("ID_CHK_RANGEBANTEMPORARY",rangebandialog):SetLabel(tCtrls["tLangs"][298])
		self:GetCtrl("ID_STT_RANGEBANDAY",rangebandialog):SetLabel(tCtrls["tLangs"][299])
		self:GetCtrl("ID_STT_RANGEBANMONTH",rangebandialog):SetLabel(tCtrls["tLangs"][300])
		self:GetCtrl("ID_STT_RANGEBANYEAR",rangebandialog):SetLabel(tCtrls["tLangs"][301])
		self:GetCtrl("ID_STT_RANGEBANHOUR",rangebandialog):SetLabel(tCtrls["tLangs"][302])
		self:GetCtrl("ID_STT_RANGEBANMINUTE",rangebandialog):SetLabel(tCtrls["tLangs"][303])
		self:GetCtrl("ID_STT_RANGEBANEXPIRATION",rangebandialog):SetLabel(tCtrls["tLangs"][304])
		local tMonths = {
		tCtrls["tLangs"][305],tCtrls["tLangs"][306],tCtrls["tLangs"][307],tCtrls["tLangs"][308],
		tCtrls["tLangs"][309],tCtrls["tLangs"][310],tCtrls["tLangs"][311],tCtrls["tLangs"][312],
		tCtrls["tLangs"][313],tCtrls["tLangs"][314],tCtrls["tLangs"][315],tCtrls["tLangs"][316],
		}
		self:GetCtrl("ID_NUM_RANGEBANMONTH",rangebandialog):Clear(); self:GetCtrl("ID_NUM_RANGEBANMONTH",rangebandialog):Append(tMonths)
		self:GetCtrl("ID_CHK_RANGEBANPERMANENT",rangebandialog):SetLabel(tCtrls["tLangs"][317])
		-- Translations end --
		local IPValidator = wx.wxTextValidator(wx.wxFILTER_INCLUDE_CHAR_LIST)
		IPValidator:SetIncludes({"0","1","2","3","4","5","6","7","8","9","."})
		self:GetCtrl("ID_TXT_RANGEBANFROMIP",rangebandialog):SetValidator(IPValidator)
		self:GetCtrl("ID_TXT_RANGEBANTOIP",rangebandialog):SetValidator(IPValidator)
		self:GetCtrl("ID_TXT_RANGEBANREASON",rangebandialog):SetValidator(tCtrls["NoP"])
		self:GetCtrl("ID_TXT_RANGEBANCREATEDBY",rangebandialog):SetValidator(tCtrls["Nick"])
		self:GetCtrl("ID_CHK_RANGEBANTEMPORARY",rangebandialog):Connect(wx.wxEVT_COMMAND_CHECKBOX_CLICKED,function(event)
			if event:IsChecked() == true then
				self:GetCtrl("ID_CHK_RANGEBANPERMANENT",rangebandialog):SetValue(false)
				self:GetCtrl("ID_STT_RANGEBANDAY",rangebandialog):Enable(true)
				self:GetCtrl("ID_STT_RANGEBANMONTH",rangebandialog):Enable(true)
				self:GetCtrl("ID_STT_RANGEBANYEAR",rangebandialog):Enable(true)
				self:GetCtrl("ID_STT_RANGEBANHOUR",rangebandialog):Enable(true)
				self:GetCtrl("ID_STT_RANGEBANMINUTE",rangebandialog):Enable(true)
				self:GetCtrl("ID_STT_RANGEBANEXPIRATION",rangebandialog):Enable(true)
				self:GetCtrl("ID_NUM_RANGEBANDAY",rangebandialog):Enable(true)
				self:GetCtrl("ID_NUM_RANGEBANMONTH",rangebandialog):Enable(true)
				self:GetCtrl("ID_NUM_RANGEBANYEAR",rangebandialog):Enable(true)
				self:GetCtrl("ID_NUM_RANGEBANHOUR",rangebandialog):Enable(true)
				self:GetCtrl("ID_NUM_RANGEBANMINUTE",rangebandialog):Enable(true)
			else 
				self:GetCtrl("ID_CHK_RANGEBANPERMANENT",rangebandialog):SetValue(true)
				self:GetCtrl("ID_STT_RANGEBANDAY",rangebandialog):Enable(false)
				self:GetCtrl("ID_STT_RANGEBANMONTH",rangebandialog):Enable(false)
				self:GetCtrl("ID_STT_RANGEBANYEAR",rangebandialog):Enable(false)
				self:GetCtrl("ID_STT_RANGEBANHOUR",rangebandialog):Enable(false)
				self:GetCtrl("ID_STT_RANGEBANMINUTE",rangebandialog):Enable(false)
				self:GetCtrl("ID_STT_RANGEBANEXPIRATION",rangebandialog):Enable(false)
				self:GetCtrl("ID_NUM_RANGEBANDAY",rangebandialog):Enable(false)
				self:GetCtrl("ID_NUM_RANGEBANMONTH",rangebandialog):Enable(false)
				self:GetCtrl("ID_NUM_RANGEBANYEAR",rangebandialog):Enable(false)
				self:GetCtrl("ID_NUM_RANGEBANHOUR",rangebandialog):Enable(false)
				self:GetCtrl("ID_NUM_RANGEBANMINUTE",rangebandialog):Enable(false)
			end
		end)
		self:GetCtrl("ID_CHK_RANGEBANPERMANENT",rangebandialog):Connect(wx.wxEVT_COMMAND_CHECKBOX_CLICKED,function(event)
			if event:IsChecked() == true then
				self:GetCtrl("ID_CHK_RANGEBANTEMPORARY",rangebandialog):SetValue(false)
				self:GetCtrl("ID_STT_RANGEBANDAY",rangebandialog):Enable(true)
				self:GetCtrl("ID_STT_RANGEBANMONTH",rangebandialog):Enable(true)
				self:GetCtrl("ID_STT_RANGEBANYEAR",rangebandialog):Enable(true)
				self:GetCtrl("ID_STT_RANGEBANHOUR",rangebandialog):Enable(true)
				self:GetCtrl("ID_STT_RANGEBANMINUTE",rangebandialog):Enable(true)
				self:GetCtrl("ID_STT_RANGEBANEXPIRATION",rangebandialog):Enable(true)
				self:GetCtrl("ID_NUM_RANGEBANDAY",rangebandialog):Enable(true)
				self:GetCtrl("ID_NUM_RANGEBANMONTH",rangebandialog):Enable(true)
				self:GetCtrl("ID_NUM_RANGEBANYEAR",rangebandialog):Enable(true)
				self:GetCtrl("ID_NUM_RANGEBANHOUR",rangebandialog):Enable(true)
				self:GetCtrl("ID_NUM_RANGEBANMINUTE",rangebandialog):Enable(true)
			else
				self:GetCtrl("ID_CHK_RANGEBANTEMPORARY",rangebandialog):SetValue(true)
				self:GetCtrl("ID_STT_RANGEBANDAY",rangebandialog):Enable(false)
				self:GetCtrl("ID_STT_RANGEBANMONTH",rangebandialog):Enable(false)
				self:GetCtrl("ID_STT_RANGEBANYEAR",rangebandialog):Enable(false)
				self:GetCtrl("ID_STT_RANGEBANHOUR",rangebandialog):Enable(false)
				self:GetCtrl("ID_STT_RANGEBANMINUTE",rangebandialog):Enable(false)
				self:GetCtrl("ID_STT_RANGEBANEXPIRATION",rangebandialog):Enable(false)
				self:GetCtrl("ID_NUM_RANGEBANDAY",rangebandialog):Enable(false)
				self:GetCtrl("ID_NUM_RANGEBANMONTH",rangebandialog):Enable(false)
				self:GetCtrl("ID_NUM_RANGEBANYEAR",rangebandialog):Enable(false)
				self:GetCtrl("ID_NUM_RANGEBANHOUR",rangebandialog):Enable(false)
				self:GetCtrl("ID_NUM_RANGEBANMINUTE",rangebandialog):Enable(false)
			end
		end)
		if t and #t == 5 then
			local sFromIP,sToIP = t[1]:match("(%S+)%s%-%s(%S+)")
			if not sFromIP then return end
			self:GetCtrl("ID_TXT_RANGEBANFROMIP",rangebandialog):SetValue(sFromIP)
			self:GetCtrl("ID_TXT_RANGEBANTOIP",rangebandialog):SetValue(sToIP)
			self:GetCtrl("ID_CHK_RANGEFULLBAN",rangebandialog):SetValue(iff(t[5] == "1",true,false))
			self:GetCtrl("ID_TXT_RANGEBANREASON",rangebandialog):SetValue(t[3])
			self:GetCtrl("ID_TXT_RANGEBANCREATEDBY",rangebandialog):SetValue(t[2])
			self:GetCtrl("ID_CHK_RANGEBANPERMANENT",rangebandialog):SetValue(iff(t[4]:find("%b<>"),true,false))
			self:GetCtrl("ID_CHK_RANGEBANTEMPORARY",rangebandialog):SetValue(iff(t[4]:find("%d"),true,false))
			if self:GetCtrl("ID_CHK_RANGEBANPERMANENT",rangebandialog):IsChecked() == true then
				self:GetCtrl("ID_STT_RANGEBANDAY",rangebandialog):Enable(false)
				self:GetCtrl("ID_STT_RANGEBANMONTH",rangebandialog):Enable(false)
				self:GetCtrl("ID_STT_RANGEBANYEAR",rangebandialog):Enable(false)
				self:GetCtrl("ID_STT_RANGEBANHOUR",rangebandialog):Enable(false)
				self:GetCtrl("ID_STT_RANGEBANMINUTE",rangebandialog):Enable(false)
				self:GetCtrl("ID_STT_RANGEBANEXPIRATION",rangebandialog):Enable(false)
				self:GetCtrl("ID_NUM_RANGEBANDAY",rangebandialog):Enable(false)
				self:GetCtrl("ID_NUM_RANGEBANMONTH",rangebandialog):Enable(false)
				self:GetCtrl("ID_NUM_RANGEBANYEAR",rangebandialog):Enable(false)
				self:GetCtrl("ID_NUM_RANGEBANHOUR",rangebandialog):Enable(false)
				self:GetCtrl("ID_NUM_RANGEBANMINUTE",rangebandialog):Enable(false)
			end
			local tExp = os.date("*t",(tonumber(t[4]) or os.time()))
			self:GetCtrl("ID_NUM_RANGEBANDAY",rangebandialog):SetValue(tExp["day"])
			self:GetCtrl("ID_NUM_RANGEBANMONTH",rangebandialog):SetSelection(tExp["month"]-1)
			self:GetCtrl("ID_NUM_RANGEBANYEAR",rangebandialog):SetValue(tExp["year"])
			self:GetCtrl("ID_NUM_RANGEBANHOUR",rangebandialog):SetValue(tExp["hour"])
			self:GetCtrl("ID_NUM_RANGEBANMINUTE",rangebandialog):SetValue(tExp["min"])
		else
			-- Maybe we got the settings: add the default tempban time to the current date (if not then 0)
			local iBanTime = tCtrls["num"]["num_16"]:GetValue()*60
			local tExp = os.date("*t",os.time()+iBanTime)
			self:GetCtrl("ID_NUM_RANGEBANDAY",rangebandialog):SetValue(tExp["day"])
			self:GetCtrl("ID_NUM_RANGEBANMONTH",rangebandialog):SetSelection(tExp["month"]-1)
			self:GetCtrl("ID_NUM_RANGEBANYEAR",rangebandialog):SetValue(tExp["year"])
			self:GetCtrl("ID_NUM_RANGEBANHOUR",rangebandialog):SetValue(tExp["hour"])
			self:GetCtrl("ID_NUM_RANGEBANMINUTE",rangebandialog):SetValue(tExp["min"])
			self:GetCtrl("ID_TXT_RANGEBANCREATEDBY",rangebandialog):SetValue(self:GetCtrl("txt_login_nick"):GetValue())
		end
		rangebandialog:Connect(wx.wxEVT_CLOSE_WINDOW,function(event)
			-- Checking
			local bFullban = self:GetCtrl("ID_CHK_RANGEFULLBAN",rangebandialog):GetValue()
			local bPermban = self:GetCtrl("ID_CHK_RANGEBANPERMANENT",rangebandialog):GetValue()
			local bTempban = self:GetCtrl("ID_CHK_RANGEBANTEMPORARY",rangebandialog):GetValue()
			local sFromIP = self:GetCtrl("ID_TXT_RANGEBANFROMIP",rangebandialog):GetValue()
			local sToIP = self:GetCtrl("ID_TXT_RANGEBANTOIP",rangebandialog):GetValue()
			local sReason = self:GetCtrl("ID_TXT_RANGEBANREASON",rangebandialog):GetValue()
			local sCreatedBy = self:GetCtrl("ID_TXT_RANGEBANCREATEDBY",rangebandialog):GetValue()
			local tExp = {}
			if bTempban then
				tExp["day"] = self:GetCtrl("ID_NUM_RANGEBANDAY",rangebandialog):GetValue()
				tExp["month"] = self:GetCtrl("ID_NUM_RANGEBANMONTH",rangebandialog):GetSelection()+1
				tExp["year"] = self:GetCtrl("ID_NUM_RANGEBANYEAR",rangebandialog):GetValue()
				tExp["hour"] = self:GetCtrl("ID_NUM_RANGEBANHOUR",rangebandialog):GetValue()
				tExp["min"] = self:GetCtrl("ID_NUM_RANGEBANMINUTE",rangebandialog):GetValue()
				if os.time(tExp) < os.time() then
					wx.wxMessageBox((self:Translate("BadTimeSpecifiedBanExpired") or "Bad time specified. With that time, the ban would already have expired!"),_APPNAME,wx.wxICON_EXCLAMATION)
					return
				end
			end
			if sFromIP == "" or sToIP == "" then
				wx.wxMessageBox((self:Translate("NoValidIpRangeSpecified") or "No valid IP range specified!"),_APPNAME,wx.wxICON_EXCLAMATION)
				return
			elseif not self:IsIP(sFromIP) then
				wx.wxMessageBox(sFromIP.." "..(self:Translate("IsNotValidIPAddress") or "is not valid IP address!"),_APPNAME,wx.wxICON_EXCLAMATION)
				return
			elseif not self:IsIP(sToIP) then
				wx.wxMessageBox(sToIP.." "..(self:Translate("IsNotValidIPAddress") or "is not valid IP address!"),_APPNAME,wx.wxICON_EXCLAMATION)
				return
			elseif self:IP2DEC(sToIP) < self:IP2DEC(sFromIP) then
				wx.wxMessageBox((self:Translate("NoValidIpRangeSpecified") or "No valid IP range specified!"),_APPNAME,wx.wxICON_EXCLAMATION)
				return
			end
			if not t then
				for i,v in ipairs(tCtrls["tRangeBans"]) do
					-- Check inside ranges
					local sFrom,sTo = v[1]:match("(%S+) %- (%S+)")
					if ((self:IP2DEC(sFromIP) >= self:IP2DEC(sFrom)) and (self:IP2DEC(sToIP) <= self:IP2DEC(sTo))) then
						wx.wxMessageBox((self:Translate("SimilarBanExist") or "Similar ban already exist!"),_APPNAME,wx.wxICON_EXCLAMATION)
						return
					end
				end
			end
			event:Skip()
		end)
		if rangebandialog:ShowModal() == wx.wxID_CANCEL then return end -- cancelled
		local bFullban = self:GetCtrl("ID_CHK_RANGEFULLBAN",rangebandialog):GetValue()
		local bTempban = self:GetCtrl("ID_CHK_RANGEBANTEMPORARY",rangebandialog):GetValue()
		local sFromIP = self:GetCtrl("ID_TXT_RANGEBANFROMIP",rangebandialog):GetValue()
		local sToIP = self:GetCtrl("ID_TXT_RANGEBANTOIP",rangebandialog):GetValue()
		local sReason = self:GetCtrl("ID_TXT_RANGEBANREASON",rangebandialog):GetValue():gsub("\"","\\\"")
		local sCreatedBy = self:GetCtrl("ID_TXT_RANGEBANCREATEDBY",rangebandialog):GetValue():gsub("\"","\\\"")
		local tExp = {}
		tExp["day"] = self:GetCtrl("ID_NUM_RANGEBANDAY",rangebandialog):GetValue()
		tExp["month"] = self:GetCtrl("ID_NUM_RANGEBANMONTH",rangebandialog):GetSelection()+1
		tExp["year"] = self:GetCtrl("ID_NUM_RANGEBANYEAR",rangebandialog):GetValue()
		tExp["hour"] = self:GetCtrl("ID_NUM_RANGEBANHOUR",rangebandialog):GetValue()
		tExp["min"] = self:GetCtrl("ID_NUM_RANGEBANMINUTE",rangebandialog):GetValue()
		return {{t},{sFromIP,sToIP,bFullban,sReason,sCreatedBy,iff(bTempban,os.time(tExp),0)}}
	else
		wx.wxMessageBox("Failed to load the rangeban dialog form from the XML resource. Please re-download the application",_APPNAME,wx.wxICON_EXCLAMATION)
	end
end

function tFuncs.ParseStat(self,stat)
	local pattern = "(Uptime:.+)(Chat messages:.+Close commands: %d+ x).-(CPU usage.-)%-%-.-(SendRests.+)"
	local _Ok,_,core,cmds,cpumem,nw = stat:find(pattern)
	if statdialog then
		local _,pre,ver,built,pro,users,logged,fin
		if _Ok and core then
			pre,ver,built,pro = core:match("(.-)(Version:.-) built on (.-)(OS:.-)Users %(")
			users,logged,share,fin = core:match("(Users.-Logged%):) (.-)(Users shared size:) (.+)")
		end
		local corestat = tostring(pre)..tostring(ver).."\n".."Build date: "..tostring(built)..tostring(users).."\n\t"..tostring(logged)..tostring(share).."\n\t"..tostring(fin)
		self:GetCtrl("ID_STT_CORE",statdialog):SetLabel(iff(_Ok,corestat,"Unable to get core statistics"))
		self:GetCtrl("ID_STT_CMDS",statdialog):SetLabel(iff(_Ok,cmds,"Unable to get commands statistics"))
		self:GetCtrl("ID_STT_CPU",statdialog):SetLabel(iff(_Ok,tostring(cpumem).."-------------------------\n"..tostring(nw),"Unable to get CPU and memory statistics"))
	end
end

function tFuncs.ShowStat(self)
	statdialog = wx.wxDialog() -- Global!
	if m_XmlResource:LoadDialog(statdialog,wx.NULL,"ID_DLG_STAT") then
		local bmp = self:GetImage("stats")
		local icon = wx.wxIcon()
		icon:CopyFromBitmap(bmp)
		statdialog:SetIcon(icon)
		icon:delete()
		bmp:delete()
		self:Send("<"..self:GetCtrl("txt_login_nick"):GetValue().."> !stats")
		local sSecs = tCtrls["tLangs"][87]
		local cbbStatRate = self:GetCtrl("ID_NUM_STATRATE",statdialog)
		cbbStatRate:Clear()
		cbbStatRate:Append({"Never","1 "..sSecs,"3 "..sSecs,"5 "..sSecs,"10 "..sSecs,"30 "..sSecs,"60 "..sSecs})
		cbbStatRate:SetSelection(5)
		tmrStat = wx.wxTimer(statdialog)
		local tSeconds,i = {1,3,5,10,30,60},0
		tmrStat:Start(1000)
		statdialog:Connect(wx.wxEVT_TIMER,function(event)
			i = i + 1
			if tSeconds[cbbStatRate:GetSelection()] and i >= tSeconds[cbbStatRate:GetSelection()] then
				self:Send("<"..self:GetCtrl("txt_login_nick"):GetValue().."> !stats")
				i = 0
			end
		end)
		statdialog:Connect(tCtrls["ID_CMD_CLIPBOARD"],wx.wxEVT_COMMAND_BUTTON_CLICKED,function(event)
			if wx.wxClipboard.Get():Open() then
				-- Not the same as Px sent...
				local stats = self:GetCtrl("ID_STT_CORE",statdialog):GetLabel()..self:GetCtrl("ID_STT_CMDS",
				statdialog):GetLabel().."\n"..self:GetCtrl("ID_STT_CPU",statdialog):GetLabel()
				wx.wxClipboard.Get():SetData(wx.wxTextDataObject(stats))
				wx.wxClipboard.Get():Close()
			end
		end)
		statdialog:Connect(wx.wxID_CLOSE,wx.wxEVT_COMMAND_BUTTON_CLICKED,function(event) statdialog:Close() end)
		statdialog:Connect(wx.wxEVT_CLOSE_WINDOW,function(event) event:Skip() tmrStat:Stop();tmrStat:delete();tmrStat = nil end)
		statdialog:Centre()
		statdialog:Show()
	else
		wx.wxMessageBox("Failed to load the statistics dialog form from the XML resource. Please re-download the application",_APPNAME,wx.wxICON_EXCLAMATION)
	end
end

function tFuncs.GeneratePassword(self)
	local pwddialog = wx.wxDialog()
	if m_XmlResource:LoadDialog(pwddialog,wx.NULL,"ID_DLG_PWGEN") then
		local GenPass = function()
			math.randomseed(os.clock())
			local tChars, sPass = {}, ""
			if self:GetCtrl("ID_CHK_PWGENSMALL",pwddialog):IsChecked() then table.insert(tChars,{97,122}) end
			if self:GetCtrl("ID_CHK_PWGENBIG",pwddialog):IsChecked() then table.insert(tChars,{65, 90 }) end
			if self:GetCtrl("ID_CHK_PWGENNUMBER",pwddialog):IsChecked() then table.insert(tChars,{48, 57 }) end
			if self:GetCtrl("ID_CHK_PWGENSPECIAL",pwddialog):IsChecked() then table.insert(tChars,{{33,47},{58,64}}) end
			if #tChars < 1 then return "" end
			for i=1,self:GetCtrl("ID_NUM_PWGENLENGTH",pwddialog):GetValue() do
				local j = math.random(#tChars)
				local iFirst,iSecond = tChars[j][1],tChars[j][2]
				if type(iFirst) == "table" then
					local iGroup = math.random(2)
					iFirst,iSecond = tChars[j][iGroup][1],tChars[j][iGroup][2]
				end
				sPass = sPass..string.char(math.random(iFirst,iSecond))
			end
			return sPass
		end
		pwddialog:Connect(tCtrls["ID_CMD_PWGENGENERATE"],wx.wxEVT_COMMAND_BUTTON_CLICKED,function(event)
			self:GetCtrl("ID_TXT_PWGENPASSWORD",pwddialog):SetValue(GenPass())
		end)
		pwddialog:Connect(tCtrls["ID_CMD_PWGENCOPY"],wx.wxEVT_COMMAND_BUTTON_CLICKED,function(event)
			if wx.wxClipboard.Get():Open() then
				wx.wxClipboard.Get():SetData(wx.wxTextDataObject(self:GetCtrl("ID_TXT_PWGENPASSWORD",pwddialog):GetValue()))
				wx.wxClipboard.Get():Close()
			end
		end)
		pwddialog:ShowModal()
		pwddialog:Destroy()
	else
		wx.wxMessageBox("Failed to load the password generator form from the XML resource. Please re-download the application")
	end
end

function tFuncs.ShowRegWindow(self,sNick,sPassword,sProfileName)
	-- Validators don't allow users to write forbidden characters into nickname/password, so no more checking needed.
	local regnickvalidator = wx.wxTextValidator(wx.wxFILTER_EXCLUDE_CHAR_LIST); regnickvalidator:SetExcludes({"$","|","<",">",":","?","*","\"","/","\\"," "})
	local regpassvalidator = wx.wxTextValidator(wx.wxFILTER_EXCLUDE_CHAR_LIST); regpassvalidator:SetExcludes({"$","|"," "})
	local regdialog = wx.wxDialog()
	if m_XmlResource:LoadDialog(regdialog,wx.NULL,"ID_DLG_REGUSER") then
		-- Translations --
		regdialog:SetTitle(self:Translate("RegisteredUser") or "Registered user")
		self:GetCtrl("ID_STT_REGNICK",regdialog):SetLabel(self:Translate("Nickname") or "Nickname")
		self:GetCtrl("ID_STT_REGPASSWORD",regdialog):SetLabel(tCtrls["tLangs"][4])
		self:GetCtrl("ID_STT_REGPROFILE",regdialog):SetLabel(self:Translate("UserProfile") or "User profile")
		self:GetCtrl("wxID_OK",regdialog):SetLabel(tCtrls["tLangs"][12])
		self:GetCtrl("wxID_CANCEL",regdialog):SetLabel(tCtrls["tLangs"][320])
		-- Translations end --
		self:GetCtrl("ID_TXT_REGNICK",regdialog):SetValidator(regnickvalidator)
		self:GetCtrl("ID_TXT_REGPASSWORD",regdialog):SetValidator(regpassvalidator)
		if sNick then
			self:GetCtrl("ID_TXT_REGNICK",regdialog):SetValue(sNick)
			self:GetCtrl("ID_TXT_REGPASSWORD",regdialog):SetValue(sPassword)
		end
		regdialog:Connect(tCtrls["ID_CMD_REGPWDGEN"],wx.wxEVT_COMMAND_BUTTON_CLICKED,function(event) self:GeneratePassword() end)
		local tProfiles = {}
		if #tCtrls["tProfiles"] > 0 then -- If user has no permission, didn't get the profiles.
			for i=0,#tCtrls["tProfiles"] do
			    table.insert(tProfiles,tCtrls["tProfiles"][i][1])
			end
		end
		self:GetCtrl("ID_NUM_REGPROFILE",regdialog):Append(tProfiles)
		local iProfile = iff(sNick,0,1);
		if sProfileName then
			for i,v in ipairs(tCtrls["tProfiles"]) do
			    if v[1] == sProfileName then
					iProfile = i
					break
				end
			end
		end
		self:GetCtrl("ID_NUM_REGPROFILE",regdialog):SetSelection(iProfile)
		if regdialog:ShowModal() == wx.wxID_OK then
		    return self:GetCtrl("ID_TXT_REGNICK",regdialog):GetValue(),
			self:GetCtrl("ID_TXT_REGPASSWORD",regdialog):GetValue(),
			self:GetCtrl("ID_NUM_REGPROFILE",regdialog):GetSelection(),
			sNick
		end
	else
		wx.wxMessageBox("Failed to load the registered user form from the XML resource. Please re-download the application")
	end
end

function tFuncs.GetSelection(self,ListCtrl)
	local selitem = 0
	for i=0,ListCtrl:GetItemCount()-1 do
		if ListCtrl:GetItemState(i,wx.wxLIST_STATE_SELECTED) == wx.wxLIST_STATE_SELECTED then
			selitem = i
			break
		end
	end
	return selitem
end

function tFuncs.GetImage(self,img)
	local m_fsfile = m_FileSystem:OpenFile("file:PRAdmin.xrs#zip:images/"..img..".xpm",wx.wxFS_READ);
	local m_stream = "";
	if m_fsfile then
		m_stream = m_fsfile:GetStream();
	end
	local m_img = wx.wxImage();
	m_img:LoadFile(m_stream,wx.wxBITMAP_TYPE_XPM);
	local m_bmp = wx.wxBitmap(m_img);
	m_img:delete();
	return m_bmp;
end

function tFuncs.Escape(self,sText)
	-- Windows escape. Nevermind if it appears crappy on linux, it doesn't need it.
	tWinChars = {
	["â‚¬"] = "€", ["â€š"] = "‚", ["â€ž"] = "„", ["â€¦"] = "…", ["â€ "] = "†", ["â€ˇ"] = "‡", ["â€°"] = "‰", ["Ĺ "] = "Š",
	["â€ą"] = "‹", ["Ĺš"] = "Ś", ["Ĺ¤"] = "Ť", ["Ĺ˝"] = "Ž", ["Ĺą"] = "Ź", ["â€"] = "‘", ["â€™"] = "’", ["â€ś"] = "“",
	["â€ť"] = "”", ["â€˘"] = "•", ["â€“"] = "–", ["â€”"] = "—", ["â„˘"] = "™", ["Ĺˇ"] = "š", ["â€ş"] = "›", ["Ĺ›"] = "ś",
	["ĹĄ"] = "ť", ["Ĺľ"] = "ž", ["Ĺş"] = "ź", ["Ë‡"] = "ˇ", ["Ë"] = "˘", ["Ĺ"] = "Ł", ["Ä„"] = "Ą", ["Ĺž"] = "Ş", ["Ĺ»"] = "Ż",
	["Ë›"] = "˛", ["Ĺ‚"] = "ł", ["Ä…"] = "ą", ["Ĺź"] = "ş", ["Ä˝"] = "Ľ", ["Ëť"] = "˝", ["Äľ"] = "ľ", ["ĹĽ"] = "ż", ["Ĺ”"] = "Ŕ",
	["Ă"] = "Á", ["Ă‚"] = "Â", ["Ä‚"] = "Ă", ["Ă„"] = "Ä", ["Äą"] = "Ĺ", ["Ä†"] = "Ć", ["Ă‡"] = "Ç", ["ÄŚ"] = "Č", ["Ă‰"] = "É",
	["Ä"] = "Ę", ["Ă‹"] = "Ë", ["Äš"] = "Ě", ["ĂŤ"] = "Í", ["ĂŽ"] = "Î", ["ÄŽ"] = "Ď", ["Ä"] = "Đ", ["Ĺ"] = "Ń", ["Ĺ‡"] = "Ň",
	["Ă“"] = "Ó", ["Ă”"] = "Ô", ["Ĺ"] = "Ő", ["Ă–"] = "Ö", ["Ă—"] = "×", ["Ĺ"] = "Ř", ["Ĺ®"] = "Ů", ["Ăš"] = "Ú", ["Ĺ°"] = "Ű",
	["Ăś"] = "Ü", ["Ăť"] = "Ý", ["Ĺ˘"] = "Ţ", ["Ăź"] = "ß", ["Ĺ•"] = "ŕ", ["Ăˇ"] = "á", ["Ă˘"] = "â", ["Ä"] = "ă", ["Ă¤"] = "ä",
	["Äş"] = "ĺ", ["Ä‡"] = "ć", ["Ă§"] = "ç", ["ÄŤ"] = "č", ["Ă©"] = "é", ["Ä™"] = "ę", ["Ă«"] = "ë", ["Ä›"] = "ě", ["Ă­"] = "í",
	["Ă®"] = "î", ["ÄŹ"] = "ď", ["Ä‘"] = "đ", ["Ĺ„"] = "ń", ["Ĺ"] = "ň", ["Ăł"] = "ó", ["Ă´"] = "ô", ["Ĺ‘"] = "ő", ["Ă¶"] = "ö",
	["Ă·"] = "÷", ["Ĺ™"] = "ř", ["ĹŻ"] = "ů", ["Ăş"] = "ú", ["Ĺ±"] = "ű", ["ĂĽ"] = "ü", ["Ă˝"] = "ý", ["ĹŁ"] = "ţ", ["Ë™"] = "˙"
	}
	-- Linux escape. It should appear correctly (each value has to appear one character). If not, convert to UTF8 w/o BOM
	tNixChars = {
	[128] = "€",[129] = "",[130] = "‚",[131] = "",[132] = "„",[133] = "…",[134] = "†",[135] = "‡",[136] = "",
	[137] = "‰",[138] = "Š",[139] = "‹",[140] = "Ś",[141] = "Ť",[142] = "Ž",[143] = "Ź",[144] = "",[145] = "‘",
	[146] = "’",[147] = "“",[148] = "”",[149] = "•",[150] = "–",[151] = "—",[152] = "",[153] = "™",[154] = "š",
	[155] = "›",[156] = "ś",[157] = "ť",[158] = "ž",[159] = "ź",[160] = " ",[161] = "ˇ",[162] = "˘",[163] = "Ł",
	[164] = "¤",[165] = "Ą",[166] = "¦",[167] = "§",[168] = "¨",[169] = "©",[170] = "Ş",[171] = "«",[172] = "¬",
	[173] = "­",[174] = "®",[175] = "Ż",[176] = "°",[177] = "±",[178] = "˛",[179] = "ł",[180] = "´",[181] = "µ",
	[182] = "¶",[183] = "·",[184] = "¸",[185] = "ą",[186] = "ş",[187] = "»",[188] = "Ľ",[189] = "˝",[190] = "ľ",
	[191] = "ż",[192] = "Ŕ",[193] = "Á",[194] = "Â",[195] = "Ă",[196] = "Ä",[197] = "Ĺ",[198] = "Ć",[199] = "Ç",
	[200] = "Č",[201] = "É",[202] = "Ę",[203] = "Ë",[204] = "Ě",[205] = "Í",[206] = "Î",[207] = "Ď",[208] = "Đ",
	[209] = "Ń",[210] = "Ň",[211] = "Ó",[212] = "Ô",[213] = "Ő",[214] = "Ö",[215] = "×",[216] = "Ř",[217] = "Ů",
	[218] = "Ú",[219] = "Ű",[220] = "Ü",[221] = "Ý",[222] = "Ţ",[223] = "ß",[224] = "ŕ",[225] = "á",[226] = "â",
	[227] = "ă",[228] = "ä",[229] = "ĺ",[230] = "ć",[231] = "ç",[232] = "č",[233] = "é",[234] = "ę",[235] = "ë",
	[236] = "ě",[237] = "í",[238] = "î",[239] = "ď",[240] = "đ",[241] = "ń",[242] = "ň",[243] = "ó",[244] = "ô",
	[245] = "ő",[246] = "ö",[247] = "÷",[248] = "ř",[249] = "ů",[250] = "ú",[251] = "ű",[252] = "ü",[253] = "ý",
	[254] = "ţ",[255] = "˙",
	}
	if wx.__WXMSW__ then
		for k,v in pairs(tWinChars) do
			sText = sText:gsub(k,v)
		end
		sText = sText:gsub("Â(.)","%1")
	else
		sText = string.gsub(sText,".",function(c)
			if string.byte(c) >= 128 then
				return tNixChars[string.byte(c)] or c
			else
				return c
			end
		end)
	end
	return sText
end

function tFuncs.GetDefaultIDs(self)
	local tBoolIDs = {
	"AntiMoGlo",                   --[[000]] "AutoStart",                --[[001]] "RedirectAll",           --[[002]] 
	"RedirectWhenHubFull",         --[[003]] "AutoRegister",             --[[004]] "RegOnly",               --[[005]] 
	"RegOnlyRedir",                --[[006]] "ShareLimitRedir",          --[[007]] "SlotsLimitRedir",       --[[008]] 
	"HubSlotRatioRedir",           --[[009]] "MaxHubsLimitRedir",        --[[010]] "ModeToMyINFO",          --[[011]]
	"ModeToDescription",           --[[012]] "StripDescription",         --[[013]] "StripTag",              --[[014]]
	"StripConnection",             --[[015]] "StripEmail",               --[[016]] "RegBot",                --[[017]]
	"UseBotNickAsHubSec",          --[[018]] "RegOpChat",                --[[019]] "TempBanRedir",          --[[020]]
	"PermBanRedir",                --[[021]] "EnableScripting",          --[[022]] "KeepSlowUsers",         --[[023]]
	"CheckNewReleases",            --[[024]] "EnableTrayIcon",           --[[025]] "StartMinimized",        --[[026]]
	"FilterKickMessages",	       --[[027]] "SendKickMessagesToOps",    --[[028]] "SendStatusMessages",    --[[029]]
	"SendStatusMessagesAsPm",      --[[030]] "EnableTextFiles",          --[[031]] "SendTextFilesAsPm",     --[[032]]
	"StopScriptOnError",           --[[033]] "MOTDAsPm",                 --[[034]] "DefloodReport",         --[[035]]
	"ReplyToHubCommandsAsPm",      --[[036]] "DisableMOTD",              --[[037]] "DontAllowPingers",      --[[038]]
	"ReportPingers",	           --[[039]] "Report3xBadPass",          --[[040]] "AdvancedPassProtection",--[[041]]
	"BindOnlySingleIp",            --[[042]] "ResolveToIp",              --[[043]] "NickLimitRedir",        --[[044]]
	"SendUserIP2ToUserOnLogin",    --[[045]] "BanMessageShowIp",         --[[046]] "BanMessageShowRange",   --[[047]]
	"BanMessageShowNick",          --[[048]] "BanMessageShowReason",     --[[049]] "BanMessageShowBy",      --[[050]]
	"ReportSuspiciousTag",	       --[[051]] "AcceptUnknownTag",         --[[052]] "CheckIpInCommands",     --[[053]]
	"PopupScriptsWindow",          --[[054]] "LogScriptErrors",          --[[055]]
	}
    local tNumberIDs = {
	"MaxUsers",                    --[[000]] "MinShareLimit",            --[[001]] "MinShareUnits",         --[[002]]
	"MaxShareLimit",               --[[003]] "MaxShareUnits",            --[[004]] "MinSlotsLimit",         --[[005]]
	"MaxSlotsLimit",               --[[006]] "HubSlotRatioHubs",         --[[007]] "HubSlotRatioSlots",     --[[008]]
	"MaxHubsLimit",                --[[009]] "NoTagOption",              --[[010]] "FullMyINFOOption",      --[[011]]
	"MaxChatLen",                  --[[012]] "MaxChatLines",             --[[013]] "MaxPmLen",              --[[014]]
	"MaxPmLines",                  --[[015]] "DefaultTempBanTime",       --[[016]] "MaxPassiveSr",          --[[017]]
	"MyINFODelay",                 --[[018]] "MainChatMessages",         --[[019]] "MainChatTime",          --[[020]]
	"MainChatAction",              --[[021]] "SameMainChatMessages",     --[[022]] "SameMainChatTime",      --[[023]]
	"SameMainChatAction",          --[[024]] "SameMultiMainChatMessages",--[[025]] "SameMultiMainChatLines",--[[026]]
	"SameMultiMainChatAction",     --[[027]] "PmMessages",               --[[028]] "PmTime",                --[[029]]
	"PmAction",                    --[[030]] "SamePmMessages",           --[[031]] "SamePmTime",            --[[032]]
	"SamePmAction",                --[[033]] "SameMultiPmMessages",      --[[034]] "SameMultiPmLines",      --[[035]]
	"SameMultiPmAction",           --[[036]] "SearchMessages",           --[[037]] "SearchTime",            --[[038]]
	"SearchAction",                --[[039]] "SameSearchMessages",       --[[040]] "SameSearchTime",        --[[041]]
	"SameSearchAction",            --[[042]] "MyINFOMessages",           --[[043]] "MyINFOTime",            --[[044]]
	"MyINFOAction",                --[[045]] "GetNickListMessages",      --[[046]] "GetNickListTime",       --[[047]]
	"GetNickListAction",           --[[048]] "NewConnectionsCount",      --[[049]] "NewConnectionsTime",    --[[050]]
	"DefloodWarningCount",         --[[051]] "DefloodWarningAction",     --[[052]] "DefloodTempBanTime",    --[[053]]
	"GlobalMainChatMessages",      --[[054]] "GlobalMainChatTime",       --[[055]] "GlobalMainChatTimeOut", --[[056]]
	"GlobalMainChatAction",        --[[057]] "MinSearchLen",             --[[058]] "MaxSearchLen",          --[[059]]
	"MinNickLen",                  --[[060]] "MaxNickLen",               --[[061]] "BruteForcePassProtectBanType",--[[062]]
	"BruteForcePassProtectTempBanTime",--[[063]] "MaxPmCountToUser",     --[[064]] "MaxSimultaneousLogins", --[[065]]
	"MainChatMessages2",           --[[066]] "MainChatTime2",            --[[067]] "MainChatAction2",       --[[068]]
	"PmMessages2",                 --[[069]] "PmTime2",                  --[[070]] "PmAction2",             --[[071]]
	"SearchMessages2",             --[[072]] "SearchTime2",              --[[073]] "SearchAction2",         --[[074]]
	"MyINFOMessages2",             --[[075]] "MyINFOTime2",              --[[076]] "MyINFOAction2",         --[[077]]
	"MaxMyINFOLen",                --[[078]] "CTMMessages",              --[[079]] "CTMTime",               --[[080]]
	"CTMAction",                   --[[081]] "CTMMessages2",             --[[082]] "CTMTime2",              --[[083]]
	"CTMAction2",                  --[[084]] "RCTMMessages",             --[[085]] "RCTMTime",              --[[086]]
	"RCTMAction",                  --[[087]] "RCTMMessages2",            --[[088]] "RCTMTime2",             --[[089]]
	"RCTMAction2",                 --[[090]] "MaxCTMLen",                --[[091]] "MaxRCTMLen",            --[[092]]
	"SRMessages",                  --[[093]] "SRTime",                   --[[094]] "SRAction",              --[[095]]
	"SRMessages2",                 --[[096]] "SRTime2",                  --[[097]] "SRAction2",             --[[098]]
	"MaxSRLen",                    --[[099]] "MaxDownAction",            --[[100]] "MaxDownKb",             --[[101]]
	"MaxDownTime",                 --[[102]] "MaxDownAction2",           --[[103]] "MaxDownKb2",            --[[104]]
	"MaxDownTime2",                --[[105]] "ChatIntervalMessages",     --[[106]] "ChatIntervalTime",      --[[107]]
	"PMIntervalMessages",          --[[108]] "PMIntervalTime",           --[[109]] "SearchIntervalMessages",--[[110]]
	"SearchIntervalTime",          --[[111]] "MaxConnSameIP",            --[[112]] "MinReConnTime",         --[[113]]
	}
	local tStringIDs = {
	"HubName",                     --[[000]] "AdminNick",                --[[001]] "HubAddress",            --[[002]]
	"TCPPorts",                    --[[003]] "UDPPort",                  --[[004]] "HubDescription",        --[[005]]
	"RedirectAddress",             --[[006]] "RegisterServers",          --[[007]] "RegOnlyMessage",        --[[008]]
	"RegOnlyRedirAddress",         --[[009]] "HubTopic",                 --[[010]] "ShareLimitMessage",     --[[011]]
	"ShareLimitRedirAddress",      --[[012]] "SlotsLimitMessage",        --[[013]] "SlotsLimitRedirAddress",--[[014]]
	"HubSlotRatioMessage",         --[[015]] "HubSlotRatioRedirAddress", --[[016]] "MaxHubsLimitMessage",   --[[017]]
	"MaxHubsLimitRedirAddress",    --[[018]] "NoTagMessage",             --[[019]] "NoTagRedirAddress",     --[[020]]
	"BotNick",                     --[[021]] "BotDescription",           --[[022]] "BotEmail",              --[[023]]
	"OpChatNick",                  --[[024]] "OpChatDescription",        --[[025]] "OpChatEmail",           --[[026]]
	"TempBanRedirAddress",         --[[027]] "PermBanRedirAddress",      --[[028]] "ChatCommandsPrefixes",  --[[029]]
	"HubOwnerEmail",               --[[030]] "NickLimitMessage",         --[[031]] "NickLimitRedirAddress", --[[032]]
	"MessageToAddToBanMessage",    --[[033]] "Language",                 --[[034]]
	}
	return tBoolIDs,tNumberIDs,tStringIDs
end

function tFuncs.GetDefaultValues(self)
	local tDefBoolVals = {
	true,   --[[0 AntiMoGlo]]                false,  --[[1 AutoStart]]             false,  --[[2 RedirectAll]]
	false,  --[[3 RedirectWhenHubFull]]      true,   --[[4 AutoRegister]]          false,  --[[5 RegOnly]]
	false,  --[[6 RegOnlyRedir]]             false,  --[[7 ShareLimitRedir]]       false,  --[[8 SlotsLimitRedir]]
	false,  --[[9 HubSlotRatioRedir]]        false,  --[[10 MaxHubsLimitRedir]]    true,   --[[11 ModeToMyINFO]]
	false,  --[[12 ModeToDescription]]       false,  --[[13 StripDescription]]     true,   --[[14 StripTag]]
	false,  --[[15 StripConnection]]         false,  --[[16 StripEmail]]           true,   --[[17 RegBot]]
	true,   --[[18 UseBotNickAsHubSec]]      true,   --[[19 RegOpChat]]            false,  --[[20 TempBanRedir]]
	false,  --[[21 PermBanRedir]]            true,   --[[22 EnableScripting]]      true,   --[[23 KeepSlowUsers]]
	true,   --[[24 CheckNewReleases]]        true,   --[[25 EnableTrayIcon]]       false,  --[[26 StartMinimized]]
	true,   --[[27 FilterKickMessages]]      true,   --[[28 SendKickMessagesToOps]]true,   --[[29 SendStatusMessages]]
	false,  --[[30 SendStatusMessagesAsPm]]  true,   --[[31 EnableTextFiles]]      false,  --[[32 SendTextFilesAsPm]]
	false,  --[[33 StopScriptOnError]]       false,  --[[34 MOTDAsPm]]             false,  --[[35 DefloodReport]]
	false,  --[[36 ReplyToHubCommandsAsPm]]  false,  --[[37 DisableMOTD]]          false,  --[[38 DontAllowPingers]]
	false,  --[[39 ReportPingers]]           true,   --[[40 Report3xBadPass]]      true,   --[[41 AdvancedPassProtection]]
	false,  --[[42 BindOnlySingleIp]]        true,	 --[[43 ResolveToIp]]          false,  --[[44 NickLimitRedir]]
	true,   --[[45 SendUserIP2ToUserOnLogin]]true,   --[[46 BanMessageShowIp]]     true,   --[[47 BanMessageShowRange]]
	true,   --[[48 BanMessageShowNick]]      true,   --[[49 BanMessageShowReason]] true,   --[[50 BanMessageShowBy]]
	true,   --[[51 ReportSuspiciousTag]]     true,   --[[52 AcceptUnknownTag]]     true,   --[[53 CheckIpInCommands]]
	false,  --[[54 PopupScriptsWindow]]      false,  --[[55 LogScriptErrors]]
	}
	local tDefIntVals = {
	250,    --[[0 MaxUsers]]                 0,      --[[1 MinShareLimit]]         0,      --[[2 MinShareUnits]]
	0,      --[[3 MaxShareLimit]]            0,      --[[4 MaxShareUnits]]         0,      --[[5 MinSlotsLimit]]
	0,      --[[6 MaxSlotsLimit]]            0,      --[[7 HubSlotRatioHubs]]      0,      --[[8 HubSlotRatioSlots]]
	0,      --[[9 MaxHubsLimit]]             0,      --[[10 NoTagOption]]          1,      --[[11 FullMyINFOOption]]
	300,    --[[12 MaxChatLen]]              5,      --[[13 MaxChatLines]]         512,    --[[14 MaxPmLen]]
	25,     --[[15 MaxPmLines]]              20,     --[[16 DefaultTempBanTime]]   100,    --[[17 MaxPassiveSr]]
	30,     --[[18 MyINFODelay]]             20,     --[[19 MainChatMessages]]     20,     --[[20 MainChatTime]]
	2,      --[[21 MainChatAction]]          5,      --[[22 SameMainChatMessages]] 60,     --[[23 SameMainChatTime]]
	2,      --[[24 SameMainChatAction]]      2,      --[[25 SameMultiMainChatMessages]]2,  --[[26 SameMultiMainChatLines]]
	3,      --[[27 SameMultiMainChatAction]] 10,     --[[28 PmMessages]]           10,     --[[29 PmTime]]
	2,      --[[30 PmAction]]                5,      --[[31 SamePmMessages]]       60,     --[[32 SamePmTime]]
	2,      --[[33 SamePmAction]]            2,      --[[34 SameMultiPmMessages]]  2,      --[[35 SameMultiPmLines]]
	3,      --[[36 SameMultiPmAction]]       2,      --[[37 SearchMessages]]       10,     --[[38 SearchTime]]
	1,      --[[39 SearchAction]]            1,      --[[40 SameSearchMessages]]   60,     --[[41 SameSearchTime]]
	1,      --[[42 SameSearchAction]]        6,      --[[43 MyINFOMessages]]       60,     --[[44 MyINFOTime]]
	2,      --[[45 MyINFOAction]]            1,      --[[46 GetNickListMessages]]  120,    --[[47 GetNickListTime]]
	2,      --[[48 GetNickListAction]]       10,     --[[49 NewConnectionsCount]]  60,     --[[50 NewConnectionsTime]]
	6,      --[[51 DefloodWarningCount]]     2,      --[[52 DefloodWarningAction]] 240,    --[[53 DefloodTempBanTime]]
	20,     --[[54 GlobalMainChatMessages]]  10,     --[[55 GlobalMainChatTime]]   10,     --[[56 GlobalMainChatTimeOut]]
	2,      --[[57 GlobalMainChatAction]]    1,      --[[58 MinSearchLen]]         96,     --[[59 MaxSearchLen]]
	2,      --[[60 MinNickLen]]              64,     --[[61 MaxNickLen]]           1,      --[[62 BruteForcePassProtectBanType]]
	24,     --[[63 BruteForcePassProtectTempBanTime]]100,--[[64 MaxPmCountToUser]] 25,     --[[65 MaxSimultaneousLogins]]
	120,    --[[66 MainChatMessages2]]       600,    --[[67 MainChatTime2]]        3,      --[[68 MainChatAction2]]
	60,     --[[69 PmMessages2]]             300,    --[[70 PmTime2]]              3,      --[[71 PmAction2]]
	31,     --[[72 SearchMessages2]]         300,    --[[73 SearchTime2]]          3,      --[[74 SearchAction2]]
	30,     --[[75 MyINFOMessages2]]         900,    --[[76 MyINFOTime2]]          3,      --[[77 MyINFOAction2]]
	256,    --[[78 MaxMyINFOLen]]            1000,   --[[79 CTMMessages]]          60,     --[[80 CTMTime]]
	1,      --[[81 CTMAction]]               1000,   --[[82 CTMMessages2]]         600,    --[[83 CTMTime2]]
	0,      --[[84 CTMAction2]]              500,    --[[85 RCTMMessages]]         60,     --[[86 RCTMTime]]
	1,      --[[87 RCTMAction]]              500,    --[[88 RCTMMessages2]]        600,    --[[89 RCTMTime2]]
	3,      --[[90 RCTMAction2]]             128,    --[[91 MaxCTMLen]]            160,    --[[92 MaxRCTMLen]]
	1000,   --[[93 SRMessages]]              60,     --[[94 SRTime]]               1,      --[[95 SRAction]]
	1000,   --[[96 SRMessages2]]             600,    --[[97 SRTime2]]              0,      --[[98 SRAction2]]
	1024,   --[[99 MaxSRLen]]                4,      --[[100 MaxDownAction]]       128,    --[[101 MaxDownKb]]
	60,     --[[102 MaxDownTime]]            5,      --[[103 MaxDownAction2]]      256,    --[[104 MaxDownKb2]]
	300,    --[[105 MaxDownTime2]]           5,      --[[106 ChatIntervalMessages]]10,     --[[107 ChatIntervalTime]]
	5,      --[[108 PMIntervalMessages]]     10,     --[[109 PMIntervalTime]]      5,      --[[110 SearchIntervalMessages]]
	60,     --[[111 SearchIntervalTime]]     5,      --[[112 MaxConnSameIP]]       10,     --[[113 MinReConnTime]]
	}
	local tDefStringVals = {
	"<Enter hub name here>",        -- 0 HubName
	"Admin",                        -- 1 AdminNick
	"<Enter hub address here>",     -- 2 HubAddress
	"1209;411",                     -- 3 TCPPorts
	"0",                            -- 4 UDPPort
	"<Enter hub description here>", -- 5 HubDescription
	"",                             -- 6 RedirectAddress
	"reg.hublist.org;bwhubreg.no-ip.info;zengeday.sytes.net;serv.hubs-list.com;hublist.cz;hublist.dreamland-net.eu;hublista.myip.hu",
                                    -- 7 RegisterServers
	"Sorry, this hub is only for registered users.",
                                    -- 8 RegOnlyMessage
	"",                             -- 9 RegOnlyRedirAddress
	"",                             -- 10 HubTopic
	"Your share is outside the limits. Min share is %[min], max share is %[max].",
                                    -- 11 ShareLimitMessage
	"",                             -- 12 ShareLimitRedirAddress
	"Your slots count is outside the limits. Min slots limit is %[min], max slots limit is %[max].",
                                    -- 13 SlotsLimitMessage
	"",                             -- 14 SlotsLimitRedirAddress
	"Your hubs/slots ratio outside the limit. Maximum allowed ratio is %[hubs]/%[slots].",
                                    -- 15 HubSlotRatioMessage
	"",                             -- 16 HubSlotRatioRedirAddress
	"Your hubs count is higher than allowed %[hubs] hubs.",
                                    -- 17 MaxHubsLimitMessage
	"",                             -- 18 MaxHubsLimitRedirAddress
	"Your client don't send description tag, or your client is not supported here.",
                                    -- 19 NoTagMessage
	"",                             -- 20 NoTagRedirAddress
	"PtokaX",                       -- 21 BotNick
	"",                             -- 22 BotDescription
	"",                             -- 23 BotEmail
	"OpChat",                       -- 24 OpChatNick
	"",                             -- 25 OpChatDescription
	"",                             -- 26 OpChatEmail
	"",                             -- 27 TempBanRedirAddress
	"",                             -- 28 PermBanRedirAddress
	"!+-/*",                        -- 29 ChatCommandsPrefixes
	"",                             -- 30 HubOwnerEmail
	"Your nick length is outside the limit. Allowed min is %[min] and max %[max].",
                                    -- 31 NickLimitMessage
	"",                             -- 32 NickLimitRedirAddress
	"",                             -- 33 MessageToAddToBanMessage
	"Default English",              -- 34 Language
	}
	return tDefBoolVals,tDefIntVals,tDefStringVals
end

function tFuncs.Lock2Key(self,lock)
	local aKey = {}
	table.insert(aKey,bit.bxor(bit.bxor(bit.bxor(lock:byte(1),lock:byte(-1),lock:byte(-2),5))))
	for i=2,#lock do
		table.insert(aKey,bit.bxor(lock:byte(i),lock:byte(i-1)))
	end
	local t = {["0"]=1,["5"]=1,["36"]=1,["96"]=1,["124"]=1,["126"]=1}
	for i=1,#aKey do
		local b = bit.bor(bit.band(aKey[i]*(2^4),240),bit.band(math.floor(aKey[i]/(2^4)),15))
		aKey[i] = (t[tostring(b)] and string.format("/%%DCN%03d%%/",b) or string.char(b))
	end
	return table.concat(aKey)
end

function tFuncs.SetupEditor(self)
	local m_setup = wx.wxDialog();
	if m_XmlResource:LoadDialog(m_setup,wx.NULL,"ID_DLG_EDITOR_SETUP") then
		for k,v in pairs(tCtrls.tEditorSettings) do
			if type(k) == "string" then
				self:GetCtrl("ID_CHK_"..k,m_setup):SetValue(iff(v,true,false));
			end
		end
		m_setup:Connect(wx.wxEVT_COMMAND_CHECKBOX_CLICKED,function(event)
			local t = {[tCtrls["ID_CHK_CC"]]="CC",[tCtrls["ID_CHK_FM"]]="FM",[tCtrls["ID_CHK_LN"]]="LN",[tCtrls["ID_CHK_TT"]]="TT"}
			tCtrls.tEditorSettings[t[event:GetId()]] = event:IsChecked();
		end)
		local tStyles = {"Default","Selected text","Comment line","Long comment","Number","Lua keywords",
		"String","Literal string","Operator","Variable","Lua functions","Lua calls 1",
		"Px functions","Px tables and values","Px table values","Line number","Brace good","Brace bad","Indent guide",
		"Fold margin","Margin +","Margin Vline","Margin L-corner","Margin Box+","Margin Box-","Margin T-corner"};
		local m_choice = self:GetCtrl("ID_CHOICE",m_setup);
		m_choice:Append(tStyles);
		m_choice:Connect(wx.wxEVT_COMMAND_CHOICE_SELECTED,function(event)
			self:GetCtrl("ID_CLR_BACK",m_setup):SetColour(tCtrls.tEditorSettings[event:GetSelection()+1][1]);
			self:GetCtrl("ID_CLR_FORE",m_setup):SetColour(tCtrls.tEditorSettings[event:GetSelection()+1][2]);
			if event:GetSelection() == 1 or event:GetSelection() > 17 then
				self:GetCtrl("ID_FONTCTRL",m_setup):Enable(false);
			else
				self:GetCtrl("ID_FONTCTRL",m_setup):Enable(true);
				self:GetCtrl("ID_FONTCTRL",m_setup):SetSelectedFont(tCtrls.tEditorSettings[event:GetSelection()+1][3]);
			end
			event:Skip();
		end)
		m_choice:Select(0);
		self:GetCtrl("ID_CLR_BACK",m_setup):SetColour(tCtrls.tEditorSettings[1][1]);
		self:GetCtrl("ID_CLR_BACK",m_setup):Layout();
		self:GetCtrl("ID_CLR_FORE",m_setup):SetColour(tCtrls.tEditorSettings[1][2]);
		self:GetCtrl("ID_CLR_FORE",m_setup):Layout();
		self:GetCtrl("ID_FONTCTRL",m_setup):SetSelectedFont(tCtrls.tEditorSettings[1][3]);
		self:GetCtrl("ID_CLR_BACK",m_setup):Connect(wx.wxEVT_COMMAND_COLOURPICKER_CHANGED,function(event)
			tCtrls.tEditorSettings[m_choice:GetCurrentSelection()+1][1] = event:GetColour();
		end)
		self:GetCtrl("ID_CLR_FORE",m_setup):Connect(wx.wxEVT_COMMAND_COLOURPICKER_CHANGED,function(event)
			tCtrls.tEditorSettings[m_choice:GetCurrentSelection()+1][2] = event:GetColour();
		end)
		self:GetCtrl("ID_FONTCTRL",m_setup):Connect(wx.wxEVT_COMMAND_FONTPICKER_CHANGED,function(event)
			tCtrls.tEditorSettings[m_choice:GetCurrentSelection()+1][3] = event:GetFont();
		end)
		m_setup:Connect(wx.wxID_APPLY,wx.wxEVT_COMMAND_BUTTON_CLICKED,function(event)
			tCtrls.tEditorSettings["sText"] = editor:GetText();
			self:CreateSTCEditor();
			event:Skip();
		end)
		if m_setup:ShowModal() == wx.wxID_OK then
			tCtrls.tEditorSettings["sText"] = editor:GetText();
			self:SaveSettings();
			self:CreateSTCEditor();
		end
	else
		wx.wxMessageBox("Failed to load the settings dialog form from the XML resource. Please re-download the application",_APPNAME,wx.wxICON_EXCLAMATION);
	end
end

function tFuncs.CreateSTCEditor(self)
	local scripteditor = self:GetCtrl("ID_SPLITTERWIN"):GetWindow1()
	editor = wxstc.wxStyledTextCtrl(self:GetCtrl("ID_SPLITTERWIN"),m_XmlResource.GetXRCID("txt_scripteditor"))
	if tCtrls.tEditorSettings["sText"] then
		editor:SetText(tCtrls.tEditorSettings["sText"]);
		tCtrls.tEditorSettings["sText"] = nil
	end
	self:GetCtrl("ID_SPLITTERWIN"):SetSashGravity(1)
	local luakeywords1 = [[coroutine debug io math os package string table string.byte string.char string.dump string.find string.format string.gmatch string.gsub 
string.len string.lower string.match string.rep string.reverse string.sub string.upper byte char dump find 
format gmatch gsub len lower match rep reverse sub upper 
table.concat table.maxn table.sort table.insert table.remove 
math.abs math.acos math.asin math.atan math.atan2 math.ceil math.cos math.cosh math.deg math.exp 
math.floor math.fmod math.frexp math.huge math.ldexp math.log math.log10 math.max math.min math.modf 
math.pi math.pow math.rad math.random math.randomseed math.sin math.sinh math.sqrt math.tan math.tanh 
coroutine.create coroutine.resume coroutine.running coroutine.status coroutine.wrap coroutine.yield 
package.cpath package.loaded package.loadlib package.path package.preload package.seeall 
io.close io.flush io.input io.lines io.open io.output io.popen io.read io.tmpfile io.type io.write 
close flush lines read seek setvbuf write 
os.clock os.date os.difftime os.execute os.exit os.getenv os.remove os.rename 
os.setlocale os.time os.tmpname 
debug.debug debug.getfenv debug.gethook debug.getinfo debug.getlocal 
debug.getmetatable debug.getregistry debug.getupvalue debug.setfenv 
debug.sethook debug.setlocal debug.setmetatable debug.setupvalue debug.traceback ]]
	local pxkeywords1 = [[BanMan Core IP2Country ProfMan RegMan ScriptMan SetMan TmrMan UDPDbg 
BanMan.Save BanMan.GetBans BanMan.GetTempBans BansMan.GetPermBans BanMan.GetBan 
BanMan.GetTempBan BanMan.GetPermBan BanMan.GetRangeBans BanMan.GetTempRangeBans BanMan.GetPermRangeBans 
BanMan.GetRangeBan BanMan.GetRangePermBan BanMan.GetRangeTempBan BanMan.Unban BanMan.UnbanPerm BanMan.UnbanTemp 
BanMan.UnbanAll BanMan.UnbanPermAll BanMan.UnbanTempAll BanMan.RangeUnban BanMan.RangeUnbanPerm BanMan.RangeUnbanTemp 
BanMan.ClearBans BanMan.ClearPermBans BanMan.ClearTempBans BanMan.ClearRangeBans BanMan.ClearRangePermBans 
BanMan.ClearRangeTempBans BanMan.Ban BanMan.BanIP BanMan.BanNick BanMan.TempBan BanMan.TempBanIP BanMan.TempBanNick 
BanMan.RangeBan BanMan.RangeTempBan 
Core.Version Core.Restart Core.SuspendAccepts Core.Shutdown Core.RegBot Core.UnregBot Core.GetBots 
Core.GetActualUsersPeak Core.GetMaxUsersPeak Core.GetCurrentSharedSize Core.GetHubIP Core.GetHubSecAlias 
Core.GetPtokaXPath Core.GetUsersCount Core.GetUpTime Core.GetOnlineNonOps Core.GetOnlineOps Core.GetOnlineRegs 
Core.GetOnlineUsers Core.GetUser Core.GetUserAllData Core.GetUserData Core.GetUserValue Core.Disconnect Core.Kick 
Core.Redirect Core.DefloodWarn Core.SendToAll Core.SendToNick Core.SendToOpChat Core.SendToOps Core.SendToProfile 
Core.SendToUser Core.SendPmToAll Core.SendPmToNick Core.SendPmToOps Core.SendPmToProfile Core.SendPmToUser 
IP2County.GetCountryCode IP2Country.GetCountryName 
ProfMan.AddProfile ProfMan.RemoveProfile ProfMan.MoveDown ProfMan.MoveUp ProfMan.GetProfile ProfMan.GetProfiles 
ProfMan.GetProfilePermission ProfMan.GetProfilePermissions ProfMan.SetProfileName ProfMan.SetProfilePermission 
RegMan.Save RegMan.GetRegsByProfile RegMan.GetNonOps RegMan.GetOps RegMan.GetReg RegMan.GetRegs RegMan.AddReg 
RegMan.DelReg RegMan.ChangeReg RegMan.ClrRegBadPass 
ScriptMan.GetScripts ScriptMan.MoveUp ScriptMan.MoveDown ScriptMan.StartScript ScriptMan.RestartScript 
ScriptMan.StopScript ScriptMan.Restart 
SetMan.Save SetMan.GetMOTD SetMan.SetMOTD SetMan.GetBool SetMan.SetBool SetMan.GetNumber SetMan.SetNumber 
SetMan.GetString SetMan.SetString SetMan.GetMinShare SetMan.SetMinShare SetMan.GetMaxShare SetMan.SetMaxShare 
SetMan.SetHubSlotRatio SetMan.GetOpChat SetMan.SetOpChat SetMan.GetHubBot SetMan.SetHubBot 
TmrMan.AddTimer TmrMan.RemoveTimer
UDPDbg.Reg UDPDbg.Unreg UDPDbg.Send ]]
	local pxkeywords2 = [[sNick sIP uptr iProfile sMode sMyInfoString sDescription sTag sConnection sEmail sClient 
sClientVersion sVersion bConnected bActive bOperator bUserCommand bQuickList bSuspiciousTag iShareSize iHubs 
iNormalHubs iRegHubs iOpHubs iSlots iLlimit iDefloodWarns iMagicByte iLoginTime sPassword sReason sBy 
iExpireTime bIpBan bNickBan bFullIpBan sIPFrom sIPTo sProfileName iProfileNumber tProfilePermissions bIsOP 
bNoDefloodGetNickList bNoDefloodNMyINFO bNoDefloodSearch bNoDefloodPM bNoDefloodMainChat bMassMsg bTopic 
bTempBan bTempUnban bRefreshTxt bNoTagCheck bDelRegUser bAddRegUser bNoChatLimits bNoMaxHubCheck bNoSlotHubRatio 
bNoSlotCheck bNoShareLimit bClrPermBan bClrTempBan bGetInfo bGetBans bRestartScripts bRestartHub bTempOP bGag 
bRedirect bBan bUnban bKick bDrop bEnterFullHub bEnterIfIPBan bAllowedOPChat bSendFullMyinfos bSendAllUserIP
bRangeBan bRangeUnban bRangeTempBan bRangeTempUnban bGetRangeBans bClearRangePermBans bClearRangeTempBans 
bNoIpCheck bClose bNoSearchLimits]]
	local HasBit = function(value, num)
		for n = 32, 0, -1 do
			local b = 2^n;local num_b,value_b = num-b,value-b
			if num_b >= 0 then num = num_b else return true end
			if value_b >= 0 then value = value_b end
			if (num_b >= 0) and (value_b < 0) then return false end
		end
		return true
	end
	local FoldSome = function()
		editor:Colourise(0,-1)
		local visible, baseFound, expanded, folded
		for ln = 2, editor.LineCount-1 do
			local foldRaw = editor:GetFoldLevel(ln)
			local foldLvl = math.fmod(foldRaw,4096)
			local foldHdr = math.fmod(math.floor(foldRaw/8192),2) == 1
			if not baseFound and (foldLvl ==  wxstc.wxSTC_FOLDLEVELBASE) then
				baseFound = true;visible = editor:GetLineVisible(ln)
			end
			if foldHdr then
				if editor:GetFoldExpanded(ln) then expanded = true else folded = true end
			end
			if expanded and folded and baseFound then break end
		end
		local show = not visible or (not baseFound and expanded) or (expanded and folded)
		local hide = visible and folded
		if show then editor:ShowLines(1, editor.LineCount-1) end
		for ln = 1, editor.LineCount - 1 do
			local foldRaw = editor:GetFoldLevel(ln)
			local foldLvl = math.fmod(foldRaw,4096)
			local foldHdr = math.fmod(math.floor(foldRaw/8192),2) == 1
			if show then
				if foldHdr then
					if not editor:GetFoldExpanded(ln) then editor:ToggleFold(ln) end
				end
			elseif hide and (foldLvl == wxstc.wxSTC_FOLDLEVELBASE) then
				if not foldHdr then editor:HideLines(ln, ln) end
			elseif foldHdr then
				if editor:GetFoldExpanded(ln) then editor:ToggleFold(ln) end
			end
		end
		editor:EnsureCaretVisible()
	end
	local CreateAutoCompList = function(keyword,j)
		local keywords = luakeywords1.." "..pxkeywords1
		local a,b = keywords:find(keyword,1,1)
		local key_list = ""
		while a do
			local c,d = keywords:find(" ",b,1)
			key_list = key_list..keywords:sub(a+j,c or -1)
			a,b = keywords:find(keyword,d,1)
		end
		return key_list
	end
	-- by Duncan Cross
	local MatchBrackets = function()
		local length = editor.Length
		if length == 0 then return -1,-1 end
		local pos = editor.CurrentPos
		if pos > 0 and editor:PositionBefore(pos) == pos-1 then
			local prevc = editor:GetCharAt(pos-1)
			if prevc == 91 or prevc == 93 or prevc == 123 or prevc == 125 or prevc == 40 or prevc == 41 then
				return pos-1,editor:BraceMatch(pos-1)
			end
		end
		return -1,-1
	end
	local ShowToolTip = function()
		if not tCtrls.tEditorSettings["TT"] then return end
		local pos,length,iOpeningBracket,sHelp = editor.CurrentPos,editor.Length,0,""
		FindLastOpeningBracket = function(pos1,pos2)
			iOpeningBracket = editor:FindText(pos1,pos2,"(")
			if editor:FindText(iOpeningBracket+1,pos2,"(") == -1 then
				local iClosingBracket = editor:BraceMatch(iOpeningBracket)
				if iClosingBracket == -1 then return end
				if editor.CurrentPos > iClosingBracket then iOpeningBracket = -1 return end
			else
				FindLastOpeningBracket(iOpeningBracket+1,pos2)
			end
		end
		FindLastOpeningBracket(0,pos)
		if iOpeningBracket > -1 then
			local tHelp = {
			--[[ Lua calls ]]--
			-- Basic functions
			["assert"]                       = "assert(bool condition [, string message])",
			["collectgarbage"]               = "collectgarage(string option [, int value])",
			["dofile"]                       = "dofile([string filename])",
			["error"]                        = "error(string message [, int level])",
			["getfenv"]                      = "getfenv(function f)",
			["getmetatable"]                 = "getmetatable(object o)",
			["ipairs"]                       = "ipairs(table t)",
			["load"]                         = "load(function f [, chunk])",
			["loadfile"]                     = "loadfile([string filename])",
			["loadstring"]                   = "loadstring(string string [, chunkname])",
			["module"]                       = "module(string name [, args])",
			["next"]                         = "next(table t [, int index])",
			["pairs"]                        = "pairs(table t)",
			["pcall"]                        = "pcall(function f [, arguments])",
			["print"]                        = "print(string message)",
			["rawequal"]                     = "rawequal(object value1 , object value2)",
			["rawget"]                       = "rawget(table t , object value)",
			["rawset"]                       = "rawset(table t , object index, object value)",
			["select"]                       = "select(int index || \"#\")",
			["setmetatable"]                 = "setmetatable(object o , table t)",
			["require"]                      = "require(string module)",
			["tonumber"]                     = "tonumber(object o [, int base])",
			["tostring"]                     = "tostring(object o)",
			["type"]                         = "type(object o)",
			["unpack"]                       = "unpack(table t [, int i [, int j]])",
			["xpcall"]                       = "xpcall(function f, string err)",
			-- coroutine library
			["coroutine.create"]             = "coroutine.create(function f)",
			["coroutine.resume"]             = "coroutine.resume(coroutine co, args)",
			["coroutine.running"]            = "coroutine.running()",
			["coroutine.status"]             = "coroutine.status(coroutine co)",
			["coroutine.wrap"]               = "coroutine.wrap(function f)",
			["coroutine.yield"]              = "coroutine.yield([args])",
			-- package library
			["package.loadlib"]              = "package.loadlib(string libname, string funcname)",
			["package.seeall"]               = "package.seeall(string module)",
			-- io library
			["io.close"]                     = "io.close([file file])",
			["io.flush"]                     = "io.flush()",
			["io.input"]                     = "io.input([file file])",
			["io.lines"]                     = "io.lines(string filename) || file file)",
			["io.open"]                      = "io.open(string filename [, string mode])",
			["io.output"]                    = "io.output([file file])",
			["io.popen"]                     = "io.popen([string appname [, string mode]])",
			["io.read"]                      = "io.read(file file)",
			["io.tmpfile"]                   = "io.tmpfile()",
			["io.type"]                      = "io.type(file file)",
			["io.write"]                     = "io.write(file file , string text)",
			[":close"]                       = "file:close()",
			[":flush"]                       = "file:flush()",
			[":lines"]                       = "file:lines()",
			[":read"]                        = "file:read()",
			[":write"]                       = "file:write(string text)",
			-- os library
			["os.clock"]                     = "os.clock()",
			["os.date"]                      = "os.date(string format [,int time])",
			["os.difftime"]                  = "os.difftime(int time1 , int time2)",
			["os.execute"]                   = "os.execute([string command])",
			["os.exit"]                      = "os.exit(int code)",
			["os.getenv"]                    = "os.getenv(string varname)",
			["os.remove"]                    = "os.remove(string filename)",
			["os.rename"]                    = "os.rename(string oldname , string newname)",
			["os.setlocale"]                 = "os.setlocale(string locale , string category)",
			["os.time"]                      = "os.time([table time])",
			["os.tmpname"]                   = "os.tmpname()",
			-- debug library
			["debug.debug"]                  = "debug.debug()",
			["debug.getfenv"]                = "debug.getfenv(object o)",
			["debug.gethook"]                = "debug.gethook([thread t])",
			["debug.getinfo"]                = "debug.getinfo([thread t,] function f [, string what])",
			["debug.getlocal"]               = "debug.getlocal([thread t,] int level , int local)",
			["debug.getmetatable"]           = "debug.getmetatable(object o)",
			["debug.getregistry"]            = "debug.getregistry()",
			["debug.getupvalue"]             = "debug.getupvalue(function f , int up)",
			["debug.setfenv"]                = "debug.setfenv(object o , table t)",
			["debug.sethook"]                = "debug.sethook([thread t,] function hook, string mask [, int count])",
			["debug.setlocal"]               = "debug.setlocal(([thread t,] int level, int local, object value)",
			["debug.setmetatable"]           = "debug.setmetatable(object o , table t)",
			["debug.setupvalue"]             = "debug.setupvalue(function f , int up , object value)",
			["debug.traceback"]              = "debug.traceback([thread t,] [string message])",
			-- string library
			["string.byte"]                  = "string.byte(string char [, int i [, int j]])",
			["string.char"]                  = "string.char(int chars)",
			["string.dump"]                  = "string.dump(function f)",
			["string.find"]                  = "string.find(string text , string pattern [, int init [, bool plain]])",
			["string.format"]                = "string.format(string formatstring , string text)",
			["string.gmatch"]                = "string.gmatch(string text , string pattern)",
			["string.gsub"]                  = "string.gsub(string text , string pattern , string repl [, int n])",
			["string.len"]                   = "string.len(string text)",
			["string.lower"]                 = "string.lower(string text)",
			["string.match"]                 = "string.match(string text , string pattern [, int init])",
			["string.rep"]                   = "string.rep(string text , int n)",
			["string.reverse"]               = "string.reverse(string text)",
			["string.sub"]                   = "string.sub(string text , int i [, int j])",
			["string.upper"]                 = "string.upper(string text)",
			[":byte"]                        = "text:byte(int i [, int j])",
			[":find"]                        = "text:find(string pattern [, int init [, bool plain]])",
			[":format"]                      = "text:format(string text)",
			[":gmatch"]                      = "text:gmatch(string pattern)",
			[":gsub"]                        = "text:gsub(string pattern , string repl [, int n])",
			[":len"]                         = "text:len()",
			[":lower"]                       = "text:lower()",
			[":match"]                       = "text:match(string pattern [, int init])",
			[":rep"]                         = "text:rep(int n)",
			[":reverse"]                     = "text:reverse()",
			[":sub"]                         = "text:sub(int i [, int j])",
			[":upper"]                       = "text:upper()",
			-- table library
			["table.concat"]                 = "table.concat(table t [, string sep [, int i [, int j]]])",
			["table.insert"]                 = "table.insert(table t [, int pos] , object value)",
			["table.maxn"]                   = "table.maxn(table t)",
			["table.remove"]                 = "table.remove(table t [, int pos])",
			["table.sort"]                   = "table.sort(table t [, function comp])",
			-- math library
			["math.abs"]                     = "math.abs(int x)",
			["math.acos"]                    = "math.acos(int x)",
			["math.asin"]                    = "math.asin(int x)",
			["math.atan"]                    = "math.atan(int x)",
			["math.atan2"]                   = "math.atan2(int x , int y)",
			["math.ceil"]                    = "math.ceil(int x)",
			["math.cos"]                     = "math.cos(int x)",
			["math.cosh"]                    = "math.cosh(int x)",
			["math.deg"]                     = "math.deg(int x)",
			["math.exp"]                     = "math.exp(int x)",
			["math.floor"]                   = "math.floor(int x)",
			["math.fmod"]                    = "math.fmod(int x , int y)",
			["math.frexp"]                   = "math.frexp(int x)",
			["math.ldexp"]                   = "math.ldexp(int m , int e)",
			["math.log"]                     = "math.log(int x)",
			["math.log10"]                   = "math.log10(int x)",
			["math.max"]                     = "math.max(int x , args)",
			["math.min"]                     = "math.min(int x , args)",
			["math.modf"]                    = "math.modf(int x)",
			["math.pow"]                     = "math.pow(int x , int y)",
			["math.rad"]                     = "math.rad(int x)",
			["math.random"]                  = "math.random([int m [, int n]])",
			["math.randomseed"]              = "math.randomseed(int x)",
			["math.sin"]                     = "math.sin(int x)",
			["math.sinh"]                    = "math.sinh(int x)",
			["math.sqrt"]                    = "math.sqrt(int x)",
			["math.tan"]                     = "math.tan(int x)",
			["math.tanh"]                    = "math.tanh(int x)",
			--[[ PtokaX calls ]]--
			-- BanMan metatable
			["BanMan.Save"]                  = "BanMan.Save()",
			["BanMan.GetBans"]               = "BanMan.GetBans()",
			["BanMan.GetTempBans"]           = "BanMan.GetTempBans()",
			["BanMan.GetPermBans"]           = "BanMan.GetPermBans()",
			["BanMan.GetBan"]                = "BanMan.GetBan(string IP || string nick)",
			["BanMan.GetPermBan"]            = "BanMan.GetPermBan(string IP || string nick)",
			["BanMan.GetTempBan"]            = "BanMan.GetTempBan(string IP || string nick)",
			["BanMan.GetRangeBans"]          = "BanMan.GetRangeBans()",
			["BanMan.GetTempRangeBans"]      = "BanMan.GetTempRangeBans()",
			["BanMan.GetPermRangeBans"]      = "BanMan.GetPermRangeBans()",
			["BanMan.GetRangeBan"]           = "BanMan.GetRangeBan(string IPFrom , string IPTo)",
			["BanMan.GetRangePermBan"]       = "BanMan.GetRangePermBan(string IPFrom , string IPTo)",
			["BanMan.GetRangeTempBan"]       = "BanMan.GetRangeTempBan(string IPFrom , string IPTo)",
			["BanMan.Unban"]                 = "BanMan.Unban(string IP || string nick)",
			["BanMan.UnbanPerm"]             = "BanMan.UnbanPerm(string IP || string nick)",
			["BanMan.UnbanTemp"]             = "BanMan.UnbanTemp(string IP || string nick)",
			["BanMan.UnbanAll"]              = "BanMan.UnbanAll(string IP)",
			["BanMan.UnbanPermAll"]          = "BanMan.UnbanPermAll(string IP)",
			["BanMan.UnbanTempAll"]          = "BanMan.UnbanTempAll(string IP)",
			["BanMan.RangeUnban"]            = "BanMan.RangeUnban(string IPFrom , string IPTo)",
			["BanMan.RangeUnbanPerm"]        = "BanMan.RangeUnbanPerm(string IPFrom , string IPTo)",
			["BanMan.RangeUnbanTemp"]        = "BanMan.RangeUnbanTemp(string IPFrom , string IPTo)",
			["BanMan.ClearBans"]             = "BanMan.ClearBans()",
			["BanMan.ClearPermBans"]         = "BanMan.ClearPermBans()",
			["BanMan.ClearTempBans"]         = "BanMan.ClearTempBans()",
			["BanMan.ClearRangeBans"]        = "BanMan.ClearRangeBans()",
			["BanMan.ClearRangePermBans"]    = "BanMan.ClearRangePermBans()",
			["BanMan.ClearRangeTempBans"]    = "BanMan.ClearRangeTempBans()",
			["BanMan.Ban"]                   = "BanMan.Ban(table user , string reason , string by , bool full)",
			["BanMan.BanIP"]                 = "BanMan.BanIP(string IP , string reason , string by , bool full)",
			["BanMan.BanNick"]               = "BanMan.BanNick(string nick , string reason , string by)",
			["BanMan.TempBan"]               = "BanMan.TempBan(table user , int time , string reason , string by , bool full)",
			["BanMan.TempBanIP"]             = "BanMan.TempBanIP(string IP , int time , string reason , string by , bool full)",
			["BanMan.TempBanNick"]           = "BanMan.TempBanNick(string nick , int time, string reason , string by)",
			["BanMan.RangeBan"]              = "BanMan.RangeBan(string IPFrom , string IPTo , string reason , string by , bool full)",
			["BanMan.RangeTempBan"]          = "BanMan.RangeTempBan(string IPFrom , string IPTo , int time , string reason , string by , bool full)",
			-- Core metatable
			["Core.Restart"]                 = "Core.Restart()",
			["Core.Shutdown"]                = "Core.Shutdown()",
			["Core.ResumeAccepts"]           = "Core.ResumeAccepts()",
			["Core.SuspendAccepts"]          = "Core.SuspendAccepts([int time])",
			["Core.RegBot"]                  = "Core.RegBot(string nick , string decription , string email , bool IsOP)",
			["Core.UnregBot"]                = "Core.UnregBot(string nick)",
			["Core.GetBots"]                 = "Core.GetBots()",
			["Core.GetActualUsersPeak"]      = "Core.GetActualUsersPeak()",
			["Core.GetMaxUsersPeak"]         = "Core.GetMaxUsersPak()",
			["Core.GetCurrentSharedSize"]    = "Core.GetCurrentSharedSize()",
			["Core.GetHubIP"]                = "Core.GetHubIP()",
			["Core.GetHubSecAlias"]          = "Core.GetHubSecAlias()",
			["Core.GetPtokaXPath"]           = "Core.GetPtokaXPath()",
			["Core.GetUsersCount"]           = "Core.GetUsersCount()",
			["Core.GetUpTime"]               = "Core.GetUpTime()",
			["Core.GetOnlineNonOps"]         = "Core.GetOnlineNonOps([bool alldata])",
			["Core.GetOnlineOps"]            = "Core.GetOnlineOps([bool alldata])",
			["Core.GetOnlineRegs"]           = "Core.GetOnlineRegs([bool alldata])",
			["Core.GetOnlineUsers"]          = "Core.GetOnlineUsers([bool alldata] || int profilenumber [, bool alldata])",
			["Core.GetUser"]                 = "Core.GetUser(string nick [, bool alldata])",
			["Core.GetUserAllData"]          = "Core.GetUserAllData(table user)",
			["Core.GetUserData"]             = "Core.GetUserData(table user , int valueid)",
			["Core.GetUserValue"]            = "Core.GetUserValue(table user , int valueid)",
			["Core.GetUsers"]                = "Core.GetUsers(string IP [, bool alldata])",
			["Core.Disconnect"]              = "Core.Disconnect(table user)\nCore.Disconnect(string nick)",
			["Core.Kick"]                    = "Core.Kick(table user , string by , string reason)",
			["Core.Redirect"]                = "Core.Redirect(table user , string address , string reason)",
			["Core.DefloodWarn"]             = "Core.DefloodWarn(table user)",
			["Core.SendToAll"]               = "Core.SendToAll(string message)",
			["Core.SendToNick"]              = "Core.SendToNick(string nick , string message)",
			["Core.SendToOpChat"]            = "Core.SendToOpChat(string message)",
			["Core.SendToOps"]               = "Core.SendToOps(string message)",
			["Core.SendToProfile"]           = "Core.SendToProfile(int profile , string message)",
			["Core.SendToUser"]              = "Core.SendToUser(table user , string message)",
			["Core.SendPmToAll"]             = "Core.SendPmToAll(string fromnick , string message)",
			["Core.SendPmToNick"]            = "Core.SendPmToNick(string tonick , string fromnick , string message)",
			["Core.SendPmToOps"]             = "Core.SendPmToOps(string fromnick , string message)",
			["Core.SendPmToProfile"]         = "Core.SendPmToProfile(int profile , string fromnick , string message)",
			["Core.SendPmToUser"]            = "Core.SendPmToUser(table user , string fromnick , string message)",
			-- IP2Country metatable
			["IP2Country.GetCountryCode"]    = "IP2Country.GetCountryCode(string IP)",
			["IP2Country.GetCountryName"]    = "IP2Country.GetCountryName(string IP || table user)",
			-- ProfMan metatable
			["ProfMan.AddProfile"]           = "ProfMan.AddProfile(string profilename)",
			["ProfMan.RemoveProfile"]        = "ProfMan.RemoveProfile(string profilename)",
			["ProfMan.MoveDown"]             = "ProfMan.MoveDown(int profile)",
			["ProfMan.MoveUp"]               = "ProfMan.MoveUp(int profile)",
			["ProfMan.GetProfile"]           = "ProfMan.GetProfile(string profilename || int profile)",
			["ProfMan.GetProfiles"]          = "ProfMan.GetProfiles()",
			["ProfMan.GetProfilePermission"] = "ProfMan.GetProfilePermission(int profile , int permissionid)",
			["ProfMan.GetProfilePermissions"]= "ProfMan.GetProfilePermissions(int profile)",
			["ProfMan.SetProfileName"]       = "ProfMan.SetProfileName(int profile , string profilename)",
			["ProfMan.SetProfilePermission"] = "Profman.SetProfilePermission(int profile , int permissionid , bool value)",
			-- RegMan metatable
			["RegMan.Save"]                  = "RegMan.Save()",
			["RegMan.GetRegsByProfile"]      = "RegMan.GetRegsByProfile(int profile)",
			["RegMan.GetNonOps"]             = "RegMan.GetNonOps()",
			["RegMan.GetOps"]                = "RegMan.GetOps()",
			["RegMan.GetReg"]                = "RegMan.GetReg(string nick)",
			["RegMan.GetRegs"]               = "RegMan.GetRegs()",
			["RegMan.AddReg"]                = "RegMan.AddReg(string nick , string password , int profile)",
			["RegMan.DelReg"]                = "RegMan.DelReg(string nick)",
			["RegMan.ChangeReg"]             = "RegMan.ChangeReg(string nick , string password , int profile)",
			["Regman.ClrRegBadPass"]         = "RegMan.ClrRegBadPass(string nick)",
			-- ScriptMan metatable
			["ScriptMan.GetScript"]          = "ScriptMan.GetScript()",
			["ScriptMan.GetScripts"]         = "ScriptMan.GetScripts()",
			["ScriptMan.MoveUp"]             = "ScriptMan.MoveUp(string script)",
			["ScriptMan.MoveDown"]           = "ScriptMan.MoveDown(string script)",
			["ScriptMan.StartScript"]        = "ScriptMan.StartScript(string script)",
			["ScriptMan.RestartScript"]      = "ScriptMan.RestartScript(string script)",
			["ScriptMan.StopScript"]         = "ScriptMan.StopScript(string script)",
			["ScriptMan.Restart"]            = "ScriptMan.Restart()",
			["ScriptMan.Refresh"]            = "ScriptMan.Refresh()",
			-- SetMan metatable
			["SetMan.Save"]                  = "SetMan.Save()",
			["SetMan.GetMOTD"]               = "SetMan.GetMOTD()",
			["SetMan.SetMOTD"]               = "SetMan.SetMOTD(string motd)",
			["SetMan.GetBool"]               = "SetMan.GetBool(int boolid)",
			["SetMan.SetBool"]               = "SetMan.SetBool(int boolid , bool value)",
			["SetMan.GetNumber"]             = "SetMan.GetNumber(int numberid)",
			["SetMan.SetNumber"]             = "SetMan.SetNumber(int numberid , int value)",
			["SetMan.GetString"]             = "SetMan.GetString(int stringid)",
			["SetMan.SetString"]             = "SetMan.SetString(int stringid , string value)",
			["SetMan.GetMinShare"]           = "SetMan.GetMinShare()",
			["SetMan.SetMinShare"]           = "SetMan.SetMinShare(int bytes)\nSetMan.SetMinShare(int minshare , int units)",
			["SetMan.GetMaxShare"]           = "SetMan.GetMaxShare()",
			["SetMan.SetMaxShare"]           = "SetMax.SetMaxShare(int bytes)\nSetMan.SetMaxShare(int maxshare , int units)",
			["SetMan.SetHubSlotRatio"]       = "SetMan.SetHubSlotRatio(int hubs , int slots)",
			["SetMan.GetOpChat"]             = "SetMan.GetOpChat()",
			["SetMan.SetOpChat"]             = "SetMan.SetOpChat(bool enabled , string name , string description , string email)",
			["SetMan.GetHubBot"]             = "SetMan.GetHubBot()",
			["SetMan.SetHubBot"]             = "SetMan.SetHubBot(bool enabled , string name , string description , string email , bool isalias)",
			-- TmrMan metatable
			["TmrMan.AddTimer"]              = "TmrMan.AddTimer(int intreval [, function f])",
			["TmrMan.RemoveTimer"]           = "TmrMan.RemoveTimer(int timerid)",
			-- UDPDbg metatable
			["UDPDbg.Reg"]                   = "UDPDbg.Reg(string IP , int port , bool alldata)",
			["UDPDbg.Unreg"]                 = "UDPDbg.Unreg()",
			["UDPDbg.Send"]                  = "UDPDbg.Send(string message)",
			}
			for kw,help in pairs(tHelp) do
				local sBefore = editor:GetTextRange(iOpeningBracket - #kw,iOpeningBracket)
				if kw == sBefore then
					sHelp = help
					break
				end
			end
		end
		if sHelp ~= "" then
			self:SetStatusText("Usage: "..sHelp,1)
		else
			self:SetStatusText("",1)
		end
	end
	editor:SetBufferedDraw(true)
	editor:StyleClearAll()
	local font = wx.wxFont(10,wx.wxFONTFAMILY_MODERN,wx.wxFONTSTYLE_NORMAL,wx.wxFONTWEIGHT_NORMAL,false,"")
    editor:SetFont(font)
    editor:StyleSetFont(wxstc.wxSTC_STYLE_DEFAULT, font)
    for i=0,32 do editor:StyleSetFont(i, font) end
	font:delete()
	editor:SetLexer(wxstc.wxSTC_LEX_LUA)
	editor:SetKeyWords(0,
	"and break do else elseif end false for function if in local nil not or repeat return then true until while")
	editor:SetKeyWords(1,
	"_G _VERSION assert collectgarbage dofile error getfenv getmetatable ipairs load loadfile loadstring next "..
	"pairs pcall print rawequal rawget rawset select setmetatable require tonumber tostring type unpack xpcall")
	editor:SetKeyWords(2,luakeywords1)
	editor:SetKeyWords(3,"OnStartup OnExit OnTimer UserConnected UserDisconnected RegConnected RegDisconnected "..
	"OpConnected OpDisconnected OnError SupportsArrival ChatArrival KeyArrival ValidateNickArrival PasswordArrival "..
	"VersionArrival GetNickListArrival MyINFOArrival GetINFOArrival SearchArrival ToArrival ConnectToMeArrival "..
	"MultiConnectToMeArrival RevConnectToMeArrival SRArrival UDPSRArrival KickArrival OpForceMoveArrival "..
	"UnknownArrival BotINFOArrival CloseArrival")
	editor:SetKeyWords(4,pxkeywords1)
	editor:SetKeyWords(5,pxkeywords2)
	if tCtrls.tEditorSettings["LN"] then
		editor:SetMarginWidth(0, editor:TextWidth(32, "99999"))
	end
	if tCtrls.tEditorSettings["FM"] then
		editor:SetMarginWidth(1, 14)
	    editor:SetMarginType(1, wxstc.wxSTC_MARGIN_SYMBOL)
	    editor:SetMarginMask(1, wxstc.wxSTC_MASK_FOLDERS)
	    editor:SetMarginSensitive(1, true)
	    editor:SetFoldFlags(wxstc.wxSTC_FOLDFLAG_LINEAFTER_CONTRACTED)
	    editor:SetProperty("fold","1")
	    editor:SetProperty("fold.compact","1")
	    editor:SetProperty("fold.comment","1")
	    editor:Connect(wxstc.wxEVT_STC_MARGINCLICK,function (event)
			local line = editor:LineFromPosition(event:GetPosition())
			if event:GetMargin() == 1 then
				if wx.wxGetKeyState(wx.WXK_SHIFT) and wx.wxGetKeyState(wx.WXK_CONTROL) then
					FoldSome()
				else
					if HasBit(editor:GetFoldLevel(line),wxstc.wxSTC_FOLDLEVELHEADERFLAG) then
						editor:ToggleFold(line)
					end
				end
			end
		end)
	end
    editor:Connect(wxstc.wxEVT_STC_CHARADDED,function(event)
		if editor:GetTextRange(editor.CurrentPos-15,editor.CurrentPos) == "SetMan.GetBool(" or 
			editor:GetTextRange(editor.CurrentPos-15,editor.CurrentPos) == "SetMan.SetBool(" then
			local tBools = {
			"Anti�MoGlo�description","Hub�autostart","Redirect�all�connecting�users","Redirect�users�when�hub�is�full",
			"Automatically�register�to�hublist","Hub�for�registered�users�only","Redirect�unregs�when�hub�is�reg-only",
			"Redirect�user�on share�limit","Redirect�user�on�slot�limit","Redirect�user�on�ratio�limit",
			"Redirect�user�on�max�hubs�limit","Add�user�mode�to�MyINFO�command","Add�user�mode�to�description",
			"Strip�user�description","Strip�user�description�tag","Strip�user�connection","Strip�user�email",
			"Register�hub�bot�on�hub","Use�hub�bot�nick�instead�of�Hub-Security","Register�Opchat�bot�on�hub",
			"Redirect�user�when�is�temp�banned","Redirect�user�when�is�perm�banned","Enable�scripting�interface",
			"Keep�slow�clients","Check�for�new�releases�on�startup","Enable�tray�icon",
			"Start�minimized","Filter�kick�messages","Send�kick�messages�to�OPs","Send�status�messages�to�OPs",
			"Send�status�messages�as�PM's","Enable�text�files","Send�text�files�as�private�messages",
			"Stop�script�on�error","Send�MOTD�as�private�message","Report�deflood�actions","Reply�to�hub�commands�with�PM's",
			"Disable�MOTD","Don't�allow�hublist�pingers","Report�hublist�pingers","Report�3x�bad�password",
			"Advanced�password�protection","Listen�only�on�single�IP","Resolve�hostname�to�IP",
			"Redirect�user�on nicklength�limits","Send�UserIP�to�user�on�login","Send�ip�in�ban�message",
			"Send�range�in�ban�message","Send�nick�in�ban�message","Send�reason�in�ban�message","Send�who�create�ban�in�ban�message",
			"Report�suspicious�tag�to�OPs","Accept�tag�from�unknown�clients","Check�IP�in�commands",
			"Popup�scripts�window�on�script�error","Save�script�errors�to�log"}
			if tCtrls.tEditorSettings["CC"] then
				editor:UserListShow(2,table.concat(tBools," "))
			end
			editor:Connect(wxstc.wxEVT_STC_USERLISTSELECTION,function(event)
				local pos = editor:GetCurrentPos()
				local start_pos,sel = editor:WordStartPosition(pos, true),-1
				editor:SetSelection(start_pos,pos)
				for i = 1,#tBools do
					if tBools[i] == event:GetText() then sel = i-1 break end
				end
				if editor:GetTextRange(editor.CurrentPos-15,editor.CurrentPos) == "SetMan.SetBool(" then
					editor:ReplaceSelection(tostring(sel)..",")
				else
					editor:ReplaceSelection(tostring(sel)..")")
				end
				editor:SetCurrentPos(editor:GetCurrentPos()+1)
				editor:Disconnect(wxstc.wxEVT_STC_USERLISTSELECTION)
			end)
		elseif editor:GetTextRange(editor.CurrentPos-17,editor.CurrentPos) == "SetMan.GetNumber(" or 
			editor:GetTextRange(editor.CurrentPos-17,editor.CurrentPos) == "SetMan.SetNumber(" then
			local tNums = {
			"Max�users�limit","Min�share�limit.�Max�9999","Min�share�units.�0=B,1=kB,2=MB,3=GB,4=TB","Max�share�limit.�Max�9999",
			"Max�share�units.�0=B,1=kB,2=MB,3=GB,4=TB","Min�slots�limit","Max�slots�limit.","Hubs�for�hub/slot�ratio",
			"Slots�for�hub/slot�ratio","Max�hubs�limit","No�tag�option.�0=acc.,1=rej.,2=redir.","Send�full�MyINFO�0=all,1=prof,2=none",
			"Max�chat�length�limit","Max�chat�lines�limit","Max�private�message�length�limit","Max�private�message�lines�limit",
			"Default�tempban�time.�>0","Max�passive�search�replys�limit","Time�before�new�user�MyINFO�is�accepted",
			"Main�chat�defl�messages�count.�1-29999","Main�chat�defl�time.�1-29999","Main�chat�defl�action.�0-6",
			"Same�main�chat�defl�msg�count.�1-29999","Same�main�chat�deflood�time.�1-29999","Same�main�chat�defl�action.�0-6",
			"Same�ml�main�chat�defl�msg�count.�2-999","Same�ml�main�chat�defl�lines.�2-999","Same�ml�main�chat�defl�action.�0-6",
			"Priv�msg�defl�msg�count.�1-29999","Priv�msg�defl�time.�1-29999","Priv�msg�defl�action.�0-6",
			"Same�priv�msg�defl�msg�count.�1-29999","Same�priv�msg�defl�time.�1-29999","Same�priv�msg�defl�action.�0-6",
			"Same�ml�priv�msg�defl�msg�count.�2-999","Same�ml�private�msg�defl�lines.�2-999","Same�ml�priv�msg�action.�0-6",
			"Search�defl�msg�count.�1-29999","Search�defl�time.�1-29999","Search�defl�action.�0-6",
			"Same�search�defl�msg�count.�0-29999","Same�search�defl�time.�1-29999","Same�search�defl�action.�0-6",
			"MyINFO�defl�msg�count.�1-29999","MyINFO�defl�time.�1-29999","MyINFO�defl�action.�0-6",
			"GetNickList�defl�msg�count.�0-29999","GetNickList�defl�time.�1-29999","GetNickList�defl�action.�0-6",
			"Connection�defl�conn�count.�0-999","Connection�defl�time.�1-999","Deflood�warnings�count.�1-29999",
			"Deflood�warnings�action�0-3","Deflood�tempban�time.�>0","Global�main�chat�msg�count.�1-29999",
			"Global�main�chat�time.�1-29999","Global�main�chat�timeout.�1-29999","Global�main�chat�action.�0-2",
			"Min�search�length","Max�search�length","Min�nick�length.�<64","Max�nick�length.�<64",
			"BF�pwd�protection�ban�type.�0-2","BF�pwd�protection�tempban�time.�>0","Max�pm�count�to�same�user�per�minute",
			"Max�simultaneous�logins.�1-500","2.�main�chat�defl�msg�count.�1-29999","2.�main�chat�defl�time.�0-29999",
			"2.�main�chat�defl�action.�0-6","2.�priv�msg�defl�msg�count.�1-29999","2.�priv�msg�defl�time.�1-29999",
			"2.�priv�msg�defl�action.�0-6","2.�search�defl�msg�count.�1-29999","2.�search�defl�time.�1-29999",
			"2.�search�defl�action.�0-6","2.�myINFO�defl�msg�count.�1-29999","2.�myINFO�defl�time.�1-29999",
			"2.�myINFO�defl�action.�0-6","Max�MyINFO�length.�64-512","CTM�defl�count.�1-29999",
			"CTM�defl�time.�0-29999","CTM�defl�action.�0-6","2.�CTM�defl�count.�1-29999","2.�CTM�defl�time.�1-29999",
			"2.�CTM�defl�action.�0-6","RCTM�defl�count.�1-29999","RCTM�defl�time.�1-29999","RCTM�defl�action.�0-6",
			"2.�RCTM�defl�count.�1-29999","2.�RCTM�defl�time.�1-29999","2.�RCTM�defl�action.�0-6","Max�CTM�length.�1-512",
			"Max�RCTM�length.�1-512","SR�defl�count.�1-29999","SR�defl�time.�1-29999","SR�defl�action.�0-6",
			"2.�SR�defl�count.�1-29999","2.�SR�defl�time.�1-29999","2.�SR�defl�action.�0-6","Max�SR�length.�1-8192",
			"recvd�data�defl�action.�0-6","recvd�data�defl�kB.�1-29999","recvd�data�defl�time.�1-29999",
			"2.�recvd�data�defl�action.�0-6","2.�recvd�data�defl�kB.�0-29999","2.�recvd�data�defl�time.�1-29999",
			"Chat�msg�interval�msg.�1-29999","Chat�msg�interval�time.�1-29999","Priv�msg�interval�msg.�1-29999",
			"Priv�msg�interval�time.�1-29999","Search�interval�count.�1-29999","Search�interval�time.�1-�29999",
			"Max�users�from�same�IP.�1-256","Min�reconn.�time�in�secs.�1-256"}
			if tCtrls.tEditorSettings["CC"] then
				editor:UserListShow(2,table.concat(tNums," "))
			end
			editor:Connect(wxstc.wxEVT_STC_USERLISTSELECTION,function(event)
				local pos = editor:GetCurrentPos()
				local start_pos,sel = editor:WordStartPosition(pos, true),-1
				editor:SetSelection(start_pos,pos)
				for i = 1,#tNums do
					if tNums[i] == event:GetText() then sel = i-1 break end
				end
				if editor:GetTextRange(editor.CurrentPos-17,editor.CurrentPos) == "SetMan.SetNumber(" then
					editor:ReplaceSelection(tostring(sel)..",")
				else
					editor:ReplaceSelection(tostring(sel)..")")
				end
				editor:SetCurrentPos(editor:GetCurrentPos()+1)
				editor:Disconnect(wxstc.wxEVT_STC_USERLISTSELECTION)
			end)
		elseif editor:GetTextRange(editor.CurrentPos-17,editor.CurrentPos) == "SetMan.GetString(" or 
			editor:GetTextRange(editor.CurrentPos-17, editor.CurrentPos) == "SetMan.SetString(" then
			local tStrings = {
			"Hub�name.�1-256","Admin�nick.�1-64","Hub�address.�1-256","TCP�ports.�1-64","UDP�port.�1-5",
			"Hub�description.�<256","Main�redirect�address.�<256","Hublist�register�servers.�<1024",
			"Regonly�message.�1-256","Regonly�redir�address.�<256","Hub�topic.�<256",
			"Share�limit�message.�1-256","Share�limit�redir�address.�<256","Slot�limit�message.�1-256",
			"Slot�limit�redir�address.�<256","Ratio�limit�message.�1-256","Ratio�limit�redir�address.�<256",
			"Max�hubs�limit�message.�1-256","Max�hubs�limit�redir�address.�<256","No�tag�rule�message.�1-256",
			"No�tag�rule�redir�address.�<256","Hub�bot�nick.�1-64","Hub�bot�desc.�<64","Hub�bot�email.�<64",
			"OpChat�bot�nick.�1-64","OpChat�bot�description.�<64","OpChat�bot�email.�<64",
			"Temp�ban�redir�address.�<256","Perm�ban�redir�address.�<256","Chat�commands�prefixes.�1-5",
			"Hub�owner�email.�<64","Nick�limit�message.�1-256","Nick�limit�redir�address.�<256",
			"Additional�ban�message.�<256","Language"}
			if tCtrls.tEditorSettings["CC"] then
				editor:UserListShow(2,table.concat(tStrings," "))
			end
			editor:Connect(wxstc.wxEVT_STC_USERLISTSELECTION,function(event)
				local pos = editor:GetCurrentPos()
				local start_pos,sel = editor:WordStartPosition(pos, true),-1
				editor:SetSelection(start_pos,pos)
				for i = 1,#tStrings do
					if tStrings[i] == event:GetText() then sel = i-1 break end
				end
				if editor:GetTextRange(editor.CurrentPos-17, editor.CurrentPos) == "SetMan.SetString(" then
					editor:ReplaceSelection(tostring(sel)..",")
				else
					editor:ReplaceSelection(tostring(sel)..")")
				end
				editor:SetCurrentPos(editor:GetCurrentPos()+1)
				editor:Disconnect(wxstc.wxEVT_STC_USERLISTSELECTION)
			end)
		elseif editor:GetTextRange(editor.CurrentPos-32,editor.CurrentPos):match("ProfMan.SetProfilePermission%(%d,") or 
			editor:GetTextRange(editor.CurrentPos-32,editor.CurrentPos):match("ProfMan.GetProfilePermission%(%d,") then
			local tPermissions = {
			"User�have�key�/�is�OP","No�GetNickList�Deflood","No�MyINFO�Deflood","No�Search�Deflood","No�PM�Deflood",
			"No�Main�Chat�Deflood","Mass�Message","Topic","TempBan","Reload�text�files","No�Tag�check","TempUnban",
			"DelRegUser","AddRegUser","No�ChatLimits","No�MaxHubs�Check","No�Slot/Hub�ratio�Check","No�SlotCheck",
			"No�ShareLimit�check","Clear�PermBan","Clear�TempBan","GetInfo","Get�Bans","Start/Stop/Restart�script(s)",
			"Restart�hub","TempOP","Gag,�Ungag","Redirect","Ban","Kick","Drop","Enter�full�hub","Enter�hub�if�IP�banned",
			"Allowed�for�OpChat","Send�all�users�IP","Range�ban","Range�unban","Range�temp�ban","Range�temp�unban",
			"Get�range�perm�bans","Clear�range�perm�bans","Clear�range�temp�bans","Unban","No�search�length�limits",
			"Send�full�myinfos","No�IP�checking�in�connection�and�search�request","Close","No�ConnectToMe�deflood",
			"No�RevConnectToMe�deflood","No�search�reply�deflood","No�received�data�deflood","No�chat�interval",
			"No�private�message�interval","No�search�interval","No�maximum�users�from�same�IP","No�reconnect�time"
			}
			if tCtrls.tEditorSettings["CC"] then
				editor:UserListShow(2,table.concat(tPermissions," "))
			end
			editor:Connect(wxstc.wxEVT_STC_USERLISTSELECTION,function(event)
				local pos = editor:GetCurrentPos()
				local start_pos,sel = editor:WordStartPosition(pos, true),-1
				editor:SetSelection(start_pos,pos)
				for i = 1,#tPermissions do
					if tPermissions[i] == event:GetText() then sel = i-1 break end
				end
				if editor:GetTextRange(editor.CurrentPos-32,editor.CurrentPos):match("ProfMan.GetProfilePermission%(%d,") then
					editor:ReplaceSelection(tostring(sel)..")")
				else
					editor:ReplaceSelection(tostring(sel)..",")
				end
				editor:SetCurrentPos(editor:GetCurrentPos()+1)
				editor:Disconnect(wxstc.wxEVT_STC_USERLISTSELECTION)
			end)
		end
		local ch = event:GetKey()
		if (ch == 10) or (ch == 13) then
			local pos = editor:GetCurrentPos()
			local line = editor:LineFromPosition(pos)
			if (line > 0) and (editor:LineLength(line) == 0) then
				local indent = editor:GetLineIndentation(line-1)
				if indent > 0 then
					editor:SetLineIndentation(line,indent)
					editor:GotoPos(pos+indent)
				end
			end
		end
		local pos = editor:GetCurrentPos()
		local start_pos = editor:WordStartPosition(pos, true)
		if (pos - start_pos > -1) and (start_pos > 0) then
			if tCtrls.tEditorSettings["CC"] then
				local userList = ""
				local key,key2 = editor:GetTextRange(start_pos-6, pos),editor:GetTextRange(pos-5,pos)
				if key2:find("os") or key2:find("io") and ch == 46 then userList = CreateAutoCompList(key2:sub(2),4) end
				if not key2:find("%.") then return end
				if userList == "" then userList = CreateAutoCompList(key,6) end
				if userList and #userList > 0 then
					editor:UserListShow(1, userList)
				end
			end
		end
		ShowToolTip()
    end)
	editor:Connect(wxstc.wxEVT_STC_UPDATEUI,function(event)
		local braceclose,braceopen = MatchBrackets()
		if braceclose > -1 and braceopen == -1 then
			editor:BraceBadLight(braceclose)
			editor:SetHighlightGuide(0)
		else
			editor:BraceHighlight(braceclose,braceopen)
		end
		ShowToolTip()
	end)
    editor:Connect(wxstc.wxEVT_STC_USERLISTSELECTION,function(event)
		local pos = editor:GetCurrentPos()
		local start_pos = editor:WordStartPosition(pos, true)
		editor:SetSelection(start_pos,pos)
		editor:ReplaceSelection(event:GetText())
	end)
	self:ColourizeEditor();
	local err = self:GetCtrl("ID_SPLITTERWIN"):GetWindow2()
	self:GetCtrl("ID_SPLITTERWIN"):Unsplit(scripteditor)
	scripteditor:Destroy()
	self:GetCtrl("ID_SPLITTERWIN"):SplitHorizontally(editor:DynamicCast("wxWindow"),err)
	self:GetCtrl("ID_SPLITTERWIN"):SetSashPosition(365,true)
end

function tFuncs.ColourizeEditor(self)
	editor:StyleSetBackground(wxstc.wxSTC_STYLE_DEFAULT,     tCtrls.tEditorSettings[1][1])
    editor:StyleSetForeground(wxstc.wxSTC_STYLE_DEFAULT,     tCtrls.tEditorSettings[1][2])
	editor:StyleSetFont(wxstc.wxSTC_STYLE_DEFAULT,           tCtrls.tEditorSettings[1][3])
	editor:StyleSetBackground(wxstc.wxSTC_LUA_DEFAULT,       tCtrls.tEditorSettings[1][1])
    editor:StyleSetForeground(wxstc.wxSTC_LUA_DEFAULT,       tCtrls.tEditorSettings[1][2])
	editor:StyleSetFont(wxstc.wxSTC_LUA_DEFAULT,             tCtrls.tEditorSettings[1][3])
	editor:SetSelForeground(true,                            tCtrls.tEditorSettings[2][1])
	editor:SetSelBackground(true,                            tCtrls.tEditorSettings[2][2])
	local c = tCtrls.tEditorSettings[1][1]:Red()+tCtrls.tEditorSettings[1][1]:Green()+tCtrls.tEditorSettings[1][1]:Blue()
	editor:SetCaretForeground(wx.wxColour(iff(c<384,"#FFFFFF","#000000")))
    editor:StyleSetBackground(wxstc.wxSTC_LUA_COMMENTLINE,   tCtrls.tEditorSettings[3][1])
    editor:StyleSetForeground(wxstc.wxSTC_LUA_COMMENTLINE,   tCtrls.tEditorSettings[3][2])
	editor:StyleSetFont(wxstc.wxSTC_LUA_COMMENTLINE,         tCtrls.tEditorSettings[3][3])
	editor:StyleSetBackground(wxstc.wxSTC_LUA_COMMENT,       tCtrls.tEditorSettings[4][1])
    editor:StyleSetForeground(wxstc.wxSTC_LUA_COMMENT,       tCtrls.tEditorSettings[4][2])
	editor:StyleSetFont(wxstc.wxSTC_LUA_COMMENT,             tCtrls.tEditorSettings[4][3])
    editor:StyleSetBackground(wxstc.wxSTC_LUA_COMMENTDOC,    tCtrls.tEditorSettings[4][1])
    editor:StyleSetForeground(wxstc.wxSTC_LUA_COMMENTDOC,    tCtrls.tEditorSettings[4][2])
	editor:StyleSetFont(wxstc.wxSTC_LUA_COMMENTDOC,          tCtrls.tEditorSettings[4][3])
	editor:StyleSetBackground(wxstc.wxSTC_LUA_NUMBER,        tCtrls.tEditorSettings[5][1])
    editor:StyleSetForeground(wxstc.wxSTC_LUA_NUMBER,        tCtrls.tEditorSettings[5][2])
	editor:StyleSetFont(wxstc.wxSTC_LUA_NUMBER,              tCtrls.tEditorSettings[5][3])
    editor:StyleSetBackground(wxstc.wxSTC_LUA_WORD,          tCtrls.tEditorSettings[6][1])
    editor:StyleSetForeground(wxstc.wxSTC_LUA_WORD,          tCtrls.tEditorSettings[6][2])
	editor:StyleSetFont(wxstc.wxSTC_LUA_WORD,                tCtrls.tEditorSettings[6][3])
	editor:StyleSetBackground(wxstc.wxSTC_LUA_CHARACTER,     tCtrls.tEditorSettings[7][1])
    editor:StyleSetForeground(wxstc.wxSTC_LUA_CHARACTER,     tCtrls.tEditorSettings[7][2]) 
	editor:StyleSetFont(wxstc.wxSTC_LUA_CHARACTER,           tCtrls.tEditorSettings[7][3])
    editor:StyleSetBackground(wxstc.wxSTC_LUA_STRING,        tCtrls.tEditorSettings[7][1])
    editor:StyleSetForeground(wxstc.wxSTC_LUA_STRING,        tCtrls.tEditorSettings[7][2])
	editor:StyleSetFont(wxstc.wxSTC_LUA_STRING,              tCtrls.tEditorSettings[7][3])
    editor:StyleSetBackground(wxstc.wxSTC_LUA_LITERALSTRING, tCtrls.tEditorSettings[8][1])
    editor:StyleSetForeground(wxstc.wxSTC_LUA_LITERALSTRING, tCtrls.tEditorSettings[8][2])
    editor:StyleSetFont(wxstc.wxSTC_LUA_LITERALSTRING,       tCtrls.tEditorSettings[8][3])
    editor:StyleSetBackground(wxstc.wxSTC_LUA_OPERATOR,      tCtrls.tEditorSettings[9][1])
    editor:StyleSetForeground(wxstc.wxSTC_LUA_OPERATOR,      tCtrls.tEditorSettings[9][2])
	editor:StyleSetFont(wxstc.wxSTC_LUA_OPERATOR,            tCtrls.tEditorSettings[9][3])
    editor:StyleSetBackground(wxstc.wxSTC_LUA_IDENTIFIER,    tCtrls.tEditorSettings[10][1])
    editor:StyleSetForeground(wxstc.wxSTC_LUA_IDENTIFIER,    tCtrls.tEditorSettings[10][2])
	editor:StyleSetFont(wxstc.wxSTC_LUA_IDENTIFIER,          tCtrls.tEditorSettings[10][3])
    editor:StyleSetEOLFilled(wxstc.wxSTC_LUA_STRINGEOL,      false)
    editor:StyleSetBackground(wxstc.wxSTC_LUA_WORD2,         tCtrls.tEditorSettings[11][1])
    editor:StyleSetForeground(wxstc.wxSTC_LUA_WORD2,         tCtrls.tEditorSettings[11][2])
	editor:StyleSetFont(wxstc.wxSTC_LUA_WORD2,               tCtrls.tEditorSettings[11][3])
	editor:StyleSetBackground(wxstc.wxSTC_LUA_WORD3,         tCtrls.tEditorSettings[12][1])
    editor:StyleSetForeground(wxstc.wxSTC_LUA_WORD3,         tCtrls.tEditorSettings[12][2])
	editor:StyleSetFont(wxstc.wxSTC_LUA_WORD3,               tCtrls.tEditorSettings[12][3])
	editor:StyleSetBackground(wxstc.wxSTC_LUA_WORD4,         tCtrls.tEditorSettings[13][1])
    editor:StyleSetForeground(wxstc.wxSTC_LUA_WORD4,         tCtrls.tEditorSettings[13][2])
	editor:StyleSetFont(wxstc.wxSTC_LUA_WORD4,               tCtrls.tEditorSettings[13][3])	
	editor:StyleSetBackground(wxstc.wxSTC_LUA_WORD5,         tCtrls.tEditorSettings[14][1])
    editor:StyleSetForeground(wxstc.wxSTC_LUA_WORD5,         tCtrls.tEditorSettings[14][2])
	editor:StyleSetFont(wxstc.wxSTC_LUA_WORD5,               tCtrls.tEditorSettings[14][3])
    editor:StyleSetBackground(wxstc.wxSTC_LUA_WORD6,         tCtrls.tEditorSettings[15][1])
    editor:StyleSetForeground(wxstc.wxSTC_LUA_WORD6,         tCtrls.tEditorSettings[15][2])
	editor:StyleSetFont(wxstc.wxSTC_LUA_WORD6,               tCtrls.tEditorSettings[15][3])
	editor:StyleSetBackground(wxstc.wxSTC_STYLE_LINENUMBER,  tCtrls.tEditorSettings[16][1])
	editor:StyleSetForeground(wxstc.wxSTC_STYLE_LINENUMBER,  tCtrls.tEditorSettings[16][2])
	editor:StyleSetFont(wxstc.wxSTC_STYLE_LINENUMBER,        tCtrls.tEditorSettings[16][3])
    editor:StyleSetBackground(wxstc.wxSTC_STYLE_BRACELIGHT,  tCtrls.tEditorSettings[17][1])
    editor:StyleSetForeground(wxstc.wxSTC_STYLE_BRACELIGHT,  tCtrls.tEditorSettings[17][2])
	editor:StyleSetFont(wxstc.wxSTC_STYLE_BRACELIGHT,        tCtrls.tEditorSettings[17][3])
    editor:StyleSetBackground(wxstc.wxSTC_STYLE_BRACEBAD,    tCtrls.tEditorSettings[18][1])
	editor:StyleSetForeground(wxstc.wxSTC_STYLE_BRACEBAD,    tCtrls.tEditorSettings[18][2])
	editor:StyleSetFont(wxstc.wxSTC_STYLE_BRACEBAD,          tCtrls.tEditorSettings[18][3])
	editor:StyleSetBackground(wxstc.wxSTC_STYLE_INDENTGUIDE, tCtrls.tEditorSettings[19][1])
    editor:StyleSetForeground(wxstc.wxSTC_STYLE_INDENTGUIDE, tCtrls.tEditorSettings[19][2])
	editor:SetFoldMarginColour(true,                         tCtrls.tEditorSettings[20][1])
    editor:SetUseTabs(true)
    editor:SetTabWidth(4)
    editor:SetIndent(4)
    editor:SetIndentationGuides(true)
    editor:SetVisiblePolicy(wxstc.wxSTC_VISIBLE_SLOP,3)
    editor:MarkerDefine(wxstc.wxSTC_MARKNUM_FOLDEROPEN,           wxstc.wxSTC_MARK_BOXMINUS)
    editor:MarkerDefine(wxstc.wxSTC_MARKNUM_FOLDER,               wxstc.wxSTC_MARK_BOXPLUS)
    editor:MarkerDefine(wxstc.wxSTC_MARKNUM_FOLDERSUB,            wxstc.wxSTC_MARK_VLINE)
    editor:MarkerDefine(wxstc.wxSTC_MARKNUM_FOLDERTAIL,           wxstc.wxSTC_MARK_LCORNER)
    editor:MarkerDefine(wxstc.wxSTC_MARKNUM_FOLDEREND,            wxstc.wxSTC_MARK_BOXPLUSCONNECTED)
    editor:MarkerDefine(wxstc.wxSTC_MARKNUM_FOLDEROPENMID,        wxstc.wxSTC_MARK_BOXMINUSCONNECTED)
    editor:MarkerDefine(wxstc.wxSTC_MARKNUM_FOLDERMIDTAIL,        wxstc.wxSTC_MARK_TCORNER)	
	editor:MarkerSetBackground(wxstc.wxSTC_MARKNUM_FOLDEROPEN,    tCtrls.tEditorSettings[21][1])
	editor:MarkerSetForeground(wxstc.wxSTC_MARKNUM_FOLDEROPEN,    tCtrls.tEditorSettings[21][2])
	editor:MarkerSetBackground(wxstc.wxSTC_MARKNUM_FOLDER,        tCtrls.tEditorSettings[21][1])
	editor:MarkerSetForeground(wxstc.wxSTC_MARKNUM_FOLDER,        tCtrls.tEditorSettings[21][2])
	editor:MarkerSetBackground(wxstc.wxSTC_MARKNUM_FOLDERSUB,     tCtrls.tEditorSettings[22][1])
	editor:MarkerSetForeground(wxstc.wxSTC_MARKNUM_FOLDERSUB,     tCtrls.tEditorSettings[22][2])
	editor:MarkerSetBackground(wxstc.wxSTC_MARKNUM_FOLDERTAIL,    tCtrls.tEditorSettings[23][1])
	editor:MarkerSetForeground(wxstc.wxSTC_MARKNUM_FOLDERTAIL,    tCtrls.tEditorSettings[23][2])
	editor:MarkerSetBackground(wxstc.wxSTC_MARKNUM_FOLDEREND,     tCtrls.tEditorSettings[24][1])
	editor:MarkerSetForeground(wxstc.wxSTC_MARKNUM_FOLDEREND,     tCtrls.tEditorSettings[24][2])
	editor:MarkerSetBackground(wxstc.wxSTC_MARKNUM_FOLDEROPENMID, tCtrls.tEditorSettings[25][1])
	editor:MarkerSetForeground(wxstc.wxSTC_MARKNUM_FOLDEROPENMID, tCtrls.tEditorSettings[25][2])
	editor:MarkerSetBackground(wxstc.wxSTC_MARKNUM_FOLDERMIDTAIL, tCtrls.tEditorSettings[26][1])
	editor:MarkerSetForeground(wxstc.wxSTC_MARKNUM_FOLDERMIDTAIL, tCtrls.tEditorSettings[26][2])
end

-- I've tried to rewrite the following function to OO way (with wx), results:
-- Loading with wxXmlDocument: more than 120 secs translation, no problem with encoding
-- Loading in this way: ~12 secs translation, problem with BOM, fixed
function tFuncs.Translate(self,str)
	if not tCtrls["langfile"] then return nil end
	local ret = nil
	if not tCtrls["file"] then
		local m_fsfile = m_FileSystem:OpenFile("file:PRAdmin.xrs#zip:language/"..tCtrls["langfile"]..".xml",wx.wxFS_READ);
		local m_stream = "";
		if m_fsfile then
			m_stream = m_fsfile:GetStream();
			tCtrls["file"] = m_stream:Read(m_stream:GetSize());
		end
	end
	if tCtrls["file"] then
		if tCtrls["file"]:find("<String Name=\""..str.."\">.+</String>") then
			ret = tCtrls["file"]:match("<String Name=\""..str.."\">(.-)</String>")
			ret = ret:gsub("&lt;","<") ret = ret:gsub("&gt;",">")
			ret = ret:gsub("&apos;","'") ret = ret:gsub("&quot;","\"")
		end
	else
		return nil
	end
	return ret
end

function tFuncs.TranslateStrings(self)
	tCtrls["tLangs"][1] = self:Translate("GeneralSettings")         or "General settings"
   	tCtrls["tLangs"][2] = self:Translate("HubAddress")              or "Hub address"
	tCtrls["tLangs"][2] = tCtrls["tLangs"][2]:gsub(" %(.+%)","")
	tCtrls["tLangs"][3] = self:Translate("Nick")                    or "Login nick"
	tCtrls["tLangs"][4] = self:Translate("Password")                or "Password"
	tCtrls["tLangs"][5] = self:Translate("Description")             or "Description"
	tCtrls["tLangs"][6] = self:Translate("Tag")                     or "Tag"
	tCtrls["tLangs"][7] = self:Translate("Email")                   or "E-mail address"
	tCtrls["tLangs"][8] = self:Translate("ShareSize")               or "Sharesize in bytes"
	tCtrls["tLangs"][9] = self:Translate("Language")                or "Language"
	tCtrls["tLangs"][10] = self:Translate("SaveSettings")           or "Save settings"
	-- Settings tab
	tCtrls["tLangs"][11] = self:Translate("Settings")               or "Settings"
	tCtrls["tLangs"][12] = self:Translate("Accept")                 or "Accept"
	tCtrls["tLangs"][13] = self:Translate("GeneralSettings")        or "General settings"
	tCtrls["tLangs"][14] = self:Translate("MOTD")                   or "MOTD"
	tCtrls["tLangs"][15] = self:Translate("DefaultBots")            or "Default bots"
	tCtrls["tLangs"][16] = self:Translate("MoreGeneral")            or "More general"
	tCtrls["tLangs"][17] = self:Translate("BanHandling")            or "Ban handling"
	tCtrls["tLangs"][18] = self:Translate("Advanced")               or "Advanced"
	tCtrls["tLangs"][19] = self:Translate("MyinfoProcess")          or "MyINFO processing"
	tCtrls["tLangs"][20] = self:Translate("AdvancedSecurity")       or "Advanced security"
	tCtrls["tLangs"][21] = self:Translate("Rules")                  or "Rules"
	tCtrls["tLangs"][22] = self:Translate("MoreRules")              or "More rules"
	tCtrls["tLangs"][23] = self:Translate("Deflood")                or "Deflood"
	tCtrls["tLangs"][24] = self:Translate("MoreDeflood")            or "More deflood"
	tCtrls["tLangs"][25] = self:Translate("MoreMoreDeflood")        or "More more deflood"
	-- 1. General settings
	tCtrls["tLangs"][26] = self:Translate("HubName")                or "Hub name"
	tCtrls["tLangs"][27] = self:Translate("HubTopic")               or "Hub topic"
	tCtrls["tLangs"][28] = self:Translate("HubDescription")         or "Hub description"
	tCtrls["tLangs"][29] = self:Translate("AntiMoGLODescription")   or "Anti MoGLO description"
	tCtrls["tLangs"][30] = self:Translate("HubAddress")             or "Hub Address (IP or Hostname)"
	tCtrls["tLangs"][31] = self:Translate("ResolveToIP")            or "If given address is hostname then resolve to IP address (needed for setting below)"
	tCtrls["tLangs"][32] = self:Translate("ListenOnlyOnIP")         or "Accept connections only on this address"
	tCtrls["tLangs"][33] = self:Translate("TCPPort")                or "TCP port"
	tCtrls["tLangs"][34] = self:Translate("TCPPortsHint")           or "More ports like 4861;666;411"
	tCtrls["tLangs"][35] = self:Translate("UDPPort")                or "UDP port"
	tCtrls["tLangs"][36] = self:Translate("AdminNick")              or "Admin nick (used in chat from hub window)"
	tCtrls["tLangs"][37] = self:Translate("HublistRegisterAddresses") or "Hublist register addresses"
	tCtrls["tLangs"][38] = self:Translate("HubListRegsHint")        or "More address like dreamland.gotdns.org;zengeday.sytes.net;hublist.zapto.org"
	tCtrls["tLangs"][39] = self:Translate("AutoReg")                or "Automatically register to hublist"
	-- 2. Advanced
	tCtrls["tLangs"][40] = self:Translate("HubStartupAndTrayIcon")  or "Hub startup and tray icon"
	tCtrls["tLangs"][41] = self:Translate("HubAutoStart")           or "Automatically start hub server on startup"
	tCtrls["tLangs"][42] = self:Translate("EnableTray")             or "Enable tray icon and minimize to tray"
	tCtrls["tLangs"][43] = self:Translate("MinimizeOnStartup")      or "Minimize to tray on startup (tray icon must be enabled)"
	tCtrls["tLangs"][44] = self:Translate("UpdateCheck")            or "Check on startup if new PtokaX version is available"
	tCtrls["tLangs"][45] = self:Translate("HubCommands")            or "Hub commands"
	tCtrls["tLangs"][46] = self:Translate("ReplyHubCmdsPm")         or "Reply to hub commands as private message"
	tCtrls["tLangs"][47] = self:Translate("ArrowPrefixesForHubCmds") or "<-- Prefixes for hub commands"
	tCtrls["tLangs"][48] = self:Translate("Scripting")              or "Scripting"
	tCtrls["tLangs"][49] = self:Translate("EnableScripting")        or "Enable Lua scripting inteface"
	tCtrls["tLangs"][50] = self:Translate("StopScriptError")        or "Stop script when lua find error in it"
	tCtrls["tLangs"][51] = self:Translate("PopupScriptsWindow")     or "Popup scripts window on script error"
	tCtrls["tLangs"][52] = self:Translate("LogScriptErrors")        or "Save script errors to log"
	tCtrls["tLangs"][53] = self:Translate("KickMessages")           or "Kick messages"
	tCtrls["tLangs"][54] = self:Translate("FilterKicks")            or "Filter kick messages (don't send them to all users)"
	tCtrls["tLangs"][55] = self:Translate("FilteredKicksToOPs")     or "Send kick messages to Operators (when previous option is enabled)"
	tCtrls["tLangs"][56] = self:Translate("StatusMessages")         or "Status messages"
	tCtrls["tLangs"][57] = self:Translate("SendStatus")             or "Send status messages to Operators"
	tCtrls["tLangs"][58] = self:Translate("SendStatusPm")           or "Send status messages as private messages"
	tCtrls["tLangs"][59] = self:Translate("Pinger")                 or "Pinger"
	tCtrls["tLangs"][60] = self:Translate("ReportPingers")          or "Report hublist pingers to Operators"
	tCtrls["tLangs"][61] = self:Translate("DisallowPingers")        or "Don't allow hublist pingers to check hub"
	-- 3. Rules
	tCtrls["tLangs"][62] = self:Translate("NickLimits")             or "Nick limits"
	tCtrls["tLangs"][63] = self:Translate("MinLen")                 or "Minimal length"
	tCtrls["tLangs"][64] = self:Translate("MaxLen")                 or "Maximal length"
	tCtrls["tLangs"][65] = self:Translate("MsgToSnd")               or "Message to send"
	tCtrls["tLangs"][66] = self:Translate("ZeroUnlimited")          or "0 = Unlimited"
	tCtrls["tLangs"][67] = self:Translate("NickLimitMessageHint")   or "Use %[min] for min length and %[max] for max length."
	tCtrls["tLangs"][68] = self:Translate("Redirect")               or "Redirect -->"
	tCtrls["tLangs"][69] = self:Translate("RedirectHint")           or "When no address is specified then is used main redirect address"
	tCtrls["tLangs"][70] = self:Translate("ShareLimits")            or "Share limits"
	tCtrls["tLangs"][71] = self:Translate("MinShare")               or "Minimal share"
	tCtrls["tLangs"][72] = self:Translate("MaxShare")               or "Maximal share"
	tCtrls["tLangs"][73] = self:Translate("ShareLimitMessageHint")  or "Use %[min] for min share and %[max] for max share."
	-- 4. DeFlood
	tCtrls["tLangs"][74] = self:Translate("Disabled")               or "Disabled"
	tCtrls["tLangs"][75] = self:Translate("Ignore")                 or "Ignore"
	tCtrls["tLangs"][76] = self:Translate("Warn")                   or "Warn"
	tCtrls["tLangs"][77] = self:Translate("Disconnect")             or "Disconnect"
	tCtrls["tLangs"][78] = self:Translate("Kick")                   or "Kick"
	tCtrls["tLangs"][79] = self:Translate("TempBan")                or "TempBan"
	tCtrls["tLangs"][80] = self:Translate("PermBan")                or "PermBan"
	tCtrls["tLangs"][81] = self:Translate("LockChat")               or "Lock chat"
	tCtrls["tLangs"][82] = self:Translate("OnlyToOPsWithIP")        or "Send only to OPs with user IP"
	tCtrls["tLangs"][83] = self:Translate("GlobalMainChatDeflood")  or "Global main chat deflood"
	tCtrls["tLangs"][84] = self:Translate("SecLwr")                 or "sec"
	tCtrls["tLangs"][85] = self:Translate("For")                    or "for"
	tCtrls["tLangs"][86] = self:Translate("MainChat")               or "Main chat"
	tCtrls["tLangs"][87] = self:Translate("SecondsLwr")             or "seconds"
	tCtrls["tLangs"][88] = self:Translate("Interval")               or "Interval"
	tCtrls["tLangs"][89] = self:Translate("SameMainChat")           or "Same main chat messages"
	tCtrls["tLangs"][90] = self:Translate("SameMultiMainChat")      or "Same main chat with multiline messages"
	tCtrls["tLangs"][91] = self:Translate("WithLwr")                or "with"
	tCtrls["tLangs"][92] = self:Translate("LinesLwr")               or "lines"
	tCtrls["tLangs"][93] = self:Translate("ConnectToMe")            or "ConnectToMe"
	tCtrls["tLangs"][94] = self:Translate("RevConnectToMe")         or "RevConnectToMe"
	tCtrls["tLangs"][95] = self:Translate("MainChatLimits")         or "Main chat limits"
	tCtrls["tLangs"][96] = self:Translate("Length")                 or "Length"
	tCtrls["tLangs"][97] = self:Translate("Lines")                  or "Lines"
	tCtrls["tLangs"][98] = self:Translate("DefloodTempBanTime")     or "Deflood temp ban time"
	tCtrls["tLangs"][99] = self:Translate("MinutesLwr")             or "minutes"
	tCtrls["tLangs"][100] = self:Translate("MaxUsersLogins")        or "Max users logins"
	tCtrls["tLangs"][101] = self:Translate("Per10Seconds")          or "/ 10 seconds"
	tCtrls["tLangs"][102] = self:Translate("CTMLenLimit")           or "CTM length limit"
	tCtrls["tLangs"][103] = self:Translate("RCTMLenLimit")          or "RCTM length limit"
	tCtrls["tLangs"][104] = self:Translate("Maximum")               or "Maximum"
	tCtrls["tLangs"][105] = self:Translate("ReportFlood")           or "Report flood to operators"
	-- 5. MOTD
	tCtrls["tLangs"][106] = self:Translate("MOTD(motd)")            or "MOTD (message of the day)"
	tCtrls["tLangs"][107] = self:Translate("DisableMOTD")           or "Disable MOTD"
	tCtrls["tLangs"][108] = self:Translate("SendMOTDinPM")          or "Send MOTD as private message"
	-- 6. Default bot
	tCtrls["tLangs"][109] = self:Translate("HubBot")                or "Hub bot"
	tCtrls["tLangs"][110] = self:Translate("EnableAndRegBotOnHub")  or "Enable and register this bot on hub"
	tCtrls["tLangs"][111] = self:Translate("UseAsAlias")            or "Use this nick instead of Hub-Security"
	tCtrls["tLangs"][112] = self:Translate("OpChatBot")             or "Operator chat bot"
	-- 7. More general
	tCtrls["tLangs"][113] = self:Translate("MaxUsersLimit")         or "Maximum users"
	tCtrls["tLangs"][114] = self:Translate("TempBanTimeAfterEtc")   or "Temp ban time after kick, drop..."
	tCtrls["tLangs"][115] = self:Translate("TextFiles")             or "Text files"
	tCtrls["tLangs"][116] = self:Translate("EnableTextFiles")       or "Enable text files support"
	tCtrls["tLangs"][117] = self:Translate("TextFilesPm")           or "Send text files as private message"
	tCtrls["tLangs"][118] = self:Translate("HubOwnerEmail")         or "Hub owner email (used for hublist pingers)"
	tCtrls["tLangs"][119] = self:Translate("MainRedirectAddress")   or "Main redirect address (is used for all redirects where is no address specified)"
	tCtrls["tLangs"][120] = self:Translate("RedirectAllConn")       or "Redirect all connecting users"
	tCtrls["tLangs"][121] = self:Translate("RedirectFull")          or "Redirect users when hub is full"
	tCtrls["tLangs"][122] = self:Translate("RegOnlyHub")            or "Registered users only hub"
	tCtrls["tLangs"][123] = self:Translate("AllowOnlyRegs")         or "Allow only registered users"
	tCtrls["tLangs"][124] = self:Translate("RegOnlyMsg")            or "Message to send when user is not registered"
	tCtrls["tLangs"][125] = self:Translate("RedirectAddress")       or "Redirect address"
	tCtrls["tLangs"][126] = self:Translate("EnableWithArrow")       or "Enable -->"
	tCtrls["tLangs"][127] = self:Translate("RedirectHint")          or "When no address is specified then is used main redirect address"
	-- 8. Ban handling
	tCtrls["tLangs"][128] = self:Translate("BanMessage")            or "Ban message"
	tCtrls["tLangs"][129] = self:Translate("ShowBannedIP")          or "Show banned IP"
	tCtrls["tLangs"][130] = self:Translate("ShowBannedRange")       or "Show banned range"
	tCtrls["tLangs"][131] = self:Translate("ShowBannedNick")        or "Show banned nick"
	tCtrls["tLangs"][132] = self:Translate("ShowReason")            or "Show reason"
	tCtrls["tLangs"][133] = self:Translate("ShowWho")               or "Show who created ban"
	tCtrls["tLangs"][134] = self:Translate("AddMsg")                or "Additional message"
	tCtrls["tLangs"][135] = self:Translate("TempBanRedirAddress")   or "Temporary ban redirect address"
	tCtrls["tLangs"][136] = self:Translate("PermBanRedirAddress")   or "Permanent ban redirect address"
	-- 9. MyINFO processing
	tCtrls["tLangs"][137] = self:Translate("MyinfoProcess")         or "MyINFO processing"
	tCtrls["tLangs"][138] = self:Translate("MinBeforeNewSend")      or "Minutes before new MyINFO is accepted for broadcast"
	tCtrls["tLangs"][139] = self:Translate("StripDescr")            or "Strip description"
	tCtrls["tLangs"][140] = self:Translate("StripTag")              or "Strip tag"
	tCtrls["tLangs"][141] = self:Translate("StripConn")             or "Strip connection"
	tCtrls["tLangs"][142] = self:Translate("StripMail")             or "Strip email"
	tCtrls["tLangs"][143] = self:Translate("ModeToMyINFO")          or "Add user connection mode to MyINFO (need support in client)"
	tCtrls["tLangs"][144] = self:Translate("ModeToDescr")           or "Add user connection mode to user description"
	tCtrls["tLangs"][145] = self:Translate("ToAllUsers")            or "To all users"
	tCtrls["tLangs"][146] = self:Translate("OnlyAllowedProfiles")   or "Only to allowed profiles"
	tCtrls["tLangs"][147] = self:Translate("DontSend")              or "Don't send"
	tCtrls["tLangs"][148] = self:Translate("MyINFOToHint")          or "Need hub restart to apply!"
	tCtrls["tLangs"][149] = self:Translate("DescriptionTag")        or "Description tag"
	tCtrls["tLangs"][150] = self:Translate("ReportBadTags")         or "Report suspicious description tag to operators"
	tCtrls["tLangs"][151] = self:Translate("AcceptUnknownTag")      or "Accept description tag from uknown client when is valid"
	tCtrls["tLangs"][152] = self:Translate("NoTagAction")           or "User without tag action"
	tCtrls["tLangs"][153] = self:Translate("Accept")                or "Accept"
	tCtrls["tLangs"][154] = self:Translate("Reject")                or "Reject"
	-- 10. Advanced security
	tCtrls["tLangs"][155] = self:Translate("ExpertsOnly")           or "Experts only"
	tCtrls["tLangs"][156] = self:Translate("KeepSlow")              or "Keep slow users online"
	tCtrls["tLangs"][157] = self:Translate("UseUserIP")             or "Send user on login his ip with UserIP command (client use it to set up active mode)"
	tCtrls["tLangs"][158] = self:Translate("CheckIP")               or "Check if user send correct ip in protocol command (DDOS protection)"
	tCtrls["tLangs"][159] = self:Translate("PasswordProtection")    or "Password protection"
	tCtrls["tLangs"][160] = self:Translate("ReportBadPass")         or "Report to Operators when bad password is received 3 times for registered user"
	tCtrls["tLangs"][161] = self:Translate("AdvPassProtect")        or "Enable advanced password protection"
	tCtrls["tLangs"][162] = self:Translate("BruteForcePassProtAct") or "Brute force password protection action"
	tCtrls["tLangs"][163] = self:Translate("TemporaryBanTime")      or "Temporary ban time"
	tCtrls["tLangs"][164] = self:Translate("HoursLwr")              or "hours"
	-- 11. More rules
	tCtrls["tLangs"][165] = self:Translate("MaximalHubsLimit")      or "Maximal hubs limit"
	tCtrls["tLangs"][166] = self:Translate("MaxHubs")               or "Max hubs"
	tCtrls["tLangs"][167] = self:Translate("HubLimitMessageHint")   or "Use %[hubs] for hubs."
	tCtrls["tLangs"][168] = self:Translate("SlotLimits")            or "Slots limit"
	tCtrls["tLangs"][169] = self:Translate("MinSlots")              or "Minimal slots"
	tCtrls["tLangs"][170] = self:Translate("MaxSlots")              or "Maximal slots"
	tCtrls["tLangs"][171] = self:Translate("SlotLimitMessageHint")  or "Use %[min] for min slots and %[max] for max slots."
	tCtrls["tLangs"][172] = self:Translate("HubSlotRatioLimit")     or "Hub / slot ratio limit"
	tCtrls["tLangs"][173] = self:Translate("Hubs")                  or "Hubs"
	tCtrls["tLangs"][174] = self:Translate("Slots")                 or "Slots"
	tCtrls["tLangs"][175] = self:Translate("HubSlotRatioMessageHint") or "Use %[hubs] for hubs and %[slots] for slots."
	-- 12. More deflood
	tCtrls["tLangs"][176] = self:Translate("PrivateMessages")       or "Private messages"
	tCtrls["tLangs"][177] = self:Translate("SamePrivateMessages")   or "Same private messages"
	tCtrls["tLangs"][178] = self:Translate("SameMultiPrivateMessages") or "Same multiline private messages"
	tCtrls["tLangs"][179] = self:Translate("PMLimToUsrFrmMultiNicks") or "Private message limit to one user from multiple nicks"
	tCtrls["tLangs"][180] = self:Translate("MaxMsgsToOneUserPerMin") or "Maximal messages to one user per minute"
	tCtrls["tLangs"][181] = self:Translate("RecvDataFromUser")      or "Received data from user"
	tCtrls["tLangs"][182] = self:Translate("WarnSettings")          or "Warn settings"
	tCtrls["tLangs"][183] = self:Translate("After")                 or "after"
	tCtrls["tLangs"][184] = self:Translate("Warnings")              or "warnings"
	tCtrls["tLangs"][185] = self:Translate("NewConnsFrmSingleIPLim") or "New connections from single IP limit"
	tCtrls["tLangs"][186] = self:Translate("PMLimits")              or "Private message limits"
	tCtrls["tLangs"][187] = self:Translate("MaxUsersSameIP")        or "Maximum users from same IP"
	tCtrls["tLangs"][188] = self:Translate("ReConnTime")            or "Reconnect time"
	tCtrls["tLangs"][189] = self:Translate("Min")                   or "Min"
	-- 13. More more deflood
	tCtrls["tLangs"][190] = self:Translate("Search")                or "Search"
	tCtrls["tLangs"][191] = self:Translate("SameSearches")          or "Same searches"
	tCtrls["tLangs"][192] = self:Translate("SR")                    or "Search reply"
	tCtrls["tLangs"][193] = self:Translate("MaxPSRLimit")           or "Maximal limit of search replies to passive search"
	tCtrls["tLangs"][194] = self:Translate("GetNickLists")          or "GetNickLists"
	tCtrls["tLangs"][195] = self:Translate("MyINFOs")               or "MyINFOs"
	tCtrls["tLangs"][196] = self:Translate("SearchLengthLimits")    or "Search length limits"
	tCtrls["tLangs"][197] = self:Translate("Minimal")               or "Minimum"
	tCtrls["tLangs"][198] = self:Translate("SRLenLimit")            or "SR length limit"
	tCtrls["tLangs"][199] = self:Translate("MyINFOLengthLimit")     or "MyINFO length limit"
	-- Scripts tab
	tCtrls["tLangs"][200] = self:Translate("Scripts")               or "Scripts"
	tCtrls["tLangs"][201] = self:Translate("RefreshScripts")        or "Refresh scripts"
	tCtrls["tLangs"][202] = self:Translate("MoveUp")                or "Move up"
	tCtrls["tLangs"][203] = self:Translate("LuaMoveUpHint")         or "Move script up"
	tCtrls["tLangs"][204] = self:Translate("MoveDown")              or "Move down"
	tCtrls["tLangs"][205] = self:Translate("LuaMoveDownHint")       or "Move script down"
	tCtrls["tLangs"][206] = self:Translate("CheckSyntax")           or "Check syntax"
	tCtrls["tLangs"][207] = self:Translate("CheckSyntaxHint")       or "Check syntax of edited scipt"
	tCtrls["tLangs"][208] = self:Translate("RestartScripts")        or "Restart scripts"
	tCtrls["tLangs"][209] = self:Translate("RestartScriptsHint")    or "Restart all scripts from script directory"
	tCtrls["tLangs"][210] = self:Translate("Load")                  or "Load"
	tCtrls["tLangs"][211] = self:Translate("LuaLoadHint")           or "Load script into editor"
	tCtrls["tLangs"][212] = self:Translate("Save")                  or "Save"
	tCtrls["tLangs"][213] = self:Translate("LuaSaveHint")           or "Save script into file"
	-- Registered users tab
	tCtrls["tLangs"][214] = self:Translate("RegUsers")              or "Registered users"
	tCtrls["tLangs"][215] = self:Translate("New")                   or "New"
	tCtrls["tLangs"][216] = self:Translate("Modify")                or "Modify"
	tCtrls["tLangs"][217] = self:Translate("Remove")                or "Remove"
	tCtrls["tLangs"][218] = self:Translate("ProfileMan")            or "Profile manager"
	tCtrls["tLangs"][219] = self:Translate("HaveKeyIsOp")           or "Have key / is Op"
	tCtrls["tLangs"][220] = self:Translate("NoGetNickListDeflood")  or "No GetNickList deflood"
	tCtrls["tLangs"][221] = self:Translate("NoMyINFODeflood")       or "No MyINFO deflood"
	tCtrls["tLangs"][222] = self:Translate("NoSearchDeflood")       or "No search deflood"
	tCtrls["tLangs"][223] = self:Translate("NoPMDeflood")           or "No private message deflood"
	tCtrls["tLangs"][224] = self:Translate("NoMainChatDeflood")     or "No main chat deflood"
	tCtrls["tLangs"][225] = self:Translate("MassMsg")               or "Mass message"
	tCtrls["tLangs"][226] = self:Translate("Topic")                 or "Topic"
	tCtrls["tLangs"][227] = self:Translate("TemporaryBan")          or "Temporary ban"
	tCtrls["tLangs"][228] = self:Translate("RldTxtFiles")           or "Reload text files"
	tCtrls["tLangs"][229] = self:Translate("NoTagCheck")            or "No tag check"
	tCtrls["tLangs"][230] = self:Translate("TemporaryUnban")        or "Temporary unban"
	tCtrls["tLangs"][231] = self:Translate("DelRegisteredUser")     or "Del registered user"
	tCtrls["tLangs"][232] = self:Translate("AddRegisteredUser")     or "Add registered user"
	tCtrls["tLangs"][233] = self:Translate("NoChatLimits")          or "No chat limits"
	tCtrls["tLangs"][234] = self:Translate("NoMaxHubsCheck")        or "No max hubs check"
	tCtrls["tLangs"][235] = self:Translate("NoRatioCheck")          or "No slot/hub check"
	tCtrls["tLangs"][236] = self:Translate("NoSlotCheck")           or "No slot check"
	tCtrls["tLangs"][237] = self:Translate("NoShareLimit")          or "No share limit"
	tCtrls["tLangs"][238] = self:Translate("ClearPermBans")         or "Clear temporary bans"
	tCtrls["tLangs"][239] = self:Translate("ClearTempBans")         or "Clear permanent bans"
	tCtrls["tLangs"][240] = self:Translate("GetUserInfo")           or "Get user info"
	tCtrls["tLangs"][241] = self:Translate("GetBans")               or "Get bans"
	tCtrls["tLangs"][242] = self:Translate("StartStopRestartScripts") or "Start/Stop/Restart script(s)"
	tCtrls["tLangs"][243] = self:Translate("RestartHub")            or "Restart hub"
	tCtrls["tLangs"][244] = self:Translate("TempOP")                or "Temp OP"
	tCtrls["tLangs"][245] = self:Translate("GagUngag")              or "Gag, Ungag"
	tCtrls["tLangs"][246] = self:Translate("Redir")                 or "Redirect"
	tCtrls["tLangs"][247] = self:Translate("PermanentBan")          or "Permanent Ban"
	tCtrls["tLangs"][248] = self:Translate("Kick")                  or "Kick user"
	tCtrls["tLangs"][249] = self:Translate("Drop")                  or "Drop"
	tCtrls["tLangs"][250] = self:Translate("EntFullHub")            or "Enter full hub"
	tCtrls["tLangs"][251] = self:Translate("AllowLoginBannedIp")    or "Allowed to login from banned IP (without fullban)"
	tCtrls["tLangs"][252] = self:Translate("AllowedForOpChat")      or "Allowed for OpChat"
	tCtrls["tLangs"][253] = self:Translate("SendUsersIP")           or "Send all users IP"
	tCtrls["tLangs"][254] = self:Translate("RangePermBan")          or "Range permanent ban"
	tCtrls["tLangs"][255] = self:Translate("RangeUnbanRangePermUnban") or "Range unban, Range permanent unban"
	tCtrls["tLangs"][256] = self:Translate("TempRangeBan")          or "Temporary range ban"
	tCtrls["tLangs"][257] = self:Translate("TempRangeUnban")        or "Temporary range unban"
	tCtrls["tLangs"][258] = self:Translate("GetRangeBans")          or "Get range bans"
	tCtrls["tLangs"][259] = self:Translate("ClearPermRangeBans")    or "Clear permanent range bans"
	tCtrls["tLangs"][260] = self:Translate("ClearTempRangeBans")    or "Clear temporary range bans"
	tCtrls["tLangs"][261] = self:Translate("UnbanPermUnban")        or "Unban, Permanent Unban"
	tCtrls["tLangs"][262] = self:Translate("NoSearchLimits")        or "No search limits"
	tCtrls["tLangs"][263] = self:Translate("SendFullMyinfos")       or "Send full myinfos"
	tCtrls["tLangs"][264] = self:Translate("DontCheckIP")           or "Don't check IP in DC commands"
	tCtrls["tLangs"][265] = self:Translate("Close")                 or "Close"
	tCtrls["tLangs"][266] = self:Translate("NoCTMDeflood")          or "No ConnectToMe deflood"
	tCtrls["tLangs"][267] = self:Translate("NoRCTMDeflood")         or "No RevConnectToMe deflood"
	tCtrls["tLangs"][268] = self:Translate("NoSRDeflood")           or "No search reply deflood"
	tCtrls["tLangs"][269] = self:Translate("NoRecvDeflood")         or "No received data deflood"
	tCtrls["tLangs"][270] = self:Translate("NoChatInterval")        or "No chat interval"
	tCtrls["tLangs"][271] = self:Translate("NoPMInterval")          or "No private message interval"
	tCtrls["tLangs"][272] = self:Translate("NoSearchInterval")      or "No search interval"
	tCtrls["tLangs"][273] = self:Translate("NoMaxUsersSameIP")      or "No maximum users from same IP"
	tCtrls["tLangs"][274] = self:Translate("NoReConnTime")          or "No reconnect time"
	tCtrls["tLangs"][275] = self:Translate("SetAll")                or "Set all"
	tCtrls["tLangs"][276] = self:Translate("ClearAll")              or "Clear all"
	tCtrls["tLangs"][277] = self:Translate("Add")                   or "Add"
	-- Bans tab
	tCtrls["tLangs"][278] = self:Translate("Bans")                  or "Bans"
	tCtrls["tLangs"][279] = self:Translate("RefreshBans")           or "Refresh bans"
	tCtrls["tLangs"][280] = self:Translate("ClearTempBansLwr")      or "Clear temporary bans"
	tCtrls["tLangs"][281] = self:Translate("ClearPermBansLwr")      or "Clear permanent bans"
	tCtrls["tLangs"][282] = self:Translate("RefreshRangeBans")      or "Refresh rangebans"
	tCtrls["tLangs"][283] = self:Translate("ClearTempRangeBansLwr") or "Clear temporary range bans"
	tCtrls["tLangs"][284] = self:Translate("ClearPermRangeBansLwr") or "Clear permanent range bans"
	-- Texts tab
	tCtrls["tLangs"][285] = self:Translate("TextFiles")             or "Text files"
	tCtrls["tLangs"][286] = self:Translate("ReloadAllTextfiles")    or "Reload all textfiles"
	tCtrls["tLangs"][287] = self:Translate("RefreshTextFiles")      or "Reload text files now!"
	tCtrls["tLangs"][288] = self:Translate("Load")                  or "Load"
	tCtrls["tLangs"][289] = self:Translate("Save")                  or "Save"
	-- (Range)Bans dialog
	tCtrls["tLangs"][290] = self:Translate("Ban")                   or "Ban"
	tCtrls["tLangs"][291] = self:Translate("NickBan")               or "Nick ban"
	tCtrls["tLangs"][292] = self:Translate("IpBan")                 or "IP ban"
	tCtrls["tLangs"][293] = self:Translate("FullBanned")            or "Full banned"
	tCtrls["tLangs"][294] = self:Translate("FullBanHint")           or "Full ban on IP disallow all users from that IP to login."
	tCtrls["tLangs"][295] = self:Translate("IP")                    or "IP"
	tCtrls["tLangs"][296] = self:Translate("Reason")                or "Reason"
	tCtrls["tLangs"][297] = self:Translate("CreatedBy")             or "Created by"
	tCtrls["tLangs"][298] = self:Translate("Temporary")             or "Temporary"
	tCtrls["tLangs"][299] = self:Translate("Day")                   or "Day"
	tCtrls["tLangs"][300] = self:Translate("Month")                 or "Month"
	tCtrls["tLangs"][301] = self:Translate("Year")                  or "Year"
	tCtrls["tLangs"][302] = self:Translate("Hour")                  or "Hour"
	tCtrls["tLangs"][303] = self:Translate("Minute")                or "Minute"
	tCtrls["tLangs"][304] = self:Translate("TempbanExpiration")     or "Tempban expiration"
	tCtrls["tLangs"][305] = self:Translate("Jan")                   or "Jan"
	tCtrls["tLangs"][306] = self:Translate("Feb")                   or "Feb"
	tCtrls["tLangs"][307] = self:Translate("Mar")                   or "Mar"
	tCtrls["tLangs"][308] = self:Translate("Apr")                   or "Apr"
	tCtrls["tLangs"][309] = self:Translate("May")                   or "May"
	tCtrls["tLangs"][310] = self:Translate("Jun")                   or "Jun"
	tCtrls["tLangs"][311] = self:Translate("Jul")                   or "Jul"
	tCtrls["tLangs"][312] = self:Translate("Aug")                   or "Aug"
	tCtrls["tLangs"][313] = self:Translate("Sep")                   or "Sep"
	tCtrls["tLangs"][314] = self:Translate("Oct")                   or "Oct"
	tCtrls["tLangs"][315] = self:Translate("Nov")                   or "Nov"
	tCtrls["tLangs"][316] = self:Translate("Dec")                   or "Dec"
	tCtrls["tLangs"][317] = self:Translate("Permanent")             or "Permanent"
	tCtrls["tLangs"][318] = self:Translate("FromIP")                or "From IP"
	tCtrls["tLangs"][319] = self:Translate("To IP")                 or "To IP"
	tCtrls["tLangs"][320] = self:Translate("Discard")               or "Discard"
	tCtrls["tLangs"][321] = self:Translate("Banned")                or "Banned"
	tCtrls["tLangs"][322] = self:Translate("RangeBans")             or "Range bans"
	tCtrls["tLangs"][323] = self:Translate("FromIP")                or "From IP"
	tCtrls["tLangs"][324] = self:Translate("To IP")                 or "To IP"
end

function tFuncs.InitTranslatableControls(self)
	local self = self or tFuncs -- If it runs from a different thread
	tCtrls["stt_login_address"]         = self:GetCtrl("stt_login_address")
	tCtrls["stt_login_nick"]            = self:GetCtrl("stt_login_nick")
	tCtrls["stt_login_passwd"]          = self:GetCtrl("stt_login_passwd")
	tCtrls["stt_login_desc"]            = self:GetCtrl("stt_login_desc")
	tCtrls["stt_login_tag"]             = self:GetCtrl("stt_login_tag")
	tCtrls["stt_login_email"]           = self:GetCtrl("stt_login_email")
	tCtrls["stt_login_share"]           = self:GetCtrl("stt_login_share")
	tCtrls["stt_login_lang"]            = self:GetCtrl("stt_login_lang")
	tCtrls["cmd_save"]                  = self:GetCtrl("wxID_CMD_LOGIN_SAVE")
	-- Settings tab
	tCtrls["ACCEPT"]                    = self:GetCtrl("wxID_ACCEPT")
	-- 1. General settings
	tCtrls["stb_hubname"]               = self:GetCtrl("stb_hubname")
	tCtrls["stb_hubtopic"]              = self:GetCtrl("stb_hubtopic")
	tCtrls["stb_hubdesc"]               = self:GetCtrl("stb_hubdesc")
	tCtrls["stb_hubaddress"]            = self:GetCtrl("stb_hubaddress")
	tCtrls["stb_tcp"]                   = self:GetCtrl("stb_tcp")
	tCtrls["stb_udp"]                   = self:GetCtrl("stb_udp")
	tCtrls["stb_adminnick"]             = self:GetCtrl("stb_adminnick")
	tCtrls["stb_hublistregs"]           = self:GetCtrl("stb_hublistregs")
	-- 2. Advanced
	tCtrls["stb_hubstartup"]            = self:GetCtrl("stb_hubstartup")
	tCtrls["stb_hubcommands"]           = self:GetCtrl("stb_hubcommands")
	tCtrls["stt_cmdprefixes"]           = self:GetCtrl("stt_cmdprefixes")
	tCtrls["stb_scripting"]             = self:GetCtrl("stb_scripting")
	tCtrls["stb_kickmessages"]          = self:GetCtrl("stb_kickmessages")
	tCtrls["stb_statusmessages"]        = self:GetCtrl("stb_statusmessages")
	tCtrls["stb_pinger"]                = self:GetCtrl("stb_pinger")
	-- 3. Rules
	tCtrls["stb_nicklimits"]            = self:GetCtrl("stb_nicklimits")
	tCtrls["stt_minnicklen"]            = self:GetCtrl("stt_minnicklen")
	tCtrls["stt_maxnicklen"]            = self:GetCtrl("stt_maxnicklen")
	tCtrls["stt_nicklimitmsg"]          = self:GetCtrl("stt_nicklimitmsg")
	tCtrls["stb_sharelimits"]           = self:GetCtrl("stb_sharelimits")
	tCtrls["stt_minshare"]              = self:GetCtrl("stt_minshare")
	tCtrls["stt_maxshare"]              = self:GetCtrl("stt_maxshare")
	tCtrls["stt_sharelimitmsg"]         = self:GetCtrl("stt_sharelimitmsg")
	-- 4. DeFlood
	tCtrls["stb_defloodglobal"]         = self:GetCtrl("stb_defloodglobal")
	tCtrls["stt_sec1"]                  = self:GetCtrl("stt_sec1")
	tCtrls["stt_for"]                   = self:GetCtrl("stt_for")
	tCtrls["stt_sec2"]                  = self:GetCtrl("stt_sec2")
	tCtrls["stb_defloodmain"]           = self:GetCtrl("stb_defloodmain")
	tCtrls["stt_seconds1"]              = self:GetCtrl("stt_seconds1")
	tCtrls["stt_seconds2"]              = self:GetCtrl("stt_seconds2")
	tCtrls["stt_interval1"]             = self:GetCtrl("stt_interval1")
	tCtrls["stt_seconds3"]              = self:GetCtrl("stt_seconds3")
	tCtrls["stb_defloodmainsame"]       = self:GetCtrl("stb_defloodmainsame")
	tCtrls["stt_seconds4"]              = self:GetCtrl("stt_seconds4")
	tCtrls["stb_defloodmainsameml"]     = self:GetCtrl("stb_defloodmainsameml")
	tCtrls["stt_with1"]                 = self:GetCtrl("stt_with1")
	tCtrls["stt_lines1"]                = self:GetCtrl("stt_lines1")
	tCtrls["stb_defloodctm"]            = self:GetCtrl("stb_defloodctm")
	tCtrls["stt_seconds5"]              = self:GetCtrl("stt_seconds5")
	tCtrls["stt_seconds6"]              = self:GetCtrl("stt_seconds6")
	tCtrls["stb_defloodrctm"]           = self:GetCtrl("stb_defloodrctm")
	tCtrls["stt_seconds7"]              = self:GetCtrl("stt_seconds7")
	tCtrls["stt_seconds8"]              = self:GetCtrl("stt_seconds8")
	tCtrls["stb_defloodmainlimits"]     = self:GetCtrl("stb_defloodmainlimits")
	tCtrls["stt_limit_length1"]         = self:GetCtrl("stt_limit_length1")
	tCtrls["stt_limit_lines1"]          = self:GetCtrl("stt_limit_lines1")
	tCtrls["stb_defloodtempban"]        = self:GetCtrl("stb_defloodtempban")
	tCtrls["stt_minutes1"]              = self:GetCtrl("stt_minutes1")
	tCtrls["stb_defloodmaxuserlogins"]  = self:GetCtrl("stb_defloodmaxuserlogins")
	tCtrls["stt_per10sec"]              = self:GetCtrl("stt_per10sec")
	tCtrls["stb_defloodctmlen"]         = self:GetCtrl("stb_defloodctmlen")
	tCtrls["stt_max1"]                  = self:GetCtrl("stt_max1")
	tCtrls["stb_defloodrctmlen"]        = self:GetCtrl("stb_defloodrctmlen")
	tCtrls["stt_max2"]                  = self:GetCtrl("stt_max2")
	-- 5. MOTD
	tCtrls["stb_motd"]                  = self:GetCtrl("stb_motd")
	-- 6. Default bots
	tCtrls["stb_hubbot"]                = self:GetCtrl("stb_hubbot")
	tCtrls["stb_hubbotnick"]            = self:GetCtrl("stb_hubbotnick")
	tCtrls["stb_hubbotdesc"]            = self:GetCtrl("stb_hubbotdesc")
	tCtrls["stb_hubbotemail"]           = self:GetCtrl("stb_hubbotemail")
	tCtrls["stb_opchat"]                = self:GetCtrl("stb_opchat")
	tCtrls["stb_opchatnick"]            = self:GetCtrl("stb_opchatnick")
	tCtrls["stb_opchatdesc"]            = self:GetCtrl("stb_opchatdesc")
	tCtrls["stb_opchatemail"]           = self:GetCtrl("stb_opchatemail")
	-- 7. More general
	tCtrls["stb_maxusers"]              = self:GetCtrl("stb_maxusers")
	tCtrls["stb_language"]              = self:GetCtrl("stb_language")
	tCtrls["stb_defaulttempban"]        = self:GetCtrl("stb_defaulttempban")
	tCtrls["stt_minutes2"]              = self:GetCtrl("stt_minutes2")
	tCtrls["stb_textfiles"]             = self:GetCtrl("stb_textfiles")
	tCtrls["stb_hubowneremail"]         = self:GetCtrl("stb_hubowneremail")
	tCtrls["stb_mainrediraddr"]         = self:GetCtrl("stb_mainrediraddr")
	tCtrls["stb_regonlyhub"]            = self:GetCtrl("stb_regonlyhub")
	tCtrls["stb_regonlymsg"]            = self:GetCtrl("stb_regonlymsg")
	tCtrls["stb_regonlyrediraddr"]      = self:GetCtrl("stb_regonlyrediraddr")
	-- 8. Ban handling
	tCtrls["stb_banmessage"]            = self:GetCtrl("stb_banmessage")
	tCtrls["stt_banmsgaddmsg"]          = self:GetCtrl("stt_banmsgaddmsg")
	tCtrls["stb_tempbanrediraddr"]      = self:GetCtrl("stb_tempbanrediraddr")
	tCtrls["stb_permbanrediraddr"]      = self:GetCtrl("stb_permbanrediraddr")
	-- 9. MyINFO processing
	tCtrls["stb_myinfoprocessing"]      = self:GetCtrl("stb_myinfoprocessing")
	tCtrls["stt_myinfosendminutes"]     = self:GetCtrl("stt_myinfosendminutes")
	tCtrls["stb_desctag"]               = self:GetCtrl("stb_desctag")
	tCtrls["stb_userwotag"]             = self:GetCtrl("stb_userwotag")
	tCtrls["stt_userwotagmsg"]          = self:GetCtrl("stt_userwotagmsg")
	tCtrls["stt_userwotagrediraddr"]    = self:GetCtrl("stt_userwotagrediraddr")
	-- 10. Advanced security
	tCtrls["stb_experts"]               = self:GetCtrl("stb_experts")
	tCtrls["stb_passwordprot"]          = self:GetCtrl("stb_passwordprot")
	tCtrls["stb_passwordbruteforce"]    = self:GetCtrl("stb_passwordbruteforce")
	tCtrls["stt_passwordbftbt"]         = self:GetCtrl("stt_passwordbftbt")
	tCtrls["stt_passwordhours"]         = self:GetCtrl("stt_passwordhours")
	-- 11. More rules
	tCtrls["stb_hubslimits"]            = self:GetCtrl("stb_hubslimits")
	tCtrls["stt_maxhubs"]               = self:GetCtrl("stt_maxhubs")
	tCtrls["stt_maxhubsmsg"]            = self:GetCtrl("stt_maxhubsmsg")
	tCtrls["stb_slotslimits"]           = self:GetCtrl("stb_slotslimits")
	tCtrls["stt_minslots"]              = self:GetCtrl("stt_minslots")
	tCtrls["stt_maxslots"]              = self:GetCtrl("stt_maxslots")
	tCtrls["stt_slotsmsg"]              = self:GetCtrl("stt_slotsmsg")
	tCtrls["stb_hubslotslimits"]        = self:GetCtrl("stb_hubslotslimits")
	tCtrls["stt_hubslothubs"]           = self:GetCtrl("stt_hubslothubs")
	tCtrls["stt_hubslotslots"]          = self:GetCtrl("stt_hubslotslots")
	tCtrls["stt_hubslotsmsg"]           = self:GetCtrl("stt_hubslotsmsg")
	-- 12. More deflood
	tCtrls["stb_defloodprivate"]        = self:GetCtrl("stb_defloodprivate")
	tCtrls["stt_seconds9"]              = self:GetCtrl("stt_seconds9")
	tCtrls["stt_seconds10"]             = self:GetCtrl("stt_seconds10")
	tCtrls["stt_interval2"]             = self:GetCtrl("stt_interval2")
	tCtrls["stt_seconds11"]             = self:GetCtrl("stt_seconds11")
	tCtrls["stb_defloodprivatesame"]    = self:GetCtrl("stb_defloodprivatesame")
	tCtrls["stt_seconds12"]             = self:GetCtrl("stt_seconds12")
	tCtrls["stb_deflood_privatesameml"] = self:GetCtrl("stb_deflood_privatesameml")
	tCtrls["stt_with2"]                 = self:GetCtrl("stt_with2")
	tCtrls["stt_lines2"]                = self:GetCtrl("stt_lines2")
	tCtrls["stb_defloodprivperuser"]    = self:GetCtrl("stb_defloodprivperuser")
	tCtrls["stt_defloodmaxmsgs"]        = self:GetCtrl("stt_defloodmaxmsgs")
	tCtrls["stb_defloodreceiveddata"]   = self:GetCtrl("stb_defloodreceiveddata")
	tCtrls["stt_seconds13"]             = self:GetCtrl("stt_seconds13")
	tCtrls["stt_seconds14"]             = self:GetCtrl("stt_seconds14")
	tCtrls["stb_defloodwarns"]          = self:GetCtrl("stb_defloodwarns")
	tCtrls["stt_after"]                 = self:GetCtrl("stt_after")
	tCtrls["stt_warnings"]              = self:GetCtrl("stt_warnings")
	tCtrls["stb_defloodnewconnsameip"]  = self:GetCtrl("stb_defloodnewconnsameip")
	tCtrls["stt_seconds15"]             = self:GetCtrl("stt_seconds15")
	tCtrls["stb_defloodprivatelimits"]  = self:GetCtrl("stb_defloodprivatelimits")
	tCtrls["stt_limit_length2"]         = self:GetCtrl("stt_limit_length2")
	tCtrls["stt_limit_lines2"]          = self:GetCtrl("stt_limit_lines2")
	tCtrls["stb_defloodmaxusersfromsameip"] = self:GetCtrl("stb_defloodmaxusersfromsameip")
	tCtrls["stb_defloodreconntime"]     = self:GetCtrl("stb_defloodreconntime")
	tCtrls["stt_min"]                   = self:GetCtrl("stt_min")
	tCtrls["stt_sec3"]                  = self:GetCtrl("stt_sec3")
	-- 13. More more deflood
	tCtrls["stb_defloodsearch"]         = self:GetCtrl("stb_defloodsearch")
	tCtrls["stt_seconds16"]             = self:GetCtrl("stt_seconds16")
	tCtrls["stt_seconds17"]             = self:GetCtrl("stt_seconds17")
	tCtrls["stt_interval3"]             = self:GetCtrl("stt_interval3")
	tCtrls["stt_seconds18"]             = self:GetCtrl("stt_seconds18")
	tCtrls["stb_defloodsearchsame"]     = self:GetCtrl("stb_defloodsearchsame")
	tCtrls["stt_seconds19"]             = self:GetCtrl("stt_seconds19")
	tCtrls["stb_searchreply"]           = self:GetCtrl("stb_searchreply")
	tCtrls["stt_seconds20"]             = self:GetCtrl("stt_seconds20")
	tCtrls["stt_seconds21"]             = self:GetCtrl("stt_seconds21")
	tCtrls["stb_defloodmaxsr"]          = self:GetCtrl("stb_defloodmaxsr")
	tCtrls["stb_defloodgetnicklist"]    = self:GetCtrl("stb_defloodgetnicklist")
	tCtrls["stt_minutes3"]              = self:GetCtrl("stt_minutes3")
	tCtrls["stb_defloodmyinfo"]         = self:GetCtrl("stb_defloodmyinfo")
	tCtrls["stt_seconds22"]             = self:GetCtrl("stt_seconds22")
	tCtrls["stt_seconds23"]             = self:GetCtrl("stt_seconds23")
	tCtrls["stb_defloodsearchlimits"]   = self:GetCtrl("stb_defloodsearchlimits")
	tCtrls["stt_minimum"]               = self:GetCtrl("stt_minimum")
	tCtrls["stt_max3"]                  = self:GetCtrl("stt_max3")
	tCtrls["stb_defloodsrlimit"]        = self:GetCtrl("stb_defloodsrlimit")
	tCtrls["stt_max4"]                  = self:GetCtrl("stt_max4")
	tCtrls["stb_defloodmyinfolimit"]    = self:GetCtrl("stb_defloodmyinfolimit")
	tCtrls["stt_max5"]                  = self:GetCtrl("stt_max5")
	-- Scripts tab
	tCtrls["LUA_REFRESH"]               = self:GetCtrl("wxID_LUA_REFRESH")
	tCtrls["LUA_UP"]                    = self:GetCtrl("wxID_LUA_UP")
	tCtrls["LUA_DOWN"]                  = self:GetCtrl("wxID_LUA_DOWN")
	tCtrls["LUA_CHECK"]                 = self:GetCtrl("wxID_LUA_CHECK")
	tCtrls["LUA_RESTART"]               = self:GetCtrl("wxID_LUA_RESTART")
	tCtrls["LUA_LOAD"]                  = self:GetCtrl("wxID_LUA_LOAD")
	tCtrls["LUA_SAVE"]                  = self:GetCtrl("wxID_LUA_SAVE")
	-- Registered users tab
	tCtrls["REG_ADD"]                   = self:GetCtrl("wxID_REG_ADD")
	tCtrls["REG_MOD"]                   = self:GetCtrl("wxID_REG_MOD")
	tCtrls["REG_DEL"]                   = self:GetCtrl("wxID_REG_DEL")
	tCtrls["stb_profman"]               = self:GetCtrl("stb_profman")
	tCtrls["PROF_ALL"]                  = self:GetCtrl("wxID_PROF_ALL")
	tCtrls["PROF_CLEAR"]                = self:GetCtrl("wxID_PROF_CLEAR")
	tCtrls["PROF_UP"]                   = self:GetCtrl("wxID_PROF_UP")
	tCtrls["PROF_DOWN"]                 = self:GetCtrl("wxID_PROF_DOWN")
	tCtrls["PROF_ADD"]                  = self:GetCtrl("wxID_PROF_ADD")
	tCtrls["PROF_DEL"]                  = self:GetCtrl("wxID_PROF_DEL")
	-- Bans tab
	tCtrls["REFRESH_BANS"]              = self:GetCtrl("wxID_REFRESH_BANS")
	tCtrls["CLEAR_TB"]                  = self:GetCtrl("wxID_CLEAR_TB")
	tCtrls["CLEAR_PB"]                  = self:GetCtrl("wxID_CLEAR_PB")
	tCtrls["REFRESH_RANGEBANS"]         = self:GetCtrl("wxID_REFRESH_RANGEBANS")
	tCtrls["CLEAR_TRB"]                 = self:GetCtrl("wxID_CLEAR_TRB")
	tCtrls["CLEAR_PRB"]                 = self:GetCtrl("wxID_CLEAR_PRB")
	-- Texts tab
	tCtrls["RELOADLIST"]                = self:GetCtrl("wxID_TEXT_RELOADLIST")
	tCtrls["TEXT_RELOAD"]               = self:GetCtrl("wxID_TEXT_RELOAD")
	tCtrls["TEXT_LOAD"]                 = self:GetCtrl("wxID_TEXT_LOAD")
	tCtrls["TEXT_SAVE"]                 = self:GetCtrl("wxID_TEXT_SAVE")
end

function tFuncs.TranslateGUI(self)
	-- Login tab
	tCtrls["tab"]:SetPageText(0,tCtrls["tLangs"][1])
	tCtrls["stt_login_address"]:SetLabel(tCtrls["tLangs"][2])
	tCtrls["stt_login_nick"]:SetLabel(tCtrls["tLangs"][3])
	tCtrls["stt_login_passwd"]:SetLabel(tCtrls["tLangs"][4])
	tCtrls["stt_login_desc"]:SetLabel(tCtrls["tLangs"][5])
	tCtrls["stt_login_tag"]:SetLabel(tCtrls["tLangs"][6])
	tCtrls["stt_login_email"]:SetLabel(tCtrls["tLangs"][7])
	tCtrls["stt_login_share"]:SetLabel(tCtrls["tLangs"][8])
	tCtrls["stt_login_lang"]:SetLabel(tCtrls["tLangs"][9])
	tCtrls["cmd_save"]:SetLabel(tCtrls["tLangs"][10])
	self:GetCtrl("ID_PNL_LOGIN"):Layout()
	-- Settings tab
	tCtrls["tab"]:SetPageText(1,tCtrls["tLangs"][11])
	tCtrls["ACCEPT"]:SetLabel(tCtrls["tLangs"][12])
	local item = tCtrls["settings_tree"]:GetFirstVisibleItem()
	local Next = function() item = tCtrls["settings_tree"]:GetNextVisible(item) end
	if not wx.__WXMSW__ then Next() end
	tCtrls["settings_tree"]:SetItemText(item,tCtrls["tLangs"][13]) Next()
	tCtrls["settings_tree"]:SetItemText(item,tCtrls["tLangs"][14]) Next()
	tCtrls["settings_tree"]:SetItemText(item,tCtrls["tLangs"][15]) Next()
	tCtrls["settings_tree"]:SetItemText(item,tCtrls["tLangs"][16]) Next()
	tCtrls["settings_tree"]:SetItemText(item,tCtrls["tLangs"][17]) Next()
	tCtrls["settings_tree"]:SetItemText(item,tCtrls["tLangs"][18]) Next()
	tCtrls["settings_tree"]:SetItemText(item,tCtrls["tLangs"][19]) Next()
	tCtrls["settings_tree"]:SetItemText(item,tCtrls["tLangs"][20]) Next()
	tCtrls["settings_tree"]:SetItemText(item,tCtrls["tLangs"][21]) Next()
	tCtrls["settings_tree"]:SetItemText(item,tCtrls["tLangs"][22]) Next()
	tCtrls["settings_tree"]:SetItemText(item,tCtrls["tLangs"][23]) Next()
	tCtrls["settings_tree"]:SetItemText(item,tCtrls["tLangs"][24]) Next()
	tCtrls["settings_tree"]:SetItemText(item,tCtrls["tLangs"][25]) Next()
	-- 1. General settings
	tCtrls["stb_hubname"]:SetLabel(tCtrls["tLangs"][26])
	tCtrls["stb_hubtopic"]:SetLabel(tCtrls["tLangs"][27])
	tCtrls["stb_hubdesc"]:SetLabel(tCtrls["tLangs"][28])
	tCtrls["chk"]["chk_0"]:SetLabel(tCtrls["tLangs"][29])
	tCtrls["stb_hubaddress"]:SetLabel(tCtrls["tLangs"][30])
	tCtrls["chk"]["chk_43"]:SetLabel(tCtrls["tLangs"][31])
	tCtrls["chk"]["chk_42"]:SetLabel(tCtrls["tLangs"][32])
	tCtrls["stb_tcp"]:SetLabel(tCtrls["tLangs"][33])
	tCtrls["txt"]["txt_3"]:SetToolTip(tCtrls["tLangs"][34])
	tCtrls["stb_udp"]:SetLabel(tCtrls["tLangs"][35])
	tCtrls["stb_adminnick"]:SetLabel(tCtrls["tLangs"][36])
	tCtrls["stb_hublistregs"]:SetLabel(tCtrls["tLangs"][37])
	tCtrls["txt"]["txt_7"]:SetToolTip(tCtrls["tLangs"][38])
	tCtrls["chk"]["chk_4"]:SetLabel(tCtrls["tLangs"][39])
	self:GetCtrl("ID_PANEL1"):Layout()
	-- 2. Advanced
	tCtrls["stb_hubstartup"]:SetLabel(tCtrls["tLangs"][40])
	tCtrls["chk"]["chk_1"]:SetLabel(tCtrls["tLangs"][41])
	tCtrls["chk"]["chk_25"]:SetLabel(tCtrls["tLangs"][42])
	tCtrls["chk"]["chk_26"]:SetLabel(tCtrls["tLangs"][43])
	tCtrls["chk"]["chk_24"]:SetLabel(tCtrls["tLangs"][44])
	tCtrls["stb_hubcommands"]:SetLabel(tCtrls["tLangs"][45])
	tCtrls["chk"]["chk_36"]:SetLabel(tCtrls["tLangs"][46])
	tCtrls["stt_cmdprefixes"]:SetLabel(tCtrls["tLangs"][47])
	tCtrls["stb_scripting"]:SetLabel(tCtrls["tLangs"][48])
	tCtrls["chk"]["chk_22"]:SetLabel(tCtrls["tLangs"][49])
	tCtrls["chk"]["chk_33"]:SetLabel(tCtrls["tLangs"][50])
	tCtrls["chk"]["chk_54"]:SetLabel(tCtrls["tLangs"][51])
	tCtrls["chk"]["chk_55"]:SetLabel(tCtrls["tLangs"][52])
	tCtrls["stb_kickmessages"]:SetLabel(tCtrls["tLangs"][53])
	tCtrls["chk"]["chk_27"]:SetLabel(tCtrls["tLangs"][54])
	tCtrls["chk"]["chk_28"]:SetLabel(tCtrls["tLangs"][55])
	tCtrls["stb_statusmessages"]:SetLabel(tCtrls["tLangs"][56])
	tCtrls["chk"]["chk_29"]:SetLabel(tCtrls["tLangs"][57])
	tCtrls["chk"]["chk_30"]:SetLabel(tCtrls["tLangs"][58])
	tCtrls["stb_pinger"]:SetLabel(tCtrls["tLangs"][59])
	tCtrls["chk"]["chk_39"]:SetLabel(tCtrls["tLangs"][60])
	tCtrls["chk"]["chk_38"]:SetLabel(tCtrls["tLangs"][61])
	tFuncs:GetCtrl("ID_PANEL2"):Layout()
	-- 3. Rules
	tCtrls["stb_nicklimits"]:SetLabel(tCtrls["tLangs"][62])
	tCtrls["stt_minnicklen"]:SetLabel(tCtrls["tLangs"][63])
	tCtrls["stt_maxnicklen"]:SetLabel(tCtrls["tLangs"][64])
	tCtrls["stt_nicklimitmsg"]:SetLabel(tCtrls["tLangs"][65])
	tCtrls["num"]["num_60"]:SetToolTip(tCtrls["tLangs"][66])
	tCtrls["num"]["num_61"]:SetToolTip(tCtrls["tLangs"][66])
	tCtrls["txt"]["txt_31"]:SetToolTip(tCtrls["tLangs"][67])
	tCtrls["chk"]["chk_44"]:SetLabel(tCtrls["tLangs"][68])
	tCtrls["txt"]["txt_32"]:SetToolTip(tCtrls["tLangs"][69])
	tCtrls["stb_sharelimits"]:SetLabel(tCtrls["tLangs"][70])
	tCtrls["stt_minshare"]:SetLabel(tCtrls["tLangs"][71])
	tCtrls["stt_maxshare"]:SetLabel(tCtrls["tLangs"][72])
	tCtrls["stt_sharelimitmsg"]:SetLabel(tCtrls["tLangs"][65])
	tCtrls["num"]["num_1"]:SetToolTip(tCtrls["tLangs"][66])
	tCtrls["num"]["num_3"]:SetToolTip(tCtrls["tLangs"][66])
	tCtrls["chk"]["chk_7"]:SetLabel(tCtrls["tLangs"][68])
	tCtrls["txt"]["txt_11"]:SetToolTip(tCtrls["tLangs"][73])
	tCtrls["txt"]["txt_12"]:SetToolTip(tCtrls["tLangs"][69])
	self:GetCtrl("ID_PANEL3"):Layout()
	-- 4. DeFlood
	local tActions = {
	tCtrls["tLangs"][74],
	tCtrls["tLangs"][75],
	tCtrls["tLangs"][76],
	tCtrls["tLangs"][77],
	tCtrls["tLangs"][78],
	tCtrls["tLangs"][79],
	tCtrls["tLangs"][80],
	}
	local tGlobal = {
	tCtrls["tLangs"][74],
	tCtrls["tLangs"][81],
	tCtrls["tLangs"][82],
	}
	local TranslateComboBox = function(combo)
		local i = combo:GetSelection(); combo:Clear(); combo:Append(tActions); combo:SetSelection(i)
	end
	TranslateComboBox(tCtrls["num"]["num_21"])
	TranslateComboBox(tCtrls["num"]["num_68"])
	TranslateComboBox(tCtrls["num"]["num_24"])
	TranslateComboBox(tCtrls["num"]["num_27"])
	TranslateComboBox(tCtrls["num"]["num_81"])
	TranslateComboBox(tCtrls["num"]["num_84"])
	TranslateComboBox(tCtrls["num"]["num_87"])
	TranslateComboBox(tCtrls["num"]["num_90"])
	tCtrls["stb_defloodglobal"]:SetLabel(tCtrls["tLangs"][83])
	tCtrls["stt_sec1"]:SetLabel(tCtrls["tLangs"][84])
	tCtrls["stt_for"]:SetLabel(tCtrls["tLangs"][85])
	tCtrls["stt_sec2"]:SetLabel(tCtrls["tLangs"][84])
	local i = tCtrls["num"]["num_57"]:GetSelection()
	tCtrls["num"]["num_57"]:Clear()
	tCtrls["num"]["num_57"]:Append(tGlobal)
	tCtrls["num"]["num_57"]:SetSelection(0)
	tCtrls["stb_defloodmain"]:SetLabel(tCtrls["tLangs"][86])
	tCtrls["stt_seconds1"]:SetLabel(tCtrls["tLangs"][87])
	tCtrls["stt_seconds2"]:SetLabel(tCtrls["tLangs"][87])
	tCtrls["stt_interval1"]:SetLabel(tCtrls["tLangs"][88])
	tCtrls["stt_seconds3"]:SetLabel(tCtrls["tLangs"][87])
	tCtrls["stb_defloodmainsame"]:SetLabel(tCtrls["tLangs"][89])
	tCtrls["stt_seconds4"]:SetLabel(tCtrls["tLangs"][87])
	tCtrls["stb_defloodmainsameml"]:SetLabel(tCtrls["tLangs"][90])
	tCtrls["stt_with1"]:SetLabel(tCtrls["tLangs"][91])
	tCtrls["stt_lines1"]:SetLabel(tCtrls["tLangs"][92])
	tCtrls["stb_defloodctm"]:SetLabel(tCtrls["tLangs"][93])
	tCtrls["stt_seconds5"]:SetLabel(tCtrls["tLangs"][87])
	tCtrls["stt_seconds6"]:SetLabel(tCtrls["tLangs"][87])
	tCtrls["stb_defloodrctm"]:SetLabel(tCtrls["tLangs"][94])
	tCtrls["stt_seconds7"]:SetLabel(tCtrls["tLangs"][87])
	tCtrls["stt_seconds8"]:SetLabel(tCtrls["tLangs"][87])
	tCtrls["stb_defloodmainlimits"]:SetLabel(tCtrls["tLangs"][95])
	tCtrls["stt_limit_length1"]:SetLabel(tCtrls["tLangs"][96])
	tCtrls["stt_limit_lines1"]:SetLabel(tCtrls["tLangs"][97])
	tCtrls["stb_defloodtempban"]:SetLabel(tCtrls["tLangs"][98])
	tCtrls["stt_minutes1"]:SetLabel(tCtrls["tLangs"][99])
	tCtrls["stb_defloodmaxuserlogins"]:SetLabel(tCtrls["tLangs"][100])
	tCtrls["stt_per10sec"]:SetLabel(tCtrls["tLangs"][101])
	tCtrls["stb_defloodctmlen"]:SetLabel(tCtrls["tLangs"][102])
	tCtrls["stt_max1"]:SetLabel(tCtrls["tLangs"][104])
	tCtrls["stb_defloodrctmlen"]:SetLabel(tCtrls["tLangs"][103])
	tCtrls["stt_max2"]:SetLabel(tCtrls["tLangs"][104])
	tCtrls["chk"]["chk_35"]:SetLabel(tCtrls["tLangs"][105])
	self:GetCtrl("ID_PANEL4"):Layout()
	-- 5. MOTD
	tCtrls["stb_motd"]:SetLabel(tCtrls["tLangs"][106])
	tCtrls["chk"]["chk_37"]:SetLabel(tCtrls["tLangs"][107])
	tCtrls["chk"]["chk_34"]:SetLabel(tCtrls["tLangs"][108])
	self:GetCtrl("ID_PANEL5"):Layout()
	-- 6. Default bots
	tCtrls["stb_hubbot"]:SetLabel(tCtrls["tLangs"][109])
	tCtrls["chk"]["chk_17"]:SetLabel(tCtrls["tLangs"][110])
	tCtrls["stb_hubbotnick"]:SetLabel(tCtrls["tLangs"][3])
	tCtrls["chk"]["chk_18"]:SetLabel(tCtrls["tLangs"][111])
	tCtrls["stb_hubbotdesc"]:SetLabel(tCtrls["tLangs"][5])
	tCtrls["stb_hubbotemail"]:SetLabel(tCtrls["tLangs"][7])
	tCtrls["stb_opchat"]:SetLabel(tCtrls["tLangs"][112])
	tCtrls["chk"]["chk_19"]:SetLabel(tCtrls["tLangs"][110])
	tCtrls["stb_opchatnick"]:SetLabel(tCtrls["tLangs"][3])
	tCtrls["stb_opchatdesc"]:SetLabel(tCtrls["tLangs"][5])
	tCtrls["stb_opchatemail"]:SetLabel(tCtrls["tLangs"][7])
	self:GetCtrl("ID_PANEL6"):Layout()
	-- 7. More general
	tCtrls["stb_maxusers"]:SetLabel(tCtrls["tLangs"][113])
	tCtrls["stb_language"]:SetLabel(tCtrls["tLangs"][9])
	tCtrls["stb_defaulttempban"]:SetLabel(tCtrls["tLangs"][114])
	tCtrls["stt_minutes2"]:SetLabel(tCtrls["tLangs"][99])
	tCtrls["stb_textfiles"]:SetLabel(tCtrls["tLangs"][115])
	tCtrls["chk"]["chk_31"]:SetLabel(tCtrls["tLangs"][116])
	tCtrls["chk"]["chk_32"]:SetLabel(tCtrls["tLangs"][117])
	tCtrls["stb_hubowneremail"]:SetLabel(tCtrls["tLangs"][118])
	tCtrls["stb_mainrediraddr"]:SetLabel(tCtrls["tLangs"][119])
	tCtrls["chk"]["chk_2"]:SetLabel(tCtrls["tLangs"][120])
	tCtrls["chk"]["chk_3"]:SetLabel(tCtrls["tLangs"][121])
	tCtrls["stb_regonlyhub"]:SetLabel(tCtrls["tLangs"][122])
	tCtrls["chk"]["chk_5"]:SetLabel(tCtrls["tLangs"][123])
	tCtrls["stb_regonlymsg"]:SetLabel(tCtrls["tLangs"][124])
	tCtrls["stb_regonlyrediraddr"]:SetLabel(tCtrls["tLangs"][125])
	tCtrls["chk"]["chk_6"]:SetLabel(tCtrls["tLangs"][126])
	tCtrls["txt"]["txt_9"]:SetToolTip(tCtrls["tLangs"][127])
	self:GetCtrl("ID_PANEL7"):Layout()
	-- 8. Ban handling
	tCtrls["stb_banmessage"]:SetLabel(tCtrls["tLangs"][128])
	tCtrls["chk"]["chk_46"]:SetLabel(tCtrls["tLangs"][129])
	tCtrls["chk"]["chk_47"]:SetLabel(tCtrls["tLangs"][130])
	tCtrls["chk"]["chk_48"]:SetLabel(tCtrls["tLangs"][131])
	tCtrls["chk"]["chk_49"]:SetLabel(tCtrls["tLangs"][132])
	tCtrls["chk"]["chk_50"]:SetLabel(tCtrls["tLangs"][133])
	tCtrls["stt_banmsgaddmsg"]:SetLabel(tCtrls["tLangs"][134])
	tCtrls["stb_tempbanrediraddr"]:SetLabel(tCtrls["tLangs"][135])
	tCtrls["chk"]["chk_20"]:SetLabel(tCtrls["tLangs"][126])
	tCtrls["txt"]["txt_27"]:SetToolTip(tCtrls["tLangs"][127])
	tCtrls["stb_permbanrediraddr"]:SetLabel(tCtrls["tLangs"][136])
	tCtrls["chk"]["chk_21"]:SetLabel(tCtrls["tLangs"][126])
	tCtrls["txt"]["txt_28"]:SetToolTip(tCtrls["tLangs"][127])
	self:GetCtrl("ID_PANEL8"):Layout()
	-- 9. MyINFO processing
	tCtrls["stb_myinfoprocessing"]:SetLabel(tCtrls["tLangs"][137])
	tCtrls["stt_myinfosendminutes"]:SetLabel(tCtrls["tLangs"][138])
	tCtrls["chk"]["chk_13"]:SetLabel(tCtrls["tLangs"][139])
	tCtrls["chk"]["chk_14"]:SetLabel(tCtrls["tLangs"][140])
	tCtrls["chk"]["chk_15"]:SetLabel(tCtrls["tLangs"][141])
	tCtrls["chk"]["chk_16"]:SetLabel(tCtrls["tLangs"][142])
	tCtrls["chk"]["chk_11"]:SetLabel(tCtrls["tLangs"][143])
	tCtrls["chk"]["chk_12"]:SetLabel(tCtrls["tLangs"][144])
	local tmyinfotosend = {tCtrls["tLangs"][145],tCtrls["tLangs"][146],tCtrls["tLangs"][147]}
	local i = tCtrls["num"]["num_11"]:GetSelection()
	tCtrls["num"]["num_11"]:Clear()
	tCtrls["num"]["num_11"]:Append(tmyinfotosend)
	tCtrls["num"]["num_11"]:SetSelection(i)
	tCtrls["num"]["num_11"]:SetToolTip(tCtrls["tLangs"][148])
	tCtrls["stb_desctag"]:SetLabel(tCtrls["tLangs"][149])
	tCtrls["chk"]["chk_51"]:SetLabel(tCtrls["tLangs"][150])
	tCtrls["chk"]["chk_52"]:SetLabel(tCtrls["tLangs"][151])
	self:GetCtrl("stb_userwotag"):SetLabel(tCtrls["tLangs"][152])
	local tActions = {tCtrls["tLangs"][153],tCtrls["tLangs"][154],tCtrls["tLangs"][68]}
	local i = tCtrls["num"]["num_10"]:GetSelection()
	tCtrls["num"]["num_10"]:Clear()
	tCtrls["num"]["num_10"]:Append(tActions)
	tCtrls["num"]["num_10"]:SetSelection(i)
	tCtrls["stt_userwotagmsg"]:SetLabel(tCtrls["tLangs"][65])
	tCtrls["stt_userwotagrediraddr"]:SetLabel(tCtrls["tLangs"][125])
	tCtrls["txt"]["txt_20"]:SetToolTip(tCtrls["tLangs"][127])
	self:GetCtrl("ID_PANEL9"):Layout()
	-- 10. Advanced security
	tCtrls["stb_experts"]:SetLabel(tCtrls["tLangs"][155])
	tCtrls["chk"]["chk_23"]:SetLabel(tCtrls["tLangs"][156])
	tCtrls["chk"]["chk_45"]:SetLabel(tCtrls["tLangs"][157])
	tCtrls["chk"]["chk_53"]:SetLabel(tCtrls["tLangs"][158])
	tCtrls["stb_passwordprot"]:SetLabel(tCtrls["tLangs"][159])
	tCtrls["chk"]["chk_40"]:SetLabel(tCtrls["tLangs"][160])
	tCtrls["chk"]["chk_41"]:SetLabel(tCtrls["tLangs"][161])
	tCtrls["stb_passwordbruteforce"]:SetLabel(tCtrls["tLangs"][162])
	tCtrls["stt_passwordbftbt"]:SetLabel(tCtrls["tLangs"][163])
	tCtrls["stt_passwordhours"]:SetLabel(tCtrls["tLangs"][164])
	local tActions = {tCtrls["tLangs"][74],tCtrls["tLangs"][80],tCtrls["tLangs"][79]}
	local i = tCtrls["num"]["num_62"]:GetSelection()
	tCtrls["num"]["num_62"]:Clear()
	tCtrls["num"]["num_62"]:Append(tActions)
	tCtrls["num"]["num_62"]:SetSelection(i)
	self:GetCtrl("ID_PANEL10"):Layout()
	-- 11. More rules
	tCtrls["stb_hubslimits"]:SetLabel(tCtrls["tLangs"][165])
	tCtrls["stt_maxhubs"]:SetLabel(tCtrls["tLangs"][166])
	tCtrls["num"]["num_9"]:SetToolTip(tCtrls["tLangs"][66])
	tCtrls["stt_maxhubsmsg"]:SetLabel(tCtrls["tLangs"][65])
	tCtrls["txt"]["txt_17"]:SetToolTip(tCtrls["tLangs"][167])
	tCtrls["chk"]["chk_10"]:SetLabel(tCtrls["tLangs"][68])
	tCtrls["txt"]["txt_18"]:SetToolTip(tCtrls["tLangs"][127])
	tCtrls["stb_slotslimits"]:SetLabel(tCtrls["tLangs"][168])
	tCtrls["stt_minslots"]:SetLabel(tCtrls["tLangs"][169])
	tCtrls["num"]["num_5"]:SetToolTip(tCtrls["tLangs"][66])
	tCtrls["stt_maxslots"]:SetLabel(tCtrls["tLangs"][170])
	tCtrls["num"]["num_6"]:SetToolTip(tCtrls["tLangs"][66])
	tCtrls["stt_slotsmsg"]:SetLabel(tCtrls["tLangs"][65])
	tCtrls["txt"]["txt_13"]:SetToolTip(tCtrls["tLangs"][171])
	tCtrls["chk"]["chk_8"]:SetLabel(tCtrls["tLangs"][68])
	tCtrls["txt"]["txt_14"]:SetToolTip(tCtrls["tLangs"][127])
	tCtrls["stb_hubslotslimits"]:SetLabel(tCtrls["tLangs"][172])
	tCtrls["stt_hubslothubs"]:SetLabel(tCtrls["tLangs"][173])
	tCtrls["stt_hubslotslots"]:SetLabel(tCtrls["tLangs"][174])
	tCtrls["num"]["num_7"]:SetToolTip(tCtrls["tLangs"][66])
	tCtrls["num"]["num_8"]:SetToolTip(tCtrls["tLangs"][66])
	tCtrls["stt_hubslotsmsg"]:SetLabel(tCtrls["tLangs"][65])
	tCtrls["txt"]["txt_15"]:SetToolTip(tCtrls["tLangs"][175])
	tCtrls["chk"]["chk_9"]:SetLabel(tCtrls["tLangs"][68])
	tCtrls["txt"]["txt_16"]:SetToolTip(tCtrls["tLangs"][127])
	self:GetCtrl("ID_PANEL11"):Layout()
	-- 12. More deflood
	local tActions2 = {tCtrls["tLangs"][77],tCtrls["tLangs"][78],tCtrls["tLangs"][79],tCtrls["tLangs"][80]}
	TranslateComboBox(tCtrls["num"]["num_30"])
	TranslateComboBox(tCtrls["num"]["num_71"])
	TranslateComboBox(tCtrls["num"]["num_33"])
	TranslateComboBox(tCtrls["num"]["num_36"])
	TranslateComboBox(tCtrls["num"]["num_100"])
	TranslateComboBox(tCtrls["num"]["num_103"])
	tCtrls["stb_defloodprivate"]:SetLabel(tCtrls["tLangs"][176])
	tCtrls["stt_seconds9"]:SetLabel(tCtrls["tLangs"][87])
	tCtrls["stt_seconds10"]:SetLabel(tCtrls["tLangs"][87])
	tCtrls["stt_interval2"]:SetLabel(tCtrls["tLangs"][88])
	tCtrls["stt_seconds11"]:SetLabel(tCtrls["tLangs"][87])
	tCtrls["stb_defloodprivatesame"]:SetLabel(tCtrls["tLangs"][177])
	tCtrls["stt_seconds12"]:SetLabel(tCtrls["tLangs"][87])
	tCtrls["stb_deflood_privatesameml"]:SetLabel(tCtrls["tLangs"][178])
	tCtrls["stt_with2"]:SetLabel(tCtrls["tLangs"][91])
	tCtrls["stt_lines2"]:SetLabel(tCtrls["tLangs"][92])
	tCtrls["stb_defloodprivperuser"]:SetLabel(tCtrls["tLangs"][179])
	tCtrls["stt_defloodmaxmsgs"]:SetLabel(tCtrls["tLangs"][180])
	tCtrls["stb_defloodreceiveddata"]:SetLabel(tCtrls["tLangs"][181])
	tCtrls["stt_seconds13"]:SetLabel(tCtrls["tLangs"][87])
	tCtrls["stt_seconds14"]:SetLabel(tCtrls["tLangs"][87])
	tCtrls["stb_defloodwarns"]:SetLabel(tCtrls["tLangs"][182])
	local i = tCtrls["num"]["num_52"]:GetSelection()
	tCtrls["num"]["num_52"]:Clear()
	tCtrls["num"]["num_52"]:Append(tActions2)
	tCtrls["num"]["num_52"]:SetSelection(i)
	tCtrls["stt_after"]:SetLabel(tCtrls["tLangs"][183])
	tCtrls["stt_warnings"]:SetLabel(tCtrls["tLangs"][184])
	tCtrls["stb_defloodnewconnsameip"]:SetLabel(tCtrls["tLangs"][185])
	tCtrls["stt_seconds15"]:SetLabel(tCtrls["tLangs"][87])
	tCtrls["stb_defloodprivatelimits"]:SetLabel(tCtrls["tLangs"][186])
	tCtrls["stt_limit_length2"]:SetLabel(tCtrls["tLangs"][96])
	tCtrls["stt_limit_lines2"]:SetLabel(tCtrls["tLangs"][97])
	tCtrls["stb_defloodmaxusersfromsameip"]:SetLabel(tCtrls["tLangs"][187])
	tCtrls["stb_defloodreconntime"]:SetLabel(tCtrls["tLangs"][188])
	tCtrls["stt_min"]:SetLabel(tCtrls["tLangs"][189])
	tCtrls["stt_sec3"]:SetLabel(tCtrls["tLangs"][84])
	self:GetCtrl("ID_PANEL12"):Layout()
	-- 13. More more deflood
	TranslateComboBox(tCtrls["num"]["num_39"])
	TranslateComboBox(tCtrls["num"]["num_74"])
	TranslateComboBox(tCtrls["num"]["num_42"])
	TranslateComboBox(tCtrls["num"]["num_95"])
	TranslateComboBox(tCtrls["num"]["num_98"])
	TranslateComboBox(tCtrls["num"]["num_48"])
	TranslateComboBox(tCtrls["num"]["num_45"])
	TranslateComboBox(tCtrls["num"]["num_77"])
	tCtrls["stb_defloodsearch"]:SetLabel(tCtrls["tLangs"][190])
	tCtrls["stt_seconds16"]:SetLabel(tCtrls["tLangs"][87])
	tCtrls["stt_seconds17"]:SetLabel(tCtrls["tLangs"][87])
	tCtrls["stt_interval3"]:SetLabel(tCtrls["tLangs"][88])
	tCtrls["stt_seconds18"]:SetLabel(tCtrls["tLangs"][87])
	tCtrls["stb_defloodsearchsame"]:SetLabel(tCtrls["tLangs"][191])
	tCtrls["stt_seconds19"]:SetLabel(tCtrls["tLangs"][87])
	tCtrls["stb_searchreply"]:SetLabel(tCtrls["tLangs"][192])
	tCtrls["stt_seconds20"]:SetLabel(tCtrls["tLangs"][87])
	tCtrls["stt_seconds21"]:SetLabel(tCtrls["tLangs"][87])
	tCtrls["stb_defloodmaxsr"]:SetLabel(tCtrls["tLangs"][193])
	tCtrls["stb_defloodgetnicklist"]:SetLabel(tCtrls["tLangs"][194])
	tCtrls["stt_minutes3"]:SetLabel(tCtrls["tLangs"][99])
	tCtrls["stb_defloodmyinfo"]:SetLabel(tCtrls["tLangs"][195])
	tCtrls["stt_seconds22"]:SetLabel(tCtrls["tLangs"][87])
	tCtrls["stt_seconds23"]:SetLabel(tCtrls["tLangs"][87])
	tCtrls["stb_defloodsearchlimits"]:SetLabel(tCtrls["tLangs"][196])
	tCtrls["stt_minimum"]:SetLabel(tCtrls["tLangs"][197])
	tCtrls["stt_max3"]:SetLabel(tCtrls["tLangs"][104])
	tCtrls["stb_defloodsrlimit"]:SetLabel(tCtrls["tLangs"][198])
	tCtrls["stt_max4"]:SetLabel(tCtrls["tLangs"][104])
	tCtrls["stb_defloodmyinfolimit"]:SetLabel(tCtrls["tLangs"][199])
	tCtrls["stt_max5"]:SetLabel(tCtrls["tLangs"][104])
	tCtrls["num"]["num_17"]:SetToolTip(tCtrls["tLangs"][66])
	self:GetCtrl("ID_PANEL13"):Layout()
	-- Scripts tab
	tCtrls["tab"]:SetPageText(2,tCtrls["tLangs"][200])
	tCtrls["LUA_REFRESH"]:SetLabel(tCtrls["tLangs"][201])
	tCtrls["LUA_UP"]:SetLabel(tCtrls["tLangs"][202])
	tCtrls["LUA_UP"]:SetToolTip(tCtrls["tLangs"][203])
	tCtrls["LUA_DOWN"]:SetLabel(tCtrls["tLangs"][204])
	tCtrls["LUA_DOWN"]:SetToolTip(tCtrls["tLangs"][205])
	tCtrls["LUA_CHECK"]:SetLabel(tCtrls["tLangs"][206])
	tCtrls["LUA_CHECK"]:SetToolTip(tCtrls["tLangs"][207])
	tCtrls["LUA_RESTART"]:SetLabel(tCtrls["tLangs"][208])
	tCtrls["LUA_RESTART"]:SetToolTip(tCtrls["tLangs"][209])
	tCtrls["LUA_LOAD"]:SetLabel(tCtrls["tLangs"][210])
	tCtrls["LUA_LOAD"]:SetToolTip(tCtrls["tLangs"][211])
	tCtrls["LUA_SAVE"]:SetLabel(tCtrls["tLangs"][212])
	tCtrls["LUA_SAVE"]:SetToolTip(tCtrls["tLangs"][213])
	-- Registered users tab
	tCtrls["tab"]:SetPageText(3,tCtrls["tLangs"][214])
	tCtrls["REG_ADD"]:SetLabel(tCtrls["tLangs"][215])
	tCtrls["REG_MOD"]:SetLabel(tCtrls["tLangs"][216])
	tCtrls["REG_DEL"]:SetLabel(tCtrls["tLangs"][217])
	tCtrls["stb_profman"]:SetLabel(tCtrls["tLangs"][218])
	tCtrls["lst_permissions"]:Clear()
	tCtrls["lst_permissions"]:Append({
	tCtrls["tLangs"][219],tCtrls["tLangs"][220],tCtrls["tLangs"][221],tCtrls["tLangs"][222],
	tCtrls["tLangs"][223],tCtrls["tLangs"][224],tCtrls["tLangs"][225],tCtrls["tLangs"][226],
	tCtrls["tLangs"][227],tCtrls["tLangs"][228],tCtrls["tLangs"][229],tCtrls["tLangs"][230],
	tCtrls["tLangs"][231],tCtrls["tLangs"][232],tCtrls["tLangs"][233],tCtrls["tLangs"][234],
	tCtrls["tLangs"][235],tCtrls["tLangs"][236],tCtrls["tLangs"][237],tCtrls["tLangs"][238],
	tCtrls["tLangs"][239],tCtrls["tLangs"][240],tCtrls["tLangs"][241],tCtrls["tLangs"][242],
	tCtrls["tLangs"][243],tCtrls["tLangs"][244],tCtrls["tLangs"][245],tCtrls["tLangs"][246],
	tCtrls["tLangs"][247],tCtrls["tLangs"][248],tCtrls["tLangs"][249],tCtrls["tLangs"][250],
	tCtrls["tLangs"][251],tCtrls["tLangs"][252],tCtrls["tLangs"][253],tCtrls["tLangs"][254],
	tCtrls["tLangs"][255],tCtrls["tLangs"][256],tCtrls["tLangs"][257],tCtrls["tLangs"][258],
	tCtrls["tLangs"][259],tCtrls["tLangs"][260],tCtrls["tLangs"][261],tCtrls["tLangs"][262],
	tCtrls["tLangs"][263],tCtrls["tLangs"][264],tCtrls["tLangs"][265],tCtrls["tLangs"][266],
	tCtrls["tLangs"][267],tCtrls["tLangs"][268],tCtrls["tLangs"][269],tCtrls["tLangs"][270],
	tCtrls["tLangs"][271],tCtrls["tLangs"][272],tCtrls["tLangs"][273],tCtrls["tLangs"][274],
	})
	tCtrls["PROF_ALL"]:SetLabel(tCtrls["tLangs"][275])
	tCtrls["PROF_CLEAR"]:SetLabel(tCtrls["tLangs"][276])
	tCtrls["PROF_UP"]:SetLabel(tCtrls["tLangs"][202])
	tCtrls["PROF_DOWN"]:SetLabel(tCtrls["tLangs"][204])
	tCtrls["PROF_ADD"]:SetLabel(tCtrls["tLangs"][277])
	tCtrls["PROF_DEL"]:SetLabel(tCtrls["tLangs"][217])
	-- Bans tab
	tCtrls["tab"]:SetPageText(4,tCtrls["tLangs"][278])
	tCtrls["REFRESH_BANS"]:SetLabel(tCtrls["tLangs"][279])
	tCtrls["CLEAR_TB"]:SetLabel(tCtrls["tLangs"][280])
	tCtrls["CLEAR_PB"]:SetLabel(tCtrls["tLangs"][281])
	tCtrls["REFRESH_RANGEBANS"]:SetLabel(tCtrls["tLangs"][282])
	tCtrls["CLEAR_TRB"]:SetLabel(tCtrls["tLangs"][283])
	tCtrls["CLEAR_PRB"]:SetLabel(tCtrls["tLangs"][284])
	-- Texts tab
	tCtrls["tab"]:SetPageText(5,tCtrls["tLangs"][285])
	tCtrls["RELOADLIST"]:SetLabel(tCtrls["tLangs"][286])
	tCtrls["TEXT_RELOAD"]:SetLabel(tCtrls["tLangs"][287])
	tCtrls["TEXT_LOAD"]:SetLabel(tCtrls["tLangs"][288])
	tCtrls["TEXT_SAVE"]:SetLabel(tCtrls["tLangs"][289])
	-- UDP debug
	self:GetCtrl("wxID_CMD_UDPCLEAR"):SetLabel(tCtrls["tLangs"][276])
end

function tFuncs.SaveSettings(self)
	local sf,err = io.open("Settings.xml","w+")
	if sf then
		sf:write("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\" ?>\n"..
		"<!--Please don't edit this file manually-->\n"..
		"<Settings>\n"..
		"\t<txt_login_address>"..self:GetCtrl("txt_login_address"):GetValue().."</txt_login_address>\n"..
		"\t<txt_login_port>"..self:GetCtrl("txt_login_port"):GetValue().."</txt_login_port>\n"..
		"\t<txt_login_nick>"..self:GetCtrl("txt_login_nick"):GetValue().."</txt_login_nick>\n"..
		"\t<txt_login_passwd>"..self:GetCtrl("txt_login_passwd"):GetValue().."</txt_login_passwd>\n"..
		"\t<txt_login_desc>"..self:GetCtrl("txt_login_desc"):GetValue().."</txt_login_desc>\n"..
		"\t<txt_login_tag>"..self:GetCtrl("txt_login_tag"):GetValue().."</txt_login_tag>\n"..
		"\t<txt_login_email>"..self:GetCtrl("txt_login_email"):GetValue().."</txt_login_email>\n"..
		"\t<txt_login_share>"..self:GetCtrl("txt_login_share"):GetValue().."</txt_login_share>\n"..
		"\t<chc_language>"..self:GetCtrl("wxID_LANGUAGE"):GetStringSelection().."</chc_language>\n")
		local CC = function(c)
			return c:Red()..","..c:Green()..","..c:Blue()
		end
		local CF = function(f)
			local ret = f:GetPointSize()..","..f:GetFamily()..","..f:GetStyle()..","..f:GetWeight()..","..
			iff(f:GetUnderlined(),"true","false")..","..string.format("%q",f:GetFaceName())
			return ret
		end
		for i=1,25 do
			if i < 19 then
				sf:write("\t<"..i.."_1>"..CC(tCtrls.tEditorSettings[i][1]).."</"..i.."_1>\n"..
				"\t<"..i.."_2>"..CC(tCtrls.tEditorSettings[i][2]).."</"..i.."_2>\n"..
				"\t<"..i.."_3>"..CF(tCtrls.tEditorSettings[i][3]).."</"..i.."_3>\n")
			else
				sf:write("\t<"..i.."_1>"..CC(tCtrls.tEditorSettings[i][1]).."</"..i.."_1>\n"..
				"\t<"..i.."_2>"..CC(tCtrls.tEditorSettings[i][2]).."</"..i.."_2>\n")
			end
		end
		for k,v in pairs(tCtrls.tEditorSettings) do
			if type(k) == "string" then
				sf:write("\t<"..k..">"..iff(v==true,"1","0").."</"..k..">\n")
			end
		end
		sf:write("</Settings>")
		sf:close()
		self:SetStatusText(self:Translate("SettingsSaved") or "Settings saved.")
	else
		self:SetStatusText("Unable to open Settings.xml file, settings couldn't be saved.")
	end
end

function tFuncs.LoadLanguage(self)
	local sf = io.open("Settings.xml","r")
	if sf then
		local c = sf:read("*a")
		if c:find("<chc_language>") or c:find("wxID_LANGUAGE") then
			local langfile = c:match("<chc_language>(.*)</chc_language>")
			if not langfile then langfile = c:match("<wxID_LANGUAGE>(.*)</wxID_LANGUAGE>") end
			tCtrls["langfile"] = langfile
		end
		sf:close()
	else
	    -- Seems it's the first run, try to find out the country -> [CC] = language_file
	    local tLangs = {[151] = "Brazilian Portuguese",[44] = "Chinese_Simplified",[52] = "Cesky",[53] = "Dansk",
		[175] = "Espanol",[78] = "French",[98] = "Hebrew",[100] = "Hungarian",[108] = "Italian",[54] = "Nederlands",
		[149] = "Polish",[150] = "Portugues",[155] = "Romanian", [156] = "Russian",[173] = "Svenska"}
	    tCtrls["langfile"] = tLangs[wx.wxLocale.GetSystemLanguage()] or nil
	end
end

function tFuncs.LoadSettings(self)
	local sf = io.open("Settings.xml","r")
	if sf then
		for line in sf:lines() do
			if line:find("<(%S+)>.*</%1>") then
				local control,value = line:match("<(%S+)>(.*)</%1>")
				if control:sub(1,3) == "txt" then -- textboxes
					self:GetCtrl(control):SetValue(value)
				elseif control:sub(1,3) == "chc" or control:sub(1,4) == "wxID" then -- language file
					self:GetCtrl("wxID_LANGUAGE"):SetStringSelection(value)
				elseif control:find("%d+_%d") then -- editor settings
					local sType,sId = control:match("(%d+)_(%d)")
					-- quite ugly,isn't it? ^_^
					if sId == "1" or sId == "2" then
						local val = "rgb = {"..value.."}"
						assert(loadstring(val))()
						tCtrls.tEditorSettings[tonumber(sType)][tonumber(sId)] = wx.wxColour(unpack(rgb))
					else
						local val = "f = {"..value.."}"
						assert(loadstring(val))()
						tCtrls.tEditorSettings[tonumber(sType)][tonumber(sId)] = wx.wxFont(unpack(f))
						f  = nil
					end
				elseif control:find("%u%u") then -- editor checkboxes
					tCtrls.tEditorSettings[control:match("%u%u")] = iff(value=="1",true,nil)
				end
			end
		end
		sf:close()
		self:GetCtrl("stt_sharesize"):SetLabel(tostring(self:ConvertShare(tonumber(self:GetCtrl("txt_login_share"):GetValue()))))
	end
end

function tFuncs.LoadFromXML(self,sFilename)
	local tBoolIDs,tNumberIDs,tStringIDs = self:GetDefaultIDs()
    local tDefBoolVals,tDefIntVals,tDefStringVals = self:GetDefaultValues()
	local curPath = sFilename:match("(.+)Settings.xml")
	local motd = io.open(curPath.."Motd.txt","r")
	if motd then motd:close() tCtrls["txt"]["txt_motd"]:LoadFile(curPath.."Motd.txt") end
	local f = io.open(sFilename,"r")
	if f then
		for line in f:lines() do
			for i,v in ipairs(tBoolIDs) do
				if line:find("<Bool Name=\""..v.."\">[01]</Bool>") then
					local sValue = line:match("<Bool Name=\""..v.."\">([01])</Bool>")
					tCtrls["chk"]["chk_"..(i-1)]:SetValue(iff(sValue=="1",true,false))
					tCtrls["tSettings"]["chk"][(i-1)] = sValue
				end
			end
			for i,v in ipairs(tNumberIDs) do
				if line:find("<Integer Name=\""..v.."\">%d+</Integer>") then
					local sValue = line:match("<Integer Name=\""..v.."\">(%d+)</Integer>")
                    if tCtrls["num"]["num_"..(i-1)]:GetClassInfo():GetClassName() == "wxSpinCtrl" then
						tCtrls["num"]["num_"..(i-1)]:SetValue(tonumber(sValue))
						tCtrls["tSettings"]["num"][(i-1)] = tonumber(sValue)
					else
						tCtrls["num"]["num_"..(i-1)]:SetSelection(tonumber(sValue))
						tCtrls["tSettings"]["num"][(i-1)] = tonumber(sValue)
					end
				end
			end
			for i,v in ipairs(tStringIDs) do
   				if line:find("<String Name=\""..v.."\">.-</String>") then
					local sValue = line:match("<String Name=\""..v.."\">(.-)</String>")
					if v == "Language" then
					 	tCtrls["txt"]["txt_34"]:SetStringSelection(sValue)
					 	tCtrls["tSettings"]["txt"][(i-1)] = sValue
					else
					 	tCtrls["txt"]["txt_"..(i-1)]:SetValue(tostring(sValue))
					 	tCtrls["tSettings"]["txt"][(i-1)] = sValue
					end
				end
			end
		end
	end
	-- The unmodified settings aren't saved into the xml. Load the default values.
	for i=0,53 do
		if not tCtrls["tSettings"]["chk"][i] then
			local bBool = tDefBoolVals[(i+1)]
			tCtrls["tSettings"]["chk"][i] = bBool
            tCtrls["chk"]["chk_"..i]:SetValue(bBool)
		end
	end
	for i=0,113 do
		if not tCtrls["tSettings"]["num"][i] then
			local iNum = tDefIntVals[(i+1)]
    		tCtrls["tSettings"]["num"][i] = iNum
        	if tCtrls["num"]["num_"..i]:GetClassInfo():GetClassName() == "wxSpinCtrl" then
				tCtrls["num"]["num_"..i]:SetValue(iNum)
			else
				tCtrls["num"]["num_"..i]:SetSelection(iNum)
			end
		end
	end
	for i=0,34 do
		if not tCtrls["tSettings"]["txt"][i] then
			local sString = tDefStringVals[(i+1)]
    		tCtrls["tSettings"]["txt"][i] = sString
			if i == 34 then
				tCtrls["txt"]["txt_34"]:SetStringSelection(sString)
			else
				tCtrls["txt"]["txt_"..i]:SetValue(sString)
			end
		end
	end
    self:SetStatusText("Settings loaded.")
end

function tFuncs.SaveToXML(self,sPath)
	local f = io.open(sPath.."/Settings.xml","w+")
	if f then
		local tBoolIDs,tNumberIDs,tStringIDs = tFuncs:GetDefaultIDs()
		local tDefBoolVals,tDefIntVals,tDefStringVals = tFuncs:GetDefaultValues()
		-- Check if something isn't the default in each group.
		local IsBool,IsInt,IsString = nil,nil,nil
		for i=0,55 do
			if tCtrls["chk"]["chk_"..i]:GetValue() ~= tDefBoolVals[i+1] then
				IsBool = true break
			end
		end
		for i=0,113 do
			if tCtrls["num"]["num_"..i]:GetClassInfo():GetClassName() == "wxSpinCtrl" then
				if tCtrls["num"]["num_"..i]:GetValue() ~= tDefIntVals[i+1] then
					IsInt = true break
				end
			else
				if tCtrls["num"]["num_"..i]:GetSelection() ~= tDefIntVals[i+1] then
					IsInt = true break
				end
			end
		end
		for i=0,34 do
			if i == 34 then
		        	if tCtrls["txt"]["txt_34"]:GetStringSelection() ~= tDefStringVals[34] then
					IsString = true break
				end
			else
				if tCtrls["txt"]["txt_"..i]:GetValue() ~= tDefStringVals[i+1] then
					IsString = true break
				end
			end
		end
		f:write("<?xml version=\"1.0\" encoding=\""..wx.wxLocale():GetSystemEncodingName().."\" standalone=\"yes\" ?>\n")
		f:write("<PtokaX Version=\""..tCtrls["sHubversion"].."\">\n")
		if IsBool then
			f:write("    <Booleans>\n")
			for i=0,55 do
			    if iff(tCtrls["chk"]["chk_"..i]:GetValue(),true,false) ~= tDefBoolVals[i+1] then
					f:write("        <Bool Name=\""..tBoolIDs[i+1].."\">"..iff(not tDefBoolVals[i+1],"1","0").."</Bool>\n")
				end
			end
			f:write("    </Booleans>\n")
		else
			f:write("    <Booleans />\n")
		end
		if IsInt then
			f:write("    <Integers>\n")
			for i=0,113 do
				if tCtrls["num"]["num_"..i]:GetClassInfo():GetClassName() == "wxSpinCtrl" then
			    		if tCtrls["num"]["num_"..i]:GetValue() ~= tDefIntVals[i+1] then
						f:write("        <Integer Name=\""..tNumberIDs[i+1].."\">"..tCtrls["num"]["num_"..i]:GetValue().."</Integer>\n")
					end
				else
					if tCtrls["num"]["num_"..i]:GetSelection() ~= tDefIntVals[i+1] then
						f:write("        <Integer Name=\""..tNumberIDs[i+1].."\">"..tCtrls["num"]["num_"..i]:GetSelection().."</Integer>\n")
					end
				end
			end
			f:write("        <Integer Name=\"MaxUsersPeak\">0</Integer>\n")
			f:write("    </Integers>\n")
		else
			f:write("    <Integers />\n")
		end
		if IsString then
			f:write("    <Strings>\n")
			for i=0,34 do
				if i == 34 then
			        if tCtrls["txt"]["txt_34"]:GetStringSelection() ~= tDefStringVals[35] then
						f:write("        <String Name=\""..tStringIDs[i+1].."\">"..tCtrls["txt"]["txt_"..i]:GetStringSelection().."</String>\n")
					end
				else
					if tCtrls["txt"]["txt_"..i]:GetValue() ~= tDefStringVals[i+1] then
						f:write("        <String Name=\""..tStringIDs[i+1].."\">"..tCtrls["txt"]["txt_"..i]:GetValue().."</String>\n")
					end
				end
			end
           	f:write("    </Strings>\n")
		else
			f:write("    <Strings />\n")
		end
		f:write("</PtokaX>\n")
		f:flush()
		f:close()
	end
	local fmotd = io.open(sPath.."/MOTD.txt","r")
	if fmotd then
		local motd = fmotd:read("*a")
		fmotd:close()
		if tCtrls["txt"]["txt_motd"]:GetValue() ~= motd then
			tCtrls["txt"]["txt_motd"]:SaveFile(sPath.."/MOTD.txt","w+")
		end
	else
		tCtrls["txt"]["txt_motd"]:SaveFile(sPath.."/MOTD.txt","w+")
	end
end

function tFuncs.Connect(self)
	if #self:GetCtrl("txt_login_address"):GetValue() < 1 then
		wx.wxMessageBox(self:Translate("CheckTheAddressPlease")); return
	end
	self:GetCtrl("wxID_CMD_LOGIN"):SetLabel(self:Translate("Disconnect") or "Disconnect")
	self:GetCtrl("txt_login_nick"):Enable(false)
	tCtrls["tcp_client"] = socket.tcp()
	tCtrls["tcp_client"]:settimeout(5) -- 5 secs timeout
	local address,port = self:GetCtrl("txt_login_address"):GetValue(),self:GetCtrl("txt_login_port"):GetValue()
	local res,err = tCtrls["tcp_client"]:connect(address,tonumber(port))
	if not res then
		-- These are the most common errors. Translate it to the user's native language
		if err:find("timeout") then -- Connection timeout
			self:SetStatusText(wx.wxSysErrorMsg(10060))
		elseif err:find("refused") then -- Connection refused by the target machine
			self:SetStatusText(wx.wxSysErrorMsg(10061))
		elseif err:find("Valid name") then -- crappy address
			self:SetStatusText(wx.wxSysErrorMsg(10049))
		else
			self:SetStatusText(err)
		end
		self:CleanUp()
	else
		tCtrls["tcp_client"]:settimeout(nil) -- remove timeout to keep connected
		tCtrls["taskbar"]:SetIcon(tCtrls["app"]:GetIcon(),"Connected to "..address.." on port "..port)
		self:Send("$Supports NoGetINFO NoHello QuickList ")
		table.insert(tCtrls["tDeadThreads"],ThreadCreate(tFuncs.TCPListen,{}))
		-- No, not dead, but the thread will call the self:CleanUp() function when it ends, and that will
		-- destroy all of them. If all scripts and all textfiles are downloaded, it can't be more than ~50
	end
end

function tFuncs.Send(self,msg,is_raw)
	msg = msg:gsub("|","[endpipe]")
	if not is_raw then
		msg = convert_output(msg)
	end
	if _DEBUG then
		DBGFILE:write("TCP >> "..msg.."\n")
	end
	tCtrls["tcp_client"]:send(msg.."|")
end

function tFuncs.TCPListen(self)
	local self = self or tFuncs
	l,e = tCtrls["tcp_client"]:receive(1)
	tDontNeed = {["$Use"] = 1,["$Sea"] = 1,["$MyI"] = 1,["$Qui"] = 1}
	while not e do
	    if l == "|" then
			if _DEBUG then
				DBGFILE:write("TCP << "..sBUFFER.."\n")
			end
			if BSKIP then
                sBUFFER = ""
				BSKIP = false
			else
				local evt = wx.wxCommandEvent(wx.wxEVT_NULL,tCtrls["wxID_EVENT_TCPPARSE"])
				evt:SetString(sBUFFER)
				tCtrls["app"]:AddPendingEvent(evt)
				sBUFFER = ""
			end
	    else
			if BSKIP == false then
				if tDontNeed[sBUFFER] then
					sBUFFER = ""
					BSKIP = true
				end
				sBUFFER = sBUFFER..l
			end
		end
		l,e = tCtrls["tcp_client"]:receive(1)
	end
	-- The loop breaks when the connection closed -> clean the GUI
	self:CleanUp()
end

function tFuncs.UDPListen(self)
	local self = self or tFuncs -- diff. thread
	local udpdata,udperr = tCtrls["udp_client"]:receive()
	if udpdata then
		while not udperr do
			while udpdata:find(string.char(0)) do
				udpdata = udpdata:sub(2)
			end
			if _DEBUG then
				DBGFILE:write("UDP << "..udpdata.."\n")
			end
			local evt = wx.wxCommandEvent(wx.wxEVT_NULL,tCtrls["wxID_EVENT_UDPPARSE"])
			evt:SetString(udpdata)
			tCtrls["app"]:AddPendingEvent(evt)
			udpdata,udperr = tCtrls["udp_client"]:receive()
		end
	end
end

function tFuncs.ParseTCP(self,data,raw_data)
	if not data then return end
	tCommands = {
	-- Standard NMDC extensions
	["$BadPass"] = function()
		self:SetStatusText((self:Translate("IncorrectPassword") or "Incorrect password").."...")
	end,
	["$GetPass"] = function()
		self:Send("$MyPass "..self:GetCtrl("txt_login_passwd"):GetValue())
	end,
	["$Hello"] = function()
	    self:Send("$Version 1,0091")
		self:Send("$GetNickList")
		self:Send("$MyINFO $ALL "..self:GetCtrl("txt_login_nick"):GetValue()..
		" "..self:GetCtrl("txt_login_desc"):GetValue()..self:GetCtrl("txt_login_tag"):GetValue().."$ "..
		"$LAN(T3)\1$"..self:GetCtrl("txt_login_email"):GetValue().."$"..self:GetCtrl("txt_login_share"):GetValue().."$")
	end,
	["$HubIsFull"] = function()
	    self:SetStatusText(self:Translate("ThisHubIsFull").."..." or "This hub is full...")
	end,
	["$HubName"] = function()
		local hubname = data:match("^%$HubName (.*)$")
		tCtrls["sHubname"] = hubname
		tCtrls["app"]:SetTitle(_APPNAME.." ".._APPVER.." - "..hubname)
	end,
	["$Lock"] = function()
		local lock = raw_data:match("%$Lock%s(%S+)%sPk")
		self:Send("$Key "..self:Lock2Key(lock), true)
	end,
	["$MyINFO"] = function()
	end,
	["$OpList"] = function()
        if tCtrls["iStatus"] == 0 then
			self:SetStatusText("Successfully logged in...")
			for i=0,7 do
				self:Send("$GET "..i)
			end
			tCtrls["iStatus"] = 1
			self:GetCtrl("wxID_CMD_STAT"):Enable(true)
		end
	end,
	["$Quit"] = function()
	end,
	["$Supports"] = function()
	    if data:find("QuickList") then
			self:Send("$MyINFO $ALL "..self:GetCtrl("txt_login_nick"):GetValue().." "..self:GetCtrl("txt_login_desc"):GetValue()..
			self:GetCtrl("txt_login_tag"):GetValue().."$ $LAN(T3)\1$"..self:GetCtrl("txt_login_email"):GetValue()..
			"$"..self:GetCtrl("txt_login_share"):GetValue().."$")
		else
		    self:Send("$ValidateNick "..self:GetCtrl("txt_login_nick"):GetValue())
		end
	end,
	["$To:"] = function()
		if data:find("[%--].-Current stats:") then
			self:ParseStat(data)
		end
	end,
	["$ValidateDenide"] = function()
		self:SetStatusText("Your nick is already taken...")
	end,
	["<"] = function() -- Statistics
		if data:find("[%--].-Current stats:") then
			self:ParseStat(data)
		end
	end,
	-- Own protocol extensions start --
	["$SET"] = function()
	    local sType,values = data:match("^%$SET%s(%d)%s(.+)")
	    sType = tonumber(sType)
		tTypes = {
		[1] = function() -- Booleans
            self:SetStatusText("Loading boolean settings...")
		    local iter = 0
			for id in values:gmatch("([01])%$%$") do
				tCtrls["chk"]["chk_"..iter]:SetValue(iff(id=="1",true,false))
				tCtrls["tSettings"]["chk"][iter] = id
				-- Send fake click
				local evt = wx.wxCommandEvent(wx.wxEVT_COMMAND_CHECKBOX_CLICKED,tCtrls["chk_"..iter])
				evt:SetInt(tonumber(id))
				tCtrls["app"]:ProcessEvent(evt)
				iter = iter + 1
			end
            self:SetStatusText("Boolean settings loaded...")
		end,
		[2] = function() -- Numbers
            self:SetStatusText("Loading number settings...")
		    local iter = 0
		    for id in values:gmatch("(.-)%$%$") do
				if tCtrls["num"]["num_"..iter]:GetClassInfo():GetClassName() == "wxSpinCtrl" then
					tCtrls["num"]["num_"..iter]:SetValue(tonumber(id))
				else
					tCtrls["num"]["num_"..iter]:SetSelection(tonumber(id))
				end
				tCtrls["tSettings"]["num"][iter] = id
				-- Send fake click
				local evt = wx.wxCommandEvent(wx.wxEVT_COMMAND_TEXT_UPDATED,tCtrls["num_"..iter])
				tCtrls["app"]:ProcessEvent(evt)
				iter = iter + 1
			end
            self:SetStatusText("Number settings loaded...")
		end,
		[3] = function() -- Strings
		    if data:find("^%$SET%s3%slang") then
				for langfile in data:sub(13):gmatch("(.-)%$%$") do
					tCtrls["txt"]["txt_34"]:Append(langfile)
				end
			elseif data:find("^%$SET%s3%smotd") then
				local motd = data:match("^%$SET%s3%smotd%s(.*)")
				tCtrls["txt"]["txt_motd"]:SetValue(motd)
				tCtrls["tSettings"]["txt"]["motd"] = motd
				return
			else
                self:SetStatusText("Loading string settings...")
				local iter = 0
				for id in values:gmatch("(.-)%$%$") do
				    if iter == 34 then
						if id == "nil" then id = "English" end
						tCtrls["txt"]["txt_"..iter]:SetStringSelection(id)
					else
						tCtrls["txt"]["txt_"..iter]:SetValue(iff(id=="nil","",id))
					end
					tCtrls["tSettings"]["txt"][iter] = iff(id=="nil","",id)
					iter = iter + 1
				end
                self:SetStatusText("String settings loaded...")
			end
			-- We got the settings, select the first page
			tCtrls["tab"]:SetSelection(1)
		end,
		[4] = function() -- Bans
		    local subtype,values = data:match("^%$SET%s4%s(%d)%s(.+)")
			subtype = tonumber(subtype)
			if subtype == 1 then -- Permanent bans
				self:SetStatusText("Loading permbans...")
				for sIP,sNick,bFullIpBan,sBy,sReason in data:sub(10):gmatch("(.-)%$(.-)%$([01])%$(.-)%$(.-)%$%$") do
					if sIP == "<Nick ban>" then sIP = "<"..tCtrls["tLangs"][291]..">" end
					if sNick == "<IP ban>" then sNick = "<"..tCtrls["tLangs"][292]..">" end
					if sBy == "N/A" then sBy = "" end
					if sReason == "N/A" then sReason = "" end
					sReason = sReason:gsub(string.char(10),""):gsub(string.char(13),"")
					table.insert(tCtrls["tBans"],{sIP,sNick,sBy,sReason,"<"..tCtrls["tLangs"][317]..">",bFullIpBan})
					local item = tCtrls["lst_bans"]:InsertItem(tCtrls["lst_bans"]:GetItemCount(),
					iff(bFullIpBan == "1",sIP.." ("..tCtrls["tLangs"][293]..")",sIP))
					tCtrls["lst_bans"]:SetItem(item,1,iff(self:IsIP(sIP),sNick,sNick.." ("..tCtrls["tLangs"][321]..")"))
					tCtrls["lst_bans"]:SetItem(item,2,sBy)
					tCtrls["lst_bans"]:SetItem(item,3,sReason)
					tCtrls["lst_bans"]:SetItem(item,4,"<"..tCtrls["tLangs"][317]..">")
					tCtrls["lst_bans"]:SetItemData(item,tCtrls["lst_bans"]:GetItemCount()-1)
				end
                self:SetStatusText("Permbans loaded...")
			elseif subtype == 2 then -- Temporary bans
				self:SetStatusText("Loading tempbans...")
				for sIP,sNick,bFullIpBan,sBy,sReason,iExpireTime in data:sub(10):gmatch("(.-)%$(.-)%$([01])%$(.-)%$(.-)%$(%d+)%$%$") do
					if sIP == "<Nick ban>" then sIP = "<"..tCtrls["tLangs"][291]..">" end
					if sNick == "<IP ban>" then sNick = "<"..tCtrls["tLangs"][292]..">" end
					if sBy == "N/A" then sBy = "" end
					if sReason == "N/A" then sReason = "" end
					table.insert(tCtrls["tBans"],{sIP,sNick,sBy,sReason,iExpireTime,bFullIpBan})
					local item = tCtrls["lst_bans"]:InsertItem(tCtrls["lst_bans"]:GetItemCount(),
					iff(bFullIpBan == "1",sIP.." ("..tCtrls["tLangs"][293]..")",sIP.." ("..tCtrls["tLangs"][321]..")"))
					tCtrls["lst_bans"]:SetItem(item,1,iff(self:IsIP(sIP),sNick,sNick.." ("..tCtrls["tLangs"][321]..")"))
					tCtrls["lst_bans"]:SetItem(item,2,sBy)
					tCtrls["lst_bans"]:SetItem(item,3,sReason)
					tCtrls["lst_bans"]:SetItem(item,4,os.date("%Y. %b %d. %H:%M:%S",tonumber(iExpireTime)))
					tCtrls["lst_bans"]:SetItemData(item,tCtrls["lst_bans"]:GetItemCount()-1)
				end
                self:SetStatusText("Tempbans loaded...")
			elseif subtype == 3 then -- Permanent rangebans
				self:SetStatusText("Loading perm rangebans...")
				for sIPFrom,sIPTo,bFullIpBan,sBy,sReason in data:sub(10):gmatch("(.-)%$(.-)%$([01])%$(.-)%$(.-)%$%$") do
					if sBy == "N/A" then sBy = "" end
					if sReason == "N/A" then sReason = "" end
					table.insert(tCtrls["tRangeBans"],{sIPFrom.." - "..sIPTo,sBy,sReason,"<"..tCtrls["tLangs"][317]..">",bFullIpBan})
					local item = tCtrls["lst_rangebans"]:InsertItem(tCtrls["lst_rangebans"]:GetItemCount(),
					iff(bFullIpBan == "1",sIPFrom.." - "..sIPTo.." ("..tCtrls["tLangs"][293]..")",sIPFrom.." - "..sIPTo))
					tCtrls["lst_rangebans"]:SetItem(item,1,sBy)
					tCtrls["lst_rangebans"]:SetItem(item,2,sReason)
					tCtrls["lst_rangebans"]:SetItem(item,3,"<"..tCtrls["tLangs"][317]..">")
					tCtrls["lst_rangebans"]:SetItemData(item,tCtrls["lst_rangebans"]:GetItemCount()-1)
				end
                self:SetStatusText("Perm rangebans loaded...")
			elseif subtype == 4 then -- Temporary rangebans
				self:SetStatusText("Loading temp rangebans...")
				for sIPFrom,sIPTo,bFullIpBan,sBy,sReason,iExpireTime in data:sub(10):gmatch("(.-)%$(.-)%$([01])%$(.-)%$(.-)%$(%d+)%$%$") do
					if sBy == "N/A" then sBy = "" end
					if sReason == "N/A" then sReason = "" end
					table.insert(tCtrls["tRangeBans"],{sIPFrom.." - "..sIPTo,sBy,sReason,iExpireTime,bFullIpBan})
					local item = tCtrls["lst_rangebans"]:InsertItem(tCtrls["lst_rangebans"]:GetItemCount(),
					iff(bFullIpBan == "1",sIPFrom.." - "..sIPTo.." ("..tCtrls["tLangs"][293]..")",sIPFrom.." - "..sIPTo))
					tCtrls["lst_rangebans"]:SetItem(item,1,sBy)
					tCtrls["lst_rangebans"]:SetItem(item,2,sReason)
					tCtrls["lst_rangebans"]:SetItem(item,3,os.date("%Y. %b %d. %H:%M:%S",tonumber(iExpireTime)))
					tCtrls["lst_rangebans"]:SetItemData(item,tCtrls["lst_rangebans"]:GetItemCount()-1)
				end
                self:SetStatusText("Temp rangebans loaded...")
			end
			-- Fetch the controls
			if tCtrls["lst_bans"]:GetItemCount() > 0 then
				tCtrls["lst_bans"]:SetColumnWidth(0,wx.wxLIST_AUTOSIZE)
				tCtrls["lst_bans"]:SetColumnWidth(1,wx.wxLIST_AUTOSIZE)
				tCtrls["lst_bans"]:SetColumnWidth(2,wx.wxLIST_AUTOSIZE)
				tCtrls["lst_bans"]:SetColumnWidth(3,wx.wxLIST_AUTOSIZE)
				tCtrls["lst_bans"]:SetColumnWidth(4,wx.wxLIST_AUTOSIZE)
			end
			if tCtrls["lst_rangebans"]:GetItemCount() > 0 then
				tCtrls["lst_rangebans"]:SetColumnWidth(0,wx.wxLIST_AUTOSIZE)
				tCtrls["lst_rangebans"]:SetColumnWidth(1,wx.wxLIST_AUTOSIZE)
				tCtrls["lst_rangebans"]:SetColumnWidth(2,wx.wxLIST_AUTOSIZE)
				tCtrls["lst_rangebans"]:SetColumnWidth(3,wx.wxLIST_AUTOSIZE)
			end
		end,
		[5] = function()
			if not bSCRIPT then
				self:SetStatusText("Loading scripts...")
			end
			for sName,bEnabled,iMemUsage in data:sub(8):gmatch("(.-)%$([01])%$(%d+)%$%$") do
			tCtrls["lst_scripts"]:Insert(sName,tCtrls["lst_scripts"]:GetCount())
			if bEnabled == "1" then
				tCtrls["lst_scripts"]:Check(tCtrls["lst_scripts"]:GetCount() - 1,true)
				end
				if iMemUsage ~= "0" then
					tCtrls["lst_scripts"]:SetToolTip(tCtrls["lst_scripts"]:GetToolTip():GetTip()..
					sName..": "..iMemUsage.." Kb\n")
				end
			end
			tCtrls["lst_scripts"]:Refresh()
			if not bSCRIPT then
				self:SetStatusText("Scripts loaded...")
				bSCRIPT = true
			end
		end,
		[6] = function()
			self:SetStatusText("Loading profiles")
			for iProfileNumber,sProfileName,sProfilePermissions in data:sub(8):gmatch("(%d+)%$(.-)%$([01]-)%$%$") do
				tCtrls["tProfiles"][tonumber(iProfileNumber)] = {sProfileName,sProfilePermissions}
				tCtrls["lst_profiles"]:Append(sProfileName)
				if tonumber(iProfileNumber) == 0 then
					self:LoadPermissions(iProfileNumber)
				end
				tCtrls["lst_profiles"]:SetSelection(0)
				self:GetCtrl("wxID_PROF_UP"):Enable(false)
			end
            self:SetStatusText("Profiles loaded")
		end,
		[7] = function()
			self:SetStatusText("Loading registered users...")
			for sNick,sPassword,iProfile in data:sub(8):gmatch("(%S-)%$(%S-)%$(%d+)%$%$") do
				table.insert(tCtrls["tRegs"],{sNick,sPassword,tCtrls["tProfiles"][tonumber(iProfile)][1]})
				local item = tCtrls["lst_regs"]:InsertItem(tCtrls["lst_regs"]:GetItemCount(),sNick)
				tCtrls["lst_regs"]:SetItem(item,1,sPassword)
				tCtrls["lst_regs"]:SetItem(item,2,tCtrls["tProfiles"][tonumber(iProfile)][1])
				tCtrls["lst_regs"]:SetItemData(item,tCtrls["lst_regs"]:GetItemCount()-1)
			end
			tCtrls["lst_regs"]:SetColumnWidth(0,wx.wxLIST_AUTOSIZE)
			tCtrls["lst_regs"]:SetColumnWidth(1,wx.wxLIST_AUTOSIZE)
			tCtrls["lst_regs"]:SetColumnWidth(2,wx.wxLIST_AUTOSIZE)
            self:SetStatusText("Registered users loaded...")
		end,
		[8] = function()
			self:SetStatusText("Loading text files...")
			for textfile in data:sub(8):gmatch("(.-)%$%$") do
				tCtrls["lst_texts"]:Append(textfile)
			end
            self:SetStatusText("Text files loaded...")
		end,}
		if tTypes[tonumber(sType)] then tTypes[tonumber(sType)]() end
	end,
	["$FILE"] = function()
		local file,content = data:match("^%$FILE%s\"(.-)\"%s(.+)$")
		if file:lower():sub(-4) == ".lua" then
			content = content:gsub("%[endpipe%]","|")
			local f = io.open("./scripts/"..file,"w+")
			f:write(content)
			f:close()
			tCtrls["tFiles"][file] = 1
		elseif file:lower():sub(-4) == ".txt" then
			content = content:gsub("%[endpipe%]","|")
			local f = io.open("./texts/"..file,"w+")
			f:write(content)
			f:close()
			tCtrls["tFiles"][file] = 1
		end
	end,
	["$ERR"] = function() -- Errors
		local level = data:match("^%$ERR%s(%d+)")
		level = tonumber(level)
		local tHandlers = {
		[1] = function()
		    -- Requested file couldn't find
			self:SetStatusText("The selected file couldn't find on the server, reloading scripts and texts...\n")
			self:ReloadScripts()
			self:ReloadTexts()
		end,
		[2] = function()
		    -- MoveDown() failed
			wx.wxMessageBox("Can't move up/down the selected script, maybe somebody else also modified the order. Scripts will be now reloaded","WARNING",wx.wxICON_WARNING)
			self:ReloadScripts()
		end,
		[3] = function()
		    -- MoveUp() failed
			wx.wxMessageBox("Can't move up/down the selected script, maybe somebody else also modified the order. Scripts will be now reloaded","WARNING",wx.wxICON_WARNING)
			self:ReloadScripts()
		end,
		[4] = function()
		    -- StartScript() failed
		    local what = data:match("^%$ERR%s4%s(.+)$")
		    local iPos,bChecked = tCtrls["lst_scripts"]:FindString(what),tCtrls["lst_scripts"]:IsChecked(tCtrls["lst_scripts"]:FindString(what))
			tCtrls["lst_scripts"]:Check(iPos,false)
			self:DownloadFile(8,what)
			table.insert(tCtrls["tDeadThreads"],ThreadCreate(tFuncs.FileAction,{ what,2}))
		end,
		[5] = function()
		    --> RestartScript(s)() failed
			self:GetCtrl("txt_scripterror"):AppendText("["..os.date("%H:%M").."] Can't restart the selected script, reloading scripts...\n")
			self:ReloadScripts()
		end,
		[6] = function()
		    --> MoveUp() failed
		    wx.wxMessageBox("Can't move up the selected profile, maybe somebody else also modified the settings. Profiles will be now reloaded","WARNING",wx.wxICON_WARNING)
		    tCtrls["lst_profiles"]:Clear()
		    self:Send("$GET 5")
		    if tCtrls["lst_profiles"]:GetCount() == 1 then
				self:GetCtrl("wxID_PROF_UP"):Enable(false)
				self:GetCtrl("wxID_PROF_DOWN"):Enable(false)
			elseif tCtrls["lst_profiles"]:IsSelected(0) then
				self:GetCtrl("wxID_PROF_DOWN"):Enable(true)
				self:GetCtrl("wxID_PROF_UP"):Enable(false)
			elseif tCtrls["lst_profiles"]:IsSelected(tCtrls["lst_profiles"]:GetCount()-1) then
				self:GetCtrl("wxID_PROF_UP"):Enable(true)
				self:GetCtrl("wxID_PROF_DOWN"):Enable(false)
			else
				self:GetCtrl("wxID_PROF_UP"):Enable(true)
				self:GetCtrl("wxID_PROF_DOWN"):Enable(true)
			end
		end,
		[7] = function()
		    --> MoveDown() failed
		    wx.wxMessageBox("Can't move down the selected profile, maybe somebody else also modified the settings. Profiles will be now reloaded","WARNING",wx.wxICON_WARNING)
		    tCtrls["lst_profiles"]:Clear()
		    self:Send("$GET 5")
		    if tCtrls["lst_profiles"]:GetCount() == 1 then
				self:GetCtrl("wxID_PROF_UP"):Enable(false)
				self:GetCtrl("wxID_PROF_DOWN"):Enable(false)
			elseif tCtrls["lst_profiles"]:IsSelected(0) then
				self:GetCtrl("wxID_PROF_DOWN"):Enable(true)
				self:GetCtrl("wxID_PROF_UP"):Enable(false)
			elseif tCtrls["lst_profiles"]:IsSelected(tCtrls["lst_profiles"]:GetCount()-1) then
				self:GetCtrl("wxID_PROF_UP"):Enable(true)
				self:GetCtrl("wxID_PROF_DOWN"):Enable(false)
			else
				self:GetCtrl("wxID_PROF_UP"):Enable(true)
				self:GetCtrl("wxID_PROF_DOWN"):Enable(true)
			end
		end,
		[8] = function()
		    --> AddProfile failed
		    wx.wxMessageBox("Couldn't add profile. ERROR.") --  Why? Don't ask... Maybe already exists?
		end,
		[9] = function()
		    --> RemoveProfile() failed
		    -- We checked this when the button pressed. But who knows? :-)
		    wx.wxMessageBox(self:Translate("ProfileDelFailed") or "Failed to delete a profile. Profile is in use.")
		end,
		[10] = function()
		    --> (Range)Unban() failed
		    local sublevel,position = data:match("^%$ERR%s10%s([01])$")
		    if sublevel then
				if sublevel == "0" then
					wx.wxMessageBox("Deleting the selected ban wasn't possible. Reloading banlist...","WARNING!",wx.wxICON_INFORMATION)
					tCtrls["lst_bans"]:DeleteAllItems()
					self:Send("$GET 3 0")
				elseif sublevel == "1" then
				    wx.wxMessageBox("Deleting the selected rangeban wasn't possible. Reloading rangebanlist...","WARNING!",wx.wxICON_INFORMATION)
					tCtrls["lst_rangebans"]:DeleteAllItems()
					self:Send("$GET 3 1")
				end
			end
		end,
		[11] = function()
		    local ID = data:match("^%$ERR%s11%s(%d+)$")
		    if ID then
				ID = tonumber(ID)
				tCtrls["lst_permissions"]:Check(ID,iff(tCtrls["lst_permissions"]:IsChecked(ID),true,false))
			end
		end,
		[12] = function()
		    --> DelReg() failed
		    local nick = data:match("^%$ERR%s12%s(%S+)")
			wx.wxMessageBox("Can't delete "..nick.."'s registration. ERROR.")
		end,
		[13] = function()
		    --> AddReg() failed
		    local nick = data:match("^%$ERR%s13%s(%S+)$")
		    wx.wxMessageBox(nick..": "..(self:Translate("UserIsAlredyReg") or "User is already registered"))
		end,
		[14] = function()
		    --> ChangeReg() failed
		    local nick = data:match("^%$ERR%s14%s(%S+)$")
		    wx.wxMessageBox("Can't change "..nick.."'s registration. ERROR.")
		end,
		[15] = function()
		    -- StopScript() failed
		    local what = data:match("^%$ERR%s15%s(.+)$")
		    local iPos,bChecked = tCtrls["lst_scripts"]:FindString(what),tCtrls["lst_scripts"]:IsChecked(tCtrls["lst_scripts"]:FindString(what))
			tCtrls["lst_scripts"]:Check(iPos,not bChecked)
		end,
		[99] = function()
		    self:SetStatusText(self:Translate("YouAreNotAlwdToUseThisCmd") or "You are not allowed to use this command")
		end
		}
		tHandlers[level]()
	end,
	["$CONF"] = function() -- Confirmations
		local level,what = data:match("^%$CONF%s(%d+)%s*(.*)$")
		level = tonumber(level)
		local tConfirmations = {
		[2] = function()
		    --> MoveDown() success
			local iPos,bChecked = tCtrls["lst_scripts"]:GetSelection(),tCtrls["lst_scripts"]:IsChecked(tCtrls["lst_scripts"]:GetSelection())
			tCtrls["lst_scripts"]:Delete(iPos)
			tCtrls["lst_scripts"]:Insert(what,iPos + 1)
			tCtrls["lst_scripts"]:Check(iPos + 1,bChecked)
			tCtrls["lst_scripts"]:Select(iPos + 1)
			if tCtrls["lst_scripts"]:IsSelected(0) then
				self:GetCtrl("wxID_LUA_DOWN"):Enable(true)
				self:GetCtrl("wxID_LUA_UP"):Enable(false)
			elseif tCtrls["lst_scripts"]:IsSelected(tCtrls["lst_scripts"]:GetCount()-1) then
				self:GetCtrl("wxID_LUA_UP"):Enable(true)
				self:GetCtrl("wxID_LUA_DOWN"):Enable(false)
			end
		end,
		[3] = function()
		    --> MoveUp() success
			local iPos,bChecked = tCtrls["lst_scripts"]:GetSelection(),tCtrls["lst_scripts"]:IsChecked(tCtrls["lst_scripts"]:GetSelection())
			tCtrls["lst_scripts"]:Delete(iPos)
			tCtrls["lst_scripts"]:Insert(what,iPos - 1)
			tCtrls["lst_scripts"]:Check(iPos - 1,bChecked)
			tCtrls["lst_scripts"]:Select(iPos - 1)
			if tCtrls["lst_scripts"]:IsSelected(0) then
				self:GetCtrl("wxID_LUA_DOWN"):Enable(true)
				self:GetCtrl("wxID_LUA_UP"):Enable(false)
			elseif tCtrls["lst_scripts"]:IsSelected(tCtrls["lst_scripts"]:GetCount()-1) then
				self:GetCtrl("wxID_LUA_UP"):Enable(true)
				self:GetCtrl("wxID_LUA_DOWN"):Enable(false)
			end
		end,
		[4] = function()
		    --> StartScript()/StartScript() success
			self:ReloadScripts()
		end,
		[5] = function()
		    --> RestartScript(s)() success
			self:GetCtrl("txt_scripterror"):AppendText(os.date("[%H:%M] ")..what.." "..(self:Translate("RestartedLwr") or "restarted").."\n")
		end,
		[6] = function()
		    --> MoveDown() success
		    local iPos,sProfile = tonumber(what),tCtrls["lst_profiles"]:GetStringSelection()
		    tCtrls["lst_profiles"]:Delete(iPos)
		    tCtrls["lst_profiles"]:Insert(sProfile,iPos+1)
		    tCtrls["lst_profiles"]:SetSelection(iPos+1)
			local temp = tCtrls["tProfiles"][iPos+1]
			tCtrls["tProfiles"][iPos+1] = tCtrls["tProfiles"][iPos]
			tCtrls["tProfiles"][iPos] = temp
		    if iPos-1 == 0 then
				self:GetCtrl("wxID_PROF_DOWN"):Enable(true)
				self:GetCtrl("wxID_PROF_UP"):Enable(false)
			elseif iPos == tCtrls["lst_profiles"]:GetCount() then
			    self:GetCtrl("wxID_PROF_DOWN"):Enable(false)
				self:GetCtrl("wxID_PROF_UP"):Enable(true)
			else
				self:GetCtrl("wxID_PROF_DOWN"):Enable(true)
				self:GetCtrl("wxID_PROF_UP"):Enable(true)
			end
		end,
		[7] = function()
		    --> MoveUp() success
		    local iPos,sProfile = tonumber(what),tCtrls["lst_profiles"]:GetStringSelection()
		    tCtrls["lst_profiles"]:Delete(iPos)
		    tCtrls["lst_profiles"]:Insert(sProfile,iPos-1)
		    tCtrls["lst_profiles"]:SetSelection(iPos-1)
			local temp = tCtrls["tProfiles"][iPos-1]
			tCtrls["tProfiles"][iPos-1] = tCtrls["tProfiles"][iPos]
			tCtrls["tProfiles"][iPos] = temp
		    if iPos-1 == 0 then
				self:GetCtrl("wxID_PROF_DOWN"):Enable(true)
				self:GetCtrl("wxID_PROF_UP"):Enable(false)
			elseif iPos == tCtrls["lst_profiles"]:GetCount() then
			    self:GetCtrl("wxID_PROF_DOWN"):Enable(false)
				self:GetCtrl("wxID_PROF_UP"):Enable(true)
			else
				self:GetCtrl("wxID_PROF_DOWN"):Enable(true)
				self:GetCtrl("wxID_PROF_UP"):Enable(true)
			end
		end,
		[8] = function()
		    --> AddProfile() success
		    tCtrls["lst_profiles"]:Insert(what,tCtrls["lst_profiles"]:GetCount())
		    table.insert(tCtrls["tProfiles"],{what,string.rep("0",47)})
		end,
		[9] = function()
			--> RemoveProfile() success
		    local item = tCtrls["lst_profiles"]:FindString(what)
		    tCtrls["lst_profiles"]:SetSelection(item-1)
		    self:LoadPermissions(item-1)
		    tCtrls["lst_profiles"]:Delete(item)
		    table.remove(tCtrls["tProfiles"],item-1)
		end,
		[10] = function()
		    --> (Range)Unban() success
		    local subtype,item = data:match("^%$CONF%s10%s([0-3])%s*(%d*)")
			item = tonumber(item)
		    if subtype then
			    if subtype == "0" then
					local i = tCtrls["lst_bans"]:GetItemData(item)+1
					tCtrls["lst_bans"]:DeleteItem(item)
					table.remove(tCtrls["tBans"],i)
					self:ReIndex("lst_bans",i)
				elseif subtype == "1" then
				    local i = tCtrls["lst_rangebans"]:GetItemData(item)+1
					tCtrls["lst_rangebans"]:DeleteItem(item)
					table.remove(tCtrls["tRangeBans"],i)
					self:ReIndex("lst_rangebans",i)
				-- All wxListCtrl item removing must be done backwards
				-- as in associated table so as in the listview.
			    elseif subtype == "2" then
					for i=#tCtrls["tBans"],1,-1 do
						if not tCtrls["tBans"][i][5]:find("%b<>") then
							for j=tCtrls["lst_bans"]:GetItemCount()-1,0,-1 do
								if tCtrls["lst_bans"]:GetItemData(j) == i-1 then
									tCtrls["lst_bans"]:DeleteItem(j)
									table.remove(tCtrls["tBans"],i)
									self:ReIndex("lst_bans",i)
								end
							end
						end
					end
				elseif subtype == "3" then
					for i=#tCtrls["tBans"],1,-1 do
						if tCtrls["tBans"][i][5]:find("%b<>") then
							for j=tCtrls["lst_bans"]:GetItemCount()-1,0,-1 do
								if tCtrls["lst_bans"]:GetItemData(j) == i-1 then
									tCtrls["lst_bans"]:DeleteItem(j)
									table.remove(tCtrls["tBans"],i)
									self:ReIndex("lst_bans",i)
								end
							end
						end
					end
				elseif subtype == "4" then
					for i=#tCtrls["tRangebans"],1,-1 do
						if not tCtrls["tRangebans"][4]:find("%b<>") then
							for j=tCtrls["lst_rangebans"]:GetItemCount()-1,0,-1 do
								if tCtrls["lst_rangebans"]:GetItemData(j) == i-1 then
									tCtrls["lst_rangebans"]:DeleteItem(j)
									table.remove(tCtrls["tRangebans"],i)
									self:ReIndex("lst_rangebans",i)
								end
							end
						end
					end
				elseif subtype == "5" then
					for i=#tCtrls["tRangebans"],1,-1 do
						if tCtrls["tRangebans"][4]:find("%b<>") then
							for j=tCtrls["lst_rangebans"]:GetItemCount()-1,0,-1 do
								if tCtrls["lst_rangebans"]:GetItemData(j) == i-1 then
									tCtrls["lst_rangebans"]:DeleteItem(j)
									table.remove(tCtrls["tRangebans"],i)
									self:ReIndex("lst_rangebans",i)
								end
							end
						end
					end
				end
			end
		end,
		[11] = function()
		    --> SetProfilePermission() success
			local ID,value = data:match("^%$CONF%s11%s(%d+)%s([01])$")
			ID = tonumber(ID)
			if ID == 56 then
				for i=0,55 do
					tCtrls["lst_permissions"]:Check(i,iff(value=="1",true,false))
				end
				local profilestring = tCtrls["tProfiles"][tCtrls["lst_profiles"]:GetSelection()][2]
				tCtrls["tProfiles"][tCtrls["lst_profiles"]:GetSelection()][2] = string.rep("1",55)
				return
			end
			tCtrls["lst_permissions"]:Check(ID,iff(value=="1",true,false))
			local profilestring = tCtrls["tProfiles"][tCtrls["lst_profiles"]:GetSelection()][2]
			tCtrls["tProfiles"][tCtrls["lst_profiles"]:GetSelection()][2] = profilestring:sub(1,ID)..value..profilestring:sub(ID+2)
		end,
		[12] = function()
		    --> DelReg() success
		    local nick = data:match("^%$CONF%s12%s(%S+)")
		    local item = tCtrls["lst_regs"]:FindItem(-1,nick,false)
		    tCtrls["lst_regs"]:DeleteItem(item)
			for i,v in ipairs(tCtrls["tRegs"]) do
				if v[1] == nick then
					table.remove(tCtrls["tRegs"],i)
					self:ReIndex("lst_regs",i)
					break
				end
			end
		end,
		[13] = function()
		    --> AddReg() success
		    local nick,pass,profile = data:match("^%$CONF%s13%s(%S+)%s(%S+)%s(%d+)$")
		    local profilename = tCtrls["tProfiles"][tonumber(profile)][1]
		    local pos = tCtrls["lst_regs"]:InsertItem(0,nick,0)
			table.insert(tCtrls["tRegs"],{nick,pass,profilename})
		    tCtrls["lst_regs"]:SetItem(pos,1,pass)
		    tCtrls["lst_regs"]:SetItem(pos,2,profilename)
		    tCtrls["lst_regs"]:SetItemImage(pos,-1)
		    tCtrls["lst_regs"]:SetItemData(pos,#tCtrls["tRegs"]-1)
		end,
		[14] = function()
		    --> ChangeReg() success
		    local nick,pass,profile = data:match("^%$CONF%s14%s(%S+)%s(%S+)%s(%d+)$")
		    local profilename = tCtrls["tProfiles"][tonumber(profile)][1]
		    local pos = tCtrls["lst_regs"]:FindItem(-1,nick,false)
		    tCtrls["lst_regs"]:SetItem(pos,1,pass)
		    tCtrls["lst_regs"]:SetItem(pos,2,profilename)
			for i,v in ipairs(tCtrls["tRegs"]) do
				if v[1] == nick then
					tCtrls["tRegs"][i] = {nick,pass,profilename}
					break
				end
			end
		end,
		}
		if tConfirmations[level] then
			tConfirmations[level]()
		end
	end,
	}
	local cmd = data:match("^(%S-)%s")
	if not cmd then cmd = data:match("^(%S+)") end
	if not cmd then return end
	if cmd:sub(1,1) == "<" then cmd = "<" end
	--collectgarbage("collect")
	if tCommands[cmd] then
		tCommands[cmd]()
		wx.wxEndBusyCursor()
	else
		if data ~= "" and data:sub(1,1) ~= "$" then
			if data:find("PtokaX DC Hub %S+") then
				local ver = data:match("PtokaX DC Hub (%S+)")
                tCtrls["sHubversion"] = ver
			end
		end
	end
end

function tFuncs.ParseUDP(self,data)
	local BoldIt = function(button)
		local font = tCtrls["app"]:GetFont()
		font:SetWeight(wx.wxFONTWEIGHT_BOLD)
		button:SetFont(font)
	end
	local Save2File = function(file,message)
		if not wx.wxDirExists("Logs") then wx.wxMkdir("Logs") end
		local f = io.open("./Logs/"..self:GetCtrl("txt_login_address"):GetValue():gsub("%W","_").."_"..file:lower()..".log","a")
		if f then f:write(message) f:close()
		else self:SetStatusText("Can't open the file to log "..file.." messages.") end
	end
	local tTypes = {
	["SYS"] = function(data)
		tCtrls["wxID_TXT_UDPSYS"]:AppendText(data)
        if tCtrls["shown_page"] ~= "SYS" then BoldIt(self:GetCtrl("wxID_CMD_UDPSYS")) end
		if self:GetCtrl("wxID_CHK_UDPSYS"):IsChecked() then Save2File("SYS",data) end
	end,
	["ERR"] = function(data)
		tCtrls["wxID_TXT_UDPERR"]:AppendText(data)
        if tCtrls["shown_page"] ~= "ERR" then BoldIt(self:GetCtrl("wxID_CMD_UDPERR")) end
        if self:GetCtrl("wxID_CHK_UDPERR"):IsChecked() then Save2File("ERR",data) end
	end,
	["HUB"] = function(data)
		tCtrls["wxID_TXT_UDPERR"]:AppendText(data)
        if tCtrls["shown_page"] ~= "ERR" then BoldIt(self:GetCtrl("wxID_CMD_UDPERR")) end
        if self:GetCtrl("wxID_CHK_UDPERR"):IsChecked() then Save2File("ERR",data) end
	end,
	["BUF"] = function(data)
		tCtrls["wxID_TXT_UDPERR"]:AppendText(data)
        if tCtrls["shown_page"] ~= "ERR" then BoldIt(self:GetCtrl("wxID_CMD_UDPERR")) end
        if self:GetCtrl("wxID_CHK_UDPERR"):IsChecked() then Save2File("ERR",data) end
	end,
	["LUA"] = function(data)
		tCtrls["wxID_TXT_UDPLUA"]:AppendText(data)
        if tCtrls["shown_page"] ~= "LUA" then BoldIt(self:GetCtrl("wxID_CMD_UDPLUA")) end
        if self:GetCtrl("wxID_CHK_UDPLUA"):IsChecked() then Save2File("LUA",data) end
	end,
	["LOG"] = function(data)
		tCtrls["wxID_TXT_UDPLOG"]:AppendText(data)
        if tCtrls["shown_page"] ~= "LOG" then BoldIt(self:GetCtrl("wxID_CMD_UDPLOG")) end
        if self:GetCtrl("wxID_CHK_UDPLOG"):IsChecked() then Save2File("LOG",data) end
	end,
	["REG"] = function(data)
		tCtrls["wxID_TXT_UDPREG"]:AppendText(data)
        if tCtrls["shown_page"] ~= "REG" then BoldIt(self:GetCtrl("wxID_CMD_UDPREG")) end
        if self:GetCtrl("wxID_CHK_UDPREG"):IsChecked() then Save2File("REG",data) end
	end,
	}
	local sType,msg = data:match(".-%[(%u%u%u)%]%s(.+)$")
	if sType and tTypes[sType] then
		msg = os.date("[%H:%M:%S] ")..msg.."\n"
		tTypes[sType](msg)
	else
		local i = data:find("%b<>")
		if i then data = os.date("[%H:%M:%S] ")..data:sub(i).."\n" end
	    tCtrls["wxID_TXT_UDPCHAT"]:AppendText(data)
		if tCtrls["shown_page"] ~= "CHAT" then BoldIt(self:GetCtrl("wxID_CMD_UDPCHAT")) end
		if self:GetCtrl("wxID_CHK_UDPCHAT"):IsChecked() then Save2File("CHAT",data) end
	end
end

function tFuncs.About(self)
	local sHTML = [[<html>
	  <body bgcolor = "#2994FD">
	    <font color = "#FFFFFF">
	      <table cellspacing = 4 cellpadding = 4 width = "100%" bgcolor = "#2994FD">
	        <tr>
	          <td>
	            <center>
	              <img src="file:PRAdmin.xrs#zip:images/ptokax.xpm">
	              <br><font size = +5><b>PtokaX Remote Administration ==APPVER==</b></font>
	              <br>Copyright � 2006-2009 Thor
	              <br>License: Lua | wxWidgets | wxLua
	              <br>
	              <br>PtokaX is a server-software for the Direct Connect P2P Network.
	              <br>It's currently in developing by PPK and Ptaczek since May 2002.
	              <br>
	              <br><b>Homepage:</b>
	              <br><a href="http://www.PtokaX.org">http://www.PtokaX.org </a>
	              <br><b>LUA Scripts forums:</b> 
	              <br><a href="http://board.ptokax.ath.cx">http://board.ptokax.ath.cx
                  </a>
	              <br><a href="http://lua.uknnet.com">http://lua.uknnet.com </a>
	              <br><b>Wiki:</b>
	              <br><a href="http://wiki.ptokax.ath.cx">http://wiki.ptokax.ath.cx</a></center>
	          </td>
	        </tr>
	      </table>
	      <hr width="80%">
	      <table border = 2 cellspacing = 4 cellpadding = 4 width = "100%" bgcolor = "#2994FD">
	        <tr>
	          <td>
	            <center>
	              It's highly recommended to register a new profile to avoid from
	              <br>abuse. In the profile editor, add a new profile called like

	              <br>'remote_admin', and <b>disallow everything</b> except have key/is op.
				  <br>and reload textfiles
	            </center>
	          </td>
	        </tr>
	      </table>
	      <hr width="80%">
	      <table cellspacing = 4 cellpadding = 4 width = "100%" bgcolor = "#2994FD">
	        <tr>
	          <td>
	            <center>
	              <b>
	                Powered by
	              </b>
	            </center>
	          </td>
	        </tr>
	        <font size=-1>
	      </table>
	      <table cellspacing = 4 cellpadding = 4 width = "100%" bgcolor = "#2994FD" height="194">
	        <tr>
	          <td height="53">
	            <center>
				  ==LUA_VERSION== <br>
	              <a href="http://www.lua.org">
	              <img src="file:PRAdmin.xrs#zip:images/lua.xpm">
	              <br>http://www.lua.org </a>
	            </center>
	          </td>
	        </tr>
	        <tr>
	          <td height="52">
	            <center>
				  ==WXLUA_VERSION== (Based on ==WXWIDGETS_VERSION==)<br>
	              <a href="http://wxlua.sf.net">
	              <img src="file:PRAdmin.xrs#zip:images/wxlua.xpm">
	              <br>http://wxlua.sf.net </a>
	            </center>
	          </td>
	        </tr>
	        <tr>
	          <td height="53">
	            <center>
	              <b>Built with NotePad++<br>The freeware editor</b>
				  <br><a href="http://notepad-plus.sourceforge.net/">
	              http://notepad-plus.sourceforge.net/ </a>
	            </center>
	          </td>
	        </tr>
	      </table>
	      <hr width="80%">
	        <table cellspacing = 4 cellpadding = 4 width = "100%" bgcolor = "#2994FD">
	          <tr>
	            <td>
	              <center>
	                Thanks for the translators:
	                <br>Brazilian Portuguese by 7P-Darkman
	                <br>Cesky by PPK
	                <br>Chinese simplified by fenxiang
	                <br>Dansk by Gnuff�
	                <br>French by CyberChris
	                <br>Hebrew by TrIp-iN-SuN
	                <br>Italian by -SkA-
	                <br>Hungarian by Hungarista
	                <br>Nederlands by CrazyGuy
	                <br>Polish by MacGyver
	                <br>Portugues by ConejoDelMal
	                <br>Romanian by FANEM008
	                <br>Russian by nikita800
	                <br>Svenska by Nillan�
	              </center>
	            </td>
	          </tr>
	        </table>
	      <hr width="80%">
	        <table cellspacing = 4 cellpadding = 4 width = "100%" bgcolor = "#2994FDs">
	          <tr>
	            <td>
	              <center>
	                If you have any kind of problem or you have bugreport (every time
	                <br>if something goes wrong, a file - called exceptioninfo.txt - will
	                <br>be generated. If you see that file in your directory, please send
	                <br>that to me to my e-mail address: ejjeliorjarat@gmail.com or contact
	                <br>me ([OP]Thor) at dchub://diablohub.hu.
	                <br>If you find any abnormal thing, send me that also a description,
	                <br>what you exactly did, and what went wrong.
                      </center>
	            </td>
	          </tr>
	        </table>
	      </font>
	    </font>
	  </body>
	</html>]]
	sHTML = sHTML:gsub("==APPVER==",_APPVER)
	sHTML = sHTML:gsub("==LUA_VERSION==",_VERSION)
	sHTML = sHTML:gsub("==WXLUA_VERSION==",wxlua.wxLUA_VERSION_STRING)
	sHTML = sHTML:gsub("==WXWIDGETS_VERSION==",wx.wxVERSION_STRING)
	local about = wx.wxDialog()
	if m_XmlResource:LoadDialog(about,wx.NULL,"ID_DLG_ABOUT") then
		self:GetCtrl("ID_HTMLWINDOW",about):SetPage(sHTML)
		about:Centre()
		about:ShowModal()
		about:Destroy()
	else
		wx.wxMessageBox("Failed to load the about form from the XML resource. Please re-download the application")
	end
end

do
	tCtrls = {
		-- TextValidators
		Nick = wx.wxTextValidator(wx.wxFILTER_EXCLUDE_CHAR_LIST),	-- For NMDC nickname
		NoP = wx.wxTextValidator(wx.wxFILTER_EXCLUDE_CHAR_LIST),	-- NoPipe
		NoPD = wx.wxTextValidator(wx.wxFILTER_EXCLUDE_CHAR_LIST),	-- NoPipeDollar
		Port = wx.wxTextValidator(wx.wxFILTER_INCLUDE_CHAR_LIST),	-- Numbers and ;
		NUM = wx.wxTextValidator(wx.wxFILTER_INCLUDE_CHAR_LIST),	-- Numeric values. FILTER_NUMERIC allows 'e,.-'. We want _just_ numbers
		-- Others
		iLastPage = 1,		-- The tree-item number which is selected
		iStatus = 0,		-- 1, when logged in the hub
		tSettings = {       -- Settings. With this, just the modified settings will be sent.
		["chk"]={},
		["txt"]={},
		["num"]={},
		},
		sHubname = "",                    -- Hub's name
		tLangs = {},                      -- Translated strings
		tDeadThreads = {},                -- The threads, which can be destroyed
		tFiles = {},                      -- Files, which are currenty downloaded
		tBans = {},                       -- Bans (temp and perm too)
		tRangeBans = {},                  -- Rangebans (temp and perm too)
		tProfiles = {},                   -- Profiles
		tRegs = {},                       -- Registered users
		tSortedLists = {},                -- Sorted lists for ListCtrl sorting
		langfile = nil,                   -- language file
		imglist = wx.wxImageList(16,16),  -- Imagelist
		shown_page = "SYS",               -- UDP debug receiver's selected page
		sHubversion = "0.4.1.1",          -- Hub's version for XML
		tEditorSettings = {},             -- Editor's settings: colours, fonts
	}

	BSKIP = false; -- Switch for the parser
	sBUFFER = ""; -- Socket buffer
	m_XmlResource = wx.wxXmlResource();
	m_FileSystem = wx.wxFileSystem();
	m_ArchiveFileSystem = wx.wxArchiveFSHandler(); -- NEVER USE IT IMPLICITLY AND NEVER DELETE IT!!!
	m_FileSystem.AddHandler(m_ArchiveFileSystem);
	m_XmlResource:InitAllHandlers();
	local xrcFilename = "PRAdmin.xrs"
	-- try to load the resource and ask for path to it if not found
	while not m_XmlResource:Load(xrcFilename) do
		-- must unload the file before we try again
		m_XmlResource:Unload(xrcFilename)
		wx.wxMessageBox("Error while loading xrc resources, please choose the path to 'PRAdmin.xrs'.",_APPNAME,wx.wxOK + wx.wxICON_EXCLAMATION)
		local fileDialog = wx.wxFileDialog(wx.NULL,"Open 'PRAdmin.xrs' resource file","","PRAdmin.xrs","XRS files (*.xrs)|*.xrs|All files (*)|*",wx.wxOPEN + wx.wxFILE_MUST_EXIST)
		if fileDialog:ShowModal() == wx.wxID_OK then
			xrcFilename = fileDialog:GetPath()
		else
			return -- quit
		end
	end

	setmetatable(tCtrls,{__index = function(t,k)
		if k and k:sub(1,4) == "wxID" or k:sub(1,3) == "ID_" 
		or k:sub(1,4) == "chk_" or k:sub(1,4) == "num_" or k:sub(1,4) == "txt_" then
			local NewId = m_XmlResource.GetXRCID(k)
			--if not NewId then NewId = wx.wxNewId() end -- Not used now
			rawset(t,k,NewId)
			return NewId
		end
	end})

	for i=1,27 do
		tCtrls.tEditorSettings[i] = {}
		setmetatable(tCtrls.tEditorSettings[i],{__index = function(t,j)
			if not rawget(t,j) then
				local tRet = {wx.wxWHITE,wx.wxBLACK,wx.wxNORMAL_FONT}
				return tRet[j]
			end
		end})
	end

	tCtrls["Nick"]:SetExcludes({" ","|","$"})
	tCtrls["NoP"]:SetExcludes({"|"})
	tCtrls["NoPD"]:SetExcludes({"|","$"})
	tCtrls["Port"]:SetIncludes({"0","1","2","3","4","5","6","7","8","9",";"})
	tCtrls["NUM"]:SetIncludes({"0","1","2","3","4","5","6","7","8","9"})
	tCtrls["imglist"]:Add(wx.wxBitmap(16,16)) -- 0 (was op, empty now)
	tCtrls["imglist"]:Add(wx.wxBitmap(16,16)) -- 1 (was user, empty now)
	tCtrls["imglist"]:Add(wx.wxArtProvider.GetBitmap(wx.wxART_GO_DOWN, wx.wxART_MENU, wx.wxSize(16,16))) -- 2
	tCtrls["imglist"]:Add(wx.wxArtProvider.GetBitmap(wx.wxART_GO_UP, wx.wxART_MENU, wx.wxSize(16,16))) -- 3
	tCtrls["imglist"]:Add(tFuncs:GetImage("settings")) -- 4
	tCtrls["imglist"]:Add(tFuncs:GetImage("lua_small")) -- 5
	tCtrls["imglist"]:Add(tFuncs:GetImage("reg")) -- 6
	tCtrls["imglist"]:Add(tFuncs:GetImage("ban")) -- 7
	tCtrls["imglist"]:Add(tFuncs:GetImage("txt")) -- 8
	tCtrls["imglist"]:Add(tFuncs:GetImage("hub")) -- 9
	tCtrls["imglist"]:Add(tFuncs:GetImage("bug")) -- 10
	tCtrls["txt"] = {}	-- wxTextCtrl's
	tCtrls["chk"] = {}	-- wxCheckBox's
	tCtrls["num"] = {}	-- wxSpinCtrl's (num up/down)

	if not wx.wxDirExists("scripts") then wx.wxMkdir("scripts") end
	if not wx.wxDirExists("texts") then wx.wxMkdir("texts") end

	-- Equivalent to C's "cond ? a : b", _ALL_ terms will be evaluated
	function iff(cond,A,B) return cond and A or B end

	-- Splash-screen
	local m_dc = wx.wxMemoryDC();
	m_dc:SelectObject(tFuncs:GetImage("splash"));
	local m_font = wx.wxFont(20,wx.wxFONTFAMILY_DECORATIVE,wx.wxFONTSTYLE_NORMAL,wx.wxFONTWEIGHT_BOLD);
	m_font:SetPointSize(16);
	m_dc:SetFont(m_font);
	m_dc:SetTextForeground(wx.wxColour(0x00,0x00,0x88));
	m_dc:DrawText(_APPVER,100,125);
	tCtrls["splash"] = wx.wxSplashScreen(m_dc:GetAsBitmap(),wx.wxSPLASH_CENTRE_ON_SCREEN+wx.wxSPLASH_NO_TIMEOUT,0,wx.NULL,wx.wxID_ANY);
	m_dc:delete();
	m_font:delete();
	--
	tCtrls["app"] = wx.wxFrame()
	if not m_XmlResource:LoadFrame(tCtrls["app"],wx.NULL,"ID_DLG_MAIN") then
		wx.wxMessageBox("Error while loading the xrc resource file! Please download the application again from http://sf.net/pradmin",_APPNAME,wx.wxOK + wx.wxICON_EXCLAMATION)
		return -- quit program
	end
	tCtrls["app"]:Iconize(true)
	tCtrls["app"]:Show(false)
	-- Seems everything is OK, load the settings and find the controls...
	tFuncs:LoadSettings()
	tCtrls["statusbar"] = tFuncs:GetCtrl("ID_STATUSBAR")
	tCtrls["taskbar"] = wx.wxTaskBarIcon()
	local m_Bitmap = tFuncs:GetImage("spider")
	-- Linux likes it 16x16
	if not wx.__WXMSW__ then
		local m_Image = m_Bitmap:ConvertToImage();
		m_Image:Rescale(16,16)
		m_Bitmap = wx.wxBitmap(m_Image);
	end
	--
	local m_Icon = wx.wxIcon()
	m_Icon:CopyFromBitmap(m_Bitmap)
	tCtrls["app"]:SetIcon(m_Icon)
	tCtrls["app"]:SetTitle(_APPNAME.." ".._APPVER)
	tCtrls["taskbar"]:SetIcon(m_Icon,_APPNAME.." ".._APPVER)
	m_Icon:delete()
	m_Bitmap:delete()
	tCtrls["tab"] = tFuncs:GetCtrl("ID_NOTEBOOK")
	tCtrls["tab"]:SetImageList(tCtrls["imglist"],wx.wxIMAGE_LIST_SMALL)
	tCtrls["tab"]:SetPageImage(0,9);tCtrls["tab"]:SetPageImage(1,4);tCtrls["tab"]:SetPageImage(2,5);
	tCtrls["tab"]:SetPageImage(3,6);tCtrls["tab"]:SetPageImage(4,7)tCtrls["tab"]:SetPageImage(5,8);
	tCtrls["tab"]:SetPageImage(6,9)
	tCtrls["tab"]:RemovePage(6)
	local tLangs,iLang = {"Default English"},0
	m_FileSystem:ChangePathTo("file:PRAdmin.xrs#zip:/language/")
	if m_FileSystem:GetPath() ~= "" then -- language folder exists
		local file = m_FileSystem:FindFirst("*.xml")
		    repeat
		        if not file:find("example") and file ~= "" then
					table.insert(tLangs,file:sub(31,-5)) -- Remove file:PRAdmin.xrs#zip/language/ and .xml
				end
				file = m_FileSystem:FindNext("*.xml")
			until file == ""
		m_FileSystem:ChangePathTo("")
	end
	tCtrls["language"] = tFuncs:GetCtrl("wxID_LANGUAGE")
	tCtrls["language"]:Append(tLangs)
	if tCtrls["langfile"] then iLang = tCtrls["language"]:FindString(tCtrls["langfile"]) end
	tCtrls["language"]:SetSelection(iLang)
	tCtrls["cmd_udpdbg"] = tFuncs:GetCtrl("cmd_udpdbg")
	tCtrls["cmd_udpdbg"]:SetToolTip("Subscribe to UDP debug messages")
	tCtrls["cmd_udpdbg"]:Connect(wx.wxEVT_COMMAND_BUTTON_CLICKED,function(event) tFuncs:CreateUDPDebugFrame() end)
	for i=0,113 do tCtrls["num"]["num_"..i] = tFuncs:GetCtrl("num_"..i) end
	for i=0,34 do tCtrls["txt"]["txt_"..i] = tFuncs:GetCtrl("txt_"..i) end
	tCtrls["txt"]["txt_motd"] = tFuncs:GetCtrl("txt_motd")
	for i=0,55 do tCtrls["chk"]["chk_"..i] = tFuncs:GetCtrl("chk_"..i) end
	tFuncs:GetCtrl("txt_login_address"):SetValidator(tCtrls["NoPD"])
	tFuncs:GetCtrl("txt_login_address"):Connect(wx.wxEVT_COMMAND_TEXT_ENTER ,function(event) tFuncs:Connect() end)
	tFuncs:GetCtrl("txt_login_nick"):SetValidator(tCtrls["Nick"])
	tFuncs:GetCtrl("txt_login_desc"):SetValidator(tCtrls["NoPD"])
	tFuncs:GetCtrl("txt_login_tag"):SetValidator(tCtrls["NoPD"])
	tFuncs:GetCtrl("txt_login_tag"):SetValue("<PRA V:".._APPVER:sub(2)..",M:A,H:0/0/1,S:2>")
	tFuncs:GetCtrl("txt_login_share"):SetValidator(tCtrls["NUM"])
	tCtrls["settings_tree"] = tFuncs:GetCtrl("ID_TRC_SETTINGS")
	local root = tCtrls["settings_tree"]:AddRoot("", -1,-1)
	local tTree = {
	tCtrls["settings_tree"]:AppendItem(root,"General settings"),
	tCtrls["settings_tree"]:AppendItem(root,"Advanced"),
	tCtrls["settings_tree"]:AppendItem(root,"Rules"),
	tCtrls["settings_tree"]:AppendItem(root,"Deflood"),
	}
	table.insert(tTree,tCtrls["settings_tree"]:AppendItem(tTree[1],"MOTD"))
	table.insert(tTree,tCtrls["settings_tree"]:AppendItem(tTree[1],"Default bots"))
	table.insert(tTree,tCtrls["settings_tree"]:AppendItem(tTree[1],"More general"))
	table.insert(tTree,tCtrls["settings_tree"]:AppendItem(tTree[1],"Ban handling"))
	table.insert(tTree,tCtrls["settings_tree"]:AppendItem(tTree[2],"MyINFO processing"))
	table.insert(tTree,tCtrls["settings_tree"]:AppendItem(tTree[2],"Advanced security"))
	table.insert(tTree,tCtrls["settings_tree"]:AppendItem(tTree[3],"More rules"))
	table.insert(tTree,tCtrls["settings_tree"]:AppendItem(tTree[4],"More deflood"))
	table.insert(tTree,tCtrls["settings_tree"]:AppendItem(tTree[4],"More more deflood"))
	-- Expand the trees
	tCtrls["settings_tree"]:Expand(tTree[1])
	tCtrls["settings_tree"]:Expand(tTree[2])
	tCtrls["settings_tree"]:Expand(tTree[3])
	tCtrls["settings_tree"]:Expand(tTree[4])
	tCtrls["settings_tree"]:Connect(wx.wxEVT_COMMAND_TREE_SEL_CHANGED,
	function(event)
		for i,v in ipairs(tTree) do
			if tCtrls["settings_tree"]:IsSelected(v) then
				tFuncs:GetCtrl("ID_PANEL"..tCtrls["iLastPage"]):Show(false)
				tFuncs:GetCtrl("ID_PANEL"..i):Show(true)
				tCtrls["iLastPage"] = i
				tFuncs:GetCtrl("ID_PNL_SETTINGS"):Layout()
				collectgarbage("collect")
			end
		end
	end)
	tCtrls["settings_tree"]:SelectItem(tTree[1])
	if wxstc then tFuncs:CreateSTCEditor() end
	tCtrls["lst_scripts"] = tFuncs:GetCtrl("wxID_LUA_LIST")
	tCtrls["lst_regs"] = tFuncs:GetCtrl("wxID_REGLIST")
	tCtrls["lst_regs"]:InsertColumn(0,tFuncs:Translate("User")     or "User",    wx.wxLIST_FORMAT_LEFT,3)
	tCtrls["lst_regs"]:InsertColumn(1,tFuncs:Translate("Password") or "Password",wx.wxLIST_FORMAT_LEFT,-1)
	tCtrls["lst_regs"]:InsertColumn(2,tFuncs:Translate("Profile")  or "Profile", wx.wxLIST_FORMAT_LEFT,-1)
	tCtrls["lst_regs"]:SetColumnWidth(0,wx.wxLIST_AUTOSIZE_USEHEADER)
	tCtrls["lst_regs"]:SetColumnWidth(1,wx.wxLIST_AUTOSIZE_USEHEADER)
	tCtrls["lst_permissions"] = tFuncs:GetCtrl("wxID_PERMISSION_LIST")
	tCtrls["lst_profiles"] = tFuncs:GetCtrl("wxID_PROFLIST")
	tFuncs:LoadLanguage()
	if tCtrls["language"]:FindString(tostring(tCtrls["langfile"])) ~= -1 then 
		tCtrls["language"]:SetStringSelection(tCtrls["langfile"])
	end
	tCtrls["lst_bans"] = tFuncs:GetCtrl("wxID_BANLIST")
	tCtrls["lst_bans"]:InsertColumn(0,tFuncs:Translate("IP")       or "IP",        wx.wxLIST_FORMAT_LEFT, 3)
	tCtrls["lst_bans"]:InsertColumn(1,tFuncs:Translate("Nick")     or "Nick",      wx.wxLIST_FORMAT_LEFT, -1)
	tCtrls["lst_bans"]:InsertColumn(2,tFuncs:Translate("BannedBy") or "Banned by", wx.wxLIST_FORMAT_LEFT, -1)
	tCtrls["lst_bans"]:InsertColumn(3,tFuncs:Translate("Reason")   or "Reason",    wx.wxLIST_FORMAT_LEFT, -1)
	tCtrls["lst_bans"]:InsertColumn(4,tFuncs:Translate("Expire")   or "Expire",    wx.wxLIST_FORMAT_LEFT, -1)
	tCtrls["lst_bans"]:SetColumnWidth(0,wx.wxLIST_AUTOSIZE_USEHEADER)
	tCtrls["lst_bans"]:SetColumnWidth(1,wx.wxLIST_AUTOSIZE_USEHEADER)
	tCtrls["lst_bans"]:SetColumnWidth(2,wx.wxLIST_AUTOSIZE_USEHEADER)
	tCtrls["lst_bans"]:SetColumnWidth(3,wx.wxLIST_AUTOSIZE_USEHEADER)
	tCtrls["lst_bans"]:SetColumnWidth(4,wx.wxLIST_AUTOSIZE_USEHEADER)
	tCtrls["lst_rangebans"] = tFuncs:GetCtrl("wxID_RANGEBANLIST")
	tCtrls["lst_rangebans"]:InsertColumn(0,tFuncs:Translate("Range")    or "Range",     wx.wxLIST_FORMAT_LEFT, 3)
	tCtrls["lst_rangebans"]:InsertColumn(1,tFuncs:Translate("BannedBy") or "Banned by", wx.wxLIST_FORMAT_LEFT, -1)
	tCtrls["lst_rangebans"]:InsertColumn(2,tFuncs:Translate("Reason")   or "Reason",    wx.wxLIST_FORMAT_LEFT, -1)
	tCtrls["lst_rangebans"]:InsertColumn(3,tFuncs:Translate("Expire")   or "Expire",    wx.wxLIST_FORMAT_LEFT, -1)
	tCtrls["lst_rangebans"]:SetColumnWidth(0,wx.wxLIST_AUTOSIZE_USEHEADER)
	tCtrls["lst_rangebans"]:SetColumnWidth(1,wx.wxLIST_AUTOSIZE_USEHEADER)
	tCtrls["lst_rangebans"]:SetColumnWidth(2,wx.wxLIST_AUTOSIZE_USEHEADER)
	tCtrls["lst_rangebans"]:SetColumnWidth(3,wx.wxLIST_AUTOSIZE_USEHEADER)
	tFuncs:GetCtrl("ID_BANSPLITTER"):SetSashPosition(255,true)
	tCtrls["lst_texts"] = tFuncs:GetCtrl("wxID_TEXTS")
	tFuncs:TranslateStrings()
	tFuncs:InitTranslatableControls()
	tFuncs:TranslateGUI()
end

-- Threadsafe calls

function OnTCP(event)
	local sString = event:DynamicCast("wxCommandEvent"):GetString();
	sRawString = sString:gsub("%[endpipe%]","|");
	sString = convert_input(sRawString);
	tFuncs:ParseTCP(sString, sRawString);
end
tCtrls["app"]:Connect(tCtrls["wxID_EVENT_TCPPARSE"],wx.wxEVT_NULL,OnTCP);

function OnUDP(event)
	sRawString = event:DynamicCast("wxCommandEvent"):GetString();
	sString = convert_input(sRawString);
	tFuncs:ParseUDP(sString, sRawString);
end
tCtrls["app"]:Connect(tCtrls["wxID_EVENT_UDPPARSE"],wx.wxEVT_NULL,OnUDP)

function OnTXT(event)
	if event:GetInt() == 0 then
		tFuncs:GetCtrl("txt_scripteditor"):LoadFile("./scripts/"..event:GetString())
	elseif event:GetInt() == 1 then
		tFuncs:GetCtrl("txt_texteditor"):LoadFile("./texts/"..event:GetString())
	elseif event:GetInt() == 2 then
		local script = event:GetString()
		local res,err = loadfile("./scripts/"..script)
		if res then
			tFuncs:GetCtrl("txt_scripterror"):AppendText("["..os.date("%H:%M").."] "..(tFuncs:Translate("NoSynErrInScriptFile") or "No syntax errors in script file:").." "..script.."\n")
		else
			tFuncs:GetCtrl("txt_scripterror"):AppendText("["..os.date("%H:%M").."] "..(tFuncs:Translate("Syntax") or "Syntax").." "..tostring(err).."\n")
		end
	else
		local m_ft = wx.wxTheMimeTypesManager:GetFileTypeFromExtension("lua")
		if not m_ft then
			wx.wxMessageBox("There is no associated application for lua files.")
			return
		else
			local cmd = m_ft:GetOpenCommand(event:GetString());
			if cmd ~= "" then
				wx.wxExecute(cmd,wx.wxEXEC_ASYNC, wx.wxProcess()); 
			end
		end
	end
end
tCtrls["app"]:Connect(tCtrls["wxID_EVENT_TEXTFILE"],wx.wxEVT_NULL,OnTXT)

-- Real event handlers
function OnButtonClick(event)
	local tButtonEvtIds = {
	[tCtrls["wxID_CMD_LOGIN"]] = function()
		if tFuncs:GetCtrl("txt_login_nick"):GetValue():len() == 0 or tFuncs:GetCtrl("txt_login_passwd"):GetValue():len() == 0 then
			wx.wxMessageBox("The nick and password field can't be empty!","Warning!",wx.wxICON_EXCLAMATION)
			return
		end
		if tFuncs:GetCtrl("wxID_CMD_LOGIN"):GetLabel() == (tFuncs:Translate("Disconnect") or "Disconnect") then
			tFuncs:CleanUp()
		else
			tFuncs:Connect()
		end
	end,
	[wx.wxID_ABOUT] = function()
		tFuncs:About()
	end,
	[tCtrls["wxID_CMD_LOGIN_SAVE"]] = function()
		tFuncs:SaveSettings()
	end,
	[tCtrls["wxID_CMD_PWGEN"]] = function()
		tFuncs:GeneratePassword()
	end,
	[tCtrls["wxID_CMD_STAT"]] = function()
		tFuncs:ShowStat()
	end,
	[tCtrls["wxID_PROF_ALL"]] = function()
		if tCtrls["iStatus"] == 1 then
			tFuncs:Send("$SET 5 "..tCtrls["lst_profiles"]:GetSelection().." p 56 1")
		end
	end,
	[tCtrls["wxID_PROF_CLEAR"]] = function()
		if tCtrls["iStatus"] == 1 then
			tFuncs:Send("$SET 5 "..tCtrls["lst_profiles"]:GetSelection().." p 56 0")
		end
	end,
	[tCtrls["wxID_PROF_DOWN"]] = function()
		if tCtrls["iStatus"] == 1 then
			if tCtrls["lst_profiles"]:GetSelection() >= 0 then
			    wx.wxBeginBusyCursor()
				tFuncs:Send("$SET 5 "..tCtrls["lst_profiles"]:GetSelection().." 0")
				tFuncs:GetCtrl("wxID_PROF_UP"):Enable(false)
				tFuncs:GetCtrl("wxID_PROF_DOWN"):Enable(false)
			end
		end
	end,
	[tCtrls["wxID_PROF_UP"]] = function()
		if tCtrls["iStatus"] == 1 then
			if tCtrls["lst_profiles"]:GetSelection() >= 0 then
			    wx.wxBeginBusyCursor()
				tFuncs:Send("$SET 5 "..tCtrls["lst_profiles"]:GetSelection().." 1")
				tFuncs:GetCtrl("wxID_PROF_UP"):Enable(false)
				tFuncs:GetCtrl("wxID_PROF_DOWN"):Enable(false)
			end
		end
	end,
	[tCtrls["wxID_PROF_ADD"]] = function()
		if tCtrls["iStatus"] == 1 then
	    	local newprofile = wx.wxGetTextFromUser(tFuncs:Translate("NewProfileName") or "New profile name:",tFuncs:Translate("Name") or "Name")
			-- GetTextFromUser hasn't got validator :-/
			newprofile = newprofile:gsub("[%$|%s]","") -- Remove dollars, endpipes and white chars
			if newprofile == "" then return end
            wx.wxBeginBusyCursor()
			for i=0,tCtrls["lst_profiles"]:GetCount() do
			    if tCtrls["lst_profiles"]:GetString(i):lower() == newprofile:lower() then
                    wx.wxEndBusyCursor()
					wx.wxMessageBox(tFuncs:Translate("ProfileNameExist") or "Profile name already exists in the list!")
					return
				end
			end
			tFuncs:Send("$SET 5 "..newprofile.." true")
		end
	end,
	[tCtrls["wxID_PROF_DEL"]] = function()
		if tCtrls["iStatus"] == 1 then
			if tCtrls["lst_profiles"]:GetSelections() > 0 then
			    wx.wxBeginBusyCursor()
				local bCanDelete = true
				for index,reguser in ipairs(tCtrls["tRegs"]) do
					if reguser[3] == tCtrls["lst_profiles"]:GetStringSelection() then
						bCanDelete = nil
						break
					end
				end
				if bCanDelete then
					tFuncs:Send("$SET 5 "..tCtrls["lst_profiles"]:GetStringSelection().." false")
				else
					wx.wxMessageBox(tFuncs:Translate("ProfileDelFailed") or "Failed to delete a profile. Profile is in use.")
				end
			end
		end
	end,
	[tCtrls["wxID_ACCEPT"]] = function()
		if tCtrls["iStatus"] == 1 then
		    wx.wxBeginBusyCursor()
			local tSet = {}
			for i=0,55 do
			    if iff(tCtrls["chk"]["chk_"..i]:GetValue(),"1","0") ~= tCtrls["tSettings"]["chk"][i] then
					table.insert(tSet,i.."$"..iff(tCtrls["chk"]["chk_"..i]:GetValue(),"1","0"))
					tCtrls["tSettings"]["chk"][i] = iff(tCtrls["chk"]["chk_"..i]:GetValue(),"1","0") -- update
				end
			end
			if next(tSet) then -- Did we modify something?
				tFuncs:Send("$SET 0 "..table.concat(tSet,"$$").."$$")
			end
			tSet = {}
			for i=0,113 do
				if tCtrls["num"]["num_"..i]:GetClassInfo():GetClassName() == "wxSpinCtrl" then
				    if tostring(tCtrls["num"]["num_"..i]:GetValue()) ~= tCtrls["tSettings"]["num"][i] then
						table.insert(tSet,i.."$"..tostring(tCtrls["num"]["num_"..i]:GetValue()))
						tCtrls["tSettings"]["num"][i] = tostring(tCtrls["num"]["num_"..i]:GetValue())
					end
				else
				    if tostring(tCtrls["num"]["num_"..i]:GetSelection()) ~= tCtrls["tSettings"]["num"][i] then
						table.insert(tSet,i.."$"..tostring(tCtrls["num"]["num_"..i]:GetSelection()))
						tCtrls["tSettings"]["num"][i] = tostring(tCtrls["num"]["num_"..i]:GetSelection())
					end
				end
			end
			if next(tSet) then
				tFuncs:Send("$SET 1 "..table.concat(tSet,"$$").."$$")
			end
			if tCtrls["txt"]["txt_motd"]:GetValue() ~= tCtrls["tSettings"]["txt"]["motd"] then
				tFuncs:Send("$SET 2 motd "..tCtrls["txt"]["txt_motd"]:GetValue())
				tCtrls["tSettings"]["txt"]["motd"] = tCtrls["txt"]["txt_motd"]:GetValue()
			end
			tSet = {}
			for i=0,34 do
			    if i == 34 then
			        if tCtrls["txt"]["txt_34"]:GetStringSelection() ~= tCtrls["tSettings"]["txt"][34] then
				 		table.insert(tSet,i.."$"..tCtrls["txt"]["txt_"..i]:GetStringSelection())
				 		tCtrls["tSettings"]["txt"][i] = tCtrls["txt"]["txt_"..i]:GetStringSelection()
					end
				else
				    if tCtrls["txt"]["txt_"..i]:GetValue() ~= tCtrls["tSettings"]["txt"][i] then
				 		table.insert(tSet,i.."$"..tCtrls["txt"]["txt_"..i]:GetValue())
				 		tCtrls["tSettings"]["txt"][i] = tCtrls["txt"]["txt_"..i]:GetValue()
					end
				end
			end
			if next(tSet) then
				tFuncs:Send("$SET 2 "..table.concat(tSet,"$$").."$$")
			end
			wx.wxEndBusyCursor()
		end
	end,
	[tCtrls["wxID_DEFAULT"]] = function()
		if wx.wxMessageBox("Are you sure you want to load the default settings?","Confirm",wx.wxYES_NO+wx.wxNO_DEFAULT) == wx.wxYES then
        	local tDefBoolVals,tDefIntVals,tDefStringVals = tFuncs:GetDefaultValues()
			for i=0,55 do
				local bBool = tDefBoolVals[(i+1)]
				tCtrls["tSettings"]["chk"][i] = bBool
            	tCtrls["chk"]["chk_"..i]:SetValue(bBool)
			end
			for i=0,113 do
				local iNum = tDefIntVals[(i+1)]
		    	tCtrls["tSettings"]["num"][i] = iNum
		        if tCtrls["num"]["num_"..i]:GetClassInfo():GetClassName() == "wxSpinCtrl" then
					tCtrls["num"]["num_"..i]:SetValue(iNum)
				else
					tCtrls["num"]["num_"..i]:SetSelection(iNum)
				end
			end
			for i=0,34 do
				local sString = tDefStringVals[(i+1)]
		    	tCtrls["tSettings"]["txt"][i] = sString
				if i == 34 then
					tCtrls["txt"]["txt_34"]:SetStringSelection(sString)
				else
					tCtrls["txt"]["txt_"..i]:SetValue(sString)
				end
			end
		end
	end,
	[tCtrls["wxID_LOADFROMXML"]] = function()
		local f = wx.wxFileSelector("Select Settings.xml file",wx.wxGetCwd(),"Settings.xml","*.xml","*.xml")
		if f ~= "" then
			tFuncs:LoadFromXML(f)
		end
	end,
	[tCtrls["wxID_SAVETOXML"]] = function()
		if not wx.wxDirExists("./cfg") then wx.wxMkdir("cfg") end
		local sPath = wx.wxDirSelector(wx.wxDirSelectorPromptStr,wx.wxGetCwd().."/cfg")
		if sPath ~= "" then
			tFuncs:SaveToXML(sPath)
			tFuncs:SetStatusText(tFuncs:Translate("SettingsSaved") or "Settings saved.")
		end
	end,
	[tCtrls["wxID_LUA_LOAD"]] = function()
	    if tCtrls["iStatus"] == 1 then
			local filename = wx.wxFileSelector("Load script", wx.wxGetCwd(),"","","*.lua",wx.wxFD_OPEN + wx.wxFD_FILE_MUST_EXIST)
			if filename ~= "" then
				if wx.wxFileExists(filename) then
					tFuncs:GetCtrl("txt_scripteditor"):LoadFile(filename)
				end
			end
		end
	end,
	[tCtrls["wxID_LUA_SAVE"]] = function()
		if tCtrls["iStatus"] == 1 then
			if not wx.wxDirExists("scripts") then wx.wxMkdir("scripts") end
			local filename = wx.wxFileSelector("Save script", wx.wxGetCwd().."/scripts","","","*.lua",wx.wxFD_SAVE)
			if filename ~= "" then
				if filename:sub(-4) ~= ".lua" then filename = filename..".lua" end
				local f = io.open(filename,"w+")
				if f then
					local c = ""
					if wxstc then
						c = tFuncs:GetCtrl("txt_scripteditor"):GetText()
					else
						c = tFuncs:GetCtrl("txt_scripteditor"):GetValue()
					end
					f:write(c)
					filename = filename:match(".+\\(.+)$")
					tFuncs:Send("$SET 7 \""..filename.."\" "..c:gsub("|","[endpipe]"))
					local bNew = true
					for i=0,tCtrls["lst_scripts"]:GetCount() -1 do
						if tCtrls["lst_scripts"]:GetString(i) == filename then
							bNew = false
							break
						end
					end
					if bNew then
						tCtrls["lst_scripts"]:Insert(filename,tCtrls["lst_scripts"]:GetCount())
					end
				end
			end
		end
	end,
	[tCtrls["wxID_LUA_REFRESH"]] = function()
		if tCtrls["iStatus"] == 1 then
			tFuncs:ReloadScripts()
		end
	end,
	[tCtrls["wxID_LUA_DOWN"]] = function()
		if tCtrls["iStatus"] == 1 then
			if tCtrls["lst_scripts"]:GetSelections() > 0 then
			    wx.wxBeginBusyCursor()
				tFuncs:Send("$SET 4 0 \""..tCtrls["lst_scripts"]:GetStringSelection().."\"")
			end
		end
	end,
	[tCtrls["wxID_LUA_UP"]] = function()
		if tCtrls["iStatus"] == 1 then
			if tCtrls["lst_scripts"]:GetSelections() > 0 then
			    wx.wxBeginBusyCursor()
				tFuncs:Send("$SET 4 1 \""..tCtrls["lst_scripts"]:GetStringSelection().."\"")
			end
		end
	end,
	[tCtrls["wxID_LUA_CHECK"]] = function()
		if tCtrls["iStatus"] == 1 then
			if tCtrls["lst_scripts"]:GetSelections() > 0 then
			    wx.wxBeginBusyCursor()
				local script = tCtrls["lst_scripts"]:GetStringSelection()
				tFuncs:DownloadFile(8,script)
				table.insert(tCtrls["tDeadThreads"],ThreadCreate(tFuncs.FileAction,{script,2}))
			else
			    tFuncs:SetStatusText("Please select a script to check first.")
			end
		end
	end,
	[tCtrls["wxID_LUA_RESTART"]] = function()
		if tCtrls["iStatus"] == 1 then
			tFuncs:Send("$SET 4 restart \".\"")
		end
	end,
	[tCtrls["wxID_CLEAR_EDITOR"]] = function()
		if wxstc then
			tFuncs:GetCtrl("txt_scripteditor"):ClearAll()
		else
			tFuncs:GetCtrl("txt_scripteditor"):Clear()
		end
	end,
	[tCtrls["wxID_CLEAR_ERROR"]] = function()
	    tFuncs:GetCtrl("txt_scripterror"):Clear()
	end,
	[tCtrls["wxID_EDITOR_SETUP"]] = function()
		tFuncs:SetupEditor();
	end,
	[tCtrls["wxID_REG_ADD"]] = function()
	    if tCtrls["iStatus"] == 1 then
	    	local sNick,sPass,iProfile = tFuncs:ShowRegWindow()
	    	if sNick then -- Maybe cancelled, check it
	    		tFuncs:Send("$SET 6 1 "..sNick.." "..sPass.." "..iProfile)
			end
		end
	end,
	[tCtrls["wxID_REG_MOD"]] = function()
	    if tCtrls["iStatus"] == 1 then
	        if tCtrls["lst_regs"]:GetSelectedItemCount() ~= 0 then
				local item = tFuncs:GetSelection(tCtrls["lst_regs"])
				local iPos = tCtrls["lst_regs"]:GetItemData(item)+1
				--local onick = tCtrls["lst_regs"]:GetItemText(item)
				local sNick,sPass,iProfile,sOldNick = tFuncs:ShowRegWindow(tCtrls["tRegs"][iPos][1],tCtrls["tRegs"][iPos][2],tCtrls["tRegs"][iPos][3])
				if sNick then -- if not cancelled
					if sNick ~= sOldNick then -- Create a new reg
						tFuncs:Send("$SET 6 0 "..sOldNick)
						tFuncs:Send("$SET 6 1 "..sNick.." "..sPass.." "..iProfile)
					else -- Just the pass/profile changed
						tFuncs:Send("$SET 6 2 "..sNick.." "..sPass.." "..iProfile)
					end
				end
			end
		end
	end,
	[tCtrls["wxID_REG_DEL"]] = function()
	    if tCtrls["iStatus"] == 1 then
	        if tCtrls["lst_regs"]:GetSelectedItemCount() ~= 0 then
				local item = tFuncs:GetSelection(tCtrls["lst_regs"])
	    		tFuncs:Send("$SET 6 0 "..tCtrls["lst_regs"]:GetItemText(item))
			end
	    end
	end,
	[tCtrls["wxID_REFRESH_BANS"]] = function()
		if tCtrls["iStatus"] == 1 then
		    tCtrls["tBans"] = {}
		    tCtrls["lst_bans"]:DeleteAllItems()
		    tFuncs:Send("$GET 3 0")
		end
	end,
	[tCtrls["wxID_REFRESH_RANGEBANS"]] = function()
		if tCtrls["iStatus"] == 1 then
		    tCtrls["tRangeBans"] = {}
	   		tCtrls["lst_rangebans"]:DeleteAllItems()
	    	tFuncs:Send("$GET 3 1")
	    end
	end,
	[tCtrls["wxID_CLEAR_TB"]] = function()
	    if tCtrls["iStatus"] == 1 then
	    	wx.wxBeginBusyCursor()
	    	tFuncs:Send("$SET 3 1")
			tFuncs:ReloadBans()
		end
	end,
	[tCtrls["wxID_CLEAR_PB"]] = function()
	    if tCtrls["iStatus"] == 1 then
        	wx.wxBeginBusyCursor()
	    	tFuncs:Send("$SET 3 2")
			tFuncs:ReloadBans()
		end
	end,
	[tCtrls["wxID_CLEAR_TRB"]] = function()
	    if tCtrls["iStatus"] == 1 then
        	wx.wxBeginBusyCursor()
	    	tFuncs:Send("$SET 3 4")
			tFuncs:ReloadRangeBans()
		end
	end,
	[tCtrls["wxID_CLEAR_PRB"]] = function()
	    if tCtrls["iStatus"] == 1 then
        	wx.wxBeginBusyCursor()
	    	tFuncs:Send("$SET 3 5")
			tFuncs:ReloadRangeBans()
		end
	end,
	[tCtrls["wxID_TEXT_RELOADLIST"]] = function()
		tFuncs:ReloadTexts()
	end,
	[tCtrls["wxID_TEXT_RELOAD"]] = function()
		-- No LUA support for it...
		if tCtrls["iStatus"] == 1 then
			tFuncs:Send("<"..tFuncs:GetCtrl("txt_login_nick"):GetValue().."> !reloadtxt")
		end
	end,
	[tCtrls["wxID_TEXT_LOAD"]] = function()
		if tCtrls["iStatus"] == 1 then
			local filename = wx.wxFileSelector("Load text file", wx.wxGetCwd(),"","","*.txt",wx.wxFD_OPEN+wx.wxFD_FILE_MUST_EXIST)
			if filename ~= "" then
				local f = io.open(filename,"r")
				if f then
					local c = f:read("*a")
					tFuncs:GetCtrl("txt_texteditor"):SetValue(c)
				end
			end
		end
	end,
	[tCtrls["wxID_TEXT_SAVE"]] = function()
		if tCtrls["iStatus"] == 1 then
			if not wx.wxDirExists("texts") then wx.wxMkdir("texts") end
			local filename = wx.wxFileSelector("Save text file", wx.wxGetCwd().."/texts","","","*.txt",wx.wxFD_SAVE)
			if filename ~= "" then
				if filename:sub(-4) ~= ".txt" then filename = filename..".txt" end
				local f = io.open(filename,"w+")
				if f then
					local c = tFuncs:GetCtrl("txt_texteditor"):GetValue():gsub("|","[endpipe]")
					f:write(c)
					filename = filename:match(".+\\(.+)$")
					tFuncs:Send("$SET 7 \""..filename.."\" "..c)
					tCtrls["lst_texts"]:Append(filename)
				end
			end
		end
	end,
	[tCtrls["wxID_CMD_UDPSYS"]] = function()
		tFuncs:UDPEnableHideCtrls("SYS")
	end,
	[tCtrls["wxID_CMD_UDPERR"]] = function()
		tFuncs:UDPEnableHideCtrls("ERR")
	end,
	[tCtrls["wxID_CMD_UDPCHAT"]] = function()
		tFuncs:UDPEnableHideCtrls("CHAT")
	end,
	[tCtrls["wxID_CMD_UDPLUA"]] = function()
		tFuncs:UDPEnableHideCtrls("LUA")
	end,
	[tCtrls["wxID_CMD_UDPREG"]] = function()
		tFuncs:UDPEnableHideCtrls("REG")
	end,
	[tCtrls["wxID_CMD_UDPLOG"]] = function()
		tFuncs:UDPEnableHideCtrls("LOG")
	end,
	[tCtrls["wxID_CMD_UDPCLEAR"]] = function()
		tFuncs:GetCtrl("wxID_TXT_UDP"..tCtrls["shown_page"]):Clear()
	end,
	[tCtrls["wxID_CMD_UDPCLOSE"]] = function()
		local tPages = {"SYS","ERR","CHAT","LUA","REG","LOG"}
		local font = tCtrls["app"]:GetFont()
		font:SetWeight(wx.wxFONTWEIGHT_NORMAL)
		for i,v in ipairs(tPages) do
			tFuncs:GetCtrl("wxID_CMD_UDP"..v):SetFont(font)
			tFuncs:GetCtrl("wxID_TXT_UDP"..v):Clear()
			tFuncs:GetCtrl("wxID_CHK_UDP"..v):SetValue(false)
		end
		if wx.__WXMSW__ then tFuncs:GetCtrl("ID_PNL_UDPDBG"):Hide() end
		if tCtrls["iStatus"] == 1 then
			tFuncs:Send("<"..tFuncs:GetCtrl("txt_login_nick"):GetValue().."> !debug off")
		end
		if tCtrls["udp_client"] then
			tCtrls["udp_client"]:close()
		end
		tCtrls["shown_page"] = "SYS"
		tCtrls["tab"]:RemovePage(6)
		tCtrls["cmd_udpdbg"]:Enable(true)
	end,
	}
	if tButtonEvtIds[event:GetId()] then
		tButtonEvtIds[event:GetId()]()
	end
end
tCtrls["app"]:Connect(wx.wxID_ANY,wx.wxEVT_COMMAND_BUTTON_CLICKED,OnButtonClick)

function OnTextUpdated(event)
	local tTextCtrlEvtIds = {
	[tCtrls["txt_login_share"]] = function()
		local share = tFuncs:GetCtrl("txt_login_share")
		if share:GetValue() == "" then
			share:SetValue("0")
		end
		tFuncs:GetCtrl("stt_sharesize"):SetLabel(tFuncs:ConvertShare(tonumber(share:GetValue())))
	end,
	[tCtrls["num_60"]] = function()
		if tCtrls["num"]["num_60"]:GetValue() == 0 and tCtrls["num"]["num_61"]:GetValue() == 0 then
			tCtrls["txt"]["txt_31"]:Enable(false)
			tCtrls["txt"]["txt_32"]:Enable(false)
			tCtrls["chk"]["chk_44"]:Enable(false)
			tFuncs:GetCtrl("stt_nicklimitmsg"):Enable(false)
		else
			tCtrls["txt"]["txt_31"]:Enable(true)
			tCtrls["txt"]["txt_32"]:Enable(true)
			tCtrls["chk"]["chk_44"]:Enable(true)
			tFuncs:GetCtrl("stt_nicklimitmsg"):Enable(true)
		end
	end,
	[tCtrls["num_61"]] = function()
		if tCtrls["num"]["num_60"]:GetValue() == 0 and tCtrls["num"]["num_61"]:GetValue() == 0 then
			tCtrls["txt"]["txt_31"]:Enable(false)
			tCtrls["txt"]["txt_32"]:Enable(false)
			tCtrls["chk"]["chk_44"]:Enable(false)
			tFuncs:GetCtrl("stt_nicklimitmsg"):Enable(false)
		else
			tCtrls["txt"]["txt_31"]:Enable(true)
			tCtrls["txt"]["txt_32"]:Enable(true)
			tCtrls["chk"]["chk_44"]:Enable(true)
			tFuncs:GetCtrl("stt_nicklimitmsg"):Enable(true)
		end
	end,
	[tCtrls["num_1"]] = function()
		if tCtrls["num"]["num_1"]:GetValue() == 0 and tCtrls["num"]["num_3"]:GetValue() == 0 then
			tCtrls["chk"]["chk_7"]:Enable(false)
			tCtrls["txt"]["txt_11"]:Enable(false)
			tCtrls["txt"]["txt_12"]:Enable(false)
			tFuncs:GetCtrl("stt_sharelimitmsg"):Enable(false)
		else
			tCtrls["chk"]["chk_7"]:Enable(true)
			tCtrls["txt"]["txt_11"]:Enable(true)
			tCtrls["txt"]["txt_12"]:Enable(true)
			tFuncs:GetCtrl("stt_sharelimitmsg"):Enable(true)
		end
	end,
	[tCtrls["num_3"]] = function()
		if tCtrls["num"]["num_1"]:GetValue() == 0 and tCtrls["num"]["num_3"]:GetValue() == 0 then
			tCtrls["chk"]["chk_7"]:Enable(false)
			tCtrls["txt"]["txt_11"]:Enable(false)
			tCtrls["txt"]["txt_12"]:Enable(false)
			tFuncs:GetCtrl("stt_sharelimitmsg"):Enable(false)
		else
			tCtrls["chk"]["chk_7"]:Enable(true)
			tCtrls["txt"]["txt_11"]:Enable(true)
			tCtrls["txt"]["txt_12"]:Enable(true)
			tFuncs:GetCtrl("stt_sharelimitmsg"):Enable(true)
		end
	end,
	[tCtrls["num_9"]] = function()
		if tCtrls["num"]["num_9"]:GetValue() == 0 then
			tCtrls["chk"]["chk_10"]:Enable(false)
			tCtrls["txt"]["txt_17"]:Enable(false)
			tCtrls["txt"]["txt_18"]:Enable(false)
			tFuncs:GetCtrl("stt_maxhubsmsg"):Enable(false)
		else
			tCtrls["chk"]["chk_10"]:Enable(true)
			tCtrls["txt"]["txt_17"]:Enable(true)
			tCtrls["txt"]["txt_18"]:Enable(true)
			tFuncs:GetCtrl("stt_maxhubsmsg"):Enable(true)
		end
	end,
	[tCtrls["num_7"]] = function()
		if tCtrls["num"]["num_7"]:GetValue() == 0 and tCtrls["num"]["num_8"]:GetValue() == 0 then
			tCtrls["chk"]["chk_9"]:Enable(false)
			tCtrls["txt"]["txt_15"]:Enable(false)
			tCtrls["txt"]["txt_16"]:Enable(false)
			tFuncs:GetCtrl("stt_hubslotsmsg"):Enable(false)
		else
			tCtrls["chk"]["chk_9"]:Enable(true)
			tCtrls["txt"]["txt_15"]:Enable(true)
			tCtrls["txt"]["txt_16"]:Enable(true)
			tFuncs:GetCtrl("stt_hubslotsmsg"):Enable(true)
		end
	end,
	[tCtrls["num_8"]] = function()
		if tCtrls["num"]["num_7"]:GetValue() == 0 and tCtrls["num"]["num_8"]:GetValue() == 0 then
			tCtrls["chk"]["chk_9"]:Enable(false)
			tCtrls["txt"]["txt_15"]:Enable(false)
			tCtrls["txt"]["txt_16"]:Enable(false)
			tFuncs:GetCtrl("stt_hubslotsmsg"):Enable(false)
		else
			tCtrls["chk"]["chk_9"]:Enable(true)
			tCtrls["txt"]["txt_15"]:Enable(true)
			tCtrls["txt"]["txt_16"]:Enable(true)
			tFuncs:GetCtrl("stt_hubslotsmsg"):Enable(true)
		end
	end,
	[tCtrls["num_5"]] = function()
		if tCtrls["num"]["num_5"]:GetValue() == 0 and tCtrls["num"]["num_6"]:GetValue() == 0 then
			tCtrls["chk"]["chk_8"]:Enable(false)
			tCtrls["txt"]["txt_13"]:Enable(false)
			tCtrls["txt"]["txt_14"]:Enable(false)
			tFuncs:GetCtrl("stt_slotsmsg"):Enable(false)
		else
			tCtrls["chk"]["chk_8"]:Enable(true)
			tCtrls["txt"]["txt_13"]:Enable(true)
			tCtrls["txt"]["txt_14"]:Enable(true)
			tFuncs:GetCtrl("stt_slotsmsg"):Enable(true)
		end
	end,
	[tCtrls["num_6"]] = function()
		if tCtrls["num"]["num_5"]:GetValue() == 0 and tCtrls["num"]["num_6"]:GetValue() == 0 then
			tCtrls["chk"]["chk_8"]:Enable(false)
			tCtrls["txt"]["txt_13"]:Enable(false)
			tCtrls["txt"]["txt_14"]:Enable(false)
			tFuncs:GetCtrl("stt_slotsmsg"):Enable(false)
		else
			tCtrls["chk"]["chk_8"]:Enable(true)
			tCtrls["txt"]["txt_13"]:Enable(true)
			tCtrls["txt"]["txt_14"]:Enable(true)
			tFuncs:GetCtrl("stt_slotsmsg"):Enable(true)
		end
	end,
	}
	if tTextCtrlEvtIds[event:GetId()] then
	    tTextCtrlEvtIds[event:GetId()]()
	end
end
tCtrls["app"]:Connect(wx.wxID_ANY,wx.wxEVT_COMMAND_TEXT_UPDATED,OnTextUpdated)

function OnCheckBox(event)
	local tCheckBoxEvtIds = {
	[tCtrls["chk_44"]] = function()
		if tCtrls["chk"]["chk_44"]:GetValue() then
			tCtrls["txt"]["txt_32"]:Enable(true)
		else
			tCtrls["txt"]["txt_32"]:Enable(false)
		end
	end,
	[tCtrls["chk_37"]] = function()
		if event:IsChecked() then
			tCtrls["chk"]["chk_34"]:Enable(false)
			tCtrls["txt"]["txt_motd"]:Enable(false)
		else
			tCtrls["chk"]["chk_34"]:Enable(true)
			tCtrls["txt"]["txt_motd"]:Enable(true)
		end
	end,
	[tCtrls["chk_17"]] = function()
		if event:IsChecked() then
			tCtrls["txt"]["txt_22"]:Enable(true)
			tCtrls["txt"]["txt_23"]:Enable(true)
			if not tCtrls["chk"]["chk_18"]:GetValue() then
				tCtrls["txt"]["txt_21"]:Enable(true)
			end
		else
			tCtrls["txt"]["txt_22"]:Enable(false)
			tCtrls["txt"]["txt_23"]:Enable(false)
			if not tCtrls["chk"]["chk_18"]:GetValue() then
				tCtrls["txt"]["txt_21"]:Enable(false)
			end
		end
	end,
	[tCtrls["chk_19"]] = function()
		if event:IsChecked() then
			tCtrls["txt"]["txt_24"]:Enable(true)
			tCtrls["txt"]["txt_25"]:Enable(true)
			tCtrls["txt"]["txt_26"]:Enable(true)
		else
			tCtrls["txt"]["txt_24"]:Enable(false)
			tCtrls["txt"]["txt_25"]:Enable(false)
			tCtrls["txt"]["txt_26"]:Enable(false)
		end
	end,
	[tCtrls["chk_18"]] = function()
		if not event:IsChecked() and not tCtrls["chk"]["chk_17"]:GetValue() then
			tCtrls["txt"]["txt_21"]:Enable(false)
		else
			tCtrls["txt"]["txt_21"]:Enable(true)
		end
	end,
	[tCtrls["chk_7"]] = function()
		if event:IsChecked() then
			tCtrls["txt"]["txt_12"]:Enable(true)
		else
			tCtrls["txt"]["txt_12"]:Enable(false)
		end
	end,
	[tCtrls["chk_31"]] = function()
		if event:IsChecked() then
			tCtrls["chk"]["chk_32"]:Enable(true)
		else
			tCtrls["chk"]["chk_32"]:Enable(false)
		end
	end,
	[tCtrls["chk_5"]] = function()
		if event:IsChecked() then
			tCtrls["chk"]["chk_6"]:Enable(true)
			tCtrls["txt"]["txt_8"]:Enable(true)
			tCtrls["txt"]["txt_9"]:Enable(true)
		else
			tCtrls["chk"]["chk_6"]:Enable(false)
			tCtrls["txt"]["txt_8"]:Enable(false)
			tCtrls["txt"]["txt_9"]:Enable(false)
		end
	end,
	[tCtrls["chk_6"]] = function()
		if event:IsChecked() then
			tCtrls["txt"]["txt_9"]:Enable(true)
		else
			tCtrls["txt"]["txt_9"]:Enable(false)
		end
	end,
	[tCtrls["chk_20"]] = function()
		if event:IsChecked() then
			tCtrls["txt"]["txt_27"]:Enable(true)
		else
			tCtrls["txt"]["txt_27"]:Enable(false)
		end
	end,
	[tCtrls["chk_21"]] = function()
		if event:IsChecked() then
			tCtrls["txt"]["txt_28"]:Enable(true)
		else
			tCtrls["txt"]["txt_28"]:Enable(false)
		end
	end,
	[tCtrls["chk_10"]] = function()
		if event:IsChecked() then
			tCtrls["txt"]["txt_18"]:Enable(true)
		else
			tCtrls["txt"]["txt_18"]:Enable(false)
		end
	end,
	[tCtrls["chk_9"]] = function()
		if event:IsChecked() then
			tCtrls["txt"]["txt_16"]:Enable(true)
		else
			tCtrls["txt"]["txt_16"]:Enable(false)
		end
	end,
	[tCtrls["chk_8"]] = function()
		if event:IsChecked() then
			tCtrls["txt"]["txt_14"]:Enable(true)
		else
			tCtrls["txt"]["txt_14"]:Enable(false)
		end
	end,
	[tCtrls["chk_22"]] = function()
		if not event:IsChecked() then
		    if wx.wxMessageBox("You are just want to disable the scripting interface. After it you won't be able to login with this "..
			"application to your hub. Are you sure you want this?","WARNING!",wx.wxICON_QUESTION+wx.wxYES_NO+wx.wxNO_DEFAULT) == wx.wxNO then
			    tCtrls["chk"]["chk_22"]:SetValue(true)
			else
			    tCtrls["chk"]["chk_22"]:SetValue(false)
			   	tCtrls["chk"]["chk_33"]:Enable(false)
			end
		end
	end,
	[tCtrls["chk_27"]] = function()
		if event:IsChecked() then
			tCtrls["chk"]["chk_28"]:Enable(true)
		else
			tCtrls["chk"]["chk_28"]:Enable(false)
		end
	end,
	[tCtrls["chk_29"]] = function()
		if event:IsChecked() then
			tCtrls["chk"]["chk_30"]:Enable(true)
		else
			tCtrls["chk"]["chk_30"]:Enable(false)
		end
	end,
	}
	if tCheckBoxEvtIds[event:GetId()] then
	    tCheckBoxEvtIds[event:GetId()]()
	end
end
tCtrls["app"]:Connect(wx.wxID_ANY,wx.wxEVT_COMMAND_CHECKBOX_CLICKED,OnCheckBox)

function OnChoice(event)
	local tChoiceEvtIds = {
	[tCtrls["wxID_LANGUAGE"]] = function()
		if tCtrls["langfile"] == tCtrls["language"]:GetStringSelection() then return end
		if tCtrls["language"]:GetStringSelection() == "Default English" then
			tCtrls["langfile"] = nil
		else
			tCtrls["langfile"] = tCtrls["language"]:GetStringSelection()
		end
		if tCtrls["file"] then
			tCtrls["file"] = nil
		end
		tCtrls["app"]:Show(false)
		tFuncs:TranslateStrings();
		tFuncs:TranslateGUI();
		tCtrls["app"]:Show(true)
	end,
    [tCtrls["num_57"]] = function()
		if event:GetSelection() == 0 then
			tCtrls["num"]["num_54"]:Enable(false)
			tCtrls["num"]["num_55"]:Enable(false)
			tCtrls["num"]["num_56"]:Enable(false)
			tFuncs:GetCtrl("stt_sec1"):Enable(false)
		else
			tCtrls["num"]["num_54"]:Enable(true)
			tCtrls["num"]["num_55"]:Enable(true)
			tCtrls["num"]["num_56"]:Enable(true)
			tFuncs:GetCtrl("stt_sec1"):Enable(true)
		end
	end,
    [tCtrls["chk_21"]] = function()
		if event:GetSelection() == 0 then
			tCtrls["num"]["num_19"]:Enable(false)
			tCtrls["num"]["num_20"]:Enable(false)
			tFuncs:GetCtrl("stt_seconds1"):Enable(false)
		else
			tCtrls["num"]["num_19"]:Enable(true)
			tCtrls["num"]["num_20"]:Enable(true)
			tFuncs:GetCtrl("stt_seconds1"):Enable(true)
		end
	end,
	[tCtrls["chk_68"]] = function()
        if event:GetSelection() == 0 then
			tCtrls["num"]["num_66"]:Enable(false)
			tCtrls["num"]["num_67"]:Enable(false)
			tFuncs:GetCtrl("stt_seconds2"):Enable(false)
		else
			tCtrls["num"]["num_66"]:Enable(true)
			tCtrls["num"]["num_67"]:Enable(true)
			tFuncs:GetCtrl("stt_seconds2"):Enable(true)
		end
	end,
	[tCtrls["chk_24"]] = function()
		if event:GetSelection() == 0 then
			tCtrls["num"]["num_22"]:Enable(false)
			tCtrls["num"]["num_23"]:Enable(false)
			tFuncs:GetCtrl("stt_seconds4"):Enable(false)
		else
			tCtrls["num"]["num_22"]:Enable(true)
			tCtrls["num"]["num_23"]:Enable(true)
			tFuncs:GetCtrl("stt_seconds4"):Enable(true)
		end
	end,
	[tCtrls["chk_27"]] = function()
		if event:GetSelection() == 0 then
			tCtrls["num"]["num_25"]:Enable(false)
			tCtrls["num"]["num_26"]:Enable(false)
			tFuncs:GetCtrl("stt_with1"):Enable(false)
			tFuncs:GetCtrl("stt_lines1"):Enable(false)
		else
			tCtrls["num"]["num_25"]:Enable(true)
			tCtrls["num"]["num_26"]:Enable(true)
			tFuncs:GetCtrl("stt_with1"):Enable(true)
			tFuncs:GetCtrl("stt_lines1"):Enable(true)
		end
	end,
	[tCtrls["chk_81"]] = function()
        if event:GetSelection() == 0 then
			tCtrls["num"]["num_79"]:Enable(false)
			tCtrls["num"]["num_80"]:Enable(false)
			tFuncs:GetCtrl("stt_seconds5"):Enable(false)
		else
			tCtrls["num"]["num_79"]:Enable(true)
			tCtrls["num"]["num_80"]:Enable(true)
			tFuncs:GetCtrl("stt_seconds5"):Enable(true)
		end
	end,
    [tCtrls["chk_84"]] = function()
        if event:GetSelection() == 0 then
			tCtrls["num"]["num_82"]:Enable(false)
			tCtrls["num"]["num_83"]:Enable(false)
			tFuncs:GetCtrl("stt_seconds6"):Enable(false)
		else
			tCtrls["num"]["num_82"]:Enable(true)
			tCtrls["num"]["num_83"]:Enable(true)
			tFuncs:GetCtrl("stt_seconds6"):Enable(true)
		end
	end,
    [tCtrls["chk_87"]] = function()
        if event:GetSelection() == 0 then
			tCtrls["num"]["num_85"]:Enable(false)
			tCtrls["num"]["num_86"]:Enable(false)
			tFuncs:GetCtrl("stt_seconds7"):Enable(false)
		else
			tCtrls["num"]["num_85"]:Enable(true)
			tCtrls["num"]["num_86"]:Enable(true)
			tFuncs:GetCtrl("stt_seconds7"):Enable(true)
		end
	end,
    [tCtrls["chk_90"]] = function()
        if event:GetSelection() == 0 then
			tCtrls["num"]["num_88"]:Enable(false)
			tCtrls["num"]["num_89"]:Enable(false)
			tFuncs:GetCtrl("stt_seconds8"):Enable(false)
		else
			tCtrls["num"]["num_88"]:Enable(true)
			tCtrls["num"]["num_89"]:Enable(true)
			tFuncs:GetCtrl("stt_seconds8"):Enable(true)
		end
	end,
	[tCtrls["chk_30"]] = function()
		if event:GetSelection() == 0 then
			tCtrls["num"]["num_28"]:Enable(false)
			tCtrls["num"]["num_29"]:Enable(false)
			tFuncs:GetCtrl("stt_seconds9"):Enable(false)
		else
			tCtrls["num"]["num_28"]:Enable(true)
			tCtrls["num"]["num_29"]:Enable(true)
			tFuncs:GetCtrl("stt_seconds9"):Enable(true)
		end
	end,
    [tCtrls["chk_71"]] = function()
		if event:GetSelection() == 0 then
			tCtrls["num"]["num_69"]:Enable(false)
			tCtrls["num"]["num_70"]:Enable(false)
			tFuncs:GetCtrl("stt_seconds10"):Enable(false)
		else
			tCtrls["num"]["num_69"]:Enable(true)
			tCtrls["num"]["num_70"]:Enable(true)
			tFuncs:GetCtrl("stt_seconds10"):Enable(true)
		end
	end,
	[tCtrls["chk_33"]] = function()
		if event:GetSelection() == 0 then
			tCtrls["num"]["num_31"]:Enable(false)
			tCtrls["num"]["num_32"]:Enable(false)
			tFuncs:GetCtrl("stt_seconds12"):Enable(false)
		else
			tCtrls["num"]["num_31"]:Enable(true)
			tCtrls["num"]["num_32"]:Enable(true)
			tFuncs:GetCtrl("stt_seconds12"):Enable(true)
		end
	end,
	[tCtrls["chk_36"]] = function()
		if event:GetSelection() == 0 then
			tCtrls["num"]["num_34"]:Enable(false)
			tCtrls["num"]["num_35"]:Enable(false)
			tFuncs:GetCtrl("stt_with2"):Enable(false)
			tFuncs:GetCtrl("stt_lines2"):Enable(false)
		else
			tCtrls["num"]["num_34"]:Enable(true)
			tCtrls["num"]["num_35"]:Enable(true)
			tFuncs:GetCtrl("stt_with2"):Enable(true)
			tFuncs:GetCtrl("stt_lines2"):Enable(true)
		end
	end,
    [tCtrls["chk_100"]] = function()
		if event:GetSelection() == 0 then
			tCtrls["num"]["num_101"]:Enable(false)
			tCtrls["num"]["num_102"]:Enable(false)
			tFuncs:GetCtrl("stt_kb1"):Enable(false)
			tFuncs:GetCtrl("stt_seconds13"):Enable(false)
		else
			tCtrls["num"]["num_101"]:Enable(true)
			tCtrls["num"]["num_102"]:Enable(true)
			tFuncs:GetCtrl("stt_kb1"):Enable(true)
			tFuncs:GetCtrl("stt_seconds13"):Enable(true)
		end
	end,
    [tCtrls["chk_103"]] = function()
		if event:GetSelection() == 0 then
			tCtrls["num"]["num_104"]:Enable(false)
			tCtrls["num"]["num_105"]:Enable(false)
			tFuncs:GetCtrl("stt_kb2"):Enable(false)
			tFuncs:GetCtrl("stt_seconds14"):Enable(false)
		else
			tCtrls["num"]["num_104"]:Enable(true)
			tCtrls["num"]["num_105"]:Enable(true)
			tFuncs:GetCtrl("stt_kb2"):Enable(true)
			tFuncs:GetCtrl("stt_seconds14"):Enable(true)
		end
	end,
	[tCtrls["chk_10"]] = function()
		if event:GetSelection() == 0 then
			tCtrls["txt"]["txt_19"]:Enable(false)
			tCtrls["txt"]["txt_20"]:Enable(false)
			tFuncs:GetCtrl("stt_userwotagmsg"):Enable(false)
		elseif event:GetSelection() == 1 then
			tCtrls["txt"]["txt_19"]:Enable(true)
			tCtrls["txt"]["txt_20"]:Enable(false)
			tFuncs:GetCtrl("stt_userwotagmsg"):Enable(true)
		else
			tCtrls["txt"]["txt_19"]:Enable(true)
			tCtrls["txt"]["txt_20"]:Enable(true)
			tFuncs:GetCtrl("stt_userwotagmsg"):Enable(true)
		end
	end,
	[tCtrls["chk_62"]]= function()
		if event:GetSelection() == 0 then
			tCtrls["num"]["num_63"]:Enable(false)
			tFuncs:GetCtrl("stt_passwordbftbt"):Enable(false)
			tFuncs:GetCtrl("stt_passwordhours"):Enable(false)
		elseif event:GetSelection() == 1 then
			tCtrls["num"]["num_63"]:Enable(false)
			tFuncs:GetCtrl("stt_passwordbftbt"):Enable(false)
			tFuncs:GetCtrl("stt_passwordhours"):Enable(false)
		else
			tCtrls["num"]["num_63"]:Enable(true)
			tFuncs:GetCtrl("stt_passwordbftbt"):Enable(true)
			tFuncs:GetCtrl("stt_passwordhours"):Enable(true)
		end
	end,
	[tCtrls["chk_39"]] = function()
    	if event:GetSelection() == 0 then
			tCtrls["num"]["num_37"]:Enable(false)
			tCtrls["num"]["num_38"]:Enable(false)
			tFuncs:GetCtrl("stt_seconds16"):Enable(false)
		else
			tCtrls["num"]["num_37"]:Enable(true)
			tCtrls["num"]["num_38"]:Enable(true)
			tFuncs:GetCtrl("stt_seconds16"):Enable(true)
		end
	end,
    [tCtrls["chk_74"]] = function()
		if event:GetSelection() == 0 then
			tCtrls["num"]["num_72"]:Enable(false)
			tCtrls["num"]["num_73"]:Enable(false)
			tFuncs:GetCtrl("stt_seconds17"):Enable(false)
		else
			tCtrls["num"]["num_72"]:Enable(true)
			tCtrls["num"]["num_73"]:Enable(true)
			tFuncs:GetCtrl("stt_seconds17"):Enable(true)
		end
	end,
	[tCtrls["chk_42"]] = function()
        if event:GetSelection() == 0 then
			tCtrls["num"]["num_40"]:Enable(false)
			tCtrls["num"]["num_41"]:Enable(false)
			tFuncs:GetCtrl("stt_seconds19"):Enable(false)
		else
			tCtrls["num"]["num_40"]:Enable(true)
			tCtrls["num"]["num_41"]:Enable(true)
			tFuncs:GetCtrl("stt_seconds19"):Enable(true)
		end
	end,
    [tCtrls["chk_95"]] = function()
		if event:GetSelection() == 0 then
			tCtrls["num"]["num_93"]:Enable(false)
			tCtrls["num"]["num_94"]:Enable(false)
			tFuncs:GetCtrl("stt_seconds20"):Enable(false)
		else
			tCtrls["num"]["num_93"]:Enable(true)
			tCtrls["num"]["num_94"]:Enable(true)
			tFuncs:GetCtrl("stt_seconds20"):Enable(true)
		end
	end,
    [tCtrls["chk_98"]] = function()
		if event:GetSelection() == 0 then
			tCtrls["num"]["num_96"]:Enable(false)
			tCtrls["num"]["num_97"]:Enable(false)
			tFuncs:GetCtrl("stt_seconds21"):Enable(false)
		else
			tCtrls["num"]["num_96"]:Enable(true)
			tCtrls["num"]["num_97"]:Enable(true)
			tFuncs:GetCtrl("stt_seconds21"):Enable(true)
		end
	end,
	[tCtrls["chk_48"]] = function()
		if event:GetSelection() == 0 then
			tCtrls["num"]["num_46"]:Enable(false)
			tCtrls["num"]["num_47"]:Enable(false)
			tFuncs:GetCtrl("stt_minutes3"):Enable(false)
		else
			tCtrls["num"]["num_46"]:Enable(true)
			tCtrls["num"]["num_47"]:Enable(true)
			tFuncs:GetCtrl("stt_minutes3"):Enable(true)
		end
	end,
	[tCtrls["chk_45"]] = function()
		if event:GetSelection() == 0 then
			tCtrls["num"]["num_43"]:Enable(false)
			tCtrls["num"]["num_44"]:Enable(false)
			tFuncs:GetCtrl("stt_seconds22"):Enable(false)
		else
			tCtrls["num"]["num_43"]:Enable(true)
			tCtrls["num"]["num_44"]:Enable(true)
			tFuncs:GetCtrl("stt_seconds22"):Enable(true)
		end
	end,
    [tCtrls["chk_77"]] = function()
		if event:GetSelection() == 0 then
			tCtrls["num"]["num_75"]:Enable(false)
			tCtrls["num"]["num_76"]:Enable(false)
			tFuncs:GetCtrl("stt_seconds23"):Enable(false)
		else
			tCtrls["num"]["num_75"]:Enable(true)
			tCtrls["num"]["num_76"]:Enable(true)
			tFuncs:GetCtrl("stt_seconds23"):Enable(true)
		end
	end,
	}
	if tChoiceEvtIds[event:GetId()] then
	    tChoiceEvtIds[event:GetId()]()
	end
end
tCtrls["app"]:Connect(wx.wxID_ANY,wx.wxEVT_COMMAND_CHOICE_SELECTED,OnChoice)

function OnListBoxDC(event)
	local tListBoxIds = {
	[tCtrls["wxID_LUA_LIST"]] = function()
		if tCtrls["iStatus"] == 1 then
			wx.wxBeginBusyCursor()
			local script = event:GetString()
			tFuncs:DownloadFile(8,script)
			table.insert(tCtrls["tDeadThreads"],ThreadCreate(tFuncs.FileAction,{ script,0}))
		end
	end,
	[tCtrls["wxID_TEXTS"]] = function()
		if tCtrls["iStatus"] == 1 then
		    wx.wxBeginBusyCursor()
			local textfile = event:GetString()
			tFuncs:DownloadFile(8,textfile..".txt")
			table.insert(tCtrls["tDeadThreads"],ThreadCreate(tFuncs.FileAction,{ textfile..".txt",1}))
		end
	end,
	}
	if tListBoxIds[event:GetId()] then
		tListBoxIds[event:GetId()]()
	end
end
tCtrls["app"]:Connect(wx.wxID_ANY,wx.wxEVT_COMMAND_LISTBOX_DOUBLECLICKED,OnListBoxDC)

function OnListBoxSel(event)
	local tListBoxEvtIds = {
	[tCtrls["wxID_LUA_LIST"]] = function()
		if tCtrls["lst_scripts"]:GetCount() == 1 then
			tFuncs:GetCtrl("wxID_LUA_UP"):Enable(false)
			tFuncs:GetCtrl("wxID_LUA_DOWN"):Enable(false)
		elseif tCtrls["lst_scripts"]:IsSelected(0) then
			tFuncs:GetCtrl("wxID_LUA_DOWN"):Enable(true)
			tFuncs:GetCtrl("wxID_LUA_UP"):Enable(false)
		elseif tCtrls["lst_scripts"]:IsSelected(tCtrls["lst_scripts"]:GetCount()-1) then
			tFuncs:GetCtrl("wxID_LUA_UP"):Enable(true)
			tFuncs:GetCtrl("wxID_LUA_DOWN"):Enable(false)
		else
			tFuncs:GetCtrl("wxID_LUA_UP"):Enable(true)
			tFuncs:GetCtrl("wxID_LUA_DOWN"):Enable(true)
		end
	end,
	[tCtrls["wxID_PROFLIST"]] = function()
	    tFuncs:LoadPermissions(event:GetSelection())
		if tCtrls["lst_profiles"]:GetCount() == 1 then
			tFuncs:GetCtrl("wxID_PROF_UP"):Enable(false)
			tFuncs:GetCtrl("wxID_PROF_DOWN"):Enable(false)
		elseif tCtrls["lst_profiles"]:IsSelected(0) then
			tFuncs:GetCtrl("wxID_PROF_DOWN"):Enable(true)
			tFuncs:GetCtrl("wxID_PROF_UP"):Enable(false)
		elseif tCtrls["lst_profiles"]:IsSelected(tCtrls["lst_profiles"]:GetCount()-1) then
			tFuncs:GetCtrl("wxID_PROF_UP"):Enable(true)
			tFuncs:GetCtrl("wxID_PROF_DOWN"):Enable(false)
		else
			tFuncs:GetCtrl("wxID_PROF_UP"):Enable(true)
			tFuncs:GetCtrl("wxID_PROF_DOWN"):Enable(true)
		end
	end,
	}
	if tListBoxEvtIds[event:GetId()] then
	    tListBoxEvtIds[event:GetId()]()
	end
end
tCtrls["app"]:Connect(wx.wxID_ANY,wx.wxEVT_COMMAND_LISTBOX_SELECTED,OnListBoxSel)

function OnCheckListBox(event)
	local tCheckListBoxEvtIds = {
	[tCtrls["wxID_LUA_LIST"]] = function()
	    wx.wxBeginBusyCursor()
		tFuncs:Send("$SET 4 "..tostring(tCtrls["lst_scripts"]:IsChecked(event:GetInt())).." \""..tCtrls["lst_scripts"]:GetString(event:GetInt()).."\"")
	end,
	[tCtrls["wxID_PERMISSION_LIST"]] = function()
	    if tCtrls["iStatus"] == 1 then
		    wx.wxBeginBusyCursor()
		    tFuncs:Send("$SET 5 "..tCtrls["lst_profiles"]:GetSelection().." p "..(event:GetInt()).." "..iff(tCtrls["lst_permissions"]:IsChecked(event:GetInt()),"1","0"))
			if tCtrls["lst_permissions"]:IsChecked(event:GetInt()) then
				tCtrls["lst_permissions"]:Check(event:GetInt(),false)
				-- Don't check it, just when the hub sends back the confirmation
			else
			    tCtrls["lst_permissions"]:Check(event:GetInt(),true)
			end
			event:Skip()
		end
	end,
	}
	if tCheckListBoxEvtIds[event:GetId()] then
	    tCheckListBoxEvtIds[event:GetId()]()
	end
end
tCtrls["app"]:Connect(wx.wxID_ANY,wx.wxEVT_COMMAND_CHECKLISTBOX_TOGGLED,OnCheckListBox)

function OnContextMenu(event)
	local tContextMenuEvtIds = {
	[tCtrls["wxID_LUA_LIST"]] = function()
		if tCtrls["lst_scripts"]:GetStringSelection() ~= "" then
			local Menu = wx.wxMenu()
			Menu:Append(tCtrls["wxID_MENU_LUA_OPEN"],tFuncs:Translate("OpenExternalEditor") or "Open in external editor")
			Menu:Append(tCtrls["wxID_MENU_LUA_RESTART"],tFuncs:Translate("ReStartScriptWithGivenFilename") or "Restart script with given filename")
			Menu:AppendSeparator()
			Menu:Append(tCtrls["wxID_MENU_LUA_SAVE"],(tFuncs:Translate("SaveScript") or "Save script").." "..tCtrls["lst_scripts"]:GetStringSelection())
			Menu:Append(tCtrls["wxID_MENU_LUA_LOAD"],(tFuncs:Translate("LoadScript") or "Load script").." "..tCtrls["lst_scripts"]:GetStringSelection())
			Menu:Append(tCtrls["wxID_MENU_LUA_DEL"],(tFuncs:Translate("DeleteScript") or "Delete script").." "..tCtrls["lst_scripts"]:GetStringSelection())
			tCtrls["lst_scripts"]:PopupMenu(Menu)
		end
	end,
	[tCtrls["wxID_REGLIST"]] = function()
		local Menu = wx.wxMenu()
		Menu:Append(tCtrls["wxID_MENU_REG_ADD"],tFuncs:Translate("Add")    or "Add")
		if tCtrls["lst_regs"]:GetSelectedItemCount() ~= 0 then
			Menu:Append(tCtrls["wxID_MENU_REG_DEL"],tFuncs:Translate("Remove") or "Remove")
			Menu:Append(tCtrls["wxID_MENU_REG_MOD"],tFuncs:Translate("Modify") or "Modify")
		end
		Menu:Append(tCtrls["wxID_MENU_REG_RELOAD"],tFuncs:Translate("Reload") or "Reload")
		tCtrls["lst_regs"]:PopupMenu(Menu)
	end,
	[tCtrls["wxID_BANLIST"]] = function()
		local Menu = wx.wxMenu()
		Menu:Append(tCtrls["wxID_MENU_ADD_BAN"],tFuncs:Translate("Add") or "Add")
		if tCtrls["lst_bans"]:GetSelectedItemCount() ~= 0 then
			local mod = Menu:Append(tCtrls["wxID_MENU_MOD_BAN"],tFuncs:Translate("Modify") or "Modify")
			if tCtrls["lst_bans"]:GetSelectedItemCount() > 1 then mod:Enable(false) end
			Menu:Append(tCtrls["wxID_MENU_DEL_BAN"],tFuncs:Translate("UnbanIpOrNick") or "Unban IP address or nick")
			Menu:AppendSeparator()
			Menu:Append(tCtrls["wxID_MENU_DEL_TEMPBANS"],tFuncs:Translate("ClearTempBans") or "Clear temporary bans")
			Menu:Append(tCtrls["wxID_MENU_DEL_PERMBANS"],(tFuncs:Translate("ClearPermBans") or "Clear permanent bans"))
		end
		tCtrls["lst_bans"]:PopupMenu(Menu)
	end,
	[tCtrls["wxID_RANGEBANLIST"]] = function()
		local Menu = wx.wxMenu()
		Menu:Append(tCtrls["wxID_MENU_ADD_RANGEBAN"],tFuncs:Translate("Add") or "Add")
		if tCtrls["lst_rangebans"]:GetSelectedItemCount() ~= 0 then
			local mod = Menu:Append(tCtrls["wxID_MENU_MOD_RANGEBAN"],tFuncs:Translate("Modify") or "Modify")
			if tCtrls["lst_rangebans"]:GetSelectedItemCount() > 1 then mod:Enable(false) end
			Menu:Append(tCtrls["wxID_MENU_DEL_RANGEBAN"],tFuncs:Translate("UnbanBannedIpRange") or "Unban IP address or nick")
			Menu:AppendSeparator()
			Menu:Append(tCtrls["wxID_MENU_DEL_RANGETEMPBANS"],tFuncs:Translate("ClearTempRangeBans") or "Clear temporary range bans")
			Menu:Append(tCtrls["wxID_MENU_DEL_RANGEPERMBANS"],(tFuncs:Translate("ClearPermRangeBans") or "Clear permanent range bans"))
		end
		tCtrls["lst_rangebans"]:PopupMenu(Menu)
	end,
	[tCtrls["wxID_TEXTS"]] = function()
	    if tCtrls["lst_texts"]:GetSelection() ~= -1 then
			local Menu = wx.wxMenu()
			Menu:Append(tCtrls["wxID_MENU_LOAD_TXT"],"Load text file "..tCtrls["lst_texts"]:GetStringSelection())
			Menu:Append(tCtrls["wxID_MENU_SAVE_TXT"],"Save text file "..tCtrls["lst_texts"]:GetStringSelection())
			Menu:Append(tCtrls["wxID_MENU_TEXT_DEL"],"Delete text file "..tCtrls["lst_texts"]:GetStringSelection())
			tCtrls["lst_texts"]:PopupMenu(Menu)
		end
	end,
	}
	local id = event:GetId()
	if event:GetId() == -212 then event:SetId(tCtrls["wxID_BANLIST"]) end -- Don't ask me why...
	if event:GetId() == -215 then event:SetId(tCtrls["wxID_RANGEBANLIST"]) end
	if tContextMenuEvtIds[event:GetId()] then
	    tContextMenuEvtIds[event:GetId()]()
	end
end
tCtrls["app"]:Connect(wx.wxID_ANY,wx.wxEVT_CONTEXT_MENU,OnContextMenu)

function OnMenuSelected(event)
	local tMenuEvtIds = {
	[tCtrls["wxID_MENU_LUA_OPEN"]] = function()
		local script = tCtrls["lst_scripts"]:GetStringSelection()
	    tFuncs:DownloadFile(8,script)
		table.insert(tCtrls["tDeadThreads"],ThreadCreate(tFuncs.FileAction,{tCtrls["lst_scripts"]:GetStringSelection(),3}))
	end,
	[tCtrls["wxID_MENU_LUA_RESTART"]] = function()
	    if tCtrls["lst_scripts"]:IsChecked(tCtrls["lst_scripts"]:GetSelection()) then
			tFuncs:Send("$SET 4 restart \""..tCtrls["lst_scripts"]:GetStringSelection().."\"")
		end
	end,
	[tCtrls["wxID_MENU_LUA_LOAD"]] = function()
	    local filename = tCtrls["lst_scripts"]:GetStringSelection()
		tFuncs:DownloadFile(8,filename)
		table.insert(tCtrls["tDeadThreads"],ThreadCreate(tFuncs.FileAction,{ filename, 0}))
	end,
	[tCtrls["wxID_MENU_LUA_SAVE"]] = function()
		if tCtrls["iStatus"] == 1 then
			local filename = tCtrls["lst_scripts"]:GetStringSelection()
			if not wx.wxDirExists("scripts") then wx.wxMkdir("scripts") end
			local f = io.open("./scripts/"..filename,"w+")
			if f then
				local c = ""
				if wxstc then
					c = tFuncs:GetCtrl("txt_scripteditor"):GetText()
				else
					c = tFuncs:GetCtrl("txt_scripteditor"):GetValue()
				end
				f:write(c)
				tFuncs:Send("$SET 7 \""..filename.."\" "..c)
			end
		end
	end,
	[tCtrls["wxID_MENU_LUA_DEL"]] = function()
        if tCtrls["iStatus"] == 1 then
			tFuncs:Send("$SET 7 \""..tCtrls["lst_scripts"]:GetStringSelection().."\" del")
            tCtrls["lst_scripts"]:Delete(tCtrls["lst_scripts"]:GetSelection())
		end
	end,
	[tCtrls["wxID_MENU_REG_ADD"]] = function()
		if tCtrls["iStatus"] == 0 then return end
		local sNick,sPass,iProfile = tFuncs:ShowRegWindow()
		if sNick then -- if not cancelled
		    tFuncs:Send("$SET 6 1 "..sNick.." "..sPass.." "..iProfile)
		end
	end,
	[tCtrls["wxID_MENU_REG_MOD"]] = function()
		local item = tFuncs:GetSelection(tCtrls["lst_regs"])
		local iPos = tCtrls["lst_regs"]:GetItemData(item)+1
		local sNick,sPass,iProfile,sOldNick = tFuncs:ShowRegWindow(tCtrls["tRegs"][iPos][1],tCtrls["tRegs"][iPos][2],tCtrls["tRegs"][iPos][3])
		if sNick then -- if not cancelled
			if sNick ~= sOldNick then -- Create a new reg
				tFuncs:Send("$SET 6 0 "..sOldNick)
				tFuncs:Send("$SET 6 1 "..sNick.." "..sPass.." "..iProfile)
			else -- Just the pass/profile changed
				tFuncs:Send("$SET 6 2 "..sNick.." "..sPass.." "..iProfile)
			end
		end
	end,
	[tCtrls["wxID_MENU_REG_DEL"]] = function()
		local item = tFuncs:GetSelection(tCtrls["lst_regs"])
		tFuncs:Send("$SET 6 0 "..tCtrls["lst_regs"]:GetItemText(item))
	end,
	[tCtrls["wxID_MENU_REG_RELOAD"]] = function()
		tFuncs:ReloadRegs()
	end,
	[tCtrls["wxID_MENU_ADD_BAN"]] = function()
		if tCtrls["iStatus"] == 0 then return end
		local tBan = tFuncs:ShowBanDialog()
		if not tBan then return end
		tFuncs:CreateBan(tBan[2])
	end,
	[tCtrls["wxID_MENU_MOD_BAN"]] = function()
		local item = tFuncs:GetSelection(tCtrls["lst_bans"])
		local tBan = tFuncs:ShowBanDialog(tCtrls["tBans"][tCtrls["lst_bans"]:GetItemData(item)+1])
		if not tBan then return end
		if tBan[1] then tFuncs:Unban(item) end
		tFuncs:CreateBan(tBan[2])
	end,
	[tCtrls["wxID_MENU_DEL_BAN"]] = function()
	    wx.wxBeginBusyCursor()
		local item = tCtrls["lst_bans"]:GetNextItem(-1,wx.wxLIST_NEXT_ALL,wx.wxLIST_STATE_SELECTED)
		while item ~= -1 do
			-- GetItemData gives back the selected items data to avoid re-sorted list's wrong indexes
			tFuncs:Unban(item)
			item = tCtrls["lst_bans"]:GetNextItem(item,wx.wxLIST_NEXT_ALL,wx.wxLIST_STATE_SELECTED)
		end
	end,
	[tCtrls["wxID_MENU_DEL_TEMPBANS"]] = function()
	    if tCtrls["iStatus"] == 1 then
			tFuncs:Send("$SET 3 1")
		end
	end,
	[tCtrls["wxID_MENU_DEL_PERMBANS"]] = function()
	    if tCtrls["iStatus"] == 1 then
			tFuncs:Send("$SET 3 2")
		end
	end,
	[tCtrls["wxID_MENU_ADD_RANGEBAN"]] = function()
		if tCtrls["iStatus"] == 0 then return end
		local tBan = tFuncs:ShowRangeBanDialog()
		if not tBan then return end
		tFuncs:CreateRangeBan(tBan[2])
	end,
	[tCtrls["wxID_MENU_MOD_RANGEBAN"]] = function()
		local item = tFuncs:GetSelection(tCtrls["lst_rangebans"])
		local tBan = tFuncs:ShowRangeBanDialog(tCtrls["tRangeBans"][tCtrls["lst_rangebans"]:GetItemData(item)+1])
		if not tBan then return end
		if tBan[1] then
			tFuncs:Send("$SET 3 3 "..item.." "..tCtrls["tRangeBans"][item+1][1])
		end
		tFuncs:CreateRangeBan(tBan[2])
	end,
	[tCtrls["wxID_MENU_DEL_RANGEBAN"]] = function()
	    wx.wxBeginBusyCursor()
	    local item = tCtrls["lst_rangebans"]:GetNextItem(-1,wx.wxLIST_NEXT_ALL,wx.wxLIST_STATE_SELECTED)
	    while item ~= -1 do
	        -- GetItemData give back the selected items data to avoid re-sorted list's wrong indexes
	        local selitem = tCtrls["lst_rangebans"]:GetItemData(item)
			tFuncs:Send("$SET 3 3 "..selitem.." "..tCtrls["tRangeBans"][selitem+1][1])
			item = tCtrls["lst_rangebans"]:GetNextItem(item,wx.wxLIST_NEXT_ALL,wx.wxLIST_STATE_SELECTED)
		end
	end,
 	[tCtrls["wxID_MENU_DEL_RANGETEMPBANS"]] = function()
        if tCtrls["iStatus"] == 1 then
			tFuncs:Send("$SET 3 4")
		end
	end,
	[tCtrls["wxID_MENU_DEL_RANGEPERMBANS"]] = function()
        if tCtrls["iStatus"] == 1 then
			tFuncs:Send("$SET 3 5")
		end
	end,
	[tCtrls["wxID_MENU_LOAD_TXT"]] = function()
	    if tCtrls["iStatus"] == 1 then
		    wx.wxBeginBusyCursor()
			local textfile = tCtrls["lst_texts"]:GetStringSelection()
			-- The program will always download the selected file
			tFuncs:DownloadFile(8,textfile..".txt")
			table.insert(tCtrls["tDeadThreads"],ThreadCreate(tFuncs.FileAction,{ textfile..".txt",1}))
		end
	end,
	[tCtrls["wxID_MENU_SAVE_TXT"]] = function()
		if tCtrls["iStatus"] == 1 then
			local filename = tCtrls["lst_texts"]:GetStringSelection()
			if not wx.wxDirExists("texts") then wx.wxMkdir("texts") end
			local f = io.open("./texts/"..filename..".txt","w+")
			if f then
				local c = tFuncs:GetCtrl("txt_texteditor"):GetValue():gsub("|","[endpipe]")
				f:write(c)
				f:close()
				tFuncs:Send("$SET 7 \""..filename..".txt\" "..c)
			end
		end
	end,
	[tCtrls["wxID_MENU_TEXT_DEL"]] = function()
		if tCtrls["iStatus"] == 1 then
			tFuncs:Send("$SET 7 \""..tCtrls["lst_texts"]:GetStringSelection()..".txt\" del")
		end
	end,
	}
	if tMenuEvtIds[event:GetId()] then
	    tMenuEvtIds[event:GetId()]()
	end
end
tCtrls["app"]:Connect(wx.wxID_ANY,wx.wxEVT_COMMAND_MENU_SELECTED,OnMenuSelected)

function OnListItem(event)
	local tActivateEvtIds = {
	[tCtrls["wxID_REGLIST"]] = function()
		local item = tFuncs:GetSelection(tCtrls["lst_regs"])
		local iPos = tCtrls["lst_regs"]:GetItemData(item)+1
		local sNick,sPass,iProfile,sOldNick = tFuncs:ShowRegWindow(tCtrls["tRegs"][iPos][1],tCtrls["tRegs"][iPos][2],tCtrls["tRegs"][iPos][3])
		if sNick then -- if not cancelled
			if sNick ~= sOldNick then -- Create a new reg
				tFuncs:Send("$SET 6 0 "..sOldNick)
				tFuncs:Send("$SET 6 1 "..sNick.." "..sPass.." "..iProfile)
			else -- Just the pass/profile changed
				tFuncs:Send("$SET 6 2 "..sNick.." "..sPass.." "..iProfile)
			end
		end
	end,
	[tCtrls["wxID_BANLIST"]] = function()
		local item = tFuncs:GetSelection(tCtrls["lst_bans"])
		local tBan = tFuncs:ShowBanDialog(tCtrls["tBans"][tCtrls["lst_bans"]:GetItemData(item)+1],tCtrls["lst_bans"]:GetItemData(item))
		if not tBan then return end
		if tBan[1] then tFuncs:Unban(item) end
		tFuncs:CreateBan(tBan[2])
	end,
	[tCtrls["wxID_RANGEBANLIST"]] = function()
		local item = tFuncs:GetSelection(tCtrls["lst_rangebans"])
		local tBan = tFuncs:ShowRangeBanDialog(tCtrls["tRangeBans"][tCtrls["lst_rangebans"]:GetItemData(item)+1])
		if not tBan then return end
		if tBan[1] then
			tFuncs:Send("$SET 3 3 "..item.." "..tCtrls["tRangeBans"][item+1][1])
		end
		tFuncs:CreateRangeBan(tBan[2])
	end,}
	if tActivateEvtIds[event:GetId()] then
	    tActivateEvtIds[event:GetId()]()
	end
end
tCtrls["app"]:Connect(wx.wxID_ANY,wx.wxEVT_COMMAND_LIST_ITEM_ACTIVATED,OnListItem)

function OnListCol(event)
	local tColumnEvtIds = {
	[tCtrls["wxID_REGLIST"]] = function()
    	tFuncs:SortListItems(event:GetColumn(),"lst_regs")
	end,
	[tCtrls["wxID_BANLIST"]] = function()
	    tFuncs:SortListItems(event:GetColumn(),"lst_bans")
	end,
	[tCtrls["wxID_RANGEBANLIST"]] = function()
	    tFuncs:SortListItems(event:GetColumn(),"lst_rangebans")
	end,
	}
	if tColumnEvtIds[event:GetId()] and tCtrls["iStatus"] == 1 then
	    tColumnEvtIds[event:GetId()]()
	end
end
tCtrls["app"]:Connect(wx.wxID_ANY,wx.wxEVT_COMMAND_LIST_COL_CLICK,OnListCol)

function OnHelp(event)
	tFuncs:About()
end
tCtrls["app"]:Connect(wx.wxEVT_HELP,OnHelp) -- Called when F1 pressed

if wx.__WXMSW__ then -- On Unix it hides the program...
	function OnIconize(event)
		if os.clock() < 3000 then return end -- A bit crappy,but useful =)
		tCtrls["app"]:Iconize(true)
		tCtrls["app"]:Show(false)
		event:Skip()
	end
	tCtrls["app"]:Connect(wx.wxEVT_ICONIZE,OnIconize)
	
	function OnTaskBar(event)
		if not tCtrls["app"] then wx.wxGetApp():ExitMainLoop() wx.wxExit(0) end
		if tCtrls["app"]:IsIconized() then
			tCtrls["app"]:Show(true)
			tCtrls["app"]:Iconize(false)
		else
			tCtrls["app"]:Iconize(true)
			tCtrls["app"]:Show(false)
		end
		event:Skip()
	end
	tCtrls["taskbar"]:Connect(wx.wxID_ANY,wx.wxEVT_TASKBAR_LEFT_DOWN,OnTaskBar)
end

function OnClose(event)
	if _DEBUG then
		DBGFILE:close()
	end
	if tCtrls["iState"] == 1 then tFuncs:CleanUp() end
	if tCtrls["udp_client"] then
		tCtrls["udp_client"]:close()
	end
	tCtrls["taskbar"]:RemoveIcon()
	wx.wxGetApp():ExitMainLoop()
	wx.wxExit(0)
	event:Skip()
end
tCtrls["app"]:Connect(wx.wxEVT_CLOSE_WINDOW,OnClose) 

tCtrls["splash"]:Destroy()
tCtrls["splash"] = nil
tFuncs:SetStatusText((tFuncs:Translate("Ready") or "Ready").."...")
tCtrls["app"]:Iconize(false)
tCtrls["app"]:Show(true)

wx.wxGetApp():MainLoop()

