Index: ChangeLog
===================================================================
--- ChangeLog	(revision 3039)
+++ ChangeLog	(working copy)
@@ -67,7 +67,7 @@
 
 
 2025-07-16 Roman (stable)
-- !:FIX:LibsDB.OscadaLibs: tmplib_base.{tmplib_DevLib}.UPS: Fixing of writing to the writeable attributes.
+- !:FIX:LibsDB.OscadaLibs: tmplib_base.tmplib_DevLib.UPS: Fixing of writing to the writeable attributes.
 - FIX:LibsDB.vcaBase: wlb_Main.objProps: Appending of tracing the user changing.
 	Appending for support real properties.
     FIX:wlb_Main.ElViewGraph: The attribute "Dimension (ed)" set to the type "String (translate)" to restore
Index: configure.ac
===================================================================
--- configure.ac	(revision 3039)
+++ configure.ac	(working copy)
@@ -159,12 +159,19 @@
 AC_SEARCH_LIBS(deflate, [z], [], AC_MSG_ERROR([Z library isn't found. Install or check the libz package!]))
 
 # Check for the PCRE library using in the OpenSCADA core
-CXXFLAGS="$CXXFLAGS $($PKG_CONFIG --cflags libpcre)"
-AC_CHECK_HEADERS([pcre.h], [], AC_MSG_ERROR([The PCRE header isn't found. Install or check the PCRE developing package!]))
-AC_SEARCH_LIBS(pcre_compile, [pcre], [
-    AC_SEARCH_LIBS(pcre16_compile, [pcre16], AC_DEFINE(HAVE_PCRE16, 1, [PCRE16 is allowed]))
-    AC_SEARCH_LIBS(pcre32_compile, [pcre32], AC_DEFINE(HAVE_PCRE32, 1, [PCRE32 is allowed]))
-], AC_MSG_ERROR([The PCRE library isn't found. Install or check the PCRE package!]))
+PKG_CHECK_MODULES([libpcre2], [libpcre2-8 > 10.0], [
+    CXXFLAGS="$CXXFLAGS $($PKG_CONFIG --cflags libpcre2-8)"
+    AC_SEARCH_LIBS(pcre2_compile_8, [pcre2-8], AC_DEFINE(HAVE_PCRE_2, 1, [PCRE2 is allowed]))
+    AC_SEARCH_LIBS(pcre2_compile_16, [pcre2-16], AC_DEFINE(HAVE_PCRE16, 1, [PCRE2-16 is allowed]))
+    AC_SEARCH_LIBS(pcre2_compile_32, [pcre2-32], AC_DEFINE(HAVE_PCRE32, 1, [PCRE2-32 is allowed]))
+], [
+    CXXFLAGS="$CXXFLAGS $($PKG_CONFIG --cflags libpcre)"
+    AC_CHECK_HEADERS([pcre.h], [], AC_MSG_ERROR([The PCRE header isn't found. Install or check the PCRE developing package!]))
+    AC_SEARCH_LIBS(pcre_compile, [pcre], [
+	AC_SEARCH_LIBS(pcre16_compile, [pcre16], AC_DEFINE(HAVE_PCRE16, 1, [PCRE16 is allowed]))
+	AC_SEARCH_LIBS(pcre32_compile, [pcre32], AC_DEFINE(HAVE_PCRE32, 1, [PCRE32 is allowed]))
+    ], AC_MSG_ERROR([The PCRE library isn't found. Install or check the PCRE package!]))
+])
 
 # Check for the GD library using into the OpenSCADA core
 if test $enable_LibGD = yes; then
Index: data/LibsDB/OscadaLibs.sql
===================================================================
--- data/LibsDB/OscadaLibs.sql	(revision 3039)
+++ data/LibsDB/OscadaLibs.sql	(working copy)
@@ -9126,6 +9126,7 @@
 if(passIn=(pMax==pMin)) { pMax = max/iMult - iAdd; pMin = min/iMult - iAdd; }
 
 //Manual input set process
+inout_ = inout;
 if(!varIn.isEVal() && (varIn != var || inout.isEVal())) {
 	if(passIn) { pMin = iMult*(pMin+iAdd); pMax = iMult*(pMax+iAdd); }
 	vCalibr = (varIn-min)/(max-min);
@@ -9132,22 +9133,23 @@
 	if(scSqr)	vCalibr = pow(vCalibr,2);
 	if(pMax < pMin) vCalibr = 1-vCalibr;
 	vCalibr = min(pMax,pMin)+vCalibr*abs(pMax-pMin);
-	inout = vCalibr/iMult - iAdd;
+	inout_ = vCalibr/iMult - iAdd;
+	if(!inout.isEVal())	inout = inout_;
 }
 
 levErr = 0;
 tErr = "0";
 //Input data check and postprocess
-if(inout > (max(pMax,pMin)+plcExcess*abs(pMax-pMin)/100)) {
+if(inout_ > (max(pMax,pMin)+plcExcess*abs(pMax-pMin)/100)) {
 	tErr = "1:"+tr("The signal exceed to upper hardware border"); levErr = -5;
 	var = max + plcExcess*(max-min)/100;
 }
-else if(inout < (min(pMax,pMin)-plcExcess*abs(pMax-pMin)/100)) {
+else if(inout_ < (min(pMax,pMin)-plcExcess*abs(pMax-pMin)/100)) {
 	tErr = "2:"+tr("The signal exceed to bottom hardware border"); levErr = -5;
 	var = min - plcExcess*(max-min)/100;
 }
 if(!tErr) {
-	vCalibr = iMult*(inout+iAdd);
+	vCalibr = iMult*(inout_+iAdd);
 	if(passIn) { pMin = iMult*(pMin+iAdd); pMax = iMult*(pMax+iAdd); }
 	if(!passIn || scSqr) {
 		vCalibr = (vCalibr-min(pMax,pMin))/abs(pMax-pMin);
@@ -9185,7 +9187,7 @@
 	else	this.alarmSet(DESCR+": "+tr("NORM"), 1);
 	f_err = tErr;
 	alDelay_ = 0;
-}','','',1686917547);
+}','','',1757077780);
 INSERT INTO tmplib_base VALUES('anUnif','Analog signal, unified','Аналоговий сигнал, уніфікований','Аналоговый сигнал, унифицированный','Common, representative and unified template of analog input signals processing. The template forms a structure of complex analog parameter (tag) which can be easily connected to most widgets and cadres of the main elements library of the user interface just pointing the parameter object.
 
 Functions:
Index: data/LibsDB/vcaBase.sql
===================================================================
--- data/LibsDB/vcaBase.sql	(revision 3039)
+++ data/LibsDB/vcaBase.sql	(working copy)
@@ -12529,6 +12529,7 @@
 	else if(sval == "ws_TableChangeSel") {
 		iM = curAlMess[value];
 		NAME = iM.mess.parse(0, messItSep);
+		if((srcO=iM.categ.match("al.+:(.+)$")).length > 1) NAME = srcO[1];	//!!!! Since new human names isn''t suitable for categories
 		DESCR = iM.mess.parse(1, messItSep) + " -> " + iM.mess.parse(2, messItSep);
 		st_open = iM.mess.parse(3, messItSep).length;
 		if(value.length) event += "usr_goquiet\n";
@@ -12555,8 +12556,10 @@
 		for(i = 0; i < curAlMess.length; i++) {
 			iM = curAlMess[i];
 			if(!iM.mess.parse(3,messItSep).length) {
-				SYS.messNote("OP:"+this.ownerSess().user()+":"+iM.mess.parse(0,messItSep),
-						"''"+iM.mess.parse(0,messItSep)+"''. "+tr("Command")+" : "+iM.mess.parse(1, messItSep) + " -> " + iM.mess.parse(2, messItSep)+" : : "+digComs.parse(0,";").parse(0,"-"));
+				tNAME = iM.mess.parse(0,messItSep);
+				if((srcO=iM.categ.match("al.+:(.+)$")).length > 1) tNAME = srcO[1];	//!!!! Since new human names isn''t suitable for categories
+				SYS.messNote("OP:"+this.ownerSess().user()+":"+tNAME,
+						"''"+iM.mess.parse(0,messItSep)+"''. "+tr("Command")+" : "+iM.mess.parse(1,messItSep) + " -> " + iM.mess.parse(2,messItSep)+" : : "+digComs.parse(0,";").parse(0,"-"));
 				tMess = iM.mess.parse(0,messItSep)+messItSep+iM.mess.parse(1,messItSep)+messItSep+iM.mess.parse(2,messItSep)+messItSep+
 						SYS.strftime(SYS.time(tmU),formDtTm.replace("%MS",(tmU/1000).toString(10,3)).replace("%US",tmU.toString(10,6)));
 				if((tVl1=iM.mess.parse(4,messItSep)).length || (tVl2=iM.mess.parse(5,messItSep)).length) {
@@ -12573,7 +12576,7 @@
 		SYS.Archive.messPut(iM.tm, iM.utm, iM.categ, iM.level, iM.mess.parse(0,messItSep)+messItSep+iM.mess.parse(1,messItSep)+messItSep+iM.mess.parse(2,messItSep)+messItSep+
 										iM.mess.parse(3,messItSep)+messItSep+iM.mess.parse(4,messItSep)+messItSep+set);
 	}
-}','','',-1,'owner;name;dscr;active;geomY;geomW;geomH;contextMenu;evProc;elType;value;items;set;',1662915469);
+}','','',-1,'owner;name;dscr;active;geomY;geomW;geomH;contextMenu;evProc;elType;value;items;set;',1757094469);
 INSERT INTO wlb_Main VALUES('alarmsSt','iVBORw0KGgoAAAANSUhEUgAAAEAAAAAnCAIAAAAw+tlrAAAAA3NCSVQICAjb4U/gAAAACXBIWXMA
 AA7EAAAOxAGVKw4bAAAE60lEQVRYhe2YTW8kRwGGn/qumpn2jJ1db+z1JpsEwgJCCkJw4PeQPwEX
 Llw5w50rd05RDhyQkDgmkdkQstpo7bXX3vXMdFd31wcHx4CEcjASGSLNc6y3q/p9qrtVUov33/9Z
@@ -12895,8 +12898,10 @@
 				alarms_items += aRow + "</r>\n";
 				if(makeReport) rep += repRow + "</tr>\n";
 				if(toMassQuitt && !iM.mess.parse(3,messItSep).length) {
-					SYS.messNote("OP:"+this.ownerSess().user()+":"+iM.mess.parse(0,messItSep),
-						"''"+iM.mess.parse(0,messItSep)+"''. "+tr("Command")+" : "+iM.mess.parse(1, messItSep) + " -> " + iM.mess.parse(2, messItSep)+" : : "+alarms_digComs.parse(0,";").parse(0,"-"));
+					tNAME = iM.mess.parse(0,messItSep);
+					if((srcO=iM.categ.match("al.+:(.+)$")).length > 1) tNAME = srcO[1];	//!!!! Since new human names isn''t suitable for categories
+					SYS.messNote("OP:"+this.ownerSess().user()+":"+tNAME,
+						"''"+iM.mess.parse(0,messItSep)+"''. "+tr("Command")+" : "+iM.mess.parse(1,messItSep) + " -> " + iM.mess.parse(2,messItSep)+" : : "+alarms_digComs.parse(0,";").parse(0,"-"));
 					tmU = 0;
 					tMess = iM.mess.parse(0,messItSep)+messItSep+iM.mess.parse(1,messItSep)+messItSep+iM.mess.parse(2,messItSep)+messItSep+
 						SYS.strftime(SYS.time(tmU),formDtTm.replace("%MS",(tmU/1000).toString(10,3)).replace("%US",tmU.toString(10,6)));
@@ -12966,6 +12971,7 @@
 	else if(sval == "ws_TableChangeSel:/alarms") {
 		iM = als[alarms_value];
 		alarms_NAME = iM.mess.parse(0, messItSep);
+		if((srcO=iM.categ.match("al.+:(.+)$")).length > 1) alarms_NAME = srcO[1];	//!!!! Since new human names isn''t suitable for categories
 		alarms_DESCR = iM.mess.parse(1, messItSep) + " -> " + iM.mess.parse(2, messItSep);
 		alarms_st_open = iM.mess.parse(3, messItSep).length;
 		if(alarms_value.length) event += "usr_goquiet:/alarms\n";
@@ -13025,7 +13031,7 @@
 }
 
 time_value = wTm ? wTm : SYS.time();
-//go_cur_active = wTm;','','',-1,'owner;name;dscr;geomX;geomY;geomW;geomH;geomZ;evProc;pgOpenSrc;pgGrp;backColor;bordWidth;bordColor;',1662915478);
+//go_cur_active = wTm;','','',-1,'owner;name;dscr;geomX;geomY;geomW;geomH;geomZ;evProc;pgOpenSrc;pgGrp;backColor;bordWidth;bordColor;',1757094809);
 INSERT INTO wlb_Main VALUES('ImgLab','iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAN
 EklEQVR4nOWb6W5dyXWFv7XPcCfegRRHiZJIiZRavE31QLtjuQ1ET+GH8O88gB8gT2IgzxD/cAAD
 toLYgdyA3XHakhrd7pZkURTHe0+t/LiUqO5I1MBBRrKAQxI8VXVWrbNr195VdQSY/8fI93//M/Dr
@@ -13809,8 +13815,7 @@
 				fColLs += "\n"+clsLsO[tVl].name+" ("+((tVl[0]=="*")?tVl.slice(1):"SP_"+tVl)+")";
 			}
 
-		//Updation the main table
-		// Where prepairing for the filter
+		// WHERE prepairing for the filter
 		noFilter = true;
 		for(wherePart = "", iF = 0; iF < fMax; iF++) {
 			this["fltrCol"+iF].attrSet("items", fColLs);
@@ -13826,8 +13831,44 @@
 
 		// Same requesting
 		dataTbl = SYS.BD.nodeAt(db,".").SQLReq("SELECT `ID`,"+clsLsReq+" FROM `sh_"+class+"` "+(wherePart.length?"WHERE"+wherePart:"")+"ORDER BY ''ID'';", false);
+		colTps = new Object();
+
+		// Updating the data
+		stPrcTime = SYS.mtime();
+		for(iR = 0; iR < dataTbl.length; iR++) {
+			//   ... the header
+			if(iR == 0)
+				for(iC = 0; iC < dataTbl[iR].length; iC++) {
+					itVl = dataTbl[iR][iC];
+					if((itVl.indexOf("SP_") == 0 && !(tVl=clsLsO[itVl.slice(3)]).isEVal()) || ((itVl == "ID" || itVl == "NAME" || itVl == "DSCR") && !(tVl=clsLsO["*"+itVl]).isEVal()))
+					{
+						if((tVl.fltr == "index" || tVl.fltr.indexOf("list") == 0) && colVars[itVl] == null) {
+							colVars[itVl] = new Object();
+							colVars[itVl].ls = new Object();
+							colVars[itVl].fltr = tVl.fltr;
+						}
+						if(tVl.tp.search("bool","i") >= 0)			colTps[iC] = "b";
+						else if(tVl.tp.search("int","i") >= 0)	colTps[iC] = "i";
+						else if(tVl.tp.search("(float|double)","i") >= 0) colTps[iC] = "r";
+						else if(tVl.tp.search("text","i") >= 0 || tVl.tp.parse(0,":") == "file")
+																				colTps[iC] = "t";
+					}
+				}
+			//  ... the data
+			else {
+				//  ... prepairing the logical cells
+				if(hasProc && (SYS.mtime()-stPrcTime) < 2000) updProc(iR, dataTbl, clsLsO);
+				//  ... getting whole lists without filters
+				for(iC = 0; noFilter && iC < dataTbl[iR].length; iC++) {
+					itVlCol = dataTbl[0][iC];
+					colLists[itVlCol] = colVars[itVlCol].ls;
+				}
+			}
+		}
+		if((SYS.mtime()-stPrcTime) > 2000)	toCalcCycles = 0.2;	//Retry unfinished calculation after 0.2 seconds
+
+		// Updation the main table
 		dataTbl_items = "<tbl sel=''row'' sortEn=''"+(btEdit_value?0:1)+"'' colsWdthFit=''0'' hHdrVis=''1'' vHdrVis=''1''>\n";
-		colTps = new Object();
 		if(toReport)	tRep = "<body>\n"
 								"<h1>"+classNm_text+"</h1>\n"
 								"<table class=''data'' width=''100%'' export=''1''>\n";
@@ -13843,18 +13884,8 @@
 					if(itVl == "ID" && clsLsO["*"+itVl] == null)	opt += " width=''0px''";
 					else if((itVl.indexOf("SP_") == 0 && !(tVl=clsLsO[itVl.slice(3)]).isEVal()) || ((itVl == "ID" || itVl == "NAME" || itVl == "DSCR") && !(tVl=clsLsO["*"+itVl]).isEVal()))
 					{
-						if((tVl.fltr == "index" || tVl.fltr.indexOf("list") == 0) && colVars[itVl] == null) {
-							colVars[itVl] = new Object();
-							colVars[itVl].ls = new Object();
-							colVars[itVl].fltr = tVl.fltr;
-						}
 						opt += (btEdit_value && !tVl.prc.length && itVl != "ID" && tVl.tp.parse(0,":") != "file") ? " edit=''1''" : "";
 						itVl = tVl.name;
-						if(tVl.tp.search("bool","i") >= 0)			colTps[iC] = "b";
-						else if(tVl.tp.search("int","i") >= 0)	colTps[iC] = "i";
-						else if(tVl.tp.search("(float|double)","i") >= 0) colTps[iC] = "r";
-						else if(tVl.tp.search("text","i") >= 0 || tVl.tp.parse(0,":") == "file")
-																				colTps[iC] = "t";
 						if((tVl2=tVl.tbl.parse(0,":")).length)	opt += " align=''"+tVl2+"''";
 						if((tVl2=tVl.tbl.parse(1,":")).length)	opt += " width=''"+tVl2+"''";
 						//this.messInfo("iC="+iC+"; tp="+tVl.tp+" = "+colTps[iC]+"; tVl.fltr="+tVl.fltr);
@@ -13864,9 +13895,6 @@
 				}
 			//  ... the data
 			else {
-				//  ... prepairing the logical cells
-				if(hasProc) updProc(iR, dataTbl, clsLsO);
-
 				//  ... representing
 				for(iC = 0; iC < dataTbl[iR].length; iC++) {
 					itVlCol = dataTbl[0][iC];
@@ -13882,7 +13910,6 @@
 						tVl = ((tVl=tVl1.parse(2,":")).length?" color=''"+tVl+"''":"") + ((tVl=tVl1.parse(3,":")).length?" font=''"+tVl+"''":"");
 						if(tVl1.parse(1,":")[0] == "1") optR += tVl; else opt += tVl;
 					}
-					if(noFilter)	colLists[itVlCol] = colVars[itVlCol].ls;
 					if(dataTbl_value.length && itVlCol == "ID" && itVl == dataTbl_value)	noDataTbl_value = false;
 				
 					if(!colTps[iC].isEVal())	cntR += "<"+colTps[iC]+opt+">"+SYS.strEncode(itVl,"HTML")+"</"+colTps[iC]+">";
@@ -14393,7 +14420,7 @@
 	if(toCalcCycles <= 10)	toCalcCycles = SYS.time()+toCalcCycles;	//Conversion the relative time in seconds to absolute
 	else if(SYS.time() > toCalcCycles)	toCalcCycles = 0, toUpdate = true;
 	//if(!(toCalcCycles=max(0,toCalcCycles-1)))	toUpdate = true;
-}','','',-1,'owner;name;dscr;geomX;geomY;geomW;geomH;geomZ;evProc;pgOpenSrc;pgGrp;backColor;bordWidth;bordColor;',1753539095);
+}','','',-1,'owner;name;dscr;geomX;geomY;geomW;geomH;geomZ;evProc;pgOpenSrc;pgGrp;backColor;bordWidth;bordColor;',1756914629);
 INSERT INTO wlb_Main VALUES('weather','iVBORw0KGgoAAAANSUhEUgAAAEAAAAAxCAIAAADldTjtAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAO
 KUlEQVRogdVa228bV3o/Z87cyRnebyJF8SJLsmRZchy7cSUncQyjDjbbNhssdrsLNFsUaNEWfSgK
 9F/xS9CgD3loUewiKFqk62w2XslO1rZs2bEki5JMihJ1o3jRkJwZzu30YWxqRMluI2eb7PdEHn7n
@@ -24078,7 +24105,7 @@
 
 Author: Roman Savochenko <roman@oscada.org>
 Sponsored by: Ustijancev Michael
-Version: 1.4.2
+Version: 1.4.3
 License: GPLv2',32,'','','','Елемент на рисунку 1.5 слугує для динамічного відображення активних порушень у табличному вигляді та із виділенням їх за кольором та текстом. Порушення отримуються із буферу поточних-активних порушень OpenSCADA. Фактично елемент реалізує функції примітиву "Протокол" для порушень та із розширенням можливостей.
 
 Для детального вивчення актуальних порушень елементом передбачено функцію збільшення висоти угору або униз за отриманням фокусу.
@@ -24105,7 +24132,7 @@
 Автор: Роман Савоченко <roman@oscada.org>
 Спонсорування: Устьянцев Михайло
 Версія: 1.4.2
-Ліцензія: GPLv2','','Элемент на рисунке 1.5 служит для динамического отображения активных нарушений в табличном виде и с выделением их цветом и текстом. Нарушения получаются из буфера текущих-активных нарушений OpenSCADA. Фактически элемент реализует функции примитива "Протокол" для нарушений и с расширением возможностей.
+Ліцензія: GPLv2<!>','','Элемент на рисунке 1.5 служит для динамического отображения активных нарушений в табличном виде и с выделением их цветом и текстом. Нарушения получаются из буфера текущих-активных нарушений OpenSCADA. Фактически элемент реализует функции примитива "Протокол" для нарушений и с расширением возможностей.
 
 Для детального изучения актуальных нарушений элементом предусмотрено функцию увеличения высоты вверх или вниз при получении фокуса.
 
@@ -24131,7 +24158,7 @@
 Автор: Роман Савоченко <roman@oscada.org>
 Спонсирование: Устьянцев Михаил
 Версия: 1.4.2
-Лицензия: GPLv2','','','','');
+Лицензия: GPLv2<!>','','','','');
 INSERT INTO wlb_Main_io VALUES('alarmsSt','dscr','The element-frame serves to display the violations history and to update their dynamically for the current time in a full-format tabular form, to highlight them in color and text and the possibility of multilevel filtering. The violations are obtained from the buffer of current-active violations of OpenSCADA and archive(s), specified in the configuration field <alArch>. In fact, the element implements the primitive "Protocol" functions for violations and extension opportunities.
 
 The frame in general contains elements:
@@ -24170,7 +24197,7 @@
 
 Author: Roman Savochenko <roman@oscada.org>
 Sponsored by: Ustijancev Michael
-Version: 1.5.3
+Version: 1.5.4
 License: GPLv2',32,'','','','Елемент-кадр слугує для відображення історії порушень та динамічного їх оновлення на поточний час у повноформатному табличному вигляді, із виділенням їх за кольором та текстом та можливістю багаторівневого фільтрування. Порушення отримуються із буферу поточних-активних порушень OpenSCADA та архіву(ів), визначеного конфігураційним полем <alArch>. Фактично елемент реалізує функції примітиву "Протокол" для порушень та із розширенням можливостей.
 
 Загалом кадр містить елементи:
@@ -24210,7 +24237,7 @@
 Автор: Роман Савоченко <roman@oscada.org>
 Спонсорування: Устьянцев Михайло
 Версія: 1.5.3
-Ліцензія: GPLv2','','Элемент-кадр служит для отображения истории нарушений и динамического их обновление для текущего времени в полноформатном табличном виде, с выделением их цветом и текстом и возможностью многоуровневого фильтрования. Нарушения получаются из буфера текущих-активных сообщений OpenSCADA и архива(ов), определённого конфигурационным полем <alArch>. Фактически элемент реализует функции примитива "Протокол" для нарушений и с расширением возможностей.
+Ліцензія: GPLv2<!>','','Элемент-кадр служит для отображения истории нарушений и динамического их обновление для текущего времени в полноформатном табличном виде, с выделением их цветом и текстом и возможностью многоуровневого фильтрования. Нарушения получаются из буфера текущих-активных сообщений OpenSCADA и архива(ов), определённого конфигурационным полем <alArch>. Фактически элемент реализует функции примитива "Протокол" для нарушений и с расширением возможностей.
 
 В целом кадр содержит элементы:
 - таблица сообщений — основное поле;
@@ -24249,7 +24276,7 @@
 Автор: Роман Савоченко <roman@oscada.org>
 Спонсирование: Устьянцев Михаил
 Версия: 1.5.3
-Лицензия: GPLv2','','','','');
+Лицензия: GPLv2<!>','','','','');
 INSERT INTO wlb_Main_io VALUES('userManager','view','7',32,'','','pass','','','','','','','');
 INSERT INTO wlb_Main_io VALUES('grpGraph','backColor','black',96,'backColorVal','','trnd1','','','','','','','');
 INSERT INTO wlb_Main_io VALUES('grpGraph10','bordColor','#000000',32,'','','trnd1','','','','','','','');
Index: data/debian/control
===================================================================
--- data/debian/control	(revision 3039)
+++ data/debian/control	(working copy)
@@ -4,7 +4,7 @@
 Standards-Version: 3.9.6
 Maintainer: Roman Savochenko <roman@oscada.org>
 Homepage: http://oscada.org
-Build-Depends: debhelper (>= 5), dh-autoreconf, sqlite3, g++, autotools-dev, pkg-config, gettext, libgd-dev | libgd2-xpm-dev | libgd2-noxpm-dev, libpcre3-dev,
+Build-Depends: debhelper (>= 5), dh-autoreconf, sqlite3, g++, autotools-dev, pkg-config, gettext, libgd-dev | libgd2-xpm-dev | libgd2-noxpm-dev, libpcre2-dev | libpcre3-dev,
  default-libmysqlclient-dev | libmysqlclient-dev | libmariadb-dev, libsqlite3-dev, firebird-dev, libpq-dev, libldap2-dev,
  libsensors-dev | libsensors4-dev, portaudio19-dev, bison, libsnmp-dev, libcomedi-dev,
  libssl-dev, libfftw3-dev,
Index: data/debian_mod/control
===================================================================
--- data/debian_mod/control	(revision 3039)
+++ data/debian_mod/control	(working copy)
@@ -4,7 +4,7 @@
 Standards-Version: 3.9.6
 Maintainer: Roman Savochenko <roman@oscada.org>
 Homepage: http://oscada.org
-Build-Depends: debhelper (>= 5), dh-autoreconf, sqlite3, g++, autotools-dev, pkg-config, gettext, libgd-dev | libgd2-xpm-dev | libgd2-noxpm-dev, libpcre3-dev,
+Build-Depends: debhelper (>= 5), dh-autoreconf, sqlite3, g++, autotools-dev, pkg-config, gettext, libgd-dev | libgd2-xpm-dev | libgd2-noxpm-dev, libpcre2-dev | libpcre3-dev,
  default-libmysqlclient-dev | libmysqlclient-dev | libmariadb-dev, libsqlite3-dev, firebird-dev, libpq-dev, libldap2-dev,
  libsensors-dev | libsensors4-dev, portaudio19-dev, bison, libsnmp-dev, libcomedi-dev,
  libssl-dev, libfftw3-dev,
Index: src/moduls/daq/Siemens/nodave.c
===================================================================
--- src/moduls/daq/Siemens/nodave.c	(revision 3039)
+++ src/moduls/daq/Siemens/nodave.c	(working copy)
@@ -48,6 +48,7 @@
 #define DECL2
 #include <time.h>
 #include <sys/time.h>
+#include <sys/socket.h>
 #endif
 
 #ifdef HAVE_UNISTD
Index: src/moduls/daq/System/da_ups.cpp
===================================================================
--- src/moduls/daq/System/da_ups.cpp	(revision 3039)
+++ src/moduls/daq/System/da_ups.cpp	(working copy)
@@ -211,10 +211,11 @@
     //Check connect and start
     AutoHD<TTransportOut> tr;
     if(!SYS->transport().at().at(tTr).at().outPresent(nTr)) {
-	SYS->transport().at().at(tTr).at().outAdd(nTr);
+	SYS->transport().at().at(tTr).at().outAdd(nTr, "");
 	tr = SYS->transport().at().at(tTr).at().outAt(nTr);
 	tr.at().setName(_("UPS"));
 	tr.at().setTimings("3:0.1");
+	tr.at().modifClr();
     }
     else tr = SYS->transport().at().at(tTr).at().outAt(nTr);
 
Index: src/moduls/protocol/HTTP/http.cpp
===================================================================
--- src/moduls/protocol/HTTP/http.cpp	(revision 3039)
+++ src/moduls/protocol/HTTP/http.cpp	(working copy)
@@ -580,13 +580,14 @@
 		ctrMkNode("fld",opt,-1,"/prm/cfg/tmplMainPage",_("HTML template of the main page"),RWRWR_,"root",SPRT_ID,3,
 		    "tp","str", "dest","sel_ed", "select","/prm/cfg/tmplMainPageList");
 		ctrMkNode("fld",opt,-1,"/prm/cfg/authSesDB",_("DB of the active authentication sessions"),RWRWR_,"root",SPRT_ID,4,
-		    "tp","str", "dest","select", "select","/db/list:onlydb",
+		    "tp","str", "dest","select", "select","/db/list:onlydb|nostor",
 		    "help",(TMess::labStor()+"\n"+
 			_("Set to empty to disable using the external table of the active authentication sessions.")).c_str());
 		if(authSessTbl().size())
 		    ctrMkNode("fld",opt,-1,"/prm/cfg/spaceUID",_("Authentication UID generation space"),RWRWR_,"root",SPRT_ID,3,"tp","dec", "min","0", "max","100");
 		ctrMkNode("fld",opt,-1,"/prm/cfg/lf_tm",_("Life time of the authentication, minutes"),RWRWR_,"root",SPRT_ID,1,"tp","dec");
-		ctrMkNode("fld",opt,-1,"/prm/cfg/aUsers",_("List of users allowed for authentication, separated by ';'"),RWRWR_,"root",SPRT_ID,1,"tp","str");
+		if(allowUsersAuth().size())
+		    ctrMkNode("fld",opt,-1,"/prm/cfg/aUsers",_("List of users allowed for authentication, separated by ';'"),RWRWR_,"root",SPRT_ID,1,"tp","str");
 		if(ctrMkNode("table",opt,-1,"/prm/cfg/alog",_("Auto login"),RWRWR_,"root",SPRT_ID,3, "s_com","add,ins,del", "rows","3",
 		    "help",_("A list of address templates can be used for the address field, for example \"192.168.1.*;192.168.2.*\".")))
 		{
@@ -816,7 +817,7 @@
 		    if((cntEl=cnt.find("pass")) != cnt.end())	pass = cntEl->second;
 		    if(mod->autoLogGet(sender) == user ||
 			((!mod->allowUsersAuth().size() || (allowUser=TRegExp("(^|;)"+user+"(;|$)").test(mod->allowUsersAuth()))) &&
-			    SYS->security().at().usrPresent(user) && SYS->security().at().usrAt(user).at().auth(pass)))
+			    SYS->security().at().usrPresent(user) && SYS->security().at().usrAt(user).at().alowRemAuth() && SYS->security().at().usrAt(user).at().auth(pass)))
 		    {
 			string prevUser;
 			if(sesId) { prevUser = mod->sesCheck(sesId); mod->sesClose(sesId); }
Index: src/moduls/protocol/HTTP/http.h
===================================================================
--- src/moduls/protocol/HTTP/http.h	(revision 3039)
+++ src/moduls/protocol/HTTP/http.h	(working copy)
@@ -169,7 +169,9 @@
 	void cntrCmdProc( XMLNode *opt );	//Control interface command process
 
 	//Attributes
-	MtxString	mDeny, mAllow, mTmpl, mTmplMainPage, mAllowUsersAuth, mAuthSessDB;
+	MtxString	mDeny, mAllow, mTmpl, mTmplMainPage,
+			mAllowUsersAuth,	//????[v1.0] Remove, due to replacing by {User}.allowUsersAuth()
+			mAuthSessDB;
 	TElem		elAuth;		//Elements of the external authentication sessions
 	map<int, SAuth>	mAuth;
 	int		mTAuth;
Index: src/moduls/protocol/SelfSystem/self.cpp
===================================================================
--- src/moduls/protocol/SelfSystem/self.cpp	(revision 3039)
+++ src/moduls/protocol/SelfSystem/self.cpp	(working copy)
@@ -100,7 +100,9 @@
 int TProt::sesOpen( const string &user, const string &pass, const string &src, int iauthTime, int isingleUserHostLimit )
 {
     string pHash;
-    if(!SYS->security().at().usrPresent(user) || !SYS->security().at().usrAt(user).at().auth(pass,&pHash)) return -1;
+    if(!(SYS->security().at().usrPresent(user) &&
+	    SYS->security().at().usrAt(user).at().alowRemAuth() && SYS->security().at().usrAt(user).at().auth(pass,&pHash)))
+	return -1;
 
     MtxAlloc res(authRes, true);
 
@@ -405,7 +407,7 @@
 	pass_ = TSYS::strDecode(pass, TSYS::Custom);
 	if(pass_ == EMPTY_PASS) pass_ = "";
 	if((ses_id=mod->sesOpen(user_,pass_,TSYS::strLine(srcAddr(),0),authTime,singleUserHostLimit)) < 0)
-	    answer = "REZ " ERR_AUTH " Error authentication: wrong user or password.\x0A";
+	    answer = "REZ " ERR_AUTH " Error authentication.\x0A";
 	else answer = "REZ " ERR_NO " " + i2s(ses_id) + "\x0A";
     }
     else if(header.find("SES_CLOSE") == 0) {
@@ -434,7 +436,8 @@
 	    user_ = TSYS::strDecode(user, TSYS::Custom);
 	    pass_ = TSYS::strDecode(pass, TSYS::Custom);
 	    if(pass_ == EMPTY_PASS) pass_ = "";
-	    if(SYS->security().at().usrPresent(user_) && SYS->security().at().usrAt(user_).at().auth(pass_,&auth.pHash))
+	    if(SYS->security().at().usrPresent(user_) &&
+		SYS->security().at().usrAt(user_).at().alowRemAuth() && SYS->security().at().usrAt(user_).at().auth(pass_,&auth.pHash))
 	    { auth.tAuth = 1; auth.name = user_; }
 	}
 	if(!auth.tAuth) { answer = "REZ " ERR_AUTH " Error authentication: invalid session or direct authentication.\x0A"; reqBuf.clear(); return false; }
Index: src/moduls/transport/SSL/modssl.cpp
===================================================================
--- src/moduls/transport/SSL/modssl.cpp	(revision 3039)
+++ src/moduls/transport/SSL/modssl.cpp	(working copy)
@@ -648,6 +648,7 @@
 
 		if(!cfile.empty() && certKeyFile().empty()) remove(cfile.c_str());
 		aErr = err.mess;
+		stErrMD5 = "";
 		continue;	//Try next
 	    }
 	    break;	//OK
Index: src/moduls/ui/WebVision/WebVisionVCA.js
===================================================================
--- src/moduls/ui/WebVision/WebVisionVCA.js	(revision 3039)
+++ src/moduls/ui/WebVision/WebVisionVCA.js	(working copy)
@@ -1622,8 +1622,10 @@
 			}
 
 			//!!!! Some workaround in preventing of loss the keyboard events during network activity.
-			if(mainTmId) clearTimeout(mainTmId);
-			mainTmId = setTimeout(makeUI, 1000);
+			if(isNN) {
+			    if(mainTmId) clearTimeout(mainTmId);
+			    mainTmId = setTimeout(makeUI, 5000);
+			}
 
 			return true;
 		    };
Index: src/tcntrnode.cpp
===================================================================
--- src/tcntrnode.cpp	(revision 3039)
+++ src/tcntrnode.cpp	(working copy)
@@ -1344,9 +1344,9 @@
 		}
 	}
     }
-    else if((a_path.find("/db/list") == 0 || a_path.find("/db/tblList") == 0) && ctrChkNode(opt)) {
+    else if((a_path.starts_with("/db/list") || a_path.starts_with("/db/tblList")) && ctrChkNode(opt)) {
 	string tblList = "";
-	if(a_path.find("/db/tblList") == 0 && !(tblList=TSYS::strParse(a_path,1,":")).size())
+	if(a_path.starts_with("/db/tblList") && !(tblList=TSYS::strParse(a_path,1,":")).size())
 	    tblList = _("[TableName]");
 	vector<string> c_list;
 	TBDS::dbList(c_list);
@@ -1363,6 +1363,11 @@
 	for(unsigned iDB = 0; iDB < c_list.size(); iDB++)
 	    if(tblList.size()) opt->childAdd("el")->setText(c_list[iDB]+"."+tblList);
 	    else opt->childAdd("el")->setAttr("id",c_list[iDB])->setText(TMess::labStorFromCode(c_list[iDB]));
+
+	if(TSYS::strParse(a_path,1,":").find("nostor") != string::npos) {
+	    if(tblList.size()) opt->childAdd("el")->setText("");
+	    else opt->childAdd("el")->setAttr("id","")->setText("");
+	}
     }
     else if(a_path == "/plang/list" && ctrChkNode(opt)) {
 	opt->childAdd("el")->setText("");
Index: src/tsecurity.cpp
===================================================================
--- src/tsecurity.cpp	(revision 3039)
+++ src/tsecurity.cpp	(working copy)
@@ -46,6 +46,7 @@
     userEl.fldAdd(new TFld("PASS",trS("Password"),TFld::String,0,"100"));
     userEl.fldAdd(new TFld("LANG",trS("Language"),TFld::String,0,"50"));
     userEl.fldAdd(new TFld("PICTURE",trS("User picture"),TFld::String,0,"100000"));
+    userEl.fldAdd(new TFld("REM_AUTH",trS("Allow remote authentication"),TFld::Boolean,0,"1","1"));
 
     //Group BD structure
     grpEl.fldAdd(new TFld("NAME",trS("Name"),TFld::String,TCfg::Key|TFld::NoWrite,i2s(limObjID_SZ).c_str()));
@@ -450,8 +451,15 @@
     //Save used groups
     vector<string> ls;
     owner().grpList(ls);
-    for(unsigned iG = 0; iG < ls.size(); iG++)
+    for(unsigned iG = 0; iG < ls.size(); iG++) {
+	if(!owner().grpAt(ls[iG]).at().isModify()) continue;
+
+	// Setting group's DB in the user's one at its emptiness
+	if(owner().grpAt(ls[iG]).at().DB().empty())
+	    owner().grpAt(ls[iG]).at().setDB(DB());
+
 	owner().grpAt(ls[iG]).at().save();
+    }
 }
 
 TVariant TUser::objFuncCall( const string &iid, vector<TVariant> &prms, const string &user_lang )
Index: src/tsecurity.h
===================================================================
--- src/tsecurity.h	(revision 3039)
+++ src/tsecurity.h	(working copy)
@@ -49,6 +49,7 @@
 	string	longDescr( )	{ return cfg("LONGDESCR").getS(); }
 	string	picture( )	{ return cfg("PICTURE").getS(); }
 	string	lang( )		{ return mLang; }
+	bool	alowRemAuth( )	{ return cfg("REM_AUTH").getB(); }
 	bool	sysItem( )	{ return mSysIt; }
 
 	bool	auth( const string &pass, string *hash = NULL );
@@ -62,6 +63,7 @@
 	void setLongDescr( const string &vl )	{ cfg("LONGDESCR").setS(vl); }
 	void setPicture( const string &pct )	{ cfg("PICTURE").setS(pct); }
 	void setLang( const string &vl )	{ mLang = vl; }
+	void setAlowRemAuth( bool vl )		{ cfg("REM_AUTH").setB(vl); }
 	void setPass( const string &n_pass );
 	void setSysItem( bool vl )		{ mSysIt = vl; }
 
Index: src/tvariant.cpp
===================================================================
--- src/tvariant.cpp	(revision 3039)
+++ src/tvariant.cpp	(working copy)
@@ -25,11 +25,17 @@
 #include <string.h>
 #include <stdlib.h>
 #include <algorithm>
-#include <pcre.h>
 
 #include <tsys.h>
 #include "tvariant.h"
 
+#if HAVE_PCRE_2
+# define PCRE2_CODE_UNIT_WIDTH 0
+# include <pcre2.h>
+#else
+# include <pcre.h>
+#endif
+
 using namespace OSCADA;
 
 //*************************************************
@@ -793,9 +799,16 @@
 //* TRegExp                                                 *
 //*   Regular expression object                             *
 //***********************************************************
+#define TRegExp_vSz 90
+
 TRegExp::TRegExp( const string &rule, const string &flg, char mode ) :
     lastIndex(0), pattern(rule), global(false), ignoreCase(false), multiline(false), ungreedy(false), isSimplePat(false), UTF8(false),
-    regex(NULL), vSz(90), capv(NULL), md(MD_8)
+    regex(NULL), md(MD_8),
+#if HAVE_PCRE_2
+    mDt(NULL)
+#else
+    capv(NULL)
+#endif
 {
     setPattern(rule, flg, mode);
 
@@ -804,14 +817,26 @@
 
 TRegExp::~TRegExp( )
 {
+#if HAVE_PCRE_2
+    if(mDt)	pcre2_match_data_free_8((pcre2_match_data_8*)mDt);
+    if(regex) {
+	if(md == MD_8)		pcre2_code_free_8((pcre2_code_8*)regex);
+# if HAVE_PCRE32
+	else if(md == MD_32)	pcre2_code_free_32((pcre2_code_32*)regex);
+# endif
+# if HAVE_PCRE16
+	else if(md == MD_16)	pcre2_code_free_16((pcre2_code_16*)regex);
+# endif
+#else
     if(capv)	delete [] capv;
     if(regex) {
 	if(md == MD_8)		pcre_free((pcre*)regex);
-#if HAVE_PCRE32
+# if HAVE_PCRE32
 	else if(md == MD_32)	pcre32_free((pcre32*)regex);
-#endif
-#if HAVE_PCRE16
+# endif
+# if HAVE_PCRE16
 	else if(md == MD_16)	pcre16_free((pcre16*)regex);
+# endif
 #endif
     }
 
@@ -835,14 +860,26 @@
     }
 
     //Check for free
+#if HAVE_PCRE_2
+    if(isSimplePat && mDt)	{ pcre2_match_data_free_8((pcre2_match_data_8*)mDt); mDt = NULL; }
+    if(regex) {
+	if(md == MD_8)		pcre2_code_free_8((pcre2_code_8*)regex);
+# if HAVE_PCRE32
+	else if(md == MD_32)	pcre2_code_free_32((pcre2_code_32*)regex);
+# endif
+# if HAVE_PCRE16
+	else if(md == MD_16)	pcre2_code_free_16((pcre2_code_16*)regex);
+# endif
+#else
     if(isSimplePat && capv)	{ delete [] capv; capv = NULL; }
     if(regex) {
 	if(md == MD_8)		pcre_free((pcre*)regex);
-#if HAVE_PCRE32
+# if HAVE_PCRE32
 	else if(md == MD_32)	pcre32_free((pcre32*)regex);
-#endif
-#if HAVE_PCRE16
+# endif
+# if HAVE_PCRE16
 	else if(md == MD_16)	pcre16_free((pcre16*)regex);
+# endif
 #endif
 	regex = NULL;
     }
@@ -860,21 +897,54 @@
 
     //Alloc for regexp
     if(!isSimplePat && pattern.size()) {
+#if HAVE_PCRE_2
+	PCRE2_SIZE erroff;
+	int cderr;
+	int options = PCRE2_DOTALL|(ignoreCase?PCRE2_CASELESS:0)|(multiline?PCRE2_MULTILINE:0)|(ungreedy?PCRE2_UNGREEDY:0);
+
+	if(md == MD_8) {
+	    regex = pcre2_compile_8((PCRE2_SPTR8)pattern.c_str(), PCRE2_ZERO_TERMINATED,
+					options|(UTF8?PCRE2_UTF|PCRE2_NO_UTF_CHECK:0), &cderr, &erroff, NULL);
+	    if(regex && !mDt) mDt = pcre2_match_data_create_from_pattern_8((pcre2_code_8*)regex, NULL);
+	}
+# if HAVE_PCRE32
+	else if(md == MD_32) {
+	    regex = pcre2_compile_32((PCRE2_SPTR32)(pattern+string(4,0)).data(), PCRE2_ZERO_TERMINATED,
+					options|(UTF8?PCRE2_UTF|PCRE2_NO_UTF_CHECK:0), &cderr, &erroff, NULL);
+	    if(regex && !mDt) mDt = pcre2_match_data_create_from_pattern_32((pcre2_code_32*)regex, NULL);
+	}
+# endif
+# if HAVE_PCRE16
+	else if(md == MD_16) {
+	    regex = pcre2_compile_16((PCRE2_SPTR16)(pattern+string(2,0)).data(), PCRE2_ZERO_TERMINATED,
+					options|(UTF8?PCRE2_UTF|PCRE2_NO_UTF_CHECK:0), &cderr, &erroff, NULL);
+	    if(regex && !mDt) mDt = pcre2_match_data_create_from_pattern_16((pcre2_code_16*)regex, NULL);
+	}
+
+	if(!regex) {
+	    char tbuf[255];
+	    pcre2_get_error_message_8(cderr, (PCRE2_UCHAR8*)tbuf, sizeof(tbuf));
+	    err = tbuf;
+	}
+# endif
+#else
+	int erroff;
 	const char *terr;
-	int erroff;
-
 	int options = PCRE_DOTALL|(ignoreCase?PCRE_CASELESS:0)|(multiline?PCRE_MULTILINE:0)|(ungreedy?PCRE_UNGREEDY:0);
 
-	if(md == MD_8) regex = pcre_compile(pattern.c_str(), options|(UTF8?PCRE_UTF8|PCRE_NO_UTF8_CHECK:0), &terr, &erroff, NULL);
-#if HAVE_PCRE32
-	else if(md == MD_32) regex = pcre32_compile((PCRE_SPTR32)(pattern+string(4,0)).data(), options|(UTF8?PCRE_UTF32|PCRE_NO_UTF32_CHECK:0), &terr, &erroff, NULL);
+	if(md == MD_8) regex = pcre_compile(pattern.c_str(),
+					options|(UTF8?PCRE_UTF8|PCRE_NO_UTF8_CHECK:0), &terr, &erroff, NULL);
+# if HAVE_PCRE32
+	else if(md == MD_32) regex = pcre32_compile((PCRE_SPTR32)(pattern+string(4,0)).data(),
+					options|(UTF8?PCRE_UTF32|PCRE_NO_UTF32_CHECK:0), &terr, &erroff, NULL);
+# endif
+# if HAVE_PCRE16
+	else if(md == MD_16) regex = pcre16_compile((PCRE_SPTR16)(pattern+string(2,0)).data(),
+					options|(UTF8?PCRE_UTF16|PCRE_NO_UTF16_CHECK:0), &terr, &erroff, NULL);
+# endif
+	if(!regex) err = terr;
+	else if(!capv) capv = new int[TRegExp_vSz];
 #endif
-#if HAVE_PCRE16
-	else if(md == MD_16) regex = pcre16_compile((PCRE_SPTR16)(pattern+string(2,0)).data(), options|(UTF8?PCRE_UTF16|PCRE_NO_UTF16_CHECK:0), &terr, &erroff, NULL);
-#endif
-
-	if(!regex) err = terr;
-	else if(!capv) capv = new int[90];
     }
 }
 
@@ -883,15 +953,29 @@
     TArrayObj *rez = new TArrayObj();
     if(!regex || md != MD_8) return rez;	//?!?! Not implemented still for 16/32 modes
 
+#if HAVE_PCRE_2
+    PCRE2_SIZE *capv = pcre2_get_ovector_pointer_8((pcre2_match_data_8*)mDt);
+#endif
+
     if(all && global)
-	for(int curPos = 0, iN = 0; pcre_exec((pcre*)regex,NULL,vl.data(),vl.size(),curPos,0,capv,vSz) > 0 && capv[1] > capv[0]; curPos = capv[1], iN++)
+	for(int curPos = 0, iN = 0;
+#if HAVE_PCRE_2
+		pcre2_match_8((pcre2_code_8*)regex,(PCRE2_SPTR8)vl.data(),vl.size(),curPos,0,(pcre2_match_data_8*)mDt,NULL) > 0
+#else
+		pcre_exec((pcre*)regex,NULL,vl.data(),vl.size(),curPos,0,capv,TRegExp_vSz) > 0
+#endif
+		    && capv[1] > capv[0]; curPos = capv[1], iN++)
 	    rez->arSet(iN, string(vl.data()+capv[0],capv[1]-capv[0]));
     else {
-	int n = pcre_exec((pcre*)regex, NULL, vl.data(), vl.size(), (global?lastIndex:0), 0, capv, vSz);
+#if HAVE_PCRE_2
+	int n = pcre2_match_8((pcre2_code_8*)regex,(PCRE2_SPTR8)vl.data(),vl.size(),(global?lastIndex:0),0,(pcre2_match_data_8*)mDt,NULL);
+#else
+	int n = pcre_exec((pcre*)regex, NULL, vl.data(), vl.size(), (global?lastIndex:0), 0, capv, TRegExp_vSz);
+#endif
 	for(int iN = 0; iN < n; iN++)
 	    rez->arSet(iN, string(vl.data()+capv[iN*2],capv[iN*2+1]-capv[iN*2]));
 	if(global) lastIndex = (n>0) ? capv[1] : 0;
-	if(n > 0) { rez->propSet("index", capv[0]); rez->propSet("input", vl); }
+	if(n > 0) { rez->propSet("index", (int)capv[0]); rez->propSet("input", vl); }
 	else if(n < 0) { rez->propSet("err", i2s(n)); }
     }
 
@@ -902,7 +986,18 @@
 {
     string rez = vl, repl;
     if(!regex || md != MD_8) return rez;	//?!?! Not implemented still for 16/32 modes
-    for(int curPos = 0, n; (!curPos || global) && (n=pcre_exec((pcre*)regex,NULL,rez.data(),rez.size(),curPos,0,capv,vSz)) > 0 && capv[1] >= capv[0];
+
+#if HAVE_PCRE_2
+    PCRE2_SIZE *capv = pcre2_get_ovector_pointer_8((pcre2_match_data_8*)mDt);
+#endif
+
+    for(int curPos = 0, n; (!curPos || global) &&
+#if HAVE_PCRE_2
+	    (n=pcre2_match_8((pcre2_code_8*)regex,(PCRE2_SPTR8)rez.data(),rez.size(),curPos,0,(pcre2_match_data_8*)mDt,NULL)) > 0
+#else
+	    (n=pcre_exec((pcre*)regex,NULL,rez.data(),rez.size(),curPos,0,capv,TRegExp_vSz)) > 0
+#endif
+		&& capv[1] >= capv[0];
 	curPos = capv[0]+repl.size())
     {
 	repl = substExprRepl(str, rez, capv, n);
@@ -915,8 +1010,19 @@
 {
     TArrayObj *rez = new TArrayObj();
     if(!regex || md != MD_8) return rez;	//?!?! Not implemented still for 16/32 modes
+
+#if HAVE_PCRE_2
+    PCRE2_SIZE *capv = pcre2_get_ovector_pointer_8((pcre2_match_data_8*)mDt);
+#endif
+
     int curPos = 0, iN = 0;
-    for(int se = 0; (se=pcre_exec((pcre*)regex,NULL,vl.data(),vl.size(),curPos,0,capv,vSz)) > 0 && capv[1] > capv[0] && (!limit || iN < limit);
+    for(int se = 0;
+#if HAVE_PCRE_2
+	    (se=pcre2_match_8((pcre2_code_8*)regex,(PCRE2_SPTR8)vl.data(),vl.size(),curPos,0,(pcre2_match_data_8*)mDt,NULL)) > 0
+#else
+	    (se=pcre_exec((pcre*)regex,NULL,vl.data(),vl.size(),curPos,0,capv,TRegExp_vSz)) > 0
+#endif
+		    && capv[1] > capv[0] && (!limit || iN < limit);
 		curPos = capv[1])
     {
 	rez->arSet(iN++, string(vl.data()+curPos,capv[0]-curPos));
@@ -958,7 +1064,16 @@
     }
     //Check by regular expression
     if(!regex || md != MD_8) return false;	//?!?! Not implemented still for 16/32 modes
-    int n = pcre_exec((pcre*)regex, NULL, vl.data(), vl.size(), (global?lastIndex:0), 0, capv, vSz);
+
+#if HAVE_PCRE_2
+    PCRE2_SIZE *capv = pcre2_get_ovector_pointer_8((pcre2_match_data_8*)mDt);
+#endif
+
+#if HAVE_PCRE_2
+    int n = pcre2_match_8((pcre2_code_8*)regex, (PCRE2_SPTR8)vl.data(), vl.size(), (global?lastIndex:0), 0, (pcre2_match_data_8*)mDt, NULL);
+#else
+    int n = pcre_exec((pcre*)regex, NULL, vl.data(), vl.size(), (global?lastIndex:0), 0, capv, TRegExp_vSz);
+#endif
     if(global) lastIndex = (n>0) ? capv[1] : 0;
     return (n>0);
 }
@@ -967,21 +1082,41 @@
 {
     if(!regex) return -1;
 
+#if HAVE_PCRE_2
+    PCRE2_SIZE *capv = pcre2_get_ovector_pointer_8((pcre2_match_data_8*)mDt);
+#endif
+
     int n = 0;
-    if(md == MD_8) n = pcre_exec((pcre*)regex, NULL, vl.data(), vl.size(), off, PCRE_NO_UTF8_CHECK, capv, vSz);
-#if HAVE_PCRE32
-    else if(md == MD_32) n = pcre32_exec((pcre32*)regex, NULL, (PCRE_SPTR32)vl.data(), vl.size()/4, off, PCRE_NO_UTF32_CHECK, capv, vSz);
+#if HAVE_PCRE_2
+    if(md == MD_8) n = pcre2_match_8((pcre2_code_8*)regex, (PCRE2_SPTR8)vl.data(), vl.size(), off, PCRE2_NO_UTF_CHECK, (pcre2_match_data_8*)mDt, NULL);
+# if HAVE_PCRE32
+    else if(md == MD_32) n = pcre2_match_32((pcre2_code_32*)regex, (PCRE2_SPTR32)vl.data(), vl.size()/4, off, PCRE2_NO_UTF_CHECK, (pcre2_match_data_32*)mDt, NULL);
+# endif
+# if HAVE_PCRE16
+    else if(md == MD_16) n = pcre2_match_16((pcre2_code_16*)regex, (PCRE2_SPTR16)vl.data(), vl.size()/2, off, PCRE2_NO_UTF_CHECK, (pcre2_match_data_16*)mDt, NULL);
+# endif
+#else
+    if(md == MD_8) n = pcre_exec((pcre*)regex, NULL, vl.data(), vl.size(), off, PCRE_NO_UTF8_CHECK, capv, TRegExp_vSz);
+# if HAVE_PCRE32
+    else if(md == MD_32) n = pcre32_exec((pcre32*)regex, NULL, (PCRE_SPTR32)vl.data(), vl.size()/4, off, PCRE_NO_UTF32_CHECK, capv, TRegExp_vSz);
+# endif
+# if HAVE_PCRE16
+    else if(md == MD_16) n = pcre16_exec((pcre16*)regex, NULL, (PCRE_SPTR16)vl.data(), vl.size()/2, off, PCRE_NO_UTF16_CHECK, capv, TRegExp_vSz);
+# endif
 #endif
-#if HAVE_PCRE16
-    else if(md == MD_16) n = pcre16_exec((pcre16*)regex, NULL, (PCRE_SPTR16)vl.data(), vl.size()/2, off, PCRE_NO_UTF16_CHECK, capv, vSz);
-#endif
 
     if(length) *length = (n > 0) ? capv[1]-capv[0] : 0;
     return (n > 0) ? capv[0] : -1;
 }
 
-string TRegExp::substExprRepl( const string &str, const string &val, int *icapv, int n )
+string TRegExp::substExprRepl( const string &str, const string &val, void *icapv_, int n )
 {
+#if HAVE_PCRE_2
+    PCRE2_SIZE *icapv = (PCRE2_SIZE *)icapv_;
+#else
+    int *icapv = (int *)icapv_;
+#endif
+
     string rez = str;
     for(size_t cpos = 0; n > 0 && (cpos=rez.find("$",cpos)) != string::npos && cpos < (rez.size()-1); )
 	switch(rez[cpos+1]) {
Index: src/tvariant.h
===================================================================
--- src/tvariant.h	(revision 3039)
+++ src/tvariant.h	(working copy)
@@ -267,7 +267,7 @@
 
     private:
 	//Methods
-	string substExprRepl( const string &str, const string &val, int *capv, int n );
+	string substExprRepl( const string &str, const string &val, void *capv, int n );
 
 	//Attributes
 	string	pattern;
@@ -279,8 +279,12 @@
 	unsigned UTF8		: 1;
 
 	void	*regex;
-	int	vSz, *capv;
 	char	md;
+#if HAVE_PCRE_2
+	void	*mDt;
+#else
+	int	*capv;
+#endif
 };
 
 //*************************************************
