Index: p/common/hmessage.cpp
===================================================================
--- /cpp/common/hmessage.cpp	(revision 374)
+++ 	(revision )
@@ -1,61 +1,0 @@
-// This file is a part of Framsticks SDK.  http://www.framsticks.com/
-// Copyright (C) 1999-2015  Maciej Komosinski and Szymon Ulatowski.
-// See LICENSE.txt for details.
-
-#include "hmessage.h"
-#include <common/nonstd_stdio.h>
-#include "stl-util.h"
-#include "Convert.h"
-
-const char* HMSG_LEVEL[]={"[DEBUG] ","","[WARN] ","[ERROR] ","[CRITICAL] "};
-
-void Hmessage(const char *o, const char *m, const char *txt, int w)
-{
-	int line = 0; //all lines except the first one get the "..." prefix
-	const char* nextsep;
-	do
-	{
-		nextsep = strchr(txt, '\n');
-		if (nextsep == NULL) //last chunk, until the end
-			nextsep = strchr(txt, '\0');
-		if ((nextsep > txt) && (nextsep[-1] == '\r'))
-			nextsep--;
-		if (line == 0)
-		{
-			if (*nextsep == 0) //there was only one line! no need to modify it in any way.
-				_HmessageSingleLine(o, m, txt, w);
-			else //first line from multi-line
-				_HmessageSingleLine(o, m, string(txt, nextsep - txt).c_str(), w);
-		}
-		else //consecutive lines from multi-line
-			_HmessageSingleLine(o, m, (HMSG_MULTILINE_CONTINUATION + string(txt, nextsep - txt)).c_str(), w); //could also add line numbers like ...(3)... but let's keep the prefix short and simple
-		line++;
-		if ((nextsep[0] == '\r') && (nextsep[1] == '\n'))
-			txt = nextsep + 2;
-		else if (*nextsep)
-			txt = nextsep + 1;
-	} while (*nextsep);
-}
-
-
-void Hprintf_va(const char *o,const char *m,int w,const char *bl,va_list va)
-{
-	string buf=ssprintf_va(bl,va);
-	Hmessage(o,m,buf.c_str(),w);
-}
-
-void Hprintf(const char *o,const char *m,int w,const char *bl, ...)
-{
-	va_list argptr;
-	va_start(argptr,bl);
-	Hprintf_va(o,m,w,bl,argptr);
-	va_end(argptr);
-}
-
-void printH(const char *bl,...)
-{
-	va_list argptr;
-	va_start(argptr,bl);
-	Hprintf_va("Message","printf",HMLV_INFO,bl,argptr);
-	va_end(argptr);
-}
Index: p/common/hmessage.h
===================================================================
--- /cpp/common/hmessage.h	(revision 374)
+++ 	(revision )
@@ -1,36 +1,0 @@
-// This file is a part of Framsticks SDK.  http://www.framsticks.com/
-// Copyright (C) 1999-2015  Maciej Komosinski and Szymon Ulatowski.
-// See LICENSE.txt for details.
-
-#ifndef _HMESSAGE_H_
-#define _HMESSAGE_H_
-
-#include <stdarg.h>
-
-extern const char* HMSG_LEVEL[];
-#define HMSG_FORMAT "%s%s.%s: %s"
-#define HMSG_MULTILINE_CONTINUATION "..."
-
-void Hprintf(const char *o,const char *m,int w,const char *bl, ...);
-void Hprintf_va(const char *o,const char *m,int w,const char *bl,va_list va); //a different name than Hprintf - otherwise the compiler could confuse the "string" parameter with va_list and could call the wrong function
-void printH(const char *bl,...); //a shorthand for printf (a different name again to avoid the risk of confusion with the two functions above. This would be unlikely but possible when the argument types would match)
-void Hmessage(const char *o,const char *m,const char *txt,int w);
-
-void _HmessageSingleLine(const char *o,const char *m,const char *txt,int w); //don't call this directly - it is used internally
-
-#define HMLV_DEBUG -1
-#define HMLV_INFO 0
-#define HMLV_WARN 1
-#define HMLV_ERROR 2
-#define HMLV_CRITICAL 3
-
-/*
-w: weight (importance) of a message
--1:debugging information, not needed for final users
-0: information
-1: warning or corrected error
-2: uncorrected error. can cause malfunction
-3: serious error, causes side effects. user should save what can be saved and restart the application
-*/
-
-#endif
Index: /cpp/common/log.cpp
===================================================================
--- /cpp/common/log.cpp	(revision 375)
+++ /cpp/common/log.cpp	(revision 375)
@@ -0,0 +1,61 @@
+// This file is a part of Framsticks SDK.  http://www.framsticks.com/
+// Copyright (C) 1999-2015  Maciej Komosinski and Szymon Ulatowski.
+// See LICENSE.txt for details.
+
+#include "log.h"
+#include <common/nonstd_stdio.h>
+#include "stl-util.h"
+#include "Convert.h"
+
+const char* LOG_LEVEL[] = { "[DEBUG] ", "", "[WARN] ", "[ERROR] ", "[CRITICAL] " };
+
+void logMessage(const char *obj, const char *method, int level, const char *msg)
+{
+	int line = 0; //all lines except the first one get the "..." prefix
+	const char* nextsep;
+	do
+	{
+		nextsep = strchr(msg, '\n');
+		if (nextsep == NULL) //last chunk, until the end
+			nextsep = strchr(msg, '\0');
+		if ((nextsep > msg) && (nextsep[-1] == '\r'))
+			nextsep--;
+		if (line == 0)
+		{
+			if (*nextsep == 0) //there was only one line! no need to modify it in any way.
+				_logMessageSingleLine(obj, method, level, msg);
+			else //first line from multi-line
+				_logMessageSingleLine(obj, method, level, string(msg, nextsep - msg).c_str());
+		}
+		else //consecutive lines from multi-line
+			_logMessageSingleLine(obj, method, level, (LOG_MULTILINE_CONTINUATION + string(msg, nextsep - msg)).c_str()); //could also add line numbers like ...(3)... but let's keep the prefix short and simple
+		line++;
+		if ((nextsep[0] == '\r') && (nextsep[1] == '\n'))
+			msg = nextsep + 2;
+		else if (*nextsep)
+			msg = nextsep + 1;
+	} while (*nextsep);
+}
+
+
+void logPrintf_va(const char *obj, const char *method, int level, const char *msgf, va_list va)
+{
+	string buf = ssprintf_va(msgf, va);
+	logMessage(obj, method, level, buf.c_str());
+}
+
+void logPrintf(const char *obj, const char *method, int level, const char *msgf, ...)
+{
+	va_list argptr;
+	va_start(argptr, msgf);
+	logPrintf_va(obj, method, level, msgf, argptr);
+	va_end(argptr);
+}
+
+void log_printf(const char *msgf, ...)
+{
+	va_list argptr;
+	va_start(argptr, msgf);
+	logPrintf_va("Message", "printf", LOG_INFO, msgf, argptr);
+	va_end(argptr);
+}
Index: /cpp/common/log.h
===================================================================
--- /cpp/common/log.h	(revision 375)
+++ /cpp/common/log.h	(revision 375)
@@ -0,0 +1,31 @@
+// This file is a part of Framsticks SDK.  http://www.framsticks.com/
+// Copyright (C) 1999-2015  Maciej Komosinski and Szymon Ulatowski.
+// See LICENSE.txt for details.
+
+#ifndef _COMMON_LOG_H_
+#define _COMMON_LOG_H_
+
+#include <stdarg.h>
+
+extern const char* LOG_LEVEL[];
+#define LOG_FORMAT "%s%s.%s: %s"
+#define LOG_MULTILINE_CONTINUATION "..."
+
+
+void logPrintf(const char *obj, const char *method, int level, const char *msgf, ...);
+void logPrintf_va(const char *obj, const char *method, int level, const char *msgf, va_list va); //a different name than logPrintf - otherwise the compiler could confuse the "string" parameter with va_list and could call the wrong function
+void log_printf(const char *msgf, ...); //a shorthand for printf (a different name again to avoid the risk of confusion with the two functions above. This would be unlikely but possible when the argument types would match)
+void logMessage(const char *obj, const char *method, int level, const char *msg);
+
+void _logMessageSingleLine(const char *obj, const char *method, int level, const char *msg); //don't call this directly - it is used internally
+
+
+
+//level (importance) of a message
+#define LOG_DEBUG -1 //debugging information, not needed for final users
+#define LOG_INFO 0 //information
+#define LOG_WARN 1 //warning or corrected error
+#define LOG_ERROR 2 //uncorrected error, can cause malfunction
+#define LOG_CRITICAL 3 //serious error, causes side effects. User should save what can be saved and restart the application
+
+#endif
Index: /cpp/common/nonstd_math.cpp
===================================================================
--- /cpp/common/nonstd_math.cpp	(revision 374)
+++ /cpp/common/nonstd_math.cpp	(revision 375)
@@ -81,5 +81,5 @@
 // But it was resolved by restarting windows and cleaning all intermediate compilation files :o (restarting windows was the key element! restarting BC++Builder and deleting files would not help)
 
-#include "hmessage.h"
+#include "log.h"
 
 unsigned int fp_control_word_std;
@@ -89,5 +89,5 @@
 {
 	//unsigned int was=_clear87();
-	//Hprintf("","fpExceptInit",HMLV_INFO,"control87 status before clear was %08x", was);
+	//logPrintf("","fpExceptInit",LOG_INFO,"control87 status before clear was %08x", was);
 	fp_control_word_std=_control87(0, 0);             //4978 = 1001101110010
 	// Make the new fp env same as the old one, except for the changes we're going to make
@@ -98,7 +98,7 @@
 {
 	unsigned int was=_clear87(); //trzeba czyscic zeby nie bylo exception...
-	//Hprintf("","fpExceptEnable ",HMLV_INFO,"control87 status before clear was %08x", was);
+	//logPrintf("","fpExceptEnable ",LOG_INFO,"control87 status before clear was %08x", was);
 	_control87(fp_control_word_std, 0xffffffff);
-	//Hprintf("","fpExceptEnable ",HMLV_INFO,"control87 flags are %08x", _control87(0, 0)); //kontrola co sie ustawilo
+	//logPrintf("","fpExceptEnable ",LOG_INFO,"control87 flags are %08x", _control87(0, 0)); //kontrola co sie ustawilo
 }
 
@@ -106,7 +106,7 @@
 {
 	unsigned int was=_clear87(); //trzeba czyscic zeby nie bylo exception...
-	//Hprintf("","fpExceptDisable",HMLV_INFO,"control87 status before clear was %08x", was);
+	//logPrintf("","fpExceptDisable",LOG_INFO,"control87 status before clear was %08x", was);
 	_control87(fp_control_word_muted, 0xffffffff);
-	//Hprintf("","fpExceptDisable",HMLV_INFO,"control87 flags are %08x", _control87(0, 0)); //kontrola co sie ustawilo
+	//logPrintf("","fpExceptDisable",LOG_INFO,"control87 flags are %08x", _control87(0, 0)); //kontrola co sie ustawilo
 }
 
Index: /cpp/common/nonstd_stdio.cpp
===================================================================
--- /cpp/common/nonstd_stdio.cpp	(revision 374)
+++ /cpp/common/nonstd_stdio.cpp	(revision 375)
@@ -242,5 +242,5 @@
 
 #ifdef __ANDROID__
-#include "hmessage.h"
+#include "log.h"
 #include "nonstd.h"
 #include "nonstd_stl.h"
@@ -248,6 +248,6 @@
 {
 	string respath=getAppResourcesDir();
-	//printH("Opening '%s', mode='%s'",path,mode);
-	//printH("getAppResourcesDir()='%s'",respath.c_str());
+	//log_printf("Opening '%s', mode='%s'",path,mode);
+	//log_printf("getAppResourcesDir()='%s'",respath.c_str());
 	NvFile *rfile=NULL; //can only read
 	FILE *rwfile=NULL;
@@ -256,12 +256,12 @@
 		path+=respath.length(); //strip the prefix, we need a relative path in assets
 		if (strstr(mode,"w"))
-			printH("Warning: attempt to open a read-only resource '%s' in writable mode '%s'",path,mode);
+			log_printf("Warning: attempt to open a read-only resource '%s' in writable mode '%s'",path,mode);
 		rfile=NvFOpen(path); //"mode" not supported! can only read
-		//printH("Opened RES file as %p",rfile);
+		//log_printf("Opened RES file as %p",rfile);
 		if (rfile==NULL) return NULL;
 	} else //a "normal" access (HOME)
 	{
 		rwfile=fopen(path,mode);
-		//printH("Opened HOME file as %p",rwfile);
+		//log_printf("Opened HOME file as %p",rwfile);
 		if (rwfile==NULL) return NULL;
 	}
Index: /cpp/common/stl-util.cpp
===================================================================
--- /cpp/common/stl-util.cpp	(revision 374)
+++ /cpp/common/stl-util.cpp	(revision 375)
@@ -9,5 +9,5 @@
 #include "Convert.h"
 #include "nonstd.h"
-#include "hmessage.h"
+#include "log.h"
 #include <assert.h>
 #ifdef USE_VIRTFILE
@@ -103,5 +103,5 @@
 	}
 	if (warn_on_missing_file && !ok)
-		Hprintf("stl-util", "readCompleteFile", HMLV_WARN, "Couldn't open file '%s'", filename);
+		logPrintf("stl-util", "readCompleteFile", LOG_WARN, "Couldn't open file '%s'", filename);
 	return ok;
 }
@@ -129,5 +129,5 @@
 	}
 	if (warn_on_fail && !ok)
-		Hprintf("stl-util", "writeCompleteFile", HMLV_WARN, "couldn't write file '%s'", filename);
+		logPrintf("stl-util", "writeCompleteFile", LOG_WARN, "couldn't write file '%s'", filename);
 	return ok;
 }
Index: /cpp/frams/Makefile-SDK-files
===================================================================
--- /cpp/frams/Makefile-SDK-files	(revision 374)
+++ /cpp/frams/Makefile-SDK-files	(revision 375)
@@ -2,5 +2,5 @@
 
 # ALL_DIRS is later expanded by the shell, no spaces/newlines allowed, or it breaks
-ALL_DIRS={common,frams,frams/canvas,frams/config,frams/mhandlers,frams/genetics,frams/genetics/f0,frams/genetics/f1,frams/genetics/f2,frams/genetics/f3,frams/genetics/f4,frams/genetics/f5,frams/genetics/f6,frams/genetics/f7,frams/genetics/f8,frams/genetics/f9,frams/genetics/fF,frams/genetics/fT,frams/model,frams/neuro,frams/neuro/impl,frams/param,frams/test,frams/util,frams/vm/classes,frams/virtfile,frams/_demos,frams/model/geometry,frams/_demos/geometry,frams/model/similarity,frams/model/similarity/SVD}
+ALL_DIRS={common,frams,frams/canvas,frams/config,frams/loggers,frams/genetics,frams/genetics/f0,frams/genetics/f1,frams/genetics/f2,frams/genetics/f3,frams/genetics/f4,frams/genetics/f5,frams/genetics/f6,frams/genetics/f7,frams/genetics/f8,frams/genetics/f9,frams/genetics/fF,frams/genetics/fT,frams/model,frams/neuro,frams/neuro/impl,frams/param,frams/test,frams/util,frams/vm/classes,frams/virtfile,frams/_demos,frams/model/geometry,frams/_demos/geometry,frams/model/similarity,frams/model/similarity/SVD}
 
 GENMANF4=frams/genetics/f4/oper_f4.o
@@ -19,5 +19,5 @@
 GENMAN_COMMON_OBJS=frams/genetics/genman.o frams/param/mutableparam.o frams/param/mutparamlist.o frams/neuro/geneticneuroparam.o frams/neuro/neurolibparam.o
 
-SDK_OBJS=frams/util/list.o frams/util/advlist.o frams/param/param.o frams/util/sstring.o frams/util/sstringutils.o frams/util/3d.o frams/vm/classes/3dobject.o frams/model/model.o frams/model/modelparts.o frams/neuro/neurolibrary.o frams/genetics/geno.o frams/genetics/genoconv.o frams/util/extvalue.o frams/vm/classes/collectionobj.o frams/util/hashtable.o common/hmessage.o common/stl-util.o common/nonstd_stdio.o frams/util/callbacks.o frams/param/syntparam.o frams/util/multirange.o frams/util/multimap.o frams/param/paramtabobj.o frams/mhandlers/mhandlers.o frams/param/paramobj.o frams/genetics/oper_fx.o common/nonstd_math.o frams/mhandlers/stderrors.o common/Convert.o frams/util/rndutil.o
+SDK_OBJS=frams/util/list.o frams/util/advlist.o frams/param/param.o frams/util/sstring.o frams/util/sstringutils.o frams/util/3d.o frams/vm/classes/3dobject.o frams/model/model.o frams/model/modelparts.o frams/neuro/neurolibrary.o frams/genetics/geno.o frams/genetics/genoconv.o frams/util/extvalue.o frams/vm/classes/collectionobj.o frams/util/hashtable.o common/log.o common/stl-util.o common/nonstd_stdio.o frams/util/callbacks.o frams/param/syntparam.o frams/util/multirange.o frams/util/multimap.o frams/param/paramtabobj.o frams/loggers/loggers.o frams/param/paramobj.o frams/genetics/oper_fx.o common/nonstd_math.o frams/util/validitychecks.o common/Convert.o frams/util/rndutil.o
 
 GEOMETRY_OBJS=frams/model/geometry/meshbuilder.o frams/model/geometry/modelgeometryinfo.o frams/model/geometry/geometryutils.o
@@ -25,29 +25,29 @@
 #### sdk_tests
 
-GENOMANIPULATION_OBJS= frams/_demos/genomanipulation.o frams/mhandlers/stdouthandler.o frams/virtfile/virtfile.o  $(SDK_OBJS) $(GENOCONV_SDK_OBJS) $(GENMAN_SDK_OBJS)
+GENOMANIPULATION_OBJS= frams/_demos/genomanipulation.o frams/loggers/loggertostdout.o frams/virtfile/virtfile.o  $(SDK_OBJS) $(GENOCONV_SDK_OBJS) $(GENMAN_SDK_OBJS)
 
-MULTILINE_F0_OBJS=frams/_demos/multiline_f0_test.o frams/virtfile/stringfile.o frams/virtfile/virtfile.o frams/mhandlers/stdouthandler.o $(SDK_OBJS) $(GENOCONV_SDK_OBJS) $(GENMAN_SDK_OBJS)
+MULTILINE_F0_OBJS=frams/_demos/multiline_f0_test.o frams/virtfile/stringfile.o frams/virtfile/virtfile.o frams/loggers/loggertostdout.o $(SDK_OBJS) $(GENOCONV_SDK_OBJS) $(GENMAN_SDK_OBJS)
 
-F0_VARIANTS_OBJS=frams/_demos/f0_variants_test.o frams/virtfile/stringfile.o frams/virtfile/virtfile.o frams/mhandlers/stdouthandler.o   $(SDK_OBJS) $(GENOCONV_SDK_OBJS)
+F0_VARIANTS_OBJS=frams/_demos/f0_variants_test.o frams/virtfile/stringfile.o frams/virtfile/virtfile.o frams/loggers/loggertostdout.o   $(SDK_OBJS) $(GENOCONV_SDK_OBJS)
 
 LOADER_TEST_OBJS=frams/_demos/genotypeloader.o frams/_demos/loader_test.o frams/virtfile/virtfile.o frams/param/multiparamload.o frams/virtfile/stdiofile.o $(SDK_OBJS) $(GENOCONV_SDK_OBJS)
 
-LOADER_TEST_PARAM_OBJS=frams/_demos/loader_test_param.o frams/virtfile/virtfile.o frams/param/multiparamload.o frams/virtfile/stdiofile.o frams/mhandlers/stdouthandler.o $(SDK_OBJS)
+LOADER_TEST_PARAM_OBJS=frams/_demos/loader_test_param.o frams/virtfile/virtfile.o frams/param/multiparamload.o frams/virtfile/stdiofile.o frams/loggers/loggertostdout.o $(SDK_OBJS)
 
-GENOCONV_TEST_OBJS= frams/_demos/genoconv_test.o frams/_demos/printconvmap.o frams/mhandlers/stdouthandler.o frams/virtfile/virtfile.o  $(SDK_OBJS) $(GENOCONV_SDK_OBJS)
+GENOCONV_TEST_OBJS= frams/_demos/genoconv_test.o frams/_demos/printconvmap.o frams/loggers/loggertostdout.o frams/virtfile/virtfile.o  $(SDK_OBJS) $(GENOCONV_SDK_OBJS)
 
-GENO_TEST_OBJS= frams/_demos/geno_test.o frams/virtfile/virtfile.o frams/mhandlers/stdouthandler.o $(SDK_OBJS) $(GENOCONV_SDK_OBJS) $(GENMAN_SDK_OBJS)
+GENO_TEST_OBJS= frams/_demos/geno_test.o frams/virtfile/virtfile.o frams/loggers/loggertostdout.o $(SDK_OBJS) $(GENOCONV_SDK_OBJS) $(GENMAN_SDK_OBJS)
 
-GENOOPER_TEST_OBJS=frams/_demos/genooper_test.o frams/virtfile/virtfile.o frams/mhandlers/stdouthandler.o $(SDK_OBJS) $(GENOCONV_SDK_OBJS) $(GENMAN_SDK_OBJS)
+GENOOPER_TEST_OBJS=frams/_demos/genooper_test.o frams/virtfile/virtfile.o frams/loggers/loggertostdout.o $(SDK_OBJS) $(GENOCONV_SDK_OBJS) $(GENMAN_SDK_OBJS)
 
 GENOOPER_TEST_FTEST_OBJS=frams/_demos/genooper_test_fTest.o frams/virtfile/virtfile.o $(SDK_OBJS) $(GENOCONV_SDK_OBJS) $(GENMAN_SDK_OBJS) $(GENMAN_FT)
 
-NEURO_TEST_OBJS= frams/_demos/neuro_test.o frams/mhandlers/stdouthandler.o frams/virtfile/virtfile.o \
+NEURO_TEST_OBJS= frams/_demos/neuro_test.o frams/loggers/loggertostdout.o frams/virtfile/virtfile.o \
 	frams/neuro/neuroimpl.o frams/neuro/neurofactory.o frams/neuro/impl/neuroimpl-simple.o frams/neuro/impl/neuroimpl-channels.o \
 	frams/neuro/impl/neuroimpl-fuzzy.o frams/neuro/impl/neuroimpl-fuzzy-f0.o  $(SDK_OBJS) $(GENOCONV_SDK_OBJS) $(GENMAN_SDK_OBJS)
 
-FULL_PROPS_OBJS= frams/_demos/full_props.o frams/mhandlers/stdouthandler.o frams/virtfile/virtfile.o  frams/virtfile/stdiofile.o $(SDK_OBJS) $(GENOCONV_SDK_OBJS) $(GENMAN_SDK_OBJS)
+FULL_PROPS_OBJS= frams/_demos/full_props.o frams/loggers/loggertostdout.o frams/virtfile/virtfile.o  frams/virtfile/stdiofile.o $(SDK_OBJS) $(GENOCONV_SDK_OBJS) $(GENMAN_SDK_OBJS)
 
-SHAPECONVERT_OBJS= frams/_demos/shapeconvert.o frams/mhandlers/stdouthandler.o frams/virtfile/virtfile.o  frams/virtfile/stdiofile.o $(SDK_OBJS) $(GENOCONV_SDK_OBJS) $(GENMAN_SDK_OBJS)
+SHAPECONVERT_OBJS= frams/_demos/shapeconvert.o frams/loggers/loggertostdout.o frams/virtfile/virtfile.o  frams/virtfile/stdiofile.o $(SDK_OBJS) $(GENOCONV_SDK_OBJS) $(GENMAN_SDK_OBJS)
 
 SERIAL_TEST_OBJS= frams/_demos/serial_test.o frams/virtfile/virtfile.o  $(SDK_OBJS) $(GENOCONV_SDK_OBJS)
@@ -55,5 +55,5 @@
 PART_SHAPES_OBJS= frams/_demos/part_shapes.o frams/virtfile/virtfile.o  $(SDK_OBJS) $(GENOCONV_SDK_OBJS)
 
-NEURO_LAYOUT_TEST_OBJS= frams/_demos/neuro_layout_test.o frams/virtfile/virtfile.o frams/mhandlers/stdouthandler.o $(SDK_OBJS) $(GENOCONV_SDK_OBJS) $(GENMAN_SDK_OBJS) frams/canvas/nn_layout_model.o frams/canvas/nn_simple_layout.o frams/canvas/nn_smart_layout.o
+NEURO_LAYOUT_TEST_OBJS= frams/_demos/neuro_layout_test.o frams/virtfile/virtfile.o frams/loggers/loggertostdout.o $(SDK_OBJS) $(GENOCONV_SDK_OBJS) $(GENMAN_SDK_OBJS) frams/canvas/nn_layout_model.o frams/canvas/nn_simple_layout.o frams/canvas/nn_smart_layout.o
 
 GEOMETRY_INFO_TEST_OBJS=frams/_demos/geometry/info_test.o frams/_demos/geometry/geometrytestutils.o frams/_demos/genotypeloader.o frams/virtfile/virtfile.o frams/param/multiparamload.o frams/virtfile/stdiofile.o $(SDK_OBJS) $(GENOCONV_SDK_OBJS) $(GEOMETRY_OBJS)
@@ -66,5 +66,5 @@
 
 SIMIL_TEST_OBJS=frams/_demos/simil_test.o frams/model/similarity/SVD/lapack.o frams/model/similarity/SVD/matrix_tools.o frams/model/similarity/simil_match.o frams/model/similarity/simil_model.o  \
-     frams/_demos/genotypeloader.o frams/virtfile/virtfile.o frams/param/multiparamload.o frams/virtfile/stdiofile.o frams/mhandlers/stdouthandler.o $(SDK_OBJS) $(GENOCONV_SDK_OBJS) $(GENMAN_SDK_OBJS)
+     frams/_demos/genotypeloader.o frams/virtfile/virtfile.o frams/param/multiparamload.o frams/virtfile/stdiofile.o frams/loggers/loggertostdout.o $(SDK_OBJS) $(GENOCONV_SDK_OBJS) $(GENMAN_SDK_OBJS)
 
 SIMIL_UNITTESTS_OBJS=frams/_demos/simil_unittests.o frams/model/similarity/simil_match.o
Index: /cpp/frams/_demos/f0_variants_test.cpp
===================================================================
--- /cpp/frams/_demos/f0_variants_test.cpp	(revision 374)
+++ /cpp/frams/_demos/f0_variants_test.cpp	(revision 375)
@@ -10,5 +10,5 @@
 #include <frams/genetics/defgenoconv.h>
 #include <frams/model/model.h>
-#include <frams/mhandlers/stdouthandler.h>
+#include <frams/loggers/loggertostdout.h>
 
 void save_as_f0(SString &gen,Model &m,bool omit_default_values)
@@ -74,5 +74,5 @@
 int main(int argc,char*argv[])
 {
-MessageHandlerToStdout messages_to_stdout(MessageHandlerBase::Enable);
+LoggerToStdout messages_to_stdout(LoggerBase::Enable);
 
 //without converters the application would only handle "format 0" genotypes
Index: /cpp/frams/_demos/full_props.cpp
===================================================================
--- /cpp/frams/_demos/full_props.cpp	(revision 374)
+++ /cpp/frams/_demos/full_props.cpp	(revision 375)
@@ -9,5 +9,5 @@
 
 #include <frams/model/model.h>
-#include <frams/mhandlers/stdouthandler.h>
+#include <frams/loggers/loggertostdout.h>
 #include <frams/genetics/preconfigured.h>
 
@@ -50,5 +50,5 @@
 {
 StdioFILE::setStdio();//setup VirtFILE::Vstdin/out/err
-MessageHandlerToStdout messages_to_stderr(MessageHandlerBase::Enable | MessageHandlerBase::DontBlock,VirtFILE::Vstderr); //errors -> stderr, don't interfere with stdout
+LoggerToStdout messages_to_stderr(LoggerBase::Enable | LoggerBase::DontBlock,VirtFILE::Vstderr); //errors -> stderr, don't interfere with stdout
 
 PreconfiguredGenetics genetics;
@@ -79,5 +79,5 @@
 if (!m.isValid())
 	{
-	Hprintf("","full_props",HMLV_ERROR,"Cannot build Model from the supplied genotype\n");
+	logPrintf("","full_props",LOG_ERROR,"Cannot build Model from the supplied genotype\n");
 	return 2;	
 	}
Index: /cpp/frams/_demos/geno_test.cpp
===================================================================
--- /cpp/frams/_demos/geno_test.cpp	(revision 374)
+++ /cpp/frams/_demos/geno_test.cpp	(revision 375)
@@ -6,5 +6,5 @@
 #include <frams/util/sstringutils.h>
 #include <frams/genetics/preconfigured.h>
-#include <frams/mhandlers/stdouthandler.h>
+#include <frams/loggers/loggertostdout.h>
 
 /**
@@ -18,5 +18,5 @@
 {
 	PreconfiguredGenetics genetics;
-	MessageHandlerToStdout messages_to_stdout(MessageHandlerBase::Enable); //comment this object out to mute error/warning messages
+	LoggerToStdout messages_to_stdout(LoggerBase::Enable); //comment this object out to mute error/warning messages
 
 	if (argc <= 1)
Index: /cpp/frams/_demos/genoconv_test.cpp
===================================================================
--- /cpp/frams/_demos/genoconv_test.cpp	(revision 374)
+++ /cpp/frams/_demos/genoconv_test.cpp	(revision 375)
@@ -9,5 +9,5 @@
 
 #include "printconvmap.h"
-#include <frams/mhandlers/stdouthandler.h>
+#include <frams/loggers/loggertostdout.h>
 
 /**
@@ -117,5 +117,5 @@
 int main(int argc,char *argv[])
 {
-MessageHandlerToStdout messages_to_stdout(MessageHandlerBase::Enable);
+LoggerToStdout messages_to_stdout(LoggerBase::Enable);
 
 DefaultGenoConvManager gcm;
Index: /cpp/frams/_demos/genomanipulation.cpp
===================================================================
--- /cpp/frams/_demos/genomanipulation.cpp	(revision 374)
+++ /cpp/frams/_demos/genomanipulation.cpp	(revision 375)
@@ -10,5 +10,5 @@
 #include <frams/model/model.h>
 #include <frams/genetics/preconfigured.h>
-#include <frams/mhandlers/stdouthandler.h>
+#include <frams/loggers/loggertostdout.h>
 
 /**
@@ -266,5 +266,5 @@
 int main(int argc,char*argv[])
 {
-MessageHandlerToStdout messages_to_stdout(MessageHandlerBase::Enable); //redirect model-related errors to stdout
+LoggerToStdout messages_to_stdout(LoggerBase::Enable); //redirect model-related errors to stdout
 
 srand(time(0));
Index: /cpp/frams/_demos/genooper_test.cpp
===================================================================
--- /cpp/frams/_demos/genooper_test.cpp	(revision 374)
+++ /cpp/frams/_demos/genooper_test.cpp	(revision 375)
@@ -3,5 +3,5 @@
 // See LICENSE.txt for details.
 
-#include <frams/mhandlers/stdouthandler.h>
+#include <frams/loggers/loggertostdout.h>
 #include <frams/genetics/preconfigured.h>
 
@@ -21,5 +21,5 @@
 int main(int argc, char *argv[])
 {
-	MessageHandlerToStdout messages_to_stdout(MessageHandlerBase::Enable);
+	LoggerToStdout messages_to_stdout(LoggerBase::Enable);
 	PreconfiguredGenetics genetics;
 
Index: /cpp/frams/_demos/loader_test_param.cpp
===================================================================
--- /cpp/frams/_demos/loader_test_param.cpp	(revision 374)
+++ /cpp/frams/_demos/loader_test_param.cpp	(revision 375)
@@ -5,5 +5,5 @@
 #include <frams/param/multiparamload.h>
 #include <frams/virtfile/stdiofile.h>
-#include <frams/mhandlers/stdouthandler.h>
+#include <frams/loggers/loggertostdout.h>
 
 /**
@@ -66,5 +66,5 @@
 	StdioFILEDontClose virt_stderr(stderr);
 	StdioFILEDontClose virt_stdout(stdout);
-	MessageHandlerToStdout messages_to_stderr(MessageHandlerBase::Enable, &virt_stderr);
+	LoggerToStdout messages_to_stderr(LoggerBase::Enable, &virt_stderr);
 	StdioFileSystem_autoselect stdiofilesys;
 	MultiParamLoader loader(argv[1]);
Index: /cpp/frams/_demos/multiline_f0_test.cpp
===================================================================
--- /cpp/frams/_demos/multiline_f0_test.cpp	(revision 374)
+++ /cpp/frams/_demos/multiline_f0_test.cpp	(revision 375)
@@ -10,10 +10,10 @@
 #include <frams/genetics/preconfigured.h>
 #include <frams/model/model.h>
-#include <frams/mhandlers/stdouthandler.h>
+#include <frams/loggers/loggertostdout.h>
 #include <frams/virtfile/stringfile.h>
 
 int main(int argc,char*argv[])
 {
-MessageHandlerToStdout messages_to_stdout(MessageHandlerBase::Enable);
+LoggerToStdout messages_to_stdout(LoggerBase::Enable);
 PreconfiguredGenetics genetics;
 
Index: /cpp/frams/_demos/neuro_layout_test.cpp
===================================================================
--- /cpp/frams/_demos/neuro_layout_test.cpp	(revision 374)
+++ /cpp/frams/_demos/neuro_layout_test.cpp	(revision 375)
@@ -7,5 +7,5 @@
 #include <frams/genetics/preconfigured.h>
 #include <frams/model/model.h>
-#include <frams/mhandlers/stdouthandler.h>
+#include <frams/loggers/loggertostdout.h>
 #include <frams/canvas/nn_layout_model.h>
 
@@ -83,5 +83,5 @@
 int main(int argc,char*argv[])
 {
-MessageHandlerToStdout messages_to_stdout(MessageHandlerBase::Enable);
+LoggerToStdout messages_to_stdout(LoggerBase::Enable);
 PreconfiguredGenetics genetics;
 
Index: /cpp/frams/_demos/neuro_test.cpp
===================================================================
--- /cpp/frams/_demos/neuro_test.cpp	(revision 374)
+++ /cpp/frams/_demos/neuro_test.cpp	(revision 375)
@@ -9,5 +9,5 @@
 #include <frams/neuro/neuroimpl.h>
 #include <frams/neuro/neurofactory.h>
-#include <frams/mhandlers/stdouthandler.h>
+#include <frams/loggers/loggertostdout.h>
 
 /**
@@ -60,5 +60,5 @@
 int main(int argc,char*argv[])
 {
-MessageHandlerToStdout messages_to_stdout(MessageHandlerBase::Enable);
+LoggerToStdout messages_to_stdout(LoggerBase::Enable);
 PreconfiguredGenetics genetics;
 
Index: /cpp/frams/_demos/shapeconvert.cpp
===================================================================
--- /cpp/frams/_demos/shapeconvert.cpp	(revision 374)
+++ /cpp/frams/_demos/shapeconvert.cpp	(revision 375)
@@ -9,5 +9,5 @@
 
 #include <frams/model/model.h>
-#include <frams/mhandlers/stdouthandler.h>
+#include <frams/loggers/loggertostdout.h>
 #include <frams/genetics/preconfigured.h>
 
@@ -34,5 +34,5 @@
 {
 	StdioFILE::setStdio();//setup VirtFILE::Vstdin/out/err
-	MessageHandlerToStdout messages_to_stderr(MessageHandlerBase::Enable | MessageHandlerBase::DontBlock, VirtFILE::Vstderr); //errors -> stderr, don't interfere with stdout
+	LoggerToStdout messages_to_stderr(LoggerBase::Enable | LoggerBase::DontBlock, VirtFILE::Vstderr); //errors -> stderr, don't interfere with stdout
 
 	PreconfiguredGenetics genetics;
@@ -50,5 +50,5 @@
 				if ((shape != Part::SHAPE_ELLIPSOID) && (shape != Part::SHAPE_CUBOID) && (shape != Part::SHAPE_CYLINDER))
 				{
-					Hprintf("", "shapeconvert", HMLV_ERROR, "Invalid shape");
+					logPrintf("", "shapeconvert", LOG_ERROR, "Invalid shape");
 					return 4;
 				}
@@ -71,5 +71,5 @@
 	if (!m.isValid())
 	{
-		Hprintf("", "shapeconvert", HMLV_ERROR, "Cannot build Model from the supplied genotype");
+		logPrintf("", "shapeconvert", LOG_ERROR, "Cannot build Model from the supplied genotype");
 		return 2;
 	}
@@ -77,5 +77,5 @@
 	if (m.getShape() != Model::SHAPE_OLD)
 	{
-		Hprintf("", "shapeconvert", HMLV_ERROR, "Only old style shapes can be converted");
+		logPrintf("", "shapeconvert", LOG_ERROR, "Only old style shapes can be converted");
 		return 3;
 	}
Index: /cpp/frams/_demos/simil_test.cpp
===================================================================
--- /cpp/frams/_demos/simil_test.cpp	(revision 374)
+++ /cpp/frams/_demos/simil_test.cpp	(revision 375)
@@ -5,5 +5,5 @@
 
 #include <vector>
-#include "frams/mhandlers/stdouthandler.h"
+#include "frams/loggers/loggertostdout.h"
 #include "frams/_demos/genotypeloader.h"
 #include "frams/genetics/preconfigured.h"
@@ -39,5 +39,5 @@
 int main(int argc, char *argv[])
 {
-    MessageHandlerToStdout messages_to_stdout(MessageHandlerBase::Enable);
+    LoggerToStdout messages_to_stdout(LoggerBase::Enable);
     typedef double *pDouble;
     int iCurrParam = 0; // index of the currently processed parameter
Index: /cpp/frams/genetics/f1/conv_f1.cpp
===================================================================
--- /cpp/frams/genetics/f1/conv_f1.cpp	(revision 374)
+++ /cpp/frams/genetics/f1/conv_f1.cpp	(revision 375)
@@ -5,5 +5,5 @@
 #include "conv_f1.h"
 #include <common/nonstd_stl.h>
-#include <common/hmessage.h>
+#include <common/log.h>
 #include <frams/util/multirange.h>
 #include <frams/util/multimap.h>
@@ -63,5 +63,5 @@
 		if ((n1<0) || (n2<0) || (n1>=neuro_f1_to_f0.size()) || (n2>=neuro_f1_to_f0.size()))
 			{
-			if (final) Hprintf("GenoConvF1","addInput",HMLV_WARN,
+			if (final) logPrintf("GenoConvF1","addInput",LOG_WARN,
 					    "illegal neuron connection %d <- %d (ignored)",n1,n2);
 			return 0;
@@ -178,5 +178,5 @@
 		else
 			{
-			Hmessage("GenoConv_F1","grow","Illegal neuron position (ignored)",1);
+			logMessage("GenoConv_F1","grow",1,"Illegal neuron position (ignored)");
 			g=skipNeuro(g+1);
 			}
Index: /cpp/frams/genetics/f4/conv_f4.cpp
===================================================================
--- /cpp/frams/genetics/f4/conv_f4.cpp	(revision 374)
+++ /cpp/frams/genetics/f4/conv_f4.cpp	(revision 375)
@@ -6,5 +6,5 @@
 
 #include "conv_f4.h"
-#include <common/hmessage.h>
+#include <common/log.h>
 #include "../oper_fx.h" //for GENOPER_OK constant
 
@@ -110,5 +110,5 @@
 		if (res)
 		{
-			Hmessage("f4_Model", "buildModelRec", "Error in building Model", 2);
+			logMessage("f4_Model", "buildModelRec", 2, "Error in building Model");
 			error = res;
 			break;
@@ -134,5 +134,5 @@
 			return cells->C[i];
 	// none!
-	Hmessage("f4_Model", "getStick", "Not a single stick", 2);
+	logMessage("f4_Model", "getStick", 2, "Not a single stick");
 	return NULL;
 }
Index: /cpp/frams/genetics/f4/f4_general.cpp
===================================================================
--- /cpp/frams/genetics/f4/f4_general.cpp	(revision 374)
+++ /cpp/frams/genetics/f4/f4_general.cpp	(revision 375)
@@ -7,5 +7,5 @@
 #include "f4_general.h"
 #include <common/nonstd_stl.h>
-#include <common/hmessage.h>
+#include <common/log.h>
 #include <frams/model/model.h> // for min and max attributes
 #include "../oper_fx.h" //for GENOPER_ constants
@@ -581,5 +581,5 @@
 			char buf[40];
 			sprintf(buf, "unknown code '%c'", gcur->name);
-			Hmessage("f4_Cell", "onestep", buf, 2);
+			logMessage("f4_Cell", "onestep", 2, buf);
 			// fix: delete it
 			org->setRepairRemove(gcur->pos, gcur);
Index: /cpp/frams/genetics/f4/oper_f4.cpp
===================================================================
--- /cpp/frams/genetics/f4/oper_f4.cpp	(revision 374)
+++ /cpp/frams/genetics/f4/oper_f4.cpp	(revision 375)
@@ -8,5 +8,5 @@
 #include "oper_f4.h"
 #include <frams/util/sstring.h>
-#include <common/hmessage.h>
+#include <common/log.h>
 
 #include <stdio.h>
@@ -51,5 +51,5 @@
 	mutation_method_names[index++] = "deleted a node";
 	mutation_method_names[index++] = "modified a node";
-	if (index != F4_COUNT + F4_ADD_COUNT - 1) Hmessage("Geno_f4", "Constructor", "Mutation names init error", 3);
+	if (index != F4_COUNT + F4_ADD_COUNT - 1) logMessage("Geno_f4", "Constructor", 3, "Mutation names init error");
 }
 
Index: /cpp/frams/genetics/genman.cpp
===================================================================
--- /cpp/frams/genetics/genman.cpp	(revision 374)
+++ /cpp/frams/genetics/genman.cpp	(revision 375)
@@ -6,8 +6,8 @@
 #include <frams/vm/classes/genoobj.h>
 #include GEN_CONFIG_FILE //configuration of active genetic operators
-#include "common/hmessage.h"
+#include "common/log.h"
 #include "common/nonstd_math.h"
 #include "common/stl-util.h"
-#include <frams/mhandlers/mhandlers.h>
+#include <frams/loggers/loggers.h>
 
 
@@ -267,5 +267,5 @@
 		if (gf->mutate(gn, chg, method) == GENOPER_OK)
 		{
-			MessageHandlerToMemory eh(MessageHandlerBase::Enable | MessageHandlerToMemory::StoreFirstMessage); //mute testValidity()
+			LoggerToMemory eh(LoggerBase::Enable | LoggerToMemory::StoreFirstMessage); //mute testValidity()
 			Geno G(gn, gv.getFormat(), "", "");
 			canvalidate = true;
@@ -284,5 +284,5 @@
 		if (!ok && (count - pcount > 100))
 		{
-			Hprintf("GenMan", "Mutate", 2, "Tried 100x and failed: %s", g.getGene().c_str());
+			logPrintf("GenMan", "Mutate", 2, "Tried 100x and failed: %s", g.getGene().c_str());
 			return Geno("", -1, "", "GENOPER_OPFAIL: Mutate() tried 100x and failed");
 		}
@@ -308,5 +308,5 @@
 
 	{
-		MessageHandlerToMemory eh(MessageHandlerBase::Enable | MessageHandlerToMemory::StoreFirstMessage); //mute testValidity()
+		LoggerToMemory eh(LoggerBase::Enable | LoggerToMemory::StoreFirstMessage); //mute testValidity()
 		bool canvalidate = true;
 		if (testValidity(g1v, canvalidate) > 0 && canvalidate == false)
@@ -333,5 +333,5 @@
 			if (g1n[0]) { gn = g1n; chg = chg1; }
 			else { gn = g2n; chg = chg2; }
-			MessageHandlerToMemory eh(MessageHandlerBase::Enable | MessageHandlerToMemory::StoreFirstMessage); //mute testValidity()
+			LoggerToMemory eh(LoggerBase::Enable | LoggerToMemory::StoreFirstMessage); //mute testValidity()
 			Geno G(gn, g1v.getFormat(), "", "");
 			bool canvalidate = true;
@@ -351,5 +351,5 @@
 		if (!ok && (count - pcount > 100))
 		{
-			Hprintf("GenMan", "CrossOver", 2, "Tried 100x and failed: %s and %s", g1.getGene().c_str(), g2.getGene().c_str());
+			logPrintf("GenMan", "CrossOver", 2, "Tried 100x and failed: %s and %s", g1.getGene().c_str(), g2.getGene().c_str());
 			return Geno("", -1, "", "GENOPER_OPFAIL: CrossOver() tried 100x and failed");
 		}
@@ -500,5 +500,5 @@
 	l.chg = chg;
 	l.fit = 0; //temporarily. Will be set when the genotype dies
-	//Hprintf("GenMan","saveLink",0,"#%d: [%d] '%s' + '%s' -> '%s'",GenoLinkList.size(),count,parent1.c_str(),parent2.c_str(),child.c_str());
+	//logPrintf("GenMan","saveLink",0,"#%d: [%d] '%s' + '%s' -> '%s'",GenoLinkList.size(),count,parent1.c_str(),parent2.c_str(),child.c_str());
 	GenoLinkList.push_back(l);
 }
@@ -533,5 +533,5 @@
 	float f1, f2;
 	int m;
-	Hmessage("GenMan", "Report", "The following genetic operators are available:", 0);
+	logMessage("GenMan", "Report", 0, "The following genetic operators are available:");
 	for (unsigned int i = 0; i < oper_fx_list.size(); i++)
 	{
@@ -549,5 +549,5 @@
 		}
 		//      if (oper_fx_list[i]->similarity("","")!=GENOPER_NOOPER) l+=" similarity";
-		Hprintf("GenMan", "Report", 0, "format f%c (%s):%s",
+		logPrintf("GenMan", "Report", 0, "format f%c (%s):%s",
 			oper_fx_list[i]->supported_format, oper_fx_list[i]->name.c_str(), l.c_str());
 	}
Index: /cpp/frams/genetics/geno.cpp
===================================================================
--- /cpp/frams/genetics/geno.cpp	(revision 374)
+++ /cpp/frams/genetics/geno.cpp	(revision 375)
@@ -250,5 +250,5 @@
 		}
 	isvalid = 0;
-	Hprintf("Geno", "validate", HMLV_WARN, "Wrong configuration? No genotype validators defined for genetic format f%c.", format);
+	logPrintf("Geno", "validate", LOG_WARN, "Wrong configuration? No genotype validators defined for genetic format f%c.", format);
 }
 
Index: /cpp/frams/genetics/oper_fx.cpp
===================================================================
--- /cpp/frams/genetics/oper_fx.cpp	(revision 374)
+++ /cpp/frams/genetics/oper_fx.cpp	(revision 375)
@@ -5,5 +5,5 @@
 #include <ctype.h>  //isupper()
 #include "oper_fx.h"
-#include <common/hmessage.h>
+#include <common/log.h>
 #include <common/nonstd_math.h>
 #include <frams/util/rndutil.h>
@@ -173,5 +173,5 @@
 		}
 		else
-			Hprintf("GenoOperators", "linearMix", HMLV_WARN, "Cannot mix values of types '%c' and '%c'", type1, type2);
+			logPrintf("GenoOperators", "linearMix", LOG_WARN, "Cannot mix values of types '%c' and '%c'", type1, type2);
 }
 
@@ -250,5 +250,5 @@
 {
 	if (s == NULL)
-		Hmessage("GenoOperators", "skipWS", "NULL reference!", HMLV_WARN);
+		logMessage("GenoOperators", "skipWS", LOG_WARN, "NULL reference!");
 	else
 	while (isWS(*s)) s++;
Index: /cpp/frams/loggers/loggers.cpp
===================================================================
--- /cpp/frams/loggers/loggers.cpp	(revision 375)
+++ /cpp/frams/loggers/loggers.cpp	(revision 375)
@@ -0,0 +1,124 @@
+// This file is a part of Framsticks SDK.  http://www.framsticks.com/
+// Copyright (C) 1999-2015  Maciej Komosinski and Szymon Ulatowski.
+// See LICENSE.txt for details.
+
+#include "loggers.h"
+#include <common/stl-util.h>
+
+void _logMessageSingleLine(const char *o, const char *m, int w, const char *txt)
+{
+	tlsGetRef(message_handler_manager_instance).send(o, m, w, txt);
+}
+
+THREAD_LOCAL_DEF(LoggerManager, message_handler_manager_instance);
+
+void LoggerManager::send(int level, const char *o, const char *m, int w, const char *bl)
+{
+	if (level >= handlers.size()) level = handlers.size() - 1;
+	bool blocked = 0;
+	for (int i = level; i >= 0; i--)
+	{
+		LoggerBase *r = handlers(i);
+		if ((!(r->options & LoggerBase::Paused)) &&
+			((!blocked) || (r->options & LoggerBase::CannotBeBlocked)))
+		{
+			r->handle(o, m, w, bl);
+			if (!(r->options & LoggerBase::DontBlock)) blocked = 1;
+		}
+	}
+}
+
+int LoggerManager::add(LoggerBase *h)
+{
+	h->manager = this;
+	handlers += h;
+	return handlers.size() - 1;
+}
+
+void LoggerManager::remove(int i)
+{
+	LoggerBase *h = handlers(i);
+	h->manager = NULL;
+	handlers.remove(i);
+}
+
+void LoggerManager::remove(LoggerBase *h)
+{
+	int i;
+	if ((i = handlers.find(h)) < 0) return;
+	remove(i);
+}
+
+void LoggerManager::removeAll()
+{
+	while (handlers.size() > 0)
+		remove(handlers.size() - 1);
+}
+
+//////////////////////////////////
+
+void LoggerBase::send(const char *o, const char *m, int w, const char *bl)
+{
+	if (!isEnabled()) return;
+	int level = manager->find(this);
+	if (level >= 0) manager->send(level - 1, o, m, w, bl);
+}
+
+void LoggerBase::logPrintf(const char *o, const char *m, int w, const char *bl, ...)
+{
+	if (!isEnabled()) return;
+	string buf;
+	va_list argptr;
+	va_start(argptr, bl);
+	buf = ssprintf_va(bl, argptr);
+	va_end(argptr);
+	send(o, m, w, buf.c_str());
+}
+
+
+void LoggerBase::enable()
+{
+	if (isEnabled()) return;
+	tlsGetRef(message_handler_manager_instance).add(this);
+}
+
+void LoggerBase::disable()
+{
+	if (!isEnabled()) return;
+	tlsGetRef(message_handler_manager_instance).remove(this);
+}
+
+void LoggerBase::pause()
+{
+	if (isPaused()) return;
+	options |= Paused;
+}
+
+void LoggerBase::resume()
+{
+	if (!isPaused()) return;
+	options &= ~Paused;
+}
+
+/////////////////////////////////
+
+void LoggerToMemory::handle(const char *o, const char *m, int w, const char *bl)
+{
+	if (w > maxlevel) maxlevel = w;
+	if (w >= LOG_INFO) infocount++;
+	if (w >= LOG_WARN) warncount++;
+	if (w >= LOG_ERROR) errcount++;
+
+	if (w >= minleveltostore)
+	{
+		storedcount++;
+		if (options & (StoreFirstMessage | StoreAllMessages))
+		{
+			if (!((options&StoreFirstMessage) && (msgs.len() > 0)))
+			{
+				if (msgs.len() > 0) msgs += '\n';
+				msgs += SString::sprintf(LOG_FORMAT,LOG_LEVEL[w+1],o,m,bl);
+			}
+		}
+	}
+}
Index: /cpp/frams/loggers/loggers.h
===================================================================
--- /cpp/frams/loggers/loggers.h	(revision 375)
+++ /cpp/frams/loggers/loggers.h	(revision 375)
@@ -0,0 +1,118 @@
+// This file is a part of Framsticks SDK.  http://www.framsticks.com/
+// Copyright (C) 1999-2015  Maciej Komosinski and Szymon Ulatowski.
+// See LICENSE.txt for details.
+
+#ifndef _FRAMS_LOGGERS_H_
+#define _FRAMS_LOGGERS_H_
+
+#include <frams/util/list.h>
+#include <frams/util/sstring.h>
+#include <common/log.h>
+#include <common/threads.h>
+
+class LoggerBase;
+
+class LoggerManager
+{
+	friend class LoggerBase;
+	SListTempl<LoggerBase*> handlers;
+	void send(int level, const char *o, const char *m, int w, const char *bl);
+public:
+	int find(LoggerBase *r) { return handlers.find(r); }
+	int add(LoggerBase *r);
+	void remove(int i);
+	void remove(LoggerBase *r);
+	void removeAll();
+	void send(const char *o, const char *m, int w, const char *bl)
+	{
+		send(handlers.size() - 1, o, m, w, bl);
+	}
+	~LoggerManager() { removeAll(); }
+};
+
+extern THREAD_LOCAL_DECL(LoggerManager, message_handler_manager_instance);
+
+////////////////////////////////////////
+
+class LoggerBase
+{
+	friend class LoggerManager;
+protected:
+	LoggerManager* manager;
+	int options;
+
+public:
+
+	enum LoggerOptions
+	{
+		DontBlock = 1, CannotBeBlocked = 2, Enable = 4, Paused = 8
+	};
+
+	void logPrintf(const char *o, const char *m, int w, const char *bl, ...);
+	void send(const char *o, const char *m, int w, const char *bl);
+
+	bool isEnabled() { return manager ? true : false; }
+	void enable();
+	void disable();
+	bool isPaused() { return (options & Paused) != 0; }
+	void pause();
+	void resume();
+
+	LoggerBase(int opts = 0) :manager(NULL), options(opts)
+	{
+		if (options&Enable) enable();
+	}
+	virtual ~LoggerBase()
+	{
+		disable();
+	}
+
+	virtual void handle(const char *o, const char *m, int w, const char *bl) {}
+};
+
+///////////////////////////////////////////
+
+class LoggerToMemory : public LoggerBase
+{
+protected:
+	int maxlevel, minleveltostore, errcount, warncount, storedcount, infocount;
+	SString msgs;
+
+public:
+
+	void reset() { maxlevel = LOG_INFO - 1; errcount = warncount = storedcount = infocount = 0; msgs = 0; }
+
+	enum Options2
+	{
+		StoreFirstMessage = 16, StoreAllMessages = 32
+	};
+
+	int getErrorCount()       { return errcount; }
+	int getWarningCount()     { return warncount; }
+	int getInfoCount()        { return infocount; }
+	int getStoredCount()      { return storedcount; }
+	int getErrorLevel()       { return maxlevel; }
+	const SString& getMessages() { return msgs; }
+
+	LoggerToMemory(int opts = 0, int minimal_level_to_store = LOG_ERROR) :LoggerBase(opts), minleveltostore(minimal_level_to_store)
+	{
+		reset();
+	}
+
+	void handle(const char *o, const char *m, int w, const char *bl);
+};
+
+class RedirectingLogger : public LoggerBase
+{
+	LoggerManager *other_manager;
+public:
+	RedirectingLogger(LoggerManager *other_mgr,int opts=0)
+		:LoggerBase(opts), other_manager(other_mgr) {}
+
+	void handle(const char *o, const char *m, int w, const char *bl)
+	{
+		other_manager->send(o, m, w, bl);
+	}
+};
+
+#endif
Index: /cpp/frams/loggers/loggertostdout.cpp
===================================================================
--- /cpp/frams/loggers/loggertostdout.cpp	(revision 375)
+++ /cpp/frams/loggers/loggertostdout.cpp	(revision 375)
@@ -0,0 +1,23 @@
+// This file is a part of Framsticks SDK.  http://www.framsticks.com/
+// Copyright (C) 1999-2015  Maciej Komosinski and Szymon Ulatowski.
+// See LICENSE.txt for details.
+
+#include "loggertostdout.h"
+#ifdef SHP
+#include <FBaseSys.h> //AppLog
+#else
+#include <stdio.h>
+#endif
+
+void LoggerToStdout::handle(const char *o, const char *m, int w, const char *bl)
+{
+	if (w < -1) w = -1; else if (w>3) w = 3;
+#ifdef SHP
+	AppLog(LOG_FORMAT "\n",LOG_LEVEL[w+1],o,m,bl);
+#else
+	if (file)
+		file->printf(LOG_FORMAT "\n", LOG_LEVEL[w + 1], o, m, bl);
+	else
+		printf(LOG_FORMAT "\n", LOG_LEVEL[w + 1], o, m, bl);
+#endif
+}
Index: /cpp/frams/loggers/loggertostdout.h
===================================================================
--- /cpp/frams/loggers/loggertostdout.h	(revision 375)
+++ /cpp/frams/loggers/loggertostdout.h	(revision 375)
@@ -0,0 +1,19 @@
+// This file is a part of Framsticks SDK.  http://www.framsticks.com/
+// Copyright (C) 1999-2015  Maciej Komosinski and Szymon Ulatowski.
+// See LICENSE.txt for details.
+
+#ifndef _STDOUT_LOGGER_H_
+#define _STDOUT_LOGGER_H_
+
+#include "loggers.h"
+#include <frams/virtfile/virtfile.h>
+
+class LoggerToStdout : public LoggerBase
+{
+	VirtFILE *file;
+public:
+	LoggerToStdout(int opts = 0, VirtFILE *_file = NULL) :LoggerBase(opts), file(_file) {}
+	void handle(const char *o, const char *m, int w, const char *bl);
+};
+
+#endif
Index: /cpp/frams/model/geometry/geometryutils.cpp
===================================================================
--- /cpp/frams/model/geometry/geometryutils.cpp	(revision 374)
+++ /cpp/frams/model/geometry/geometryutils.cpp	(revision 375)
@@ -82,5 +82,5 @@
 			break;
 	}
-	Hprintf("GeometryUtils", "isPointInsidePart", HMLV_ERROR, "Part shape=%d not supported", part->shape);
+	logPrintf("GeometryUtils", "isPointInsidePart", LOG_ERROR, "Part shape=%d not supported", part->shape);
 	return false;
 }
@@ -102,5 +102,5 @@
 			break;
 	}
-	Hprintf("GeometryUtils", "isPointStrictlyInsidePart", HMLV_ERROR, "Part shape=%d not supported", part->shape);
+	logPrintf("GeometryUtils", "isPointStrictlyInsidePart", LOG_ERROR, "Part shape=%d not supported", part->shape);
 	return false;
 }
Index: /cpp/frams/model/geometry/meshbuilder.cpp
===================================================================
--- /cpp/frams/model/geometry/meshbuilder.cpp	(revision 374)
+++ /cpp/frams/model/geometry/meshbuilder.cpp	(revision 375)
@@ -639,5 +639,5 @@
 
 		default:
-			Hprintf("MeshBuilder::PartSurface", "initialize", HMLV_WARN, "Part shape=%d not supported, skipping...", part->shape);
+			logPrintf("MeshBuilder::PartSurface", "initialize", LOG_WARN, "Part shape=%d not supported, skipping...", part->shape);
 	}
 }
@@ -725,5 +725,5 @@
 
 		default:
-			Hprintf("MeshBuilder::PartApices", "initialize", HMLV_WARN, "Part shape=%d not supported, skipping...", part->shape);
+			logPrintf("MeshBuilder::PartApices", "initialize", LOG_WARN, "Part shape=%d not supported, skipping...", part->shape);
 	}
 }
Index: /cpp/frams/model/geometry/modelgeometryinfo.cpp
===================================================================
--- /cpp/frams/model/geometry/modelgeometryinfo.cpp	(revision 374)
+++ /cpp/frams/model/geometry/modelgeometryinfo.cpp	(revision 375)
@@ -16,5 +16,5 @@
 	if (points.size() < 1) //maybe 1 or 2 points are also not enough for findSizesAndAxesOfPointsGroup() to work...
 	{
-		Hprintf("ModelGeometryInfo", "findSizesAndAxesOfModel", HMLV_ERROR, "Empty points sample for model with %d part(s)", model.getPartCount());
+		logPrintf("ModelGeometryInfo", "findSizesAndAxesOfModel", LOG_ERROR, "Empty points sample for model with %d part(s)", model.getPartCount());
 		sizes = Pt3D_0;
 		axes = Orient_1;
@@ -116,5 +116,5 @@
 			return externalAreaOfCylinder(model, partIndex, density);
 	}
-	Hprintf("ModelGeometryInfo", "externalAreaOfPart", HMLV_ERROR, "Part shape=%d not supported", part->shape);
+	logPrintf("ModelGeometryInfo", "externalAreaOfPart", LOG_ERROR, "Part shape=%d not supported", part->shape);
 	return 0;
 }
Index: /cpp/frams/model/model.cpp
===================================================================
--- /cpp/frams/model/model.cpp	(revision 374)
+++ /cpp/frams/model/model.cpp	(revision 375)
@@ -5,7 +5,7 @@
 #include <common/nonstd_math.h>
 #include "model.h"
-#include <common/hmessage.h>
+#include <common/log.h>
 #include <frams/util/multimap.h>
-#include <frams/mhandlers/mhandlers.h>
+#include <frams/loggers/loggers.h>
 
 Model::Model()
@@ -317,5 +317,5 @@
 SString line;
 MultiRange frommap;
-MessageHandlerToMemory mh(MessageHandlerBase::Enable | MessageHandlerBase::DontBlock);
+LoggerToMemory mh(LoggerBase::Enable | LoggerBase::DontBlock);
 for (;f0txt.getNextToken(pos,line,'\n');lnum++)
 	{
@@ -329,5 +329,5 @@
 		{
 		buildstatus=invalid;
-		Hprintf("Model","build",HMLV_ERROR,
+		logPrintf("Model","build",LOG_ERROR,
 			 geno.getName().len()?"illegal f0 code at line %d (%s)":"illegal f0 code at line %d",
 			 lnum,geno.getName().c_str());
@@ -513,5 +513,5 @@
 {
 if (buildstatus!=building)
-	Hprintf("Model","close",HMLV_WARN,"unexpected close() - no open()");
+	logPrintf("Model","close",LOG_WARN,"unexpected close() - no open()");
 if (internalcheck(1)>0)
 	{
@@ -609,5 +609,5 @@
 		{
 		delete j;
-		Hprintf("Model","build",HMLV_ERROR,
+		logPrintf("Model","build",LOG_ERROR,
 			 "invalid part reference for joint #%d",getJointCount()-1);
 		return -1;
@@ -694,5 +694,5 @@
 		return 0;
 		}
-	Hprintf("Model","build",HMLV_ERROR,
+	logPrintf("Model","build",LOG_ERROR,
 		 "invalid neuron connection #%d <- #%d",c.n1_refno,c.n2_refno);
 	return -1;
@@ -782,5 +782,5 @@
 			else
 				{
-				Hprintf("Model","internalCheck",HMLV_ERROR,
+				logPrintf("Model","internalCheck",LOG_ERROR,
 					 "illegal N-N connection #%d (reference to #%d) (%s)",
 					 i,n->conn_refno,(const char*)geno.getName());
@@ -853,8 +853,8 @@
 if (var -> field < getMin ## template () . field) \
 	{ var->field= getMin ## template () . field; \
-	Hprintf("Model","internalCheck",HMLV_WARN,# field " too small in " # template "#%d (adjusted)",i);} \
+	logPrintf("Model","internalCheck",LOG_WARN,# field " too small in " # template "#%d (adjusted)",i);} \
 else if (var -> field > getMax ## template () . field) \
 	{ var->field= getMax ## template ()  . field; \
-	Hprintf("Model","internalCheck",HMLV_WARN,# field " too big in " # template "#%d (adjusted)",i);}
+	logPrintf("Model","internalCheck",LOG_WARN,# field " too big in " # template "#%d (adjusted)",i);}
 
 #define LINKFLAG 0x8000000
@@ -912,5 +912,5 @@
 			{
 			shape=SHAPE_ILLEGAL;
-			Hprintf("Model","internalCheck",HMLV_WARN,"Inconsistent part shapes (mixed old and new shapes)");
+			logPrintf("Model","internalCheck",LOG_WARN,"Inconsistent part shapes (mixed old and new shapes)");
 			}
 		}
@@ -941,5 +941,5 @@
 				{
 				ret=0;
-				Hprintf("Model","internalCheck",HMLV_ERROR,
+				logPrintf("Model","internalCheck",LOG_ERROR,
 					 "delta joint cycle detected at joint#%d (%s)",
 					 i,geno.getName().c_str());
@@ -978,5 +978,5 @@
 			{
 			ret=0;
-			Hprintf("Model","internalCheck",HMLV_ERROR,"delta too big in joint #%d (%s)",
+			logPrintf("Model","internalCheck",LOG_ERROR,"delta too big in joint #%d (%s)",
 				 i,geno.getName().c_str());
 			}
@@ -984,5 +984,5 @@
 			{
 			ret=0;
-			Hprintf("Model","internalCheck",HMLV_ERROR,"delta too small in joint #%d (%s)",
+			logPrintf("Model","internalCheck",LOG_ERROR,"delta too small in joint #%d (%s)",
 				 i,geno.getName().c_str());
 			}
@@ -992,5 +992,5 @@
 	else
 		{
-		Hprintf("Model","internalCheck",HMLV_ERROR,"illegal part references in joint #%d (%s)",
+		logPrintf("Model","internalCheck",LOG_ERROR,"illegal part references in joint #%d (%s)",
 			 i,geno.getName().c_str());
 		ret=0;
@@ -1001,5 +1001,5 @@
 			{
 			shape=SHAPE_ILLEGAL;
-			Hprintf("Model","internalCheck",HMLV_WARN,"Inconsistent joint shapes (mixed old and new shapes)");
+			logPrintf("Model","internalCheck",LOG_WARN,"Inconsistent joint shapes (mixed old and new shapes)");
 			}
 		}
@@ -1071,5 +1071,5 @@
 		if (!(p->flags&LINKFLAG))
 			{
-			Hprintf("Model","internalCheck",HMLV_ERROR,"not all parts connected (eg.#0-#%d) (%s)",
+			logPrintf("Model","internalCheck",LOG_ERROR,"not all parts connected (eg.#0-#%d) (%s)",
 				 i,geno.getName().c_str());
 			ret=0;
@@ -1084,5 +1084,5 @@
 	if (j->p1_refno==j->p2_refno)
 		{
-		Hprintf("Model","internalCheck",HMLV_ERROR,"illegal self connection, joint #%d (%s)",
+		logPrintf("Model","internalCheck",LOG_ERROR,"illegal self connection, joint #%d (%s)",
 			 i,geno.getName().c_str());
 		ret=0;
@@ -1095,5 +1095,5 @@
 		    || ((j->p1_refno==j2->p2_refno)&&(j->p2_refno==j2->p1_refno)))
 			{
-			Hprintf("Model","internalCheck",HMLV_ERROR,"illegal duplicate joints #%d and #%d (%s)",
+			logPrintf("Model","internalCheck",LOG_ERROR,"illegal duplicate joints #%d and #%d (%s)",
 				 i,k,geno.getName().c_str());
 			ret=0;
@@ -1125,5 +1125,5 @@
 {
 if (buildstatus==building)
-	Hprintf("Model","getGeno",HMLV_WARN,"model was not completed - missing close()");
+	logPrintf("Model","getGeno",LOG_WARN,"model was not completed - missing close()");
 if (buildstatus!=valid)
 	return Geno("",'0',"","invalid");
Index: /cpp/frams/neuro/neurofactory.cpp
===================================================================
--- /cpp/frams/neuro/neurofactory.cpp	(revision 374)
+++ /cpp/frams/neuro/neurofactory.cpp	(revision 375)
@@ -98,5 +98,5 @@
 	}
 if (removed.len())
-	Hprintf("NeuroFactory","removeUninmplemented",HMLV_INFO,
+	logPrintf("NeuroFactory","removeUninmplemented",LOG_INFO,
 	 "Removed Neuro classes: %s",removed.c_str());
 }
Index: /cpp/frams/neuro/neuroimpl.cpp
===================================================================
--- /cpp/frams/neuro/neuroimpl.cpp	(revision 374)
+++ /cpp/frams/neuro/neuroimpl.cpp	(revision 375)
@@ -72,5 +72,5 @@
 	n->userdata[mytags_id]=ni;
 	if (!ni) { errorcount++;
-		Hprintf("NeuroNetImpl","create",HMLV_WARN,"neuron #%d (%s) implementation not available",
+		logPrintf("NeuroNetImpl","create",LOG_WARN,"neuron #%d (%s) implementation not available",
 			 i,n->getClassName().c_str());
 		continue; } // implementation not available?!
@@ -87,5 +87,5 @@
 	if (!ni->lateinit())
 		{ ni->status=NeuroImpl::InitError; errorcount++;
-		Hprintf("NeuroNetImpl","create",HMLV_WARN,"neuron #%d (%s) initialization failed",
+		logPrintf("NeuroNetImpl","create",LOG_WARN,"neuron #%d (%s) initialization failed",
 			 i,n->getClassName().c_str());
 		continue; }
Index: /cpp/frams/neuro/neuroimpl.h
===================================================================
--- /cpp/frams/neuro/neuroimpl.h	(revision 374)
+++ /cpp/frams/neuro/neuroimpl.h	(revision 375)
@@ -8,5 +8,5 @@
 #include <frams/model/model.h>
 #include <frams/param/param.h>
-#include <common/hmessage.h>
+#include <common/log.h>
 #ifdef NEURO_SIGNALS
 #include <frams/simul/signals.h>
Index: /cpp/frams/param/multiparamload.cpp
===================================================================
--- /cpp/frams/param/multiparamload.cpp	(revision 374)
+++ /cpp/frams/param/multiparamload.cpp	(revision 375)
@@ -5,5 +5,5 @@
 #include "multiparamload.h"
 #include <frams/util/sstringutils.h>
-#include "common/hmessage.h"
+#include "common/log.h"
 #include <ctype.h>
 
@@ -107,5 +107,5 @@
 	else if (status==BeforeUnknown)
 		{
-		Hprintf("MultiParamLoader","go",HMLV_WARN,"Skipping object '%s'",lastunknown.c_str());
+		logPrintf("MultiParamLoader","go",LOG_WARN,"Skipping object '%s'",lastunknown.c_str());
 		loadObjectNow(&emptyparam,false);
 		continue;
@@ -137,5 +137,5 @@
 				{
 				const char* thisfilename=file->VgetPath();
-				Hprintf("MultiParamLoader","go",HMLV_WARN,"invalid \"%s\"%s%s",buf.c_str(),
+				logPrintf("MultiParamLoader","go",LOG_WARN,"invalid \"%s\"%s%s",buf.c_str(),
 					 (thisfilename?" in ":""),(thisfilename?thisfilename:""));
 				}
@@ -204,5 +204,5 @@
 if (alreadyIncluded(newfilename.c_str()))
 	{
-	Hprintf("MultiParamLoader","include",HMLV_WARN,"circular reference ignored (\"%s\")",
+	logPrintf("MultiParamLoader","include",LOG_WARN,"circular reference ignored (\"%s\")",
 		    filename.c_str());
 	return;
@@ -212,5 +212,5 @@
 if (!f)
 	{
-	Hprintf("MultiParamLoader","include",HMLV_WARN,"\"%s\" not found",newfilename.c_str());
+	logPrintf("MultiParamLoader","include",LOG_WARN,"\"%s\" not found",newfilename.c_str());
 	}
 else
Index: /cpp/frams/param/param.cpp
===================================================================
--- /cpp/frams/param/param.cpp	(revision 374)
+++ /cpp/frams/param/param.cpp	(revision 375)
@@ -8,5 +8,5 @@
 #include "param.h"
 #include <frams/util/extvalue.h>
-#include "common/hmessage.h"
+#include "common/log.h"
 #include <frams/util/sstringutils.h>
 
@@ -445,5 +445,5 @@
 		{
 			SString name(p0, p_len);
-			Hprintf("ParamInterface", "load", HMLV_WARN, "Ignored unknown property '%s' while reading object '%s'", name.c_str(), getName());
+			logPrintf("ParamInterface", "load", LOG_WARN, "Ignored unknown property '%s' while reading object '%s'", name.c_str(), getName());
 		}
 
@@ -518,5 +518,5 @@
 	case 'o':	ret.setObject(getObject(i)); break;
 	case 'x':	ret = getExtValue(i); break;
-	default: Hprintf("ParamInterface", "get", HMLV_ERROR, "'%s.%s' is not a field", getName(), id(i));
+	default: logPrintf("ParamInterface", "get", LOG_ERROR, "'%s.%s' is not a field", getName(), id(i));
 	}
 }
@@ -562,5 +562,5 @@
 			if (v.type == TObj)
 			{
-				Hprintf("ParamInterface", "set", HMLV_WARN, "Getting integer value from object reference (%s)", v.getString().c_str());
+				logPrintf("ParamInterface", "set", LOG_WARN, "Getting integer value from object reference (%s)", v.getString().c_str());
 				return 0;
 			}
@@ -574,5 +574,5 @@
 			if (v.type == TObj)
 			{
-				Hprintf("ParamInterface", "set", HMLV_WARN, "Getting floating point value from object reference (%s)", v.getString().c_str());
+				logPrintf("ParamInterface", "set", LOG_WARN, "Getting floating point value from object reference (%s)", v.getString().c_str());
 				return 0;
 			}
@@ -583,5 +583,5 @@
 	case 'o': return setObject(i, v.getObject());
 	case 'x': return setExtValue(i, v);
-	default: Hprintf("ParamInterface", "set", HMLV_ERROR, "'%s.%s' is not a field", getName(), id(i));
+	default: logPrintf("ParamInterface", "set", LOG_ERROR, "'%s.%s' is not a field", getName(), id(i));
 	}
 	return 0;
@@ -605,5 +605,5 @@
 			if ((after == NULL) || (*after))
 			{
-				Hprintf("ParamInterface", "set", HMLV_WARN, "serialization format mismatch in %s.%s", (getName() ? getName() : "<Unknown>"), id(i));
+				logPrintf("ParamInterface", "set", LOG_WARN, "serialization format mismatch in %s.%s", (getName() ? getName() : "<Unknown>"), id(i));
 				e.setEmpty();
 			}
@@ -690,5 +690,5 @@
 	}
 	if (err!=NULL)
-		Hprintf("SimpleAbstractParam","sanityCheck", HMLV_ERROR,
+		logPrintf("SimpleAbstractParam","sanityCheck", LOG_ERROR,
 		"Invalid ParamEntry for %s.%s (%s)", getName(), pe->id, err);
 }	
@@ -961,5 +961,5 @@
 	else
 	{
-		Hprintf("SimpleAbstractParam", "call", HMLV_ERROR,
+		logPrintf("SimpleAbstractParam", "call", LOG_ERROR,
 			(*pe->type != 'p') ? "'%s.%s' is not a function" : "Internal error - undefined function pointer for '%s.%s'", getName(), pe->id);
 		ret->setInvalid();
@@ -1060,5 +1060,5 @@
 			{
 				SString name(t, (int)(equals_sign - t));
-				Hprintf("Param", "load2", HMLV_WARN, "Unknown property '%s' while reading object '%s' (ignored)", name.c_str(), getName());
+				logPrintf("Param", "load2", LOG_WARN, "Unknown property '%s' while reading object '%s' (ignored)", name.c_str(), getName());
 			}
 			t = equals_sign + 1; // t=value
@@ -1070,5 +1070,5 @@
 #endif
 			{
-			Hprintf("Param", "load2", HMLV_WARN, "Missing property name in '%s' (assuming '%s')",
+			logPrintf("Param", "load2", LOG_WARN, "Missing property name in '%s' (assuming '%s')",
 				getName(), id(i) ? id(i) : "unknown property?");
 			}
@@ -1092,5 +1092,5 @@
 			fields_loaded++;
 			if (ret&(PSET_HITMAX | PSET_HITMIN))
-				Hprintf("Param", "load2", HMLV_WARN, "Adjusted '%s' in '%s' (was too %s)",
+				logPrintf("Param", "load2", LOG_WARN, "Adjusted '%s' in '%s' (was too %s)",
 				id(i), getName(), (ret&PSET_HITMAX) ? "big" : "small");
 			*(char*)valstop = remember;
Index: /cpp/frams/param/param.h
===================================================================
--- /cpp/frams/param/param.h	(revision 374)
+++ /cpp/frams/param/param.h	(revision 375)
@@ -12,5 +12,5 @@
 #include <frams/util/statrick.h>
 #include <frams/virtfile/virtfile.h>
-#include <common/hmessage.h>
+#include <common/log.h>
 
 class ExtValue;
@@ -273,5 +273,5 @@
 			SString svaluetoset = SString::valueOf(valuetoset); //converts any type to SString
 			SString actual = get(i);
-			Hprintf("Param", "set", HMLV_WARN, "Setting '%s.%s = %s' exceeded allowed range (too %s). Adjusted to %s.",
+			logPrintf("Param", "set", LOG_WARN, "Setting '%s.%s = %s' exceeded allowed range (too %s). Adjusted to %s.",
 				getName(), id(i), svaluetoset.c_str(), (setflags&PSET_HITMAX) ? "big" : "small", actual.c_str());
 		}
Index: /cpp/frams/util/3d.cpp
===================================================================
--- /cpp/frams/util/3d.cpp	(revision 374)
+++ /cpp/frams/util/3d.cpp	(revision 375)
@@ -4,5 +4,5 @@
 
 #include <common/nonstd_math.h>
-#include <common/hmessage.h>
+#include <common/log.h>
 #include "3d.h"
 
@@ -17,5 +17,5 @@
 {
 	double q = x*x + y*y + z*z;
-	if (q < 0) { if (report_errors) Hprintf("Pt3D", "operator()", HMLV_ERROR, "sqrt(%g): domain error", q); return 0; }
+	if (q < 0) { if (report_errors) logPrintf("Pt3D", "operator()", LOG_ERROR, "sqrt(%g): domain error", q); return 0; }
 	return sqrt(q);
 }
@@ -24,5 +24,5 @@
 {
 	double len = length();
-	if (fabs(len) < 1e-50) { if (report_errors) Hprintf("Pt3D", "normalize()", HMLV_WARN, "vector[%g,%g,%g] too small", x, y, z); x = 1; y = 0; z = 0; return false; }
+	if (fabs(len) < 1e-50) { if (report_errors) logPrintf("Pt3D", "normalize()", LOG_WARN, "vector[%g,%g,%g] too small", x, y, z); x = 1; y = 0; z = 0; return false; }
 	operator/=(len);
 	return true;
@@ -64,5 +64,5 @@
 	if (dx == 0 && dy == 0)
 	{
-		if (report_errors) Hprintf("Pt3D", "getAngle()", HMLV_WARN, "atan2(%g,%g)", dy, dx);
+		if (report_errors) logPrintf("Pt3D", "getAngle()", LOG_WARN, "atan2(%g,%g)", dy, dx);
 		return 0; // incorrect result, but there is no correct one
 	}
@@ -147,5 +147,5 @@
 {
 	double q = x*x + y*y;
-	if (q < 0) { if (Pt3D::report_errors) Hprintf("", "d2()", HMLV_ERROR, "sqrt(%g): domain error", q); return 0; }
+	if (q < 0) { if (Pt3D::report_errors) logPrintf("", "d2()", LOG_ERROR, "sqrt(%g): domain error", q); return 0; }
 	return sqrt(q);
 }
Index: /cpp/frams/util/extvalue.cpp
===================================================================
--- /cpp/frams/util/extvalue.cpp	(revision 374)
+++ /cpp/frams/util/extvalue.cpp	(revision 375)
@@ -98,5 +98,5 @@
 	if (warn)
 	{
-		Hprintf("ExtValue", "getObjectTarget", HMLV_WARN, "%s object expected, %s found", classname, interfaceName());
+		logPrintf("ExtValue", "getObjectTarget", LOG_WARN, "%s object expected, %s found", classname, interfaceName());
 	}
 
@@ -269,5 +269,5 @@
 			if (tmp.len() > 30) tmp = tmp.substr(0, 30) + "...";
 			if (type == TString) tmp = SString("\"") + tmp + SString("\"");
-			Hprintf("ExtValue", "getObjectTarget", HMLV_WARN, "%s object expected, %s found", classname, tmp.c_str());
+			logPrintf("ExtValue", "getObjectTarget", LOG_WARN, "%s object expected, %s found", classname, tmp.c_str());
 		}
 		return NULL;
@@ -419,5 +419,5 @@
 				context->v2->typeAndValue().c_str());
 		}
-		Hprintf("ExtValue", "interpretCompare", HMLV_ERROR, "%s", msg.c_str());
+		logPrintf("ExtValue", "interpretCompare", LOG_ERROR, "%s", msg.c_str());
 		ret = -1;
 	}
@@ -448,5 +448,5 @@
 		{
 		case TDouble:
-			Hprintf("ExtValue", "add", HMLV_WARN, "Adding %s to %s", src.typeAndValue().c_str(), typeAndValue().c_str());
+			logPrintf("ExtValue", "add", LOG_WARN, "Adding %s to %s", src.typeAndValue().c_str(), typeAndValue().c_str());
 			setDouble(double(getInt()) + src.getDouble());
 			return;
@@ -487,5 +487,5 @@
 	default:;
 	}
-	Hprintf("ExtValue", "add", HMLV_ERROR, "Can't add %s to %s", src.typeAndValue().c_str(), typeAndValue().c_str());
+	logPrintf("ExtValue", "add", LOG_ERROR, "Can't add %s to %s", src.typeAndValue().c_str(), typeAndValue().c_str());
 }
 
@@ -502,5 +502,5 @@
 			return;
 		case TDouble:
-			Hprintf("ExtValue", "subtract", HMLV_WARN, "Subtracting %s from %s", src.typeAndValue().c_str(), typeAndValue().c_str());
+			logPrintf("ExtValue", "subtract", LOG_WARN, "Subtracting %s from %s", src.typeAndValue().c_str(), typeAndValue().c_str());
 			setDouble(double(getInt()) - src.getDouble());
 			return;
@@ -520,5 +520,5 @@
 	default:;
 	}
-	Hprintf("ExtValue", "subtract", HMLV_ERROR, "Can't subtract %s from %s", src.typeAndValue().c_str(), typeAndValue().c_str());
+	logPrintf("ExtValue", "subtract", LOG_ERROR, "Can't subtract %s from %s", src.typeAndValue().c_str(), typeAndValue().c_str());
 }
 
@@ -535,5 +535,5 @@
 			return;
 		case TDouble:
-			Hprintf("ExtValue", "multiply", HMLV_WARN, "Multiplying %s by %s", typeAndValue().c_str(), src.typeAndValue().c_str());
+			logPrintf("ExtValue", "multiply", LOG_WARN, "Multiplying %s by %s", typeAndValue().c_str(), src.typeAndValue().c_str());
 			setDouble(double(getInt())*src.getDouble());
 			return;
@@ -591,5 +591,5 @@
 	default:;
 	}
-	Hprintf("ExtValue", "multiply", HMLV_WARN, "Can't multiply %s by %s", typeAndValue().c_str(), src.typeAndValue().c_str());
+	logPrintf("ExtValue", "multiply", LOG_WARN, "Can't multiply %s by %s", typeAndValue().c_str(), src.typeAndValue().c_str());
 }
 
@@ -611,5 +611,5 @@
 	else
 	{
-		Hprintf("ExtValue", "divide", HMLV_CRITICAL, "Division by zero: %d/0", idata());
+		logPrintf("ExtValue", "divide", LOG_CRITICAL, "Division by zero: %d/0", idata());
 		setInvalid();
 	}
@@ -620,5 +620,5 @@
 	if (a == 0.0)
 	{
-		Hprintf("ExtValue", "divide", HMLV_CRITICAL, "Division by zero: %s/0.0", getString().c_str());
+		logPrintf("ExtValue", "divide", LOG_CRITICAL, "Division by zero: %s/0.0", getString().c_str());
 		setInvalid();
 	}
@@ -629,5 +629,5 @@
 		if (!finite(tmp))
 		{
-			Hprintf("ExtValue", "divide", HMLV_CRITICAL, "Overflow %s/%g", getString().c_str(), a); setInvalid();
+			logPrintf("ExtValue", "divide", LOG_CRITICAL, "Overflow %s/%g", getString().c_str(), a); setInvalid();
 		}
 		else
@@ -635,5 +635,5 @@
 		// niby dobrze ale lepiej byloby to robic bardziej systematycznie a nie tylko w dzieleniu?
 		//if (isnan(ddata())) //http://www.digitalmars.com/d/archives/c++/Traping_divide_by_zero_5728.html
-		//	  { Hprintf("ExtValue","divide",HMLV_ERROR,"not-a-number",(const char*)getString()); setInvalid(); }
+		//	  { logPrintf("ExtValue","divide",LOG_ERROR,"not-a-number",(const char*)getString()); setInvalid(); }
 		fpExceptEnable();
 	}
@@ -651,5 +651,5 @@
 			return;
 		case TDouble:
-			Hprintf("ExtValue", "divide", HMLV_WARN, "Dividing %s by %s", typeAndValue().c_str(), src.typeAndValue().c_str());
+			logPrintf("ExtValue", "divide", LOG_WARN, "Dividing %s by %s", typeAndValue().c_str(), src.typeAndValue().c_str());
 			divDouble(src.ddata());
 			return;
@@ -673,5 +673,5 @@
 	default:;
 	}
-	Hprintf("ExtValue", "divide", HMLV_ERROR, "Can't divide %s by %s", typeAndValue().c_str(), src.typeAndValue().c_str());
+	logPrintf("ExtValue", "divide", LOG_ERROR, "Can't divide %s by %s", typeAndValue().c_str(), src.typeAndValue().c_str());
 }
 
@@ -778,5 +778,5 @@
 
 	case TObj: case TUnknown: case TInvalid:
-		Hprintf("ExtValue", "modulo", HMLV_WARN, "Can't apply modulo to %s", typeDescription().c_str());
+		logPrintf("ExtValue", "modulo", LOG_WARN, "Can't apply modulo to %s", typeDescription().c_str());
 
 	default:;
@@ -791,5 +791,5 @@
 	{
 		if (error)
-			Hprintf("ExtValue", "parseInt", HMLV_ERROR, "Could not parse '%s'%s", s, strict ? " (strict)" : "");
+			logPrintf("ExtValue", "parseInt", LOG_ERROR, "Could not parse '%s'%s", s, strict ? " (strict)" : "");
 		return false;
 	}
@@ -805,5 +805,5 @@
 	{
 		if (error)
-			Hprintf("ExtValue", "parseDouble", HMLV_ERROR, "Could not parse '%s'", s);
+			logPrintf("ExtValue", "parseDouble", LOG_ERROR, "Could not parse '%s'", s);
 		return false;
 	}
@@ -836,5 +836,5 @@
 	case TString: return getInt(sdata().c_str());
 	case TObj:
-		Hprintf("ExtValue", "getInt", HMLV_WARN, "Getting integer value from object reference (%s)", getString().c_str());
+		logPrintf("ExtValue", "getInt", LOG_WARN, "Getting integer value from object reference (%s)", getString().c_str());
 		return (paInt)(intptr_t)odata().param;
 	default:;
@@ -851,5 +851,5 @@
 	case TString: return getDouble(sdata().c_str());
 	case TObj:
-		Hprintf("ExtValue", "getDouble", HMLV_WARN, "Getting floating point value from object reference (%s)", getString().c_str());
+		logPrintf("ExtValue", "getDouble", LOG_WARN, "Getting floating point value from object reference (%s)", getString().c_str());
 		return (double)(intptr_t)odata().param;
 	default:;
@@ -989,5 +989,5 @@
 		else
 		{
-			Hprintf("ExtValue", "deserialize", HMLV_ERROR, "Missing '\"' in string: '%s'", ret);
+			logPrintf("ExtValue", "deserialize", LOG_ERROR, "Missing '\"' in string: '%s'", ret);
 			return NULL;
 		}
@@ -1011,5 +1011,5 @@
 				else if (*p != ']')
 				{
-					Hprintf("ExtValue", "deserialize", HMLV_ERROR, "Missing ',' in Vector: '%s'", p);
+					logPrintf("ExtValue", "deserialize", LOG_ERROR, "Missing ',' in Vector: '%s'", p);
 					return NULL;
 				}
@@ -1037,5 +1037,5 @@
 			if ((!ret) || (args[1].getType() != TString)) { p = NULL; break; }
 			p = ret;
-			if (*p != ':') { Hprintf("ExtValue", "deserialize", HMLV_ERROR, "Missing ':' in Dictionary: '%s'", p); p = NULL; break; }
+			if (*p != ':') { logPrintf("ExtValue", "deserialize", LOG_ERROR, "Missing ':' in Dictionary: '%s'", p); p = NULL; break; }
 			p++;
 			ret = args[0].deserialize(p);
@@ -1046,5 +1046,5 @@
 			else if (*p != '}')
 			{
-				Hprintf("ExtValue", "deserialize", HMLV_ERROR, "Missing ',' in Dictionary: '%s'", p);
+				logPrintf("ExtValue", "deserialize", LOG_ERROR, "Missing ',' in Dictionary: '%s'", p);
 				return NULL;
 			}
@@ -1086,5 +1086,5 @@
 			}
 		}
-		Hprintf("ExtValue", "deserialize", HMLV_ERROR, "Invalid reference: '%s'", in - 1);
+		logPrintf("ExtValue", "deserialize", LOG_ERROR, "Invalid reference: '%s'", in - 1);
 		return NULL;
 	}
@@ -1133,8 +1133,8 @@
 		}
 		setEmpty();
-		Hprintf("ExtValue", "deserialize", HMLV_WARN, "object of class \"%s\" could not be deserialized", clsname.c_str());
+		logPrintf("ExtValue", "deserialize", LOG_WARN, "object of class \"%s\" could not be deserialized", clsname.c_str());
 		return ret;
 	}
-	Hprintf("ExtValue", "deserialize", HMLV_ERROR, "Bad syntax: '%s'", in);
+	logPrintf("ExtValue", "deserialize", LOG_ERROR, "Bad syntax: '%s'", in);
 	setEmpty();
 	return NULL;
Index: /cpp/frams/util/sstringutils.cpp
===================================================================
--- /cpp/frams/util/sstringutils.cpp	(revision 374)
+++ /cpp/frams/util/sstringutils.cpp	(revision 375)
@@ -5,5 +5,5 @@
 #include "sstringutils.h"
 #include <frams/virtfile/virtfile.h>
-#include <common/hmessage.h>
+#include <common/log.h>
 #include <common/nonstd.h>
 
@@ -19,5 +19,5 @@
 	}
 	else if (framsgmodule)
-		Hprintf(framsgmodule, "loadSString", HMLV_WARN, error ? error : "can't open file \"%s\"", filename);
+		logPrintf(framsgmodule, "loadSString", LOG_WARN, error ? error : "can't open file \"%s\"", filename);
 	return ret;
 }
Index: /cpp/frams/util/validitychecks.cpp
===================================================================
--- /cpp/frams/util/validitychecks.cpp	(revision 375)
+++ /cpp/frams/util/validitychecks.cpp	(revision 375)
@@ -0,0 +1,34 @@
+// This file is a part of Framsticks SDK.  http://www.framsticks.com/
+// Copyright (C) 1999-2015  Maciej Komosinski and Szymon Ulatowski.
+// See LICENSE.txt for details.
+
+#include "validitychecks.h"
+#include <frams/util/sstringutils.h>
+#include <common/log.h>
+
+bool listIndexCheck(SList* list,int index,const char* msgobj,const char* msgfun)
+{
+	int size=list->size();
+if ((index<0)||(index>=size))
+	{
+	if (size>0) 
+		logPrintf(msgobj,msgfun,LOG_ERROR,"Invalid index %d (allowed range is 0..%d)",index,size-1);
+	else
+		logPrintf(msgobj,msgfun,LOG_ERROR,"Invalid index %d (this list is empty)",index);
+	return 0;
+	}
+return 1;
+}
+
+SString stringCheck(SString& in,const char* msgobj,const char* msgfun,const char* msg,SString (*checker)(SString& in))
+{
+if (!checker)
+	checker=trim;
+SString corrected=checker(in);
+if (corrected!=in)
+	{
+	SString msg2=SString(msg)+": \"%s\" (adjusted to \"%s\")";
+	logPrintf(msgobj,msgfun,LOG_WARN,msg2.c_str(),in.c_str(),corrected.c_str());
+	}
+return corrected;
+}
Index: /cpp/frams/util/validitychecks.h
===================================================================
--- /cpp/frams/util/validitychecks.h	(revision 375)
+++ /cpp/frams/util/validitychecks.h	(revision 375)
@@ -0,0 +1,14 @@
+// This file is a part of Framsticks SDK.  http://www.framsticks.com/
+// Copyright (C) 1999-2015  Maciej Komosinski and Szymon Ulatowski.
+// See LICENSE.txt for details.
+
+#ifndef _VALIDITY_CHECKS_H_
+#define _VALIDITY_CHECKS_H_
+
+#include <frams/util/list.h>
+#include <frams/util/sstring.h>
+
+bool listIndexCheck(SList* list,int index,const char* msgobj,const char* msgfun);
+SString stringCheck(SString& in,const char* msgobj,const char* msgfun,const char* msg,SString (*checker)(SString& in)=NULL);
+
+#endif
Index: /cpp/frams/virtfile/stdiofile.cpp
===================================================================
--- /cpp/frams/virtfile/stdiofile.cpp	(revision 374)
+++ /cpp/frams/virtfile/stdiofile.cpp	(revision 375)
@@ -6,10 +6,10 @@
 #include <common/nonstd_dir.h>
 #include <common/nonstd_stdio.h>
-#include <common/hmessage.h>
+#include <common/log.h>
 #include <common/Convert.h>
 
 VirtFILE* StdioFileSystem::Vfopen(const char *path, const char *mode)
 {
-	//printH("Vfopen %s %s",path,mode);
+	//log_printf("Vfopen %s %s",path,mode);
 #if defined USE_MFILE || defined _WIN32
 	MFILE *f = mfopen(path, mode);
@@ -17,5 +17,5 @@
 	FILE *f = fopen(path, mode);
 #endif
-	//printH("%p",f);
+	//log_printf("%p",f);
 	if (f) return new StdioFILE(f, path); else return NULL;
 }
@@ -23,5 +23,5 @@
 VirtDIR* StdioFileSystem::Vopendir(const char* path)
 {
-	//printH("Vopendir %s",path);
+	//log_printf("Vopendir %s",path);
 #ifdef _WIN32
 	DIRTYPE *d = wopendir(Convert::utf8ToUtf16(path).c_str());
@@ -29,5 +29,5 @@
 	DIR *d = opendir(path);
 #endif
-	//printH("%p",d);
+	//log_printf("%p",d);
 	if (d) return new StdioDIR(d); else return NULL;
 }
@@ -52,5 +52,5 @@
 dirent* StdioDIR::Vreaddir()
 {
-	//printH("Vreaddir %s",dir);
+	//log_printf("Vreaddir %s",dir);
 #ifdef _WIN32
 	wdirent *wde=wreaddir(dir);
Index: /cpp/frams/vm/classes/collectionobj.cpp
===================================================================
--- /cpp/frams/vm/classes/collectionobj.cpp	(revision 374)
+++ /cpp/frams/vm/classes/collectionobj.cpp	(revision 375)
@@ -5,5 +5,5 @@
 #include "collectionobj.h"
 #include <common/nonstd_math.h> //sqrt in borland
-#include <frams/mhandlers/stderrors.h>
+#include <frams/util/validitychecks.h>
 #include <common/nonstd_stl.h>
 #include <frams/util/sstringutils.h>
@@ -232,5 +232,5 @@
 	{
 	ret=false;
-	Hprintf("VectorElementComparator","",HMLV_ERROR,"Comparison function returned no value");
+	logPrintf("VectorElementComparator","",LOG_ERROR,"Comparison function returned no value");
 	}
 else
Index: /cpp/frams/vm/framscript.y
===================================================================
--- /cpp/frams/vm/framscript.y	(revision 374)
+++ /cpp/frams/vm/framscript.y	(revision 375)
@@ -5,5 +5,5 @@
 %{
 #include "framscript-defs.h"
-#include "common/framsg.h"
+#include "common/log.h"
 #include <math.h>
 #include <ctype.h>
@@ -145,5 +145,5 @@
  {
 #ifdef FRAMSCRIPT_GOTO
-trctx.out->printf("jump :%s\n",str($2)); FMprintf("FramScriptCompiler","translate",FMLV_WARN,"goto is not recommended"); trctx.emitLine();
+trctx.out->printf("jump :%s\n",str($2)); logPrintf("FramScriptCompiler","translate",LOG_WARN,"goto is not recommended"); trctx.emitLine();
 #else
 trctx.err->printf("goto is not supported\n");return 1;
@@ -1515,5 +1515,5 @@
 {
 if (t.assign && (!t.parens))
-	FMprintf("FramScriptCompiler","translate",FMLV_WARN,"Assignment used as truth value, use ((double parens)) if you really mean it");
+	logPrintf("FramScriptCompiler","translate",LOG_WARN,"Assignment used as truth value, use ((double parens)) if you really mean it");
 }
 
