Index: cpp/frams/genetics/defgenoconv.cpp
===================================================================
--- cpp/frams/genetics/defgenoconv.cpp	(revision 779)
+++ cpp/frams/genetics/defgenoconv.cpp	(revision 780)
@@ -43,4 +43,13 @@
 #include "fn/fn_conv.h"
 #endif
+#ifdef USE_GENCONV_fBH
+#include "fB/fB_conv.h"
+#endif
+#ifdef USE_GENCONV_fH0
+#include "fH/fH_conv.h"
+#endif
+#ifdef USE_GENCONV_fL0
+#include "fL/fL_conv.h"
+#endif
 
 void DefaultGenoConvManager::addDefaultConverters()
@@ -82,4 +91,13 @@
 	addConverter(new GenoConv_fn0);
 #endif
+#ifdef USE_GENCONV_fBH
+	addConverter(new GenoConv_fBH);
+#endif
+#ifdef USE_GENCONV_fH0
+	addConverter(new GenoConv_fH0);
+#endif
+#ifdef USE_GENCONV_fL0
+	addConverter(new GenoConv_fL0);
+#endif
 
 	param.updatetab();
Index: cpp/frams/genetics/fB/fB_conv.cpp
===================================================================
--- cpp/frams/genetics/fB/fB_conv.cpp	(revision 780)
+++ cpp/frams/genetics/fB/fB_conv.cpp	(revision 780)
@@ -0,0 +1,181 @@
+#include "fB_conv.h"
+
+#include <frams/param/paramobj.h>
+#include <vector>
+#include <frams/util/multimap.h>
+#include "fB_general.h"
+
+double GenoConv_fBH::convertCharacterTo01(char c)
+{
+	return (double)(c - 'a') / 25.0;
+}
+
+double GenoConv_fBH::convertCharacterToWeight(char c)
+{
+	if (c <= 'm')
+	{
+		return -0.001 * pow(2.0, (double)('m' - c));
+	}
+	else
+	{
+		return 0.001 * pow(2.0, (double)(c - 'n'));
+	}
+}
+
+fH_Handle* GenoConv_fBH::convertCharacterToHandle(char c, int dims, int start, int end, std::vector<IRange> ranges[3])
+{
+	fH_Handle *handle = NULL;
+	if (c >= 'a' && c <= 'i')
+	{
+		handle = new fH_StickHandle(dims, start, end);
+		ranges[0].push_back(IRange(start, end));
+	}
+	else if (c >= 'j' && c <= 'p')
+	{
+		handle = new fH_NeuronHandle(dims, start, end);
+		ranges[1].push_back(IRange(start, end));
+	}
+	else
+	{
+		handle = new fH_ConnectionHandle(dims, start, end);
+		ranges[2].push_back(IRange(start, end));
+	}
+	return handle;
+}
+
+SString GenoConv_fBH::convert(SString &i, MultiMap *map, bool using_checkpoints)
+{
+	// if there is no genotype to load, then return error
+
+	std::vector<IRange> ranges[3];
+
+	int pos = 0;
+	SString line;
+	i.getNextToken(pos, line, '\n');
+	int dims = 0;
+	// extract dimensions
+	if (!ExtValue::parseInt(line.c_str(), dims, true, false))
+	{
+		logMessage("f2::Builder", "parseGenotype", LOG_ERROR, "Could not parse number of dimensions");
+		return "";
+	}
+
+	if (dims < 1)
+	{
+		logMessage("f2::Builder", "parseGenotype", LOG_ERROR, "Number of dimensions cannot be lower than 1");
+		return 1;
+	}
+
+	fH_Builder creature(dims, false);
+
+	for (int q = 0; q < fB_GenoHelpers::geneCount(i); q++)
+	{
+		int start, end;
+		SString gene = fB_GenoHelpers::getGene(q, i, start, end);
+		end -= 1; // last character is included in range, so decrementation is required
+		int endoffset = 0;
+		if (gene.indexOf("zz", 0) != -1) endoffset = 2;
+		if (gene.len() - endoffset < 3)
+		{
+			fH_StickHandle *handle = new fH_StickHandle(dims, start, end);
+			ParamEntry *tab = creature.getParamTab(handle->type);
+			void *obj = ParamObject::makeObject(tab);
+			Param par(tab, NULL);
+			par.select(obj);
+			par.setDefault();
+			handle->loadProperties(par);
+			ranges[0].push_back(IRange(start, end));
+			creature.addHandle(handle);
+			continue;
+		}
+		fH_Handle *handle = convertCharacterToHandle(gene[2], dims, start, end, ranges);
+		ParamEntry *tab = creature.getParamTab(handle->type);
+		void *obj = ParamObject::makeObject(tab);
+		Param par(tab, NULL);
+		par.select(obj);
+		par.setDefault();
+
+		int propindex = 0;
+		int z = 3;
+		endoffset = 0;
+		if (gene.indexOf("zz", 0) != -1) endoffset = 2;
+		while (z < gene.len() - endoffset)
+		{
+			if (processNextLetter(creature, handle, par, gene, propindex, z, ranges) == -1)
+			{
+				logMessage("GenoConv_fBH", "convert", LOG_WARN, "Property of fH could not be parsed");
+			}
+		}
+		handle->loadProperties(par);
+		creature.addHandle(handle);
+	}
+
+	SString fHgenotype = creature.toString();
+
+	if (NULL != map)
+	{
+		int fHpos = 0;
+		SString line;
+		fHgenotype.getNextToken(fHpos, line, '\n');
+		int lastpos = fHpos;
+		for (int t = 0; t < 3; t++)
+		{
+			for (unsigned int q = 0; q < ranges[t].size(); q++)
+			{
+				fHgenotype.getNextToken(fHpos, line, '\n');
+				map->add(ranges[t][q].begin, ranges[t][q].end, lastpos, fHpos - 1);
+			}
+		}
+	}
+
+	return fHgenotype;
+}
+
+int GenoConv_fBH::processNextLetter(fH_Builder &creature, fH_Handle *&currhandle, Param &par, SString gene, int &propindex, int &i, std::vector<IRange> ranges[3])
+{
+	if (propindex >= par.getPropCount())
+	{
+		int tmpend = currhandle->end;
+		currhandle->end = i - 1;
+		currhandle->loadProperties(par);
+		creature.addHandle(currhandle);
+		currhandle = convertCharacterToHandle(gene[i], currhandle->getDimensions(), currhandle->begin + i, tmpend, ranges);
+		ParamEntry *tab = creature.getParamTab(currhandle->type);
+		par.setParamTab(tab);
+		void *obj = ParamObject::makeObject(tab);
+		par.select(obj);
+		par.setDefault();
+		propindex = 0;
+		i++;
+		return 0;
+	}
+	else
+	{
+		if (*par.type(propindex) == 'f')
+		{
+			if (currhandle->type == fHBodyType::CONNECTION && *par.id(propindex) == 'w')
+			{
+				par.setDouble(propindex, convertCharacterToWeight(gene[i]));
+			}
+			else
+			{
+				double val = convertCharacterTo01(gene[i]);
+				double mn, mx, def;
+				par.getMinMaxDouble(propindex, mn, mx, def);
+				par.setDouble(propindex, min(mx, max(mn, (mx - mn) * val + mn)));
+			}
+			propindex++;
+			i++;
+			return 0;
+		}
+		else if (currhandle->type == fHBodyType::NEURON && *par.id(propindex) == 'd')
+		{
+			//TODO: handle neuron classes and properties
+			propindex++;
+			i++;
+			return 0;
+		}
+		// other property types are not available in this encoding
+		return -1;
+	}
+}
Index: cpp/frams/genetics/fB/fB_conv.h
===================================================================
--- cpp/frams/genetics/fB/fB_conv.h	(revision 780)
+++ cpp/frams/genetics/fB/fB_conv.h	(revision 780)
@@ -0,0 +1,28 @@
+#ifndef _FB_CONV_H_
+#define _FB_CONV_H_
+
+#include <frams/genetics/genoconv.h>
+#include "../fH/fH_general.h"
+
+class GenoConv_fBH : public GenoConverter
+{
+private:
+	double convertCharacterTo01(char c);
+	double convertCharacterToWeight(char c);
+	static fH_Handle* convertCharacterToHandle(char c, int dims, int start, int end, std::vector<IRange> ranges[3]);
+	int processNextLetter(fH_Builder &creature, fH_Handle *&currhandle, Param &par, SString gene, int &propindex, int &i, std::vector<IRange> ranges[3]);
+
+public:
+	GenoConv_fBH() :GenoConverter()
+	{
+		name = "Biological encoding";
+
+		in_format = 'B';
+		out_format = 'H';
+		mapsupport = 1;
+	}
+	SString convert(SString &i, MultiMap *map, bool using_checkpoints);
+	~GenoConv_fBH() {};
+};
+
+#endif //_FB_CONV_H_
Index: cpp/frams/genetics/fB/fB_general.h
===================================================================
--- cpp/frams/genetics/fB/fB_general.h	(revision 780)
+++ cpp/frams/genetics/fB/fB_general.h	(revision 780)
@@ -0,0 +1,46 @@
+#ifndef _FB_GENERAL_H_
+#define _FB_GENERAL_H_
+
+#include <frams/util/sstring.h>
+
+class fB_GenoHelpers
+{
+public:
+	static int geneCount(SString geno)
+	{
+		int start = 0;
+		int count = -1;
+		do {
+			count++;
+			start = geno.indexOf("aa", start) + 1; // +1 is for progress, starting codons can overlap
+		} while (start - 1 != -1);
+		return count;
+	}
+
+	static SString getGene(int i, SString genotype, int &start, int &end)
+	{
+		start = 0;
+		int count = -1;
+		do {
+			count++;
+			start = genotype.indexOf("aa", start) + 1;
+		} while (start - 1 != -1 && count != i);
+		if (start - 1 == -1) // there is no gene with a given "i"
+		{
+			start = -1;
+			end = -1;
+			return "";
+		}
+		end = start;
+		end = genotype.indexOf("zz", end);
+		if (end == -1) end = genotype.len();
+		else end += 2;
+		start -= 1;
+		return genotype.substr(start, end - start);
+	}
+
+private:
+	fB_GenoHelpers() {}
+};
+
+#endif // _FB_GENERAL_H_
Index: cpp/frams/genetics/fB/fB_oper.cpp
===================================================================
--- cpp/frams/genetics/fB/fB_oper.cpp	(revision 780)
+++ cpp/frams/genetics/fB/fB_oper.cpp	(revision 780)
@@ -0,0 +1,372 @@
+#include <frams/util/sstring.h>
+#include <vector>
+#include <frams/param/param.h>
+#include "fB_conv.h"
+#include "fB_general.h"
+#include "fB_oper.h"
+
+#define FIELDSTRUCT Geno_fB
+
+static ParamEntry GENOfBparam_tab[] =
+{
+	{ "Genetics: fB", 3, FB_MUT_COUNT + FB_XOVER_COUNT, }, // ask about it
+	{ "Genetics: fB: Mutation", },
+	{ "Genetics: fB: Crossover", },
+	{ "fB_mut_substitution", 1, 0, "Substitution", "f 0 1 0.6", FIELD(mutationprobs[FB_SUBSTITUTION]), "Probability of mutation by changing single random letter in genotype", },
+	{ "fB_mut_insertion", 1, 0, "Insertion", "f 0 1 0.1", FIELD(mutationprobs[FB_INSERTION]), "Probability of mutation by inserting characters in random place of genotype", },
+	{ "fB_mut_deletion", 1, 0, "Deletion", "f 0 1 0.1", FIELD(mutationprobs[FB_DELETION]), "Probability of mutation by deleting random characters in genotype", },
+	{ "fB_mut_duplication", 1, 0, "Duplication", "f 0 1 0.05", FIELD(mutationprobs[FB_DUPLICATION]), "Probability of mutation by copying single *gene* of genotype and appending it to the beginning of this genotype", },
+	{ "fB_mut_translocation", 1, 0, "Translocation", "f 0 1 0.15", FIELD(mutationprobs[FB_TRANSLOCATION]), "Probability of mutation by replacing two substrings in genotype", },
+	{ "fB_cross_gene_transfer", 2, 0, "Horizontal gene transfer", "f 0 1 0.8", FIELD(crossoverprobs[FB_GENE_TRANSFER]), "Probability of crossing over by transferring single genes from both parents to beginning of each other", },
+	{ "fB_cross_crossover", 2, 0, "Crossing over", "f 0 1 0.2", FIELD(crossoverprobs[FB_CROSSING_OVER]), "Probability of crossing over by random distribution of genes from both parents to both children", },
+	{ 0, },
+};
+
+#undef FIELDSTRUCT
+
+Geno_fB::Geno_fB()
+{
+	par.setParamTab(GENOfBparam_tab);
+	par.select(this);
+	par.setDefault();
+	supported_format = 'B';
+}
+
+bool Geno_fB::hasStick(SString genotype)
+{
+	for (int i = 0; i < fB_GenoHelpers::geneCount(genotype); i++)
+	{
+		int start, end;
+		SString gene = fB_GenoHelpers::getGene(i, genotype, start, end);
+		int endoffset = 0;
+		if (gene.indexOf("zz", 0) != -1) endoffset = 2;
+		if (gene.len() - endoffset < 3)
+		{
+			return true; // genes with length < 3 are always sticks
+		}
+		else if (gene[2] >= 'a' && gene[2] <= 'i')
+		{
+			return true; // gene within this range is stick
+		}
+	}
+	return false;
+}
+
+int Geno_fB::checkValidity(const char *geno, const char *genoname)
+{
+	// load genotype
+	SString genotype(geno);
+	SString line;
+	int pos = 0;
+	// if there is no genotype to load, then return error
+	if (!genotype.getNextToken(pos, line, '\n'))
+	{
+		return pos + 1;
+	}
+	// extract dimensions
+	int dims = 0;
+	if (!ExtValue::parseInt(line.c_str(), dims, true, false))
+	{
+		return 1;
+	}
+	// extract next token in order to check if next line starts with "aa"
+	int genstart = genotype.indexOf("aa", 0);
+	if (genstart != pos)
+	{
+		return pos + 1;
+	}
+	// check if rest of characters are lowercase
+	for (int i = genstart; i < genotype.len(); i++)
+	{
+		if (!islower(genotype[i]))
+		{
+			return i + 1;
+		}
+	}
+	if (!hasStick(genotype))
+	{
+		return 1;
+	}
+	return GENOPER_OK;
+}
+
+int Geno_fB::validate(char *&geno, const char *genoname)
+{
+	// load genotype
+	SString genotype(geno);
+	SString strdims;
+	int pos = 0;
+	if (!genotype.getNextToken(pos, strdims, '\n'))
+	{
+		return GENOPER_OPFAIL;
+	}
+	// parse dimension
+	int dims = 0;
+	if (!ExtValue::parseInt(strdims.c_str(), dims, true, false))
+	{
+		return GENOPER_OPFAIL;
+	}
+	SString line;
+	bool fix = false;
+	int genstart = genotype.indexOf("aa", 0);
+	// if there is no "aa" codon in the beginning of a genotype, then add it
+	if (genstart != pos)
+	{
+		genotype = strdims + "\naa" + genotype.substr(pos);
+		fix = true;
+	}
+	for (int i = pos; i < genotype.len(); i++)
+	{
+		// if character is not alphabetic - error
+		if (!isalpha(genotype[i]))
+		{
+			return GENOPER_OPFAIL;
+		}
+		// if character is uppercase, then convert it to lowercase
+		if (isupper(genotype[i]))
+		{
+			genotype.directWrite()[i] = tolower(genotype[i]);
+			fix = true;
+		}
+	}
+	// if the genotype does not contain any stick - add it
+	if (!hasStick(genotype))
+	{
+		genotype = SString("aaazz") + genotype;
+	}
+	// if there were any changes - save them
+	if (fix)
+	{
+		free(geno);
+		geno = strdup(genotype.c_str());
+	}
+	return GENOPER_OK;
+}
+
+int Geno_fB::mutate(char *&geno, float &chg, int &method)
+{
+	SString genotype(geno);
+	SString strdims;
+	int pos = 0;
+	genotype.getNextToken(pos, strdims, '\n');
+	SString line;
+	genotype.getNextToken(pos, line, '\n');
+	method = roulette(mutationprobs, FB_MUT_COUNT);
+	switch (method)
+	{
+	case FB_SUBSTITUTION:
+	{
+		int rndid = randomN(line.len()); // select random letter from genotype
+		// increment/decrement character - when overflow happens, this method
+		// uses reflect method
+		if (randomN(2) == 0)
+		{
+			if (line[rndid] == 'a') line.directWrite()[rndid] = 'b';
+			else line.directWrite()[rndid] = line[rndid] - 1;
+		}
+		else
+		{
+			if (line[rndid] == 'z') line.directWrite()[rndid] = 'y';
+			else line.directWrite()[rndid] = line[rndid] + 1;
+		}
+		chg = 1.0 / line.len();
+		break;
+	}
+	case FB_INSERTION:
+	{
+		chg = 1.0 / line.len();
+		int rndid = randomN(genotype.len()); // select random insertion point
+		char letter = 'a' + randomN(26);
+		SString result = line.substr(0, rndid);
+		result += letter;
+		result += line.substr(rndid);
+		line = result;
+		break;
+	}
+	case FB_DELETION:
+	{
+		chg = 1.0 / line.len();
+		int rndid = randomN(line.len()); // select random insertion point
+		if (rndid == line.len() - 1)
+		{
+			line = line.substr(0, line.len() - 1);
+		}
+		else
+		{
+			line = line.substr(0, rndid) + line.substr(rndid + 1);
+		}
+		break;
+	}
+	case FB_DUPLICATION:
+	{
+		int rndgene = randomN(fB_GenoHelpers::geneCount(line));
+		int start, end;
+		SString gene = fB_GenoHelpers::getGene(rndgene, line, start, end);
+		if (gene.indexOf("zz", 0) == -1) gene += "zz";
+		chg = (float)gene.len() / line.len();
+		line = gene + line;
+		break;
+	}
+	case FB_TRANSLOCATION:
+	{
+		std::vector<int> cuts(4);
+		for (int i = 0; i < 4; i++)
+		{
+			cuts[i] = randomN(line.len());
+		}
+		std::sort(cuts.begin(), cuts.end());
+		SString first = line.substr(cuts[0], cuts[1] - cuts[0]);
+		SString second = line.substr(cuts[2], cuts[3] - cuts[2]);
+		SString result = line.substr(0, cuts[0]) + second +
+			line.substr(cuts[1], cuts[2] - cuts[1]) + first + line.substr(cuts[3]);
+		line = result;
+		chg = (float)(cuts[3] - cuts[2] + cuts[1] - cuts[0]) / line.len();
+		break;
+	}
+	}
+	SString result = strdims + "\n" + line;
+	free(geno);
+	geno = strdup(result.c_str());
+	return GENOPER_OK;
+}
+
+int Geno_fB::crossOver(char *&g1, char *&g2, float& chg1, float& chg2)
+{
+	SString p1(g1);
+	SString p2(g2);
+
+	int dims1 = 0, dims2 = 0;
+	int pos = 0;
+	SString strdims;
+	p1.getNextToken(pos, strdims, '\n');
+	ExtValue::parseInt(strdims.c_str(), dims1, true, false);
+	SString parent1;
+	p1.getNextToken(pos, parent1, '\n');
+
+	pos = 0;
+	p2.getNextToken(pos, strdims, '\n');
+	ExtValue::parseInt(strdims.c_str(), dims2, true, false);
+
+	if (dims1 != dims2)
+	{
+		return GENOPER_OPFAIL;
+	}
+
+	SString parent2;
+	p2.getNextToken(pos, parent2, '\n');
+
+	SString child1 = "";
+	SString child2 = "";
+
+	switch (roulette(crossoverprobs, FB_XOVER_COUNT))
+	{
+	case FB_GENE_TRANSFER:
+	{
+		// get random gene from first parent
+		int choice = randomN(fB_GenoHelpers::geneCount(parent1));
+		int start, end;
+		SString gene = fB_GenoHelpers::getGene(choice, parent1, start, end);
+		// add this gene to the beginning of the second parent genotype
+		child2 = gene + parent2;
+		chg2 = (float)parent2.len() / (float)child2.len();
+		// do the same for second parent
+		choice = randomN(fB_GenoHelpers::geneCount(parent2));
+		gene = fB_GenoHelpers::getGene(choice, parent2, start, end);
+		child1 = gene + parent1;
+		chg1 = (float)parent1.len() / (float)child1.len();
+		break;
+	}
+	case FB_CROSSING_OVER:
+	{
+		// iterate through all genes of the first parent and assign them
+		// randomly to children
+		for (int i = 0; i < fB_GenoHelpers::geneCount(parent1); i++)
+		{
+			int start, end;
+			SString gene = fB_GenoHelpers::getGene(i, parent1, start, end);
+			if (randomN(2) == 0)
+			{
+				child1 += gene;
+				chg1 += 1.0f;
+			}
+			else
+			{
+				child2 += gene;
+			}
+		}
+		chg1 /= fB_GenoHelpers::geneCount(parent1);
+
+		// do the same with second parent
+		for (int i = 0; i < fB_GenoHelpers::geneCount(parent2); i++)
+		{
+			int start, end;
+			SString gene = fB_GenoHelpers::getGene(i, parent2, start, end);
+			if (randomN(2) == 0)
+			{
+				child1 += gene;
+			}
+			else
+			{
+				child2 += gene;
+				chg2 += 1.0f;
+			}
+		}
+		chg2 /= fB_GenoHelpers::geneCount(parent2);
+		break;
+	}
+	}
+
+	free(g1);
+	free(g2);
+	if (child1.len() > 0 && child2.len() == 0)
+	{
+		child1 = strdims + "\n" + child1;
+		g1 = strdup(child1.c_str());
+		g2 = strdup("");
+	}
+	else if (child2.len() > 0 && child1.len() == 0)
+	{
+		child2 = strdims + "\n" + child2;
+		g1 = strdup(child2.c_str());
+		g2 = strdup("");
+	}
+	else
+	{
+		child1 = strdims + "\n" + child1;
+		child2 = strdims + "\n" + child2;
+		g1 = strdup(child1.c_str());
+		g2 = strdup(child2.c_str());
+	}
+	return GENOPER_OK;
+}
+
+uint32_t Geno_fB::style(const char *geno, int pos)
+{
+	char ch = geno[pos];
+	if (isdigit(ch))
+	{
+		while (pos > 0)
+		{
+			pos--;
+			if (isdigit(geno[pos]) == 0)
+			{
+				return GENSTYLE_CS(0, GENSTYLE_INVALID);
+			}
+		}
+		return GENSTYLE_RGBS(0, 0, 200, GENSTYLE_BOLD);
+	}
+	if (islower(ch) == 0)
+	{
+		return GENSTYLE_CS(0, GENSTYLE_INVALID);
+	}
+	uint32_t style = GENSTYLE_CS(GENCOLOR_TEXT, GENSTYLE_NONE);
+	if (ch == 'a' && pos > 0 && (geno[pos - 1] == 'a' || geno[pos - 1] == '\n'))
+	{
+		style = GENSTYLE_RGBS(0, 200, 0, GENSTYLE_BOLD);
+	}
+	else if (ch == 'z' && pos > 0 && geno[pos - 1] == 'z')
+	{
+		style = GENSTYLE_RGBS(200, 0, 0, GENSTYLE_BOLD);
+	}
+	return style;
+}
Index: cpp/frams/genetics/fB/fB_oper.h
===================================================================
--- cpp/frams/genetics/fB/fB_oper.h	(revision 780)
+++ cpp/frams/genetics/fB/fB_oper.h	(revision 780)
@@ -0,0 +1,47 @@
+#ifndef _FB_OPER_H_
+#define _FB_OPER_H_
+
+#include "../genooperators.h"
+
+/** @name Codes for general fB mutation types */
+//@{
+#define FB_SUBSTITUTION  0 ///<Relative probability of mutation by changing single random letter in genotype (substitution)
+#define FB_INSERTION     1 ///<Relative probability of mutation by inserting characters in random place of genotype
+#define FB_DELETION      2 ///<Relative probability of mutation by deleting random characters in genotype
+#define FB_DUPLICATION   3 ///<Relative probability of mutation by copying single *gene* of genotype and appending it to the beginning of this genotype
+#define FB_TRANSLOCATION 4 ///<Relative probability of mutation by replacing two substrings in genotype
+#define FB_MUT_COUNT     5 ///<Count of mutation types
+//@}
+
+/** @name Codes for fB cross over types */
+//@{
+#define FB_GENE_TRANSFER 0 ///<Relative probability of crossing over by transferring single genes from both parents to beginning of each other
+#define FB_CROSSING_OVER 1 ///<Relative probability of crossing over by random distribution of genes from both parents to both children
+#define FB_XOVER_COUNT   2 ///<Count of crossing over types
+//@}
+
+class Geno_fB : public GenoOperators
+{
+private:
+	bool hasStick(SString genotype);
+
+public:
+	double mutationprobs[FB_MUT_COUNT];
+	double crossoverprobs[FB_XOVER_COUNT];
+
+	Geno_fB();
+
+	int checkValidity(const char *geno, const char *genoname);
+
+	int validate(char *&geno, const char *genoname);
+
+	int mutate(char *&geno, float& chg, int &method);
+
+	int crossOver(char *&g1, char *&g2, float& chg1, float& chg2);
+
+	virtual const char* getSimplest() { return "5\naaazz"; }
+
+	uint32_t style(const char *geno, int pos);
+};
+
+#endif //_FB_OPER_H_
Index: cpp/frams/genetics/fH/fH_conv.cpp
===================================================================
--- cpp/frams/genetics/fH/fH_conv.cpp	(revision 780)
+++ cpp/frams/genetics/fH/fH_conv.cpp	(revision 780)
@@ -0,0 +1,16 @@
+#include "fH_conv.h"
+
+SString GenoConv_fH0::convert(SString &i, MultiMap *map, bool using_checkpoints)
+{
+	fH_Builder builder(0, NULL != map);
+	builder.parseGenotype(i);
+	if (!builder.sticksExist()) return "";
+	Model * m = builder.buildModel(using_checkpoints);
+	if (!m) return SString(); // oops
+	if (NULL != map)
+		// generate to-f0 conversion map
+		m->getCurrentToF0Map(*map);
+	SString gen = m->getF0Geno().getGenes();
+	delete m;
+	return gen;
+}
Index: cpp/frams/genetics/fH/fH_conv.h
===================================================================
--- cpp/frams/genetics/fH/fH_conv.h	(revision 780)
+++ cpp/frams/genetics/fH/fH_conv.h	(revision 780)
@@ -0,0 +1,22 @@
+#ifndef _FH_CONV_H_
+#define _FH_CONV_H_
+
+#include <frams/genetics/genoconv.h>
+#include "fH_general.h"
+
+class GenoConv_fH0 : public GenoConverter
+{
+public:
+	GenoConv_fH0() :GenoConverter()
+	{
+		name = "Similarity encoding";
+
+		in_format = 'H';
+		out_format = '0';
+		mapsupport = 1;
+	}
+	SString convert(SString &i, MultiMap *map, bool using_checkpoints);
+	~GenoConv_fH0() {};
+};
+
+#endif //_FH_CONV_H_
Index: cpp/frams/genetics/fH/fH_general.cpp
===================================================================
--- cpp/frams/genetics/fH/fH_general.cpp	(revision 780)
+++ cpp/frams/genetics/fH/fH_general.cpp	(revision 780)
@@ -0,0 +1,972 @@
+#include <string>
+#include <limits>
+#include <algorithm>
+#include <frams/util/multirange.h>
+#include <utility>
+#include "fH_general.h"
+
+using namespace std;
+#undef max //this macro is not needed here and it clashes with numeric_limits<>::max()
+
+
+
+// Methods for loading handles
+
+const char *fH_part_names[PART_PROPS_COUNT] = { "dn", "fr", "ing", "as" };
+
+const char *fH_joint_names[JOINT_PROPS_COUNT] = { "stif", "rotstif", "stam" };
+
+void fH_Handle::loadProperties(Param par)
+{
+	// loading values for vectors
+	for (int i = 0; i < dimensions; i++)
+	{
+		first[i] = par.getDouble(i);
+		second[i] = par.getDouble(dimensions + i);
+	}
+	obj = par.getSelected();
+}
+
+void fH_Builder::addHandle(fH_Handle *handle)
+{
+	switch (handle->type)
+	{
+	case fHBodyType::JOINT:
+		sticks.push_back((fH_StickHandle*)handle);
+		break;
+	case fHBodyType::NEURON:
+		neurons.push_back((fH_NeuronHandle*)handle);
+		break;
+	case fHBodyType::CONNECTION:
+		connections.push_back((fH_ConnectionHandle*)handle);
+		break;
+	}
+}
+
+// Methods for saving properties of handles in params
+
+void fH_Handle::saveProperties(Param &par)
+{
+	par.select(obj);
+	for (int i = 0; i < dimensions; i++)
+	{
+		par.setDouble(i, first[i]);
+		par.setDouble(dimensions + i, second[i]);
+	}
+}
+
+// Destructor of Builder
+
+fH_Builder::~fH_Builder()
+{
+	for (fH_StickHandle *obj : sticks)
+	{
+		delete obj;
+	}
+	sticks.clear();
+	for (fH_NeuronHandle *obj : neurons)
+	{
+		delete obj;
+	}
+	neurons.clear();
+	for (fH_ConnectionHandle *obj : connections)
+	{
+		delete obj;
+	}
+	connections.clear();
+
+	if (stickparamtab) ParamObject::freeParamTab(stickparamtab);
+	if (neuronparamtab) ParamObject::freeParamTab(neuronparamtab);
+	if (connectionparamtab) ParamObject::freeParamTab(connectionparamtab);
+
+}
+
+// Methods for parsing genotype
+
+void fH_Builder::prepareParams()
+{
+	for (int i = 0; i < dimensions; i++) // preparing first vector fields
+	{
+		string x = "x";
+		x += to_string(i);
+		stickmut.addProperty(NULL, x.c_str(), HANDLE_VECTOR_TYPE, x.c_str(), "", PARAM_CANOMITNAME, 0, -1);
+		neuronmut.addProperty(NULL, x.c_str(), HANDLE_VECTOR_TYPE, x.c_str(), "", PARAM_CANOMITNAME, 0, -1);
+		connectionmut.addProperty(NULL, x.c_str(), HANDLE_VECTOR_TYPE, x.c_str(), "", PARAM_CANOMITNAME, 0, -1);
+
+	}
+	for (int i = 0; i < dimensions; i++) // preparing second vector fields
+	{
+		string y = "y";
+		y += to_string(i);
+		stickmut.addProperty(NULL, y.c_str(), HANDLE_VECTOR_TYPE, y.c_str(), "", PARAM_CANOMITNAME, 0, -1);
+		neuronmut.addProperty(NULL, y.c_str(), HANDLE_VECTOR_TYPE, y.c_str(), "", PARAM_CANOMITNAME, 0, -1);
+		connectionmut.addProperty(NULL, y.c_str(), HANDLE_VECTOR_TYPE, y.c_str(), "", PARAM_CANOMITNAME, 0, -1);
+
+	}
+
+	Part p;
+	for (int i = 0; i < PART_PROPS_COUNT; i++)
+	{
+		stickmut.addProperty(&p.properties().getParamTab()[p.properties().findId(fH_part_names[i]) + p.properties().getGroupCount()], -1);
+	}
+
+	Joint j;
+	for (int i = 0; i < JOINT_PROPS_COUNT; i++)
+	{
+		stickmut.addProperty(&j.properties().getParamTab()[j.properties().findId(fH_joint_names[i]) + j.properties().getGroupCount()], -1);
+	}
+	stickmut.addProperty(NULL, "l", STICKH_LENGTH_TYPE, "length", "", 0, 0, -1);
+
+	Neuro n;
+	neuronmut.addProperty(&n.properties().getParamTab()[n.properties().findId(PE_NEURO_DET) + n.properties().getGroupCount()], -1);
+
+	Param tmp(f0_neuroconn_paramtab, NULL);
+	connectionmut.addProperty(&tmp.getParamTab()[tmp.findId(PE_CONN_WEIGHT) + tmp.getGroupCount()], -1);
+
+	stickparamtab = ParamObject::makeParamTab((ParamInterface *)&stickmut, 0, 0, stickmut.firstMutableIndex());
+	neuronparamtab = ParamObject::makeParamTab((ParamInterface *)&neuronmut, 0, 0, neuronmut.firstMutableIndex());
+	connectionparamtab = ParamObject::makeParamTab((ParamInterface *)&connectionmut, 0, 0, connectionmut.firstMutableIndex());
+}
+
+int fH_Builder::processLine(SString line, int linenumber, int begin, int end)
+{
+	// Firstly, method determines if line describes joint, neuron or neural connection
+	// and prepares corresponding ParamTab
+	fH_Handle *handle = NULL;
+	ParamEntry *tab = NULL;
+	if (line.startsWith("j:")) //joint
+	{
+		handle = new fH_StickHandle(dimensions, begin, end);
+		tab = stickparamtab;
+	}
+	else if (line.startsWith("n:")) //neuron
+	{
+		handle = new fH_NeuronHandle(dimensions, begin, end);
+		tab = neuronparamtab;
+	}
+	else if (line.startsWith("c:")) //connection
+	{
+		handle = new fH_ConnectionHandle(dimensions, begin, end);
+		tab = connectionparamtab;
+	}
+	else // could not determine type of a handle
+	{
+		string message = "Cannot determine handle type at line:  " + to_string(linenumber);
+		logMessage("fH_Builder", "processLine", LOG_ERROR, message.c_str());
+		return begin;
+	}
+	line = line.substr(2); // skip of "j:", "c:" or "n:"
+
+	// Secondly, ParamObject for holding handle properties is created
+	void *obj = ParamObject::makeObject(tab);
+	Param par(tab, obj);
+	par.setDefault();
+	ParamInterface::LoadOptions opts;
+
+	// After preparing Param objects, vector values and body properties are parsed
+	par.load(ParamInterface::FormatSingleLine, line, &opts);
+
+	// If parsing failed, method writes error message and ends processing
+	if (opts.parse_failed)
+	{
+		string message = "Error in parsing handle parameters at line:  " + to_string(linenumber);
+		logMessage("fH_Builder", "processLine", LOG_ERROR, message.c_str());
+		delete handle;
+		ParamObject::freeObject(obj);
+		return begin;
+	}
+
+	// If parsing ended successfully, parsed properties are loaded into handle fields
+	handle->loadProperties(par);
+
+	// In the end, ready handle is stored in an appropriate vector
+	addHandle(handle);
+	return 0;
+}
+
+int fH_Builder::parseGenotype(SString genotype)
+{
+	// Firstly, number of dimensions is parsed
+	int pos = 0;
+	SString numdimensions;
+	genotype.getNextToken(pos, numdimensions, '\n');
+	if (!ExtValue::parseInt(numdimensions.c_str(), dimensions, true, false))
+	{
+		logMessage("fH_Builder", "parseGenotype", LOG_ERROR, "Could not parse number of dimensions");
+		return 1;
+	}
+	if (dimensions < 1)
+	{
+		logMessage("fH_Builder", "parseGenotype", LOG_ERROR, "Number of dimensions cannot be lower than 1");
+		return 1;
+	}
+	SString line;
+	int linenumber = 2;
+
+	// With known number of dimensions ParamTabs for handles are prepared
+	prepareParams();
+
+	// After preparing Builder for parsing, each line is processed with processLine
+	int lastpos = pos;
+	while (genotype.getNextToken(pos, line, '\n'))
+	{
+		if (line.len() > 0)
+		{
+			int res = processLine(line, linenumber, lastpos, pos - 1);
+			if (res != 0)
+			{
+				return res;
+			}
+		}
+		lastpos = pos;
+		linenumber++;
+	}
+	if (sticks.size() == 0)
+	{
+		logMessage("fH_Builder", "parseGenotype", LOG_ERROR, "Genotype does not contain any stick");
+		return 1;
+	}
+	return 0;
+}
+
+// Distance calculations
+
+double fH_Handle::dist(vector<double> left, vector<double> right)
+{
+	double sum = 0;
+	for (unsigned int i = 0; i < left.size(); i++)
+	{
+		sum += (left[i] - right[i]) * (left[i] - right[i]);
+	}
+	return sqrt(sum);
+}
+
+vector<double> fH_Handle::getVectorsAverage()
+{
+	vector<double> result(dimensions, 0);
+	for (int i = 0; i < dimensions; i++)
+	{
+		result[i] = (first[i] + second[i]) / 2;
+	}
+	return result;
+}
+
+double fH_StickHandle::distance(fH_Handle *right)
+{
+	double distance = 0;
+	switch (right->type)
+	{
+	case fHBodyType::JOINT:
+		// distance is computed between second vector of current handle and first
+		// vector of second handle
+		distance = dist(second, right->first);
+		break;
+	case fHBodyType::NEURON:
+	{
+		// if neuron has to be connected to joint, then distance is calculated
+		// between averages of both handles
+		vector<double> avgs = getVectorsAverage();
+		vector<double> avgn = right->getVectorsAverage();
+		distance = dist(avgs, avgn);
+		break;
+	}
+	case fHBodyType::CONNECTION:
+		// it is impossible to calculate distance between Joint and Connection
+		return numeric_limits<double>::quiet_NaN();
+	}
+	return distance;
+}
+
+double fH_NeuronHandle::distance(fH_Handle *right)
+{
+	double distance = 0;
+	switch (right->type)
+	{
+	case fHBodyType::JOINT:
+	{
+		// if neuron has to be connected to joint, then distance is calculated
+		// between averages of both handles
+		vector<double> avgs = right->getVectorsAverage();
+		vector<double> avgn = getVectorsAverage();
+		distance = dist(avgs, avgn);
+		break;
+	}
+	case fHBodyType::CONNECTION:
+		// this calculation is meant for input neuron - it compares second vector
+		// of neuron and first vector of connection
+		distance = dist(second, right->first);
+		break;
+	case fHBodyType::NEURON:
+		// it is impossible to calculate distance between two Neurons
+		return numeric_limits<double>::quiet_NaN();
+	}
+	return distance;
+}
+
+double fH_NeuronHandle::distance(fH_StickHandle *right, bool first)
+{
+	vector<double> avgn = getVectorsAverage();
+	double distance = 0;
+	if (first)
+	{
+		distance = dist(avgn, right->firstparthandle);
+	}
+	else
+	{
+		distance = dist(avgn, right->secondparthandle);
+	}
+	return distance;
+}
+
+double fH_ConnectionHandle::distance(fH_Handle *right)
+{
+	double distance = 0;
+	switch (right->type)
+	{
+	case fHBodyType::NEURON:
+		// this calculation is meant for output neuron - it compares second vector
+		// of connection and first vector of neuron
+		distance = dist(second, right->first);
+		break;
+	case fHBodyType::JOINT:
+	case fHBodyType::CONNECTION:
+		// it is impossible to calculate distance between Connection and other
+		// Connection or Joint
+		return numeric_limits<double>::quiet_NaN();
+	}
+	return distance;
+}
+
+// Creature build functions
+
+Part * fH_StickHandle::createPart(ParamEntry *tab, std::vector<fH_StickHandle *> children, Model *model, bool createmapping)
+{
+	Param par(tab, obj);
+	double partprops[PART_PROPS_COUNT];
+	for (int i = 0; i < PART_PROPS_COUNT; i++)
+	{
+		partprops[i] = par.getDouble(2 * getDimensions() + i);
+	}
+
+	unsigned int stickscount = children.size() + 1;
+
+	MultiRange ranges;
+	ranges.add(begin, end);
+
+	for (fH_StickHandle *child : children)
+	{
+		par.select(child->obj);
+		for (int i = 0; i < PART_PROPS_COUNT; i++)
+		{
+			partprops[i] += par.getDouble(2 * getDimensions() + i);
+		}
+		ranges.add(child->begin, child->end);
+	}
+
+	for (int i = 0; i < PART_PROPS_COUNT; i++)
+	{
+		partprops[i] /= stickscount;
+	}
+
+	Part *newpart = new Part();
+
+	model->addPart(newpart);
+
+	newpart->density = partprops[0];
+	newpart->friction = partprops[1];
+	newpart->ingest = partprops[2];
+	newpart->assim = partprops[3];
+
+	if (createmapping) newpart->addMapping(ranges);
+
+	return newpart;
+}
+
+Joint* fH_StickHandle::createJoint(ParamEntry *tab, Model *model, bool createmapping)
+{
+	Param par(tab, obj);
+	if (firstpart == NULL || secondpart == NULL)
+	{
+		return NULL;
+	}
+	Joint *newjoint = new Joint();
+
+	model->addJoint(newjoint);
+
+	newjoint->stif = par.getDoubleById("stif");
+	newjoint->rotstif = par.getDoubleById("rotstif");
+	newjoint->stamina = par.getDoubleById("stam");
+	newjoint->attachToParts(firstpart, secondpart);
+	if (createmapping) newjoint->addMapping(IRange(begin, end));
+	return newjoint;
+}
+
+void fH_Builder::buildBody()
+{
+	// stickconnections vector holds information about connections between sticks.
+	// Left side of pair should hold pointer to stick that is connected with second
+	// vector, and right side of pair should hold pointer to stick that is connected
+	// with first vector
+	stickconnections.clear();
+
+	// if body consists of single stick, just add it to body
+	if (sticks.size() == 1)
+	{
+		stickconnections.push_back(pair<fH_StickHandle *, fH_StickHandle *>(NULL, sticks[0]));
+		sticksorder.push_back(0);
+		return;
+	}
+
+	vector<bool> remainingsticks(sticks.size(), true);
+
+	// first we find two handles that have minimal distances between their second
+	// and first vector
+	fH_StickHandle *left = sticks[0];
+	fH_StickHandle *right = sticks[1];
+	double mindist = left->distance(right);
+	int leftid = 0;
+	int rightid = 1;
+	for (unsigned int i = 0; i < sticks.size(); i++)
+	{
+		for (unsigned int j = i + 1; j < sticks.size(); j++)
+		{
+			double distance = sticks[i]->distance(sticks[j]);
+			if (distance < mindist)
+			{
+				mindist = distance;
+				left = sticks[i];
+				right = sticks[j];
+				leftid = i;
+				rightid = j;
+			}
+			distance = sticks[j]->distance(sticks[i]);
+			if (distance < mindist)
+			{
+				mindist = distance;
+				left = sticks[j];
+				right = sticks[i];
+				leftid = j;
+				rightid = i;
+			}
+		}
+	}
+
+	// two found handles are the beginning of creature body
+	stickconnections.push_back(pair<fH_StickHandle *, fH_StickHandle *>(NULL, left));
+	stickconnections.push_back(pair<fH_StickHandle *, fH_StickHandle *>(left, right));
+
+	// after selecting two handles as beginning of body, they are marked as used
+	// in the list of remaining sticks
+	remainingsticks[leftid] = false;
+	remainingsticks[rightid] = false;
+
+	sticksorder.push_back(leftid);
+	sticksorder.push_back(rightid);
+
+	// next stick is selected by minimum distance between first vector of its handle
+	// and second vector of any existing StickHandle in body
+	int remaining = sticks.size() - 2;
+	while (remaining > 0)
+	{
+		leftid = -1;
+		rightid = -1;
+		mindist = numeric_limits<double>::max();
+		for (unsigned int i = 0; i < sticks.size(); i++)
+		{
+			// if stick is not already in
+			if (remainingsticks[i])
+			{
+				for (int stickid : sticksorder)
+				{
+					double distance = sticks[stickid]->distance(sticks[i]);
+					if (distance < mindist)
+					{
+						mindist = distance;
+						leftid = stickid;
+						rightid = i;
+					}
+				}
+			}
+		}
+		stickconnections.push_back(pair<fH_StickHandle *, fH_StickHandle *>(sticks[leftid], sticks[rightid]));
+		remainingsticks[rightid] = false;
+		sticksorder.push_back(rightid);
+		remaining--;
+	}
+}
+
+int fH_Builder::developBrain(Model *model, bool createmapping)
+{
+	Param par(neuronparamtab, NULL);
+	// First of all, neurons are attached to body
+	for (fH_NeuronHandle *currneu : neurons)
+	{
+		par.select(currneu->obj);
+		// create Neuro object and set details
+		currneu->neuron = new Neuro();
+		SString det = par.getStringById("d");
+		if (det != "")
+		{
+			currneu->neuron->setDetails(det);
+		}
+		else
+		{
+			currneu->neuron->setDetails("N");
+		}
+
+		// get class of neuron. If class with given name does not exist - return error
+		NeuroClass *nclass = currneu->neuron->getClass();
+		if (!nclass)
+		{
+			SString msg = "NeuroClass given in details \"";
+			msg += det + "\" does not exist";
+			logMessage("fH_Builder", "developBrain", LOG_ERROR, msg.c_str());
+			return -1;
+		}
+		// add neuron to model -> required before attaching to body part
+		model->addNeuro(currneu->neuron);
+		if (nclass->getPreferredLocation() == 2) // attach to Joint
+		{
+			// find stick that has closest average handle to average handle of
+			// neuron
+			double mindist = currneu->distance(sticks[0]);
+			fH_StickHandle *minstick = sticks[0];
+			for (unsigned int i = 1; i < sticks.size(); i++)
+			{
+				double distance = currneu->distance(sticks[i]);
+				if (distance < mindist)
+				{
+					mindist = distance;
+					minstick = sticks[i];
+				}
+			}
+			currneu->neuron->attachToJoint(minstick->joint);
+		}
+		else if (nclass->getPreferredLocation() == 1) // attach to Part
+		{
+			// in the beginning we take first part of first stick to calculate
+			// distance between them as initial minimal distance
+			double mindist = currneu->distance(sticks[0], true);
+			Part *minpart = sticks[0]->firstpart;
+			for (unsigned int i = 0; i < sticks.size(); i++)
+			{
+				// after this we take only second parts of following sticks to
+				// avoid repetition (thats why we start from i = 0)
+				double distance = currneu->distance(sticks[i], false);
+				if (distance < mindist)
+				{
+					mindist = distance;
+					minpart = sticks[i]->secondpart;
+				}
+			}
+			currneu->neuron->attachToPart(minpart);
+		}
+		if (createmapping) currneu->neuron->addMapping(IRange(currneu->begin, currneu->end));
+		model->checkpoint();
+	}
+
+	par.setParamTab(connectionparamtab);
+	// Secondly, connections are created
+	for (fH_ConnectionHandle *currcon : connections)
+	{
+		par.select(currcon->obj);
+		// Connection is created as follows:
+		//   beginneu ---> endneu
+		// distance between beginneu and connection is calculated as distance
+		// between second handle of beginneu and first handle of connection.
+		// This is why calculation is written as beginneu->distance(currcon).
+		// In case of connection and endneu distance between them is calculated
+		// as distance between second handle of connection and first handle of
+		// endneu. This is why calculation is written as currcon->distance(endneu).
+
+		fH_NeuronHandle *beginneu = NULL;
+		double mindist = numeric_limits<double>::max();
+		// find beginning of connection
+		for (fH_NeuronHandle *neuron : neurons)
+		{
+			// These method checked earlier if all neurons have valid classes.
+			// If a neuron does not have output, then it's skipped from comparison.
+			// Otherwise:
+			if (neuron->neuron->getClass()->getPreferredOutput() > 0)
+			{
+				double distance = neuron->distance(currcon);
+				if (distance < mindist)
+				{
+					mindist = distance;
+					beginneu = neuron;
+				}
+			}
+		}
+		// if there was no neuron that could begin connection, then return warning
+		if (!beginneu)
+		{
+			logMessage("fH_Builder", "developBrain", LOG_WARN, "There are no available neurons with outputs, connection could not be established");
+			continue;
+		}
+
+		fH_NeuronHandle *endneu = NULL;
+		mindist = numeric_limits<double>::max();
+		// find ending of connection
+		for (fH_NeuronHandle *neuron : neurons)
+		{
+			// Method checked earlier if all neurons have valid classes.
+			// If neuron does not accept input or all inputs are already connected,
+			// then it's skipped from comparison.
+			// Otherwise:
+			if (neuron->neuron->getClass()->getPreferredInputs() == -1 ||
+				neuron->neuron->getClass()->getPreferredInputs() > neuron->neuron->getInputCount())
+			{
+				double distance = currcon->distance(neuron);
+				if (distance < mindist)
+				{
+					mindist = distance;
+					endneu = neuron;
+				}
+			}
+		}
+		// if there was no neuron that could end connection, then return warning
+		if (!endneu)
+		{
+			logMessage("fH_Builder", "developBrain", LOG_WARN, "There are no available neurons with free inputs, connection could not be established");
+			continue;
+		}
+		endneu->neuron->addInput(beginneu->neuron, par.getDoubleById("w"));
+		if (createmapping) endneu->neuron->addMapping(IRange(currcon->begin, currcon->end));
+		model->checkpoint();
+	}
+	return 0;
+}
+
+Pt3D fH_Builder::getNextDirection(int count, int number)
+{
+	// In order to get evenly distributed sticks coming from the same Part method
+	// uses algorithm for even distribution of points on a sphere. There are several
+	// methods to perform this, usually they are iterative. This method introduced
+	// below offers not fully accurate, yet quite satisfying results. This is
+	// RSZ method (Rakhmanov, Saff and Zhou method), with use of the golden angle.
+	// This method is based on distribution of points along spiral that covers sphere
+	// surface.
+
+	// Following method works partially on spherical coordinates (r and theta is used).
+	// The Z coordinate is from Cartesian coordinate system. The golden angle is used
+	// to "iterate" along spiral, while Z coordinate is used to move down the
+	// sphere.
+
+	double golden_angle = M_PI * (3.0 - sqrt(5));
+	double dz = 2.0 / (double)count;
+	double z = 1 - ((double)number + 0.5) * dz;
+	double r = sqrt(1 - z * z);
+	double theta = golden_angle * number;
+	Pt3D vec;
+	// In the end X and Y coordinates are calculated with current values of
+	// r and theta. Value z is already calculated
+	vec.x = r * cos(theta);
+	vec.y = r * sin(theta);
+	vec.z = z;
+	vec.normalize();
+	return vec;
+}
+
+Orient fH_Builder::getRotationMatrixToFitVector(Pt3D currdir, Pt3D expecteddir)
+{
+	Orient res;
+	// first method normalizes vectors for easy calculations
+	currdir.normalize();
+	expecteddir.normalize();
+	double c = currdir.dotProduct(expecteddir); // dot product of both vectors
+	// if the dot product of both vectors equals 0
+	if (c == 0)
+	{
+		res.x.x = -1;
+		res.x.y = 0;
+		res.x.z = 0;
+
+		res.y.x = 0;
+		res.y.y = -1;
+		res.y.z = 0;
+
+		res.z.x = 0;
+		res.z.y = 0;
+		res.z.z = -1;
+	}
+	Pt3D v = Pt3D(0); // cross product of both vectors
+	v.x = currdir.y * expecteddir.z - currdir.z * expecteddir.y;
+	v.y = currdir.z * expecteddir.x - currdir.x * expecteddir.z;
+	v.z = currdir.x * expecteddir.y - currdir.y * expecteddir.x;
+
+	// Rotation matrix that enables aligning currdir to expecteddir comes from
+	// following calculation
+	// R = I + [v]_x + ([v]_x)^2 / (1+c)
+	// where [v]_x is the skew-symmetric cross-product matrix of v
+	res.x.x = 1 - (v.y * v.y + v.z * v.z) / (1 + c);
+	res.x.y = v.z + (v.x * v.y) / (1 + c);
+	res.x.z = -v.y + (v.x * v.z) / (1 + c);
+	res.y.x = -v.z + (v.x * v.y) / (1 + c);
+	res.y.y = 1 - (v.x * v.x + v.z * v.z) / (1 + c);
+	res.y.z = v.x + (v.y * v.z) / (1 + c);
+	res.z.x = v.y + (v.x * v.z) / (1 + c);
+	res.z.y = -v.x + (v.y * v.z) / (1 + c);
+	res.z.z = 1 - (v.x * v.x + v.y * v.y) / (1 + c);
+
+	return res;
+}
+
+Model* fH_Builder::buildModel(bool using_checkpoints)
+{
+	Model *model = new Model();
+
+	// At first, floating sticks are connected
+	buildBody();
+
+	model->open(using_checkpoints);
+
+	// Secondly, parts and joints are created
+	// For every stick in body, starting with initial
+	Param par(stickparamtab, NULL);
+	for (int currid : sticksorder)
+	{
+		fH_StickHandle *currstick = sticks[currid];
+		fH_StickHandle *parent = NULL;
+		// find parent of current stick - it is first element of pair, in which
+		// current stick is second
+		for (pair<fH_StickHandle *, fH_StickHandle *> conn : stickconnections)
+		{
+			if (conn.second == currstick)
+			{
+				parent = conn.first;
+				break;
+			}
+		}
+
+		// if parent is NULL, then create Part with current stick properties and
+		// location at (0,0,0)
+		if (!parent)
+		{
+			vector<fH_StickHandle *> emptylist;
+			Part *firstpart = currstick->createPart(stickparamtab, emptylist, model, createmapping);
+			firstpart->p = Pt3D(0);
+			currstick->firstpart = firstpart;
+			currstick->firstparthandle = currstick->first; // this is used to calculate later distance between
+			model->checkpoint();
+		}
+		else //otherwise first part of current stick is the second part of previous stick
+		{
+			currstick->firstpart = parent->secondpart;
+			currstick->firstparthandle = parent->secondparthandle;
+		}
+		// position of second part depends on two things
+		//  1. direction of previous joint
+		//  2. how many sticks are connected to the same parent
+		// default direction of growth (without parent) is (1,0,0)
+		Pt3D direction(1, 0, 0);
+		Pt3D secondposition(currstick->firstpart->p);
+		// if parent does exist, then determine how many sticks are connected to
+		// parent and distribute them evenly on a sphere surrounding second part
+		if (parent)
+		{
+			// improved RSZ method creates vectors that starts in
+			// center of sphere (which will act as shared part), so direction
+			// calculated below should point from shared part to previous part
+			// in order to perform proper aligning
+			direction = parent->secondpart->p - parent->firstpart->p;
+			direction.normalize();
+			// determine how many sticks are connected to parent and when connection
+			// between parent and current stick appear
+			int count = 0;
+			int id = -1;
+			for (unsigned int i = 0; i < stickconnections.size(); i++)
+			{
+				if (stickconnections[i].first == parent)
+				{
+					if (stickconnections[i].second == currstick)
+					{
+						id = count;
+					}
+					count++;
+				}
+			}
+			if (id == -1)
+			{
+				logMessage("fH_Builder", "buildModel", LOG_ERROR, "Invalid behaviour");
+				delete model;
+				return NULL;
+			}
+
+			// if there is only one child, then don't change direction - continue
+			// along axis of parent. Otherwise calculate direction of id-th stick
+			// (that is currstick) with use of RSZ/Vogel method of distributing points
+			// evenly on a sphere
+			if (count > 1)
+			{
+				direction = parent->firstpart->p - parent->secondpart->p;
+				direction.normalize();
+				// there has to be count+1 directions, so method needs to generate
+				// count+1 evenly distributed points on a sphere to make vectors
+				// from point (0,0,0) to those points. First generated vector
+				// will act as parent joint direction vector
+				Pt3D sphere0direction = getNextDirection(count + 1, 0);
+
+				// First generated vector needs to be aligned to parent vector
+				Orient rotmatrix = getRotationMatrixToFitVector(sphere0direction, direction);
+
+				// Calculation of direction from sphere for currstick
+				direction = getNextDirection(count + 1, id + 1);
+				// Rotation matrix aligning
+				direction = rotmatrix.transform(direction);
+				direction.normalize();
+			}
+		}
+
+		// calculate second position
+		par.select(currstick->obj);
+		secondposition += direction * par.getDoubleById("l");
+
+		// find every stick connected to current stick in order to calculate second
+		// part properties
+		vector<fH_StickHandle *> children;
+		currstick->secondparthandle = currstick->second;
+		for (pair<fH_StickHandle *, fH_StickHandle *> conn : stickconnections)
+		{
+			if (conn.first == currstick)
+			{
+				children.push_back(conn.second);
+				for (int i = 0; i < dimensions; i++)
+				{
+					currstick->secondparthandle[i] += conn.second->first[i];
+				}
+			}
+		}
+		// create part from current stick and other sticks connected to this part
+		Part *secondpart = currstick->createPart(stickparamtab, children, model, createmapping);
+		secondpart->p = secondposition;
+		currstick->secondpart = secondpart;
+		double count = (double)children.size() + 1;
+		for (int i = 0; i < dimensions; i++)
+		{
+			currstick->secondparthandle[i] /= count;
+		}
+
+		//after creating second part connect two parts with joint
+		Joint * joint = currstick->createJoint(stickparamtab, model, createmapping);
+		if (!joint)
+		{
+			logMessage("fH_Builder", "buildModel", LOG_ERROR, "Joint cannot be created");
+			delete model;
+			return NULL;
+
+		}
+		currstick->joint = joint;
+		model->checkpoint();
+	}
+	// after creating a body, attach neurons to body and link them according to
+	// connections
+	if (developBrain(model, createmapping) == -1)
+	{
+		delete model;
+		return NULL;
+	}
+	model->close();
+	return model;
+}
+
+int fH_Builder::removeNeuronsWithInvalidClasses()
+{
+	int count = neurons.size();
+	if (count == 0)
+	{
+		return 0;
+	}
+	vector<fH_NeuronHandle *>::iterator it = neurons.begin();
+	Param par(neuronparamtab, NULL);
+	while (it != neurons.end())
+	{
+		par.select((*it)->obj);
+		SString det = par.getStringById("d");
+		if (det == "")
+		{
+			it++;
+		}
+		else
+		{
+			Neuro *neu = new Neuro();
+			neu->setDetails(det);
+			if (neu->getClass())
+			{
+				it++;
+			}
+			else
+			{
+				fH_NeuronHandle *tmp = (*it);
+				it = neurons.erase(it);
+				delete tmp;
+			}
+			delete neu;
+		}
+
+	}
+	return count - neurons.size();
+}
+
+SString fH_Builder::toString()
+{
+	SString result = "";
+	result += to_string(dimensions).c_str();
+	result += "\n";
+	// first method stringifies parts
+	Param par(stickparamtab, NULL);
+	void *def = ParamObject::makeObject(stickparamtab);
+	par.select(def);
+	par.setDefault();
+	for (fH_StickHandle *currstick : sticks)
+	{
+		currstick->saveProperties(par);
+		SString props;
+		par.saveSingleLine(props, def, true, false);
+		result += "j:";
+		result += props;
+	}
+	ParamObject::freeObject(def);
+	par.setParamTab(neuronparamtab);
+	def = ParamObject::makeObject(neuronparamtab);
+	par.select(def);
+	par.setDefault();
+	for (fH_NeuronHandle *currneuron : neurons)
+	{
+		currneuron->saveProperties(par);
+		SString props;
+		par.saveSingleLine(props, def, true, false);
+		result += "n:";
+		result += props;
+	}
+	ParamObject::freeObject(def);
+	par.setParamTab(connectionparamtab);
+	def = ParamObject::makeObject(connectionparamtab);
+	par.select(def);
+	par.setDefault();
+	for (fH_ConnectionHandle *currconnection : connections)
+	{
+		currconnection->saveProperties(par);
+		SString props;
+		par.saveSingleLine(props, def, true, false);
+		result += "c:";
+		result += props;
+	}
+	ParamObject::freeObject(def);
+	return result;
+}
+
+ParamEntry* fH_Builder::getParamTab(fHBodyType type)
+{
+	switch (type)
+	{
+	case fHBodyType::JOINT:
+		return stickparamtab;
+		break;
+	case fHBodyType::NEURON:
+		return neuronparamtab;
+		break;
+	default:
+		return connectionparamtab;
+		break;
+	}
+}
Index: cpp/frams/genetics/fH/fH_general.h
===================================================================
--- cpp/frams/genetics/fH/fH_general.h	(revision 780)
+++ cpp/frams/genetics/fH/fH_general.h	(revision 780)
@@ -0,0 +1,453 @@
+#ifndef _FH_GENERAL_H_
+#define _FH_GENERAL_H_
+
+#include <vector>
+#include "../../model/modelparts.h"
+#include <frams/util/sstring.h>
+#include <frams/param/mutableparam.h>
+#include <frams/param/param.h>
+#include <frams/model/model.h>
+#include <frams/param/paramobj.h>
+
+/** @name Constants used in fH methods */
+//@{
+#define HANDLE_VECTOR_TYPE "f -1.0 1.0 0.0" ///<Vector values type definition
+#define STICKH_LENGTH_TYPE "f 0.001 1.999 1.0" ///<Length of stick handle. Minimum should not be equal to 0, because calculating direction of next part from current stick with length 0 would be impossible
+#define PART_PROPS_COUNT   4 ///<Count of part properties
+#define JOINT_PROPS_COUNT  3 ///<Count of joint properties
+#define PE_NEURO_DET       "d" ///<Id of details type definition in f0_neuro_paramtab
+#define PE_CONN_WEIGHT     "w" ///<Id of weight type definition in f0_neuroconn_paramtab
+//@}
+
+extern const char *fL_part_names[];
+
+extern const char *fL_joint_names[];
+
+class Geno_fH; // from oper.fH
+
+/// Determines to which class Handle belongs.
+enum fHBodyType
+{
+	JOINT, ///<joint type
+	NEURON, ///<neuron type
+	CONNECTION ///<connection type
+};
+
+/**
+ * Base class for all kinds of handles in fH encoding.Each line of fH genotype
+ * describes a handle. Handles can be divided into joints, neurons and
+ * connections. Every handle is described with 2 vectors of 'dimensions' values.
+ * During process of body development those vectors are compared in order to
+ * connect sticks of creature, connect neurons to body parts, and create connections
+ * between neurons.
+ */
+class fH_Handle
+{
+private:
+	int dimensions; ///< number of elements in each vector of a handle. This is read-only field
+protected:
+	static double dist(std::vector<double> left, std::vector<double> right);
+public:
+	fHBodyType type; ///< type of handle, can be stick, neural connection or neuron
+	std::vector<double> first; ///< first vector of handle
+	std::vector<double> second; ///< second vector of handle
+
+	int begin; ///<begin of handle definition in genotype, used in mapping
+	int end; ///<end of handle definition in genotype, used in mapping
+
+	void *obj; ///<pointer to all properties that can be accessed via Param object
+
+	/**
+	 * Prepares memory for both handle vectors, according to value in 'dimensions'
+	 * variable.
+	 * @param type type of handle
+	 * @param dimensions number of elements in each vector of handle
+	 */
+	fH_Handle(fHBodyType type, int dimensions, int begin, int end) :
+		dimensions(dimensions),
+		type(type),
+		first(dimensions, 0),
+		second(dimensions, 0),
+		begin(begin),
+		end(end),
+		obj(NULL)
+	{}
+
+	int getDimensions() { return dimensions; }
+
+	virtual ~fH_Handle() { if (obj) ParamObject::freeObject(obj); }
+
+	/**
+	 * Loads properties of handle after parsing them from genotype.
+	 * All properties are available from Param object. This base method only
+	 * loads values for handle vectors. Other properties, like stiffness for
+	 * stick require overloading this method. The method presumes that values
+	 * for vectors are first in ParamTab.
+	 * @param par Param object holding parsed properties from genotype
+	 */
+	void loadProperties(Param par);
+
+	/**
+	 * Saves properties from handle into ParamObject selected by Param.
+	 * @param par Param object that has needed paramtab configured and selected ParamObject
+	 */
+	void saveProperties(Param &par);
+
+	/**
+	 * Calculates distance between current and given handle. Method should
+	 * be reimplemented in inheriting classes in order to provide valid values.
+	 * @param right second handle to which distance is calculated
+	 * @return distance between this and second handle
+	 */
+	virtual double distance(fH_Handle * right) = 0;
+
+
+	/**
+	 * Computes average of first and second vector of Handle.
+	 * @return vector with average values from both handle vectors
+	 */
+	std::vector<double> getVectorsAverage();
+};
+
+/**
+ * Class representing stick handle of fH encoding. Every stick has following properties:
+ *  - double stif -  joint property of a stick representing stiffness
+ *  - double rotstif -  joint property of a stick representing rotation stiffness
+ *  - double stamina -  joint property of a stick representing stamina
+ *  - double density -  parts property of a stick representing density
+ *  - double friction -  parts property of a stick representing friction
+ *  - double ingest -  parts property of a stick representing ingestion
+ *  - double assimilation -  parts property of a stick representing assimilation
+ *  - double length -  length of a stick
+ */
+class fH_StickHandle : public fH_Handle
+{
+public:
+	Part *firstpart; ///< first part of created stick
+	Part *secondpart; ///< second part of created stick
+	Joint *joint; ///< joint connecting both parts of created stick
+
+	// vectors used for connecting neurons to parts
+	vector<double> firstparthandle; ///< vector for first part. Used in connecting neurons to parts. Inherited from previous stick
+	vector<double> secondparthandle; ///< vector for second part. Used in connecting neurons to parts. Vector is calculated as average of second vector in current stick handle and first vector of all sticks connected to this part
+
+	/**
+	 * This constructor initializes each property of joint and parts of a stick
+	 * with default values represented in f0 genotype.
+	 * @param dimensions number of elements in each vector of handle
+	 */
+	fH_StickHandle(int dimensions, int begin, int end) :
+		fH_Handle(fHBodyType::JOINT, dimensions, begin, end),
+		firstparthandle(dimensions, 0),
+		secondparthandle(dimensions, 0)
+	{
+		firstpart = secondpart = NULL;
+		joint = NULL;
+	}
+
+	/**
+	 * Calculates distance between current and given handle. Distance from
+	 * StickHandle to StickHandle is calculated as distance between second
+	 * vector of current handle and first vector of given handle.
+	 * Distance from StickHandle to NeuronHandle is designed only for neurons
+	 * that need to be attached to joints and is computed as distance between
+	 * average of first and second vector for each handle.
+	 * Distance between StickHandle and ConnectionHandle cannot be calculated.
+	 * @param right second handle to which distance is calculated
+	 * @return Euclidean distance between two vectors
+	 */
+	double distance(fH_Handle *right);
+	/**
+	 * Creates new part from current stick and its children. Part properties
+	 * are calculated as mean of properties of current stick and properties
+	 * of other sticks that share this part. Method requires model to add
+	 * created part and map genotype responsible for this part.
+	 * @param tab Param tab object for access to variables
+	 * @param children stick handles that share created part
+	 * @param model pointer to model that is being developed in buildModel method
+	 * @param createmapping true if mapping should be added to created Model element
+	 * @return created part
+	 */
+	Part *createPart(ParamEntry *tab, std::vector<fH_StickHandle *> children, Model *model, bool createmapping);
+
+	/**
+	 * Creates new joint from current stick. Method should be called after
+	 * creating parts with createPart method. Method sets properties of joint
+	 * according to genotype values and connects both parts of stick.
+	 * @param tab Param tab object for access to variables
+	 * @param model pointer to model that is being developed in buildModel method
+	 * @param createmapping true if mapping should be added to created Model element
+	 * @return pointer to created joint or NULL if one or both of stick parts were not created
+	 */
+	Joint *createJoint(ParamEntry *tab, Model *model, bool createmapping);
+
+	~fH_StickHandle() {}
+};
+
+/**
+ * Class representing neuron handle of fH encoding. It has one property, called
+ * details.
+ */
+class fH_NeuronHandle : public fH_Handle
+{
+public:
+	Neuro *neuron; ///< pointer to created neuron from handle
+
+	fH_NeuronHandle(int dimensions, int begin, int end) :
+		fH_Handle(fHBodyType::NEURON, dimensions, begin, end)
+	{
+		neuron = NULL;
+	}
+
+	/**
+	 * Calculates distance between current and given handle.
+	 * Distance from StickHandle to NeuronHandle is designed only for neurons
+	 * that need to be attached to joints and is computed as distance between
+	 * average of first and second vector for each handle.
+	 * Distance from current NeuronHandle to a given ConnectionHandle is used
+	 * only for neurons that should act as inputs. Distance is calculated
+	 * as Euclidean distance between second vector of NeuronHandle and first
+	 * vector of ConnectionHandle. In order to calculate distance between
+	 * connection and output neuron use distance function implemented in
+	 * ConnectionHandle class.
+	 * Distance between two NeuronHandles cannot be calculated
+	 * @param right second handle to which distance is calculated
+	 * @return Euclidean distance between two vectors
+	 */
+	double distance(fH_Handle *right);
+
+	/**
+	 * Calculate distance between neuron and given part.
+	 * In this case distance between neuron and part is calculated as Euclidean
+	 * distance between average of two vectors of NeuronHandle and average of
+	 * second vector of given StickHandle and all first vectors of StickHandles
+	 * that share this part with given StickHandle. First parameter determines
+	 * if method should calculate distance for first or second part.
+	 * @param right second handle to which distance is calculated
+	 * @param first true if method should calculate distance between current neuron and first part of StickHandle, false if method should calculate distance between current neuron and second part
+	 * @return Euclidean distance between two vectors
+	 */
+	double distance(fH_StickHandle *right, bool first);
+	~fH_NeuronHandle() {}
+};
+
+/**
+ * Class representing connection handle of fH encoding. It has one property, called
+ * weight.
+ */
+class fH_ConnectionHandle : public fH_Handle
+{
+public:
+
+	fH_ConnectionHandle(int dimensions, int begin, int end) :
+		fH_Handle(fHBodyType::CONNECTION, dimensions, begin, end) {}
+
+	/**
+	 * This method can calculate distance only between current connection and
+	 * NeuronHandle.
+	 * Distance from current ConnectionHandle to a given NeuronHandle is used
+	 * only for neurons that should act as outputs. Distance is calculated
+	 * as Euclidean distance between second vector of ConnectionHandle and first
+	 * vector of NeuronHandle. In order to calculate distance between
+	 * input neuron and connection use distance function implemented in
+	 * NeuronHandle class.
+	 * @param right second handle to which distance is calculated
+	 * @return Euclidean distance between two vectors
+	 */
+	double distance(fH_Handle *right);
+
+	~fH_ConnectionHandle() {}
+};
+
+/**
+ * Main class for parsing fH genotypes. It reads all genotype, prepares
+ * all objects required for parsing it and holds prepared handles for further
+ * development of a creature.
+ */
+class fH_Builder
+{
+private:
+	friend class ::Geno_fH; // Geno_fH class requires access to private fields of Builder for performing mutations and cross-over
+	int dimensions; ///<number of dimensions for this genotype
+	bool createmapping; ///<determines if mapping should be created or not
+
+	std::vector<fH_StickHandle*> sticks; ///<vector holding sticks of a genotype
+	std::vector<fH_NeuronHandle*> neurons; ///<vector holding neurons of a genotype
+	std::vector<fH_ConnectionHandle*> connections; ///<vector holding connections of a genotype
+
+	MutableParam stickmut; ///<object holding all generated properties for sticks in genotype
+	MutableParam neuronmut; ///<object holding all generated properties for neurons in genotype
+	MutableParam connectionmut; ///<object holding all generated properties for connections in genotype
+
+	ParamEntry *stickparamtab; ///< ParamTab generated from stickmut
+	ParamEntry *neuronparamtab; ///< ParamTab generated from neuronmut
+	ParamEntry *connectionparamtab; ///< ParamTab generated from connectionmut
+
+	std::vector<std::pair<fH_StickHandle *, fH_StickHandle *>> stickconnections; ///< this vector holds all connections determined by development of fH body in method buildBody
+	std::vector<int> sticksorder; ///< vector holds ids of StickHandles in 'sticks' vector in order of adding sticks to a body during buildBody
+
+	/**
+	 * Processes single line of genotype. This line should begin with
+	 * "j:", "n:" or "c:". Otherwise it will be considered as error.
+	 * @param line line of a genotype
+	 * @param linenumber number of line in genotype, required for error messages
+	 * @return 0 if processing was successful, 1 if type of handle could not be determined or loading of properties failed
+	 */
+	int processLine(SString line, int linenumber, int begin, int end);
+
+	/**
+	 * Prepares ParamTab objects according to a given number of dimensions.
+	 */
+	void prepareParams();
+
+	/**
+	 * Connects floating sticks into consistent body. It does not create Model,
+	 * it only fills 'stickconnections' with pairs of connected sticks and
+	 * 'stickorder' with order of adding sticks to body.
+	 */
+	void buildBody();
+
+	/**
+	 * Creates neurons and neural connections between them, according to
+	 * NeuronHandles and ConnectionHandles. Needs to be called after developing
+	 * body with buildBody function and adding parts and joints to Model given
+	 * in input parameter of method. Method connects neurons, attaches them
+	 * to parts or joints and save mappings from genotype to model.
+	 * @param model currently created model by Builder with parts and joints created by sticks in buildBody
+	 * @param createmapping true if mapping should be added to created Model element
+	 * @return 0 if brain was developed successfully, -1 if one of neurons had invalid class
+	 */
+	int developBrain(Model *model, bool createmapping);
+
+	/**
+	 * Calculates direction in which new joint should develop. When there
+	 * is more than one joint coming out from current part, all parts with
+	 * joints starting from the same point should be as far away from each
+	 * other as possible. This problem can be defined as even distribution
+	 * of points on a sphere. This method, called improved RSZ method offers
+	 * non-iterative and fast calculation of such directions. Name of method
+	 * comes from creators Rakhmanov, Saff and Zhou.
+	 * Method works partially on spherical coordinates (r and theta is used).
+	 * Z coordinate is from Cartesian coordinate system. Golden angle is used
+	 * to "iterate" along spiral, while Z coordinate is used to move down the
+	 * sphere.
+	 * Method requires two parameters - count of all joints that share same
+	 * part, and number of current joint to calculate.
+	 *
+	 * Full description of algorithm is in article:
+	 * Mary K. Arthur, "Point Picking and Distributing on the Disc and Sphere",
+	 * Army Research Laboratory, July 2015
+	 *
+	 * @param count number of joints that share same sphere
+	 * @param number number of joint in array of joints
+	 * @return direction where new joint should point
+	 */
+	static Pt3D getNextDirection(int count, int number);
+
+	/** TODO move to the Orient class?
+	 * Creates rotation matrix that aligns current vector to some expected
+	 * vector. Method is used with RSZ method. When method calculates n+1
+	 * evenly distributed points (that will act as ends of vectors representing
+	 * n joints directions), 0 point is acting as direction of previous joint.
+	 * In order to properly use directions of new joints they need to be
+	 * multiplied by rotation matrix that aligns direction represented by
+	 * 0 point to direction pointing from shared part to second part of parent
+	 * joint.
+	 * Let:
+	 * - cross product of a and b
+	 * \f[ v = a \times b \f]
+	 * - sine of angle
+	 * \f[ s = ||v|| \f]
+	 * - cosine of angle
+	 * \f[ c = a \cdot b \f]
+	 * - skew-symmetric cross-product matrix of \f$ v \f$
+	 * \f[
+	 * [v]_\times =
+	 * \begin{bmatrix}
+	 * 0 & -v_3 & v_2 \\
+	 * v_3 & 0 & -v_1 \\
+	 * -v_2 & v_1 & 0
+	 * \end{bmatrix}
+	 * \f]
+	 *
+	 * Then rotation matrix is following:
+	 * \f[ R = I + [v]_{\times} + [v]_{\times}^{2}\frac{1}{1+c} \f]
+	 * @param currdir current direction of vector
+	 * @param expecteddir where vector should point
+	 * @return rotation matrix
+	 */
+	static Orient getRotationMatrixToFitVector(Pt3D currdir, Pt3D expecteddir);
+
+public:
+	fH_Builder(int dimensions = 0, bool createmapping = true) : dimensions(dimensions),
+		createmapping(createmapping),
+		stickmut("Stick handle", "Properties"),
+		neuronmut("Neuron handle", "Properties"),
+		connectionmut("Connection handle", "Properties")
+	{
+		stickparamtab = neuronparamtab = connectionparamtab = NULL;
+		if (dimensions > 0)
+		{
+			prepareParams();
+		}
+	}
+
+	~fH_Builder();
+
+	/**
+	 * Parses fH genotype, starting with line holding number of dimensions for
+	 * this genotype. Secondly, it prepares ParamTabs for sticks, neurons and
+	 * connections in order to parse following lines. During parsing method
+	 * creates handle for each nonempty line and stores in vector matching
+	 * its type.
+	 * @param genotype fH genotype
+	 * @return 0 if processing was successful, 1 if parsing of dimensions went wrong or one of genotype lines could not be parsed
+	 */
+	int parseGenotype(SString genotype);
+
+	/**
+	 * Removes neurons with invalid class names. This method is used in
+	 * repairing the genotype. It should be called before building Model,
+	 * otherwise Model will return failure and validation will show error.
+	 * @return number of neurons removed from genotype
+	 */
+	int removeNeuronsWithInvalidClasses();
+
+	/**
+	 * Builds model for current fH genotype. Should be called after parseGenotype
+	 * method.
+	 * @param using_checkpoints true if checkpoints should be generated, false otherwise
+	 */
+	Model* buildModel(bool using_checkpoints);
+
+	/**
+	 * Converts Handle objects into strings with validated properties by
+	 * Paramtab helper classes. To ensure toString method will return repaired
+	 * genotype methods parseGenotype(...), remoeNeuronsWithInvalidClasses()
+	 * and buildModel(...) should be called. If buildModel will return NULL
+	 * then toString method will not return proper output.
+	 * @return genotype held in Builder, with minor repairs of properties and removed neurons with invalid class names
+	 */
+	SString toString();
+
+	/**
+	 * Adds handle to proper handles vector.
+	 * @param handle handle to add
+	 */
+	void addHandle(fH_Handle *handle);
+
+	/**
+	 * Checks if there is any stick in creature.
+	 * @return true if there is at least one stick, false otherwise
+	 */
+	bool sticksExist() { return sticks.size() > 0; }
+
+	/**
+	 * Returns Param for a given handle type.
+	 * @param type type of handle
+	 * @return proper Param object
+	 */
+	ParamEntry* getParamTab(fHBodyType type);
+};
+
+#endif //_FH_GENERAL_H_
Index: cpp/frams/genetics/fH/fH_oper.cpp
===================================================================
--- cpp/frams/genetics/fH/fH_oper.cpp	(revision 780)
+++ cpp/frams/genetics/fH/fH_oper.cpp	(revision 780)
@@ -0,0 +1,486 @@
+#include "fH_oper.h"
+
+#include <common/loggers/loggers.h>
+#include <frams/param/syntparam.h>
+#include <frams/param/paramobj.h>
+
+#define FIELDSTRUCT Geno_fH
+
+static ParamEntry GENOfHparam_tab[] =
+{
+	{ "Genetics: fH", 1, FH_OPCOUNT + FH_ADD_OPCOUNT, },
+	{ "fH_mut_addition", 0, 0, "Add element", "f 0 1 0.3", FIELD(operations[FH_ADD]), "Probability of adding new element to genotype", },
+	{ "fH_mut_add_joint", 0, 0, " - add joint", "f 0 1 0.33", FIELD(addoperations[FH_ADD_STICK]), "Probability of adding new stick handle", },
+	{ "fH_mut_add_neuron", 0, 0, " - add neuron", "f 0 1 0.33", FIELD(addoperations[FH_ADD_NEURO]), "Probability of adding new neuron handle", },
+	{ "fH_mut_add_connection", 0, 0, " - add connection", "f 0 1 0.33", FIELD(addoperations[FH_ADD_CONN]), "Probability of adding new connection handle", },
+	{ "fH_mut_deletion", 0, 0, "Delete element", "f 0 1 0.1", FIELD(operations[FH_DEL]), "Probability of removing element from genotype", },
+	{ "fH_mut_handle", 0, 0, "Modify vectors of handles", "f 0 1 0.3", FIELD(operations[FH_HANDLE]), "Probability of changing values in vectors of handle", },
+	{ "fH_mut_property", 0, 0, "Modify properties of handles", "f 0 1 0.3", FIELD(operations[FH_PROP]), "Probability of changing properties of handles", },
+	{ 0, },
+};
+
+#undef FIELDSTRUCT
+
+Geno_fH::Geno_fH()
+{
+	par.setParamTab(GENOfHparam_tab);
+	par.select(this);
+	par.setDefault();
+	supported_format = 'H';
+}
+
+int Geno_fH::checkValidity(const char* geno, const char* genoname)
+{
+	LoggerToMemory eh(LoggerBase::Enable | LoggerToMemory::StoreAllMessages, LOG_WARN);
+	fH_Builder builder;
+	// during parsing method tries to approximate error position
+	int err = builder.parseGenotype(geno);
+	if (err != 0)
+	{
+		return err;
+	}
+	if (builder.sticks.size() == 0)
+	{
+		return 1;
+	}
+	int amount = builder.removeNeuronsWithInvalidClasses();
+	if (amount > 0)
+	{
+		return 1;
+	}
+	return 0;
+}
+
+int Geno_fH::validate(char *&geno, const char *genoname)
+{
+	// 'eh' variable is used for "hiding" error and warning messages generated during fH
+	// genotype parsing
+	LoggerToMemory eh(LoggerBase::Enable | LoggerToMemory::StoreAllMessages, LOG_WARN);
+	fH_Builder builder;
+	int err = builder.parseGenotype(geno);
+	// if parsing failed, then it is impossible to repair genotype
+	if (err != 0)
+	{
+		return GENOPER_OPFAIL;
+	}
+	// method removes definitions of neurons that have invalid genotype
+	int amount = builder.removeNeuronsWithInvalidClasses();
+	// if there were any warnings, then rewrite genotype
+	if (eh.getWarningCount() > 0 || amount > 0)
+	{
+		free(geno);
+		geno = strdup(builder.toString().c_str());
+	}
+	return GENOPER_OK;
+}
+
+int Geno_fH::crossOver(char *&g1, char *&g2, float& chg1, float& chg2)
+{
+	fH_Builder *parent1 = new fH_Builder();
+	fH_Builder *parent2 = new fH_Builder();
+
+	// first of all, both parents need to be parsed. If parents cannot be
+	// parsed or their dimensionality differs, then method returns GENOPER_OPFAIL
+	if (parent1->parseGenotype(g1) != 0 || parent2->parseGenotype(g2) != 0 ||
+		parent1->dimensions != parent2->dimensions)
+	{
+		return GENOPER_OPFAIL;
+	}
+
+	// Builders for children are defined
+	fH_Builder *child1 = new fH_Builder();
+	fH_Builder *child2 = new fH_Builder();
+
+	child1->dimensions = child2->dimensions = parent1->dimensions;
+
+	// Children Params are prepared for incoming handles
+	child1->prepareParams();
+	child2->prepareParams();
+
+	int child1count = 0;
+	int child2count = 0;
+
+	for (unsigned int i = 0; i < parent1->sticks.size(); i++)
+	{
+		if (randomN(2) == 0)
+		{
+			child1->sticks.push_back(parent1->sticks[i]);
+			child1count++;
+		}
+		else
+		{
+			child2->sticks.push_back(parent1->sticks[i]);
+		}
+	}
+
+	for (unsigned int i = 0; i < parent2->sticks.size(); i++)
+	{
+		if (randomN(2) == 0)
+		{
+			child1->sticks.push_back(parent2->sticks[i]);
+		}
+		else
+		{
+			child2->sticks.push_back(parent2->sticks[i]);
+			child2count++;
+		}
+	}
+
+	// if one of children does not have any sticks, then other child takes
+	// everything else
+	bool skip1 = false;
+	bool skip2 = false;
+	if (child1->sticks.size() == 0) skip1 = true;
+	if (child2->sticks.size() == 0) skip2 = true;
+
+	for (unsigned int i = 0; i < parent1->neurons.size(); i++)
+	{
+		if ((randomN(2) == 0 || skip2) && !skip1)
+		{
+			child1->neurons.push_back(parent1->neurons[i]);
+			child1count++;
+		}
+		else
+		{
+			child2->neurons.push_back(parent1->neurons[i]);
+		}
+	}
+
+	for (unsigned int i = 0; i < parent2->neurons.size(); i++)
+	{
+		if ((randomN(2) == 0 || skip2) && !skip1)
+		{
+			child1->neurons.push_back(parent2->neurons[i]);
+		}
+		else
+		{
+			child2->neurons.push_back(parent2->neurons[i]);
+			child2count++;
+		}
+	}
+
+	for (unsigned int i = 0; i < parent1->connections.size(); i++)
+	{
+		if ((randomN(2) == 0 || skip2) && !skip1)
+		{
+			child1->connections.push_back(parent1->connections[i]);
+			child1count++;
+		}
+		else
+		{
+			child2->connections.push_back(parent1->connections[i]);
+		}
+	}
+
+	for (unsigned int i = 0; i < parent2->connections.size(); i++)
+	{
+		if ((randomN(2) == 0 || skip2) && !skip1)
+		{
+			child1->connections.push_back(parent2->connections[i]);
+		}
+		else
+		{
+			child2->connections.push_back(parent2->connections[i]);
+			child2count++;
+		}
+	}
+
+	chg1 = (float)child1count / (parent1->sticks.size() + parent1->neurons.size() + parent1->connections.size());
+	chg2 = (float)child2count / (parent2->sticks.size() + parent2->neurons.size() + parent2->connections.size());
+
+	free(g1);
+	free(g2);
+	if (skip1 && !skip2)
+	{
+		g1 = strdup(child2->toString().c_str());
+		g2 = strdup("");
+	}
+	else if (!skip1 && skip2)
+	{
+		g1 = strdup(child1->toString().c_str());
+		g2 = strdup("");
+	}
+	else
+	{
+		g1 = strdup(child1->toString().c_str());
+		g2 = strdup(child2->toString().c_str());
+	}
+
+	child1->sticks.clear();
+	child1->neurons.clear();
+	child1->connections.clear();
+
+	child2->sticks.clear();
+	child2->neurons.clear();
+	child2->connections.clear();
+
+	delete parent1;
+	delete parent2;
+	delete child1;
+	delete child2;
+
+	return GENOPER_OK;
+}
+
+int Geno_fH::mutate(char *&geno, float& chg, int &method)
+{
+	// method only needs to parse genotype - it won't create Model
+	fH_Builder *creature = new fH_Builder();
+	if (creature->parseGenotype(geno) != 0)
+	{
+		return GENOPER_OPFAIL;
+	}
+
+	// used for computing chg
+	unsigned int sumgenes = creature->sticks.size() + creature->neurons.size() + creature->connections.size();
+
+	// if there is only one element in genotype (stick), then deletion would end
+	// up with wrong genotype. If this occurs, deletion is skipped (deletion is
+	// last possible operation listed in #defines, so fH_OPCOUNT - 1 will skip
+	// this mutation, and roulette method will normalize the rest of probabilities)
+	int skipdelete = 0;
+	if (creature->sticks.size() + creature->neurons.size() + creature->connections.size() == 1)
+	{
+		skipdelete = 1;
+	}
+
+	method = roulette(operations, FH_OPCOUNT - skipdelete);
+	switch (method) {
+	case FH_ADD:
+	{
+		fH_Handle *handle = NULL;
+		method = FH_OPCOUNT + roulette(addoperations, FH_ADD_OPCOUNT);
+		switch (method - FH_OPCOUNT)
+		{
+		case FH_ADD_STICK:
+		{
+			handle = new fH_StickHandle(creature->dimensions, 0, 0);
+			createHandleVectors(handle, creature->stickparamtab, creature->dimensions);
+			break;
+		}
+		case FH_ADD_NEURO:
+		{
+			handle = new fH_NeuronHandle(creature->dimensions, 0, 0);
+			createHandleVectors(handle, creature->neuronparamtab, creature->dimensions);
+			break;
+		}
+		case FH_ADD_CONN:
+		{
+			handle = new fH_ConnectionHandle(creature->dimensions, 0, 0);
+			createHandleVectors(handle, creature->connectionparamtab, creature->dimensions);
+			break;
+		}
+		}
+		creature->addHandle(handle);
+		break;
+	}
+	case FH_HANDLE:
+	{
+		ParamEntry *tab = NULL;
+		fH_Handle *handle = NULL;
+		getRandomHandle(creature, handle, tab, true);
+		mutateHandleValues(handle, tab, creature->dimensions, true, false);
+		break;
+	}
+	case FH_PROP:
+	{
+		ParamEntry *tab = NULL;
+		fH_Handle *handle = NULL;
+		getRandomHandle(creature, handle, tab, true);
+		if (handle->type == fHBodyType::NEURON)
+		{
+			mutateNeuronHandleProperties((fH_NeuronHandle *)handle, creature->neuronparamtab);
+		}
+		else
+		{
+			mutateHandleValues(handle, tab, creature->dimensions, false, true);
+		}
+		break;
+	}
+	case FH_DEL:
+	{
+		ParamEntry *tab = NULL;
+		fH_Handle *handle = NULL;
+		int todelete = getRandomHandle(creature, handle, tab, true);
+		switch (handle->type)
+		{
+		case JOINT:
+			creature->sticks.erase(creature->sticks.begin() + todelete);
+			break;
+		case NEURON:
+			creature->neurons.erase(creature->neurons.begin() + todelete);
+			break;
+		case CONNECTION:
+			creature->connections.erase(creature->connections.begin() + todelete);
+			break;
+		}
+		delete handle;
+		break;
+	}
+	}
+	free(geno);
+	geno = strdup(creature->toString().c_str());
+	chg = (double)1.0 / sumgenes;
+	delete creature;
+	return GENOPER_OK;
+}
+
+void Geno_fH::mutateHandleValues(fH_Handle *handle, ParamEntry *tab,
+	int dimensions, bool changedimensions, bool changeproperties)
+{
+	Param par(tab, handle->obj);
+	handle->saveProperties(par);
+	if (changedimensions)
+	{
+		int i = randomN(2 * dimensions);
+		changeDoubleProperty(i, par, handle->type);
+	}
+
+	if (changeproperties)
+	{
+		int i = 2 * dimensions + randomN(par.getPropCount() - 2 * dimensions);
+		changeDoubleProperty(i, par, handle->type);
+	}
+	handle->loadProperties(par);
+	//ParamObject::freeObject(obj);
+}
+
+void Geno_fH::createHandleVectors(fH_Handle *handle, ParamEntry *tab, int dimensions)
+{
+	void *obj = ParamObject::makeObject(tab);
+	Param par(tab, obj);
+	par.setDefault();
+	double min, max, def;
+	par.getMinMaxDouble(0, min, max, def);
+	for (int i = 0; i < dimensions; i++)
+	{
+		par.setDouble(i, min + rnd0N(max - min));
+		par.setDouble(i + dimensions, min + rnd0N(max - min));
+	}
+	handle->loadProperties(par);
+	if (handle->type != fHBodyType::NEURON)
+	{
+		int i = 2 * dimensions + randomN(par.getPropCount() - 2 * dimensions);
+		changeDoubleProperty(i, par, handle->type);
+	}
+	else
+	{
+		mutateNeuronHandleProperties((fH_NeuronHandle *)handle, tab, true);
+	}
+}
+
+void Geno_fH::changeDoubleProperty(int id, Param &par, fHBodyType type)
+{
+	double min, max, def;
+	if (*par.type(id) == 'f')
+	{
+		// need to check if property is not weight of connection
+		if (type != fHBodyType::CONNECTION || *par.id(id) != 'w')
+		{
+			par.getMinMaxDouble(id, min, max, def);
+			par.setDouble(id, mutateCreep('f', par.getDouble(id), min, max, true));
+		}
+		else
+		{
+			// if it is weight, then method needs to use mutateNeuProperty
+			double current = par.getDouble(id);
+			par.setDouble(id, mutateNeuProperty(current, NULL, -1));
+		}
+	}
+	else
+	{
+		logMessage("Geno_fH", "changeDoubleProperty", LOG_WARN, "fH mutations are not prepared for non-double properties");
+	}
+}
+
+unsigned int Geno_fH::getRandomHandle(fH_Builder *creature, fH_Handle *&handle, ParamEntry *&tab, bool skipalonestick)
+{
+	unsigned int allhandlescount = creature->connections.size() + creature->neurons.size();
+	if (!skipalonestick || creature->sticks.size() > 1)
+	{
+		allhandlescount += creature->sticks.size();
+	}
+	unsigned int toselect = randomN(allhandlescount);
+	if (toselect < creature->connections.size())
+	{
+		handle = creature->connections[toselect];
+		tab = creature->connectionparamtab;
+		return toselect;
+	}
+	else if (toselect - creature->connections.size() < creature->neurons.size())
+	{
+		toselect -= creature->connections.size();
+		handle = creature->neurons[toselect];
+		tab = creature->neuronparamtab;
+		return toselect;
+	}
+	toselect -= creature->connections.size() + creature->neurons.size();
+	handle = creature->sticks[toselect];
+	tab = creature->stickparamtab;
+	return toselect;
+}
+
+void Geno_fH::mutateNeuronHandleProperties(fH_NeuronHandle *handle, ParamEntry *tab, bool userandomclass)
+{
+	Neuro neu;
+	Param hpar(tab, handle->obj);
+	SString det = hpar.getStringById("d");
+	neu.setDetails(det == "" ? "N" : det);
+	NeuroClass *nc = neu.getClass();
+
+	if (userandomclass)
+	{
+		nc = getRandomNeuroClass();
+		if (!nc) nc = Neuro::getClass("N");
+	}
+
+	det = nc->getName();
+	neu.setDetails(det);
+
+	SyntParam par = neu.classProperties();
+
+	if (par.getPropCount() > 0)
+	{
+		int i = randomN(par.getPropCount());
+		if (*par.type(i) == 'f')
+		{
+			double change = mutateNeuProperty(par.getDouble(i), &neu, 100 + i);
+			par.setDouble(i, change);
+		}
+		SString line;
+		int tmp = 0;
+		par.update(&line);
+		SString props;
+		line.getNextToken(tmp, props, '\n'); // removal of newline character
+		if (props != "")
+		{
+			det += ": ";
+			det += props;
+			hpar.setStringById("d", det);
+		}
+	}
+}
+
+uint32_t Geno_fH::style(const char *geno, int pos)
+{
+	char ch = geno[pos];
+	uint32_t style = GENSTYLE_CS(0, GENSTYLE_STRIKEOUT);
+	if (pos == 0 || geno[pos - 1] == '\n' || ch == ':') // single-character handle type and all colons
+	{
+		style = GENSTYLE_CS(GENCOLOR_TEXT, GENSTYLE_BOLD);
+	}
+	else if (isalpha(ch)) // properties name
+	{
+		style = GENSTYLE_RGBS(0, 200, 0, GENSTYLE_BOLD);
+	}
+	else if (isdigit(ch) || strchr(",.=", ch)) // properties values
+	{
+		style = GENSTYLE_CS(GENCOLOR_TEXT, GENSTYLE_NONE);
+	}
+	else if (ch == '\"')
+	{
+		style = GENSTYLE_RGBS(200, 0, 0, GENSTYLE_BOLD);
+	}
+
+	return style;
+}
Index: cpp/frams/genetics/fH/fH_oper.h
===================================================================
--- cpp/frams/genetics/fH/fH_oper.h	(revision 780)
+++ cpp/frams/genetics/fH/fH_oper.h	(revision 780)
@@ -0,0 +1,104 @@
+#ifndef _FH_OPER_H_
+#define _FH_OPER_H_
+
+#include "../genooperators.h"
+#include "fH_general.h"
+
+/** @name Codes for general fH mutation types */
+//@{
+#define FH_ADD     0 ///<Adding new handle
+#define FH_HANDLE  1 ///<Modifying vectors of handles
+#define FH_PROP    2 ///<Modifying properties of sticks/neurons/connections
+#define FH_DEL     3 ///<Deleting single handle from genotype. WARNING! this type of mutation must be last in defines, because later during mutation this method may be skipped due to the lack of genotypes to remove
+#define FH_OPCOUNT 4 ///<Count of mutation types
+//@}
+
+/** @name Codes for specific FH_ADD mutation subtypes */
+//@{
+#define FH_ADD_STICK 0 ///<Adding stick
+#define FH_ADD_NEURO 1 ///<Adding neuron
+#define FH_ADD_CONN  2 ///<Adding connection
+#define FH_ADD_OPCOUNT 3 ///<Count of addition types
+//@}
+
+class Geno_fH : public GenoOperators
+{
+private:
+	/**
+	 * Mutates vectors and/or properties of a given handle.
+	 * Properties and vector values are set with mutateCreep method, with respect to their
+	 * minimal, maximal and default values. Only weights of connections are mutated
+	 * with mutateNeuProperty.
+	 * @param handle handle that has to be modified
+	 * @param tab ParamTab holding definitions of properties of a given handle
+	 * @param dimensions number of values stored in each vector of handle
+	 * @param changedimensions true if values of vectors should be changed, false otherwise
+	 * @param changeproperties true if values of properties should be changed, false otherwise
+	 */
+	void mutateHandleValues(fH_Handle *handle, ParamEntry *tab, int dimensions, bool changedimensions, bool changeproperties);
+
+	/**
+	 * Creates new handle with random vectors and one mutated property. Vector values are
+	 * set to values from [-1,1] - probabilities of each values are evenly distributed.
+	 * It also creates required obj for handle and initializes it with default
+	 * values.
+	 * @param handle the handle for which obj is created and mutation is performed
+	 * @param tab the corresponding ParamTab for handle
+	 * @param dimensions number of values in vectors
+	 */
+	void createHandleVectors(fH_Handle *handle, ParamEntry *tab, int dimensions);
+
+	/**
+	 * Mutates "details" property of neurons. First it tries to parse neuron class
+	 * given in "details" field. It it fails, or "userandomclass" parameter is set
+	 * to true, then new available class is picked (or "N", if there are no
+	 * available classes). When neuron class is established, method iterates through
+	 * neuron properties and mutates them with mutateNeuProperty method.
+	 * @param handle handle that has to be modified
+	 * @param tab ParamTab holding definitions of properties of a given handle
+	 * @param userandomclass true if method should find random class, false if current class or "N" should be used
+	 */
+	void mutateNeuronHandleProperties(fH_NeuronHandle *handle, ParamEntry *tab, bool userandomclass = false);
+
+	/**
+	 * Mutates single double property in par, accessed by id. If property is weight
+	 * of connection, then it is mutated with mutateNeuProperty.
+	 * @param id numerical id of property in Param
+	 * @param par Param with properties to modify
+	 * @param type used to determine if property is weight of connection
+	 */
+	void changeDoubleProperty(int id, Param &par, fHBodyType type);
+
+	/**
+	 * Gets random handle and corresponding ParamTab from a given body. Both pointers
+	 * are returned in parameters "handle" and "tab" respectively. Parameter
+	 * "skipalonestick" should be set if method selects handle for deleting (valid
+	 * body should have at least one stick).
+	 * @param creature Builder object with parsed genotype, from which random handle is selected
+	 * @param handle reference to pointer pointing to selected handle
+	 * @param tab reference to pointer pointing to corresponding ParamTab
+	 * @param skipalonestick true if method should skip only stick during random selection of handles, false if method should randomly choose handle from all available handles
+	 * @return position of handle pointer in vector of handles of same type in Builder (if selected handle is of STICK type, then returned value is its position in "sticks" vector of Builder)
+	 */
+	unsigned int getRandomHandle(fH_Builder *creature, fH_Handle *&handle, ParamEntry *&tab, bool skipalonestick = false);
+
+public:
+	double operations[FH_OPCOUNT];    ///<relative probabilities of selecting mutation types in fH genotype
+	double addoperations[FH_ADD_OPCOUNT]; ///<relative probabilities of selecting mutation addition subtypes
+
+	Geno_fH();
+
+	int checkValidity(const char *geno, const char *genoname);
+
+	int validate(char *&geno, const char *genoname);
+
+	int mutate(char *&geno, float& chg, int &method);
+
+	int crossOver(char *&g1, char *&g2, float& chg1, float& chg2);
+
+	virtual const char* getSimplest() { return "3\nj:"; }
+
+	uint32_t style(const char *geno, int pos);
+};
+
+#endif //_FH_OPER_H_
Index: cpp/frams/genetics/fL/fL_conv.cpp
===================================================================
--- cpp/frams/genetics/fL/fL_conv.cpp	(revision 780)
+++ cpp/frams/genetics/fL/fL_conv.cpp	(revision 780)
@@ -0,0 +1,6 @@
+#include "fL_conv.h"
+
+SString GenoConv_fL0::convert(SString &i, MultiMap *map, bool using_checkpoints)
+{
+	return "";
+}
Index: cpp/frams/genetics/fL/fL_conv.h
===================================================================
--- cpp/frams/genetics/fL/fL_conv.h	(revision 780)
+++ cpp/frams/genetics/fL/fL_conv.h	(revision 780)
@@ -0,0 +1,21 @@
+#ifndef _FL_CONV_
+#define _FL_CONV_
+
+#include <frams/genetics/genoconv.h>
+
+class GenoConv_fL0 : public GenoConverter
+{
+public:
+	GenoConv_fL0() : GenoConverter()
+	{
+		name = "L-System encoding";
+
+		in_format = 'L';
+		out_format = '0';
+		mapsupport = 1;
+	}
+	SString convert(SString &i, MultiMap *map, bool using_checkpoints);
+	~GenoConv_fL0() {}
+};
+
+#endif // _FL_CONV_
Index: cpp/frams/genetics/fL/fL_general.cpp
===================================================================
--- cpp/frams/genetics/fL/fL_general.cpp	(revision 780)
+++ cpp/frams/genetics/fL/fL_general.cpp	(revision 780)
@@ -0,0 +1,1057 @@
+#include <algorithm>
+#include <stack>
+#include "fL_general.h"
+
+const char *fL_part_names[PART_PROPS_COUNT] = { "dn", "fr", "ing", "as" };
+const char *fL_part_fullnames[PART_PROPS_COUNT] = { "details", "friction", "ingestion", "assimilation" };
+
+const char *fL_joint_names[JOINT_PROPS_COUNT] = { "stif", "rotstif", "stam" };
+const char *fL_joint_fullnames[JOINT_PROPS_COUNT] = { "stiffness", "rotation stiffness", "stamina" };
+
+#define FIELDSTRUCT fL_Word
+ParamEntry fL_word_paramtab[] =
+{
+	{ "Word", 1, 2, "w" },
+	{ "name", 0, PARAM_CANOMITNAME, "word name", "s", FIELD(name), },
+	{ "npar", 0, PARAM_CANOMITNAME, "number of parameters", "d 0 3 0", FIELD(npar), },
+	{ 0, 0, 0, }
+};
+#undef FIELDSTRUCT
+
+#define FIELDSTRUCT fL_Rule
+ParamEntry fL_rule_paramtab[] =
+{
+	{ "Rule", 1, 3, "r" },
+	{ "pred", 0, PARAM_CANOMITNAME, "predecessor", "s", FIELD(predecessor), },
+	{ "cond", 0, PARAM_CANOMITNAME, "parameter condition", "s", FIELD(condition), },
+	{ "succ", 0, PARAM_CANOMITNAME, "successor", "s", FIELD(successor), },
+	{ 0, 0, 0, }
+};
+#undef FIELDSTRUCT
+
+#define FIELDSTRUCT fL_Builder
+ParamEntry fL_builder_paramtab[] =
+{
+	{ "LSystemInfo", 1, 3, "i" },
+	{ "axiom", 0, PARAM_CANOMITNAME, "starting sequence of L-System", "s", FIELD(axiom), },
+	{ "time", 0, PARAM_CANOMITNAME, "development time", "f 1.0 100.0 1.0", FIELD(time), },
+	{ "numckp", 0, PARAM_CANOMITNAME, "number of checkpoints", "d 1 50 1", FIELD(numckp), },
+	{ 0, 0, 0, }
+};
+#undef FIELDSTRUCT
+
+fL_Builder::~fL_Builder()
+{
+	// first remove words from builder
+	for (fL_Word *word : genotype)
+	{
+		delete word;
+	}
+	genotype.clear();
+	// remove rules from builder
+	for (fL_Rule *rule : rules)
+	{
+		delete rule;
+	}
+	rules.clear();
+
+	// remove words definitions with their ParamTabs
+	std::unordered_map<std::string, fL_Word *>::iterator it;
+	for (it = words.begin(); it != words.end(); it++)
+	{
+		ParamObject::freeParamTab(it->second->tab);
+		delete it->second;
+	}
+	words.clear();
+}
+
+bool fL_Builder::getNextObject(int &pos, SString src, SString &token)
+{
+	// if position exceeds length then return false
+	if (pos >= src.len()) return false;
+	int opencount = -1;
+	int i = pos;
+	for (; i < src.len(); i++)
+	{
+		// token cannot contain branching parenthesis
+		if (src[i] == '[' || src[i] == ']')
+		{
+			// if token started - return parenthesis mismatch
+			if (opencount != -1)
+			{
+				pos = -1;
+				return false;
+			}
+			// otherwise [ and ] are interpreted as tokens and they do not have parenthesis
+			token = src.substr(pos, i + 1 - pos);
+			pos = i + 1;
+			return true;
+		}
+		// every word, except [ and ], has () parenthesis
+		// every open parenthesis increment opencount counter;
+		if (src[i] == '(')
+		{
+			if (opencount == -1) opencount = 1;
+			else opencount++;
+		}
+		// every close parenthesis decrement opencount counter
+		else if (src[i] == ')')
+		{
+			// if there were no open parenthesis, return parenthesis mismatch
+			if (opencount == -1)
+			{
+				pos = -1;
+				return false;
+			}
+			else opencount--;
+		}
+		// if counter reaches 0, the token extraction is finished
+		if (opencount == 0)
+		{
+			break;
+		}
+	}
+	if (opencount == 0)
+	{
+		token = src.substr(pos, i + 1 - pos);
+		pos = i + 1;
+		return true;
+	}
+	// if there was no closing parenthesis, then return parenthesis mismatch
+	pos = -1;
+	return false;
+}
+
+std::string fL_Builder::trimSpaces(std::string data)
+{
+	size_t first = data.find_first_not_of(' ');
+	if (std::string::npos == first)
+	{
+		return data;
+	}
+	size_t last = data.find_last_not_of(' ');
+	return data.substr(first, (last - first + 1));
+}
+
+int fL_Builder::tokenize(SString sequence, std::list<fL_Word *> &result, int numparams)
+{
+	int pos = 0;
+	SString token;
+	int branchcount = 0;
+	if (result.size() > 0)
+	{
+		for (fL_Word *word : result)
+		{
+			delete word;
+		}
+		result.clear();
+	}
+	// iterate through available tokens
+	while (getNextObject(pos, sequence, token))
+	{
+		// if token is of open branch type, then add start of branch
+		if (token.indexOf("[", 0) != -1)
+		{
+			fL_Branch *word = new fL_Branch(fL_Branch::BranchType::OPEN);
+			result.push_back(word);
+			branchcount++;
+			continue;
+		}
+		// if token is of closed branch type, then add end of branch
+		if (token.indexOf("]", 0) != -1)
+		{
+			if (branchcount == 0)
+			{
+				SString message = "Branch parenthesis mismatch at:  ";
+				message += sequence;
+				logMessage("fL_Builder", "tokenize", LOG_ERROR, message.c_str());
+				return 1;
+			}
+			fL_Branch *word = new fL_Branch(fL_Branch::BranchType::CLOSE);
+			result.push_back(word);
+			branchcount--;
+			continue;
+		}
+		SString wordn;
+		int tokpos = 0;
+		// if word name cannot be extracted, then return error
+		if (!token.getNextToken(tokpos, wordn, '('))
+		{
+			SString message = "Error during parsing words sequence:  ";
+			message += sequence;
+			logMessage("fL_Builder", "tokenize", LOG_ERROR, message.c_str());
+			return 1;
+		}
+		std::string wordname = fL_Builder::trimSpaces(wordn.c_str());
+		// if word cannot be found in available words, then return error
+		if (words.find(wordname) == words.end())
+		{
+			SString message = "Word '";
+			message += wordname.c_str();
+			message += "' in sequence does not exist";
+			logMessage("fL_Builder", "tokenize", LOG_ERROR, message.c_str());
+			return 1;
+		}
+
+		// create new word and assign parameters
+		fL_Word *word = new fL_Word();
+
+		*word = *words[wordname];
+
+		// if word has parameters
+		if (word->npar > 0)
+		{
+			// create ParamObject that will hold parameter data
+			word->data = ParamObject::makeObject(word->tab);
+			Param par(word->tab);
+			par.select(word->data);
+			par.setDefault();
+			ParamInterface::LoadOptions opts;
+
+			SString temp;
+			temp = token.substr(tokpos);
+			temp = temp.substr(0, temp.len() - 1);
+			// load parameters from string
+			par.load(ParamInterface::FormatSingleLine, temp, &opts);
+			for (int i = 0; i < par.getPropCount(); i++)
+			{
+				// create MathEvaluation object to check if string contained by
+				// parameter is valid
+				double tmp;
+				MathEvaluation *eval = new MathEvaluation(numparams);
+				SString seq = par.getString(i);
+				// if string is empty, then evaluate this with 0
+				if (seq.len() == 0)
+				{
+					eval->evaluate("0", tmp);
+				}
+				// if sequence could not be evaluated, then return error
+				else if (eval->evaluate(seq.c_str(), tmp) != 0)
+				{
+					SString message = "Word in sequence has invalid parameter:  ";
+					message += temp;
+					logMessage("fL_Builder", "tokenize", LOG_ERROR, message.c_str());
+					delete eval;
+					delete word;
+					return 1;
+				}
+				word->parevals.push_back(eval);
+			}
+		}
+		result.push_back(word);
+	}
+
+	// check if there were no parenthesis errors in genotype
+	if (pos == -1)
+	{
+		SString message = "Parenthesis mismatch at:  ";
+		message += sequence;
+		logMessage("fL_Builder", "tokenize", LOG_ERROR, message.c_str());
+		return 1;
+	}
+	if (branchcount != 0)
+	{
+		SString message = "Branching mismatch at:  ";
+		message += sequence;
+		logMessage("fL_Builder", "tokenize", LOG_ERROR, message.c_str());
+		return 1;
+	}
+	return 0;
+}
+
+void fL_Word::operator=(const fL_Word& src)
+{
+	if (&src != this)
+	{
+		name = src.name;
+		npar = src.npar;
+
+		//mut = src.mut;
+		tab = src.tab;
+
+		parevals = src.parevals;
+
+		data = NULL; // properties cannot be copied
+	}
+}
+
+int fL_Word::processDefinition(fL_Builder *builder)
+{
+	// if word already exist, then return error
+	if (this->name.len() == 0)
+	{
+		logMessage("fL_Word", "processDefinition", LOG_ERROR, "Axiom name is empty");
+		return 1;
+	}
+	if (builder->words.find(this->name.c_str()) != builder->words.end())
+	{
+		std::string message = "Word redefinition:  ";
+		message += this->name.c_str();
+		logMessage("fL_Word", "processDefinition", LOG_ERROR, message.c_str());
+		return 1;
+	}
+
+	// create ParamTab for word
+	for (int i = 0; i < npar; i++)
+	{
+		std::string n = "n";
+		n += std::to_string(i);
+		mut.addProperty(NULL, n.c_str(), LSYSTEM_PARAM_TYPE, n.c_str(), "", PARAM_CANOMITNAME, 0, -1);
+	}
+
+	tab = ParamObject::makeParamTab((ParamInterface *)&mut, 0, 0, mut.firstMutableIndex());
+
+	builder->words[this->name.c_str()] = this;
+	return 0;
+}
+
+int fL_Rule::processDefinition(fL_Builder *builder)
+{
+	// if there is no word among words that matches predecessor, then return error
+	if (builder->words.find(predecessor.c_str()) == builder->words.end())
+	{
+		logMessage("fL_Rule", "processDefinition", LOG_ERROR, "Word in Rule condition does not exist");
+		return 1;
+	}
+
+	objpred = new fL_Word();
+	*objpred = *builder->words[predecessor.c_str()];
+
+	// parse condition
+	if (condition != "")
+	{
+		std::string cond = condition.c_str();
+		condeval = new MathEvaluation(objpred->npar);
+		double tmp;
+		if (condeval->evaluate(condition.c_str(), tmp) != 0)
+		{
+			SString message = "Parametric condition of rule invalid:  ";
+			message += condition;
+			logMessage("fL_Rule", "processDefinition", LOG_ERROR, message.c_str());
+			return 1;
+		}
+	}
+
+	// parse successor
+	if (successor == "")
+	{
+		logMessage("fL_Rule", "processDefinition", LOG_ERROR, "Successor cannot be empty");
+		return 1;
+	}
+
+	if (builder->tokenize(successor, objsucc, objpred->npar) != 0)
+	{
+		logMessage("fL_Rule", "processDefinition", LOG_ERROR, "Unable to process successor sequence");
+		return 1;
+	}
+
+	builder->rules.push_back(this);
+	return 0;
+}
+
+int fL_Builder::processDefinition(fL_Builder *builder)
+{
+	// tokenize axiom
+	if (tokenize(axiom, genotype, 0) != 0)
+	{
+		logMessage("fL_Builder", "processDefinition", LOG_ERROR, "Unable to process axiom sequence");
+		return 1;
+	}
+	else if (genotype.size() == 0)
+	{
+		logMessage("fL_Builder", "processDefinition", LOG_ERROR, "Axiom sequence is empty");
+		return 1;
+	}
+	return 0;
+}
+
+int fL_Builder::processLine(fLElementType type, SString line, fL_Element *&obj, int linenumber, int begin, int end)
+{
+	ParamEntry *tab;
+	// choose proper ParamTab and construct proper object
+	switch (type)
+	{
+	case fLElementType::TERM:
+	{
+		tab = fL_word_paramtab;
+		obj = new fL_Word();
+		break;
+	}
+	case fLElementType::INFO:
+	{
+		tab = fL_builder_paramtab;
+		obj = this;
+		break;
+	}
+	case fLElementType::RULE:
+	{
+		tab = fL_rule_paramtab;
+		obj = new fL_Rule(begin, end);
+		break;
+	}
+	default:
+		break;
+	}
+	Param par(tab);
+	par.select(obj);
+	par.setDefault();
+	ParamInterface::LoadOptions opts;
+
+	par.load(ParamInterface::FormatSingleLine, line, &opts);
+
+	if (opts.parse_failed)
+	{
+		std::string message = "Error in parsing parameters at line:  " + std::to_string(linenumber);
+		logMessage("fL_Builder", "processLine", LOG_ERROR, message.c_str());
+		delete obj;
+		return begin + 1;
+	}
+
+	return 0;
+}
+
+void fL_Builder::addModelWords()
+{
+	// stick S
+	fL_Word *stick = new fL_Word(true);
+	stick->name = "S";
+	stick->npar = 8;
+	for (int i = 0; i < PART_PROPS_COUNT; i++)
+	{
+		stick->mut.addProperty(NULL, fL_part_names[i], "s", fL_part_fullnames[i], fL_part_fullnames[i], PARAM_CANOMITNAME, 0, -1);
+	}
+
+	for (int i = 0; i < JOINT_PROPS_COUNT; i++)
+	{
+		stick->mut.addProperty(NULL, fL_joint_names[i], "s", fL_joint_fullnames[i], fL_joint_fullnames[i], PARAM_CANOMITNAME, 0, -1);
+	}
+
+	stick->mut.addProperty(NULL, "l", "s", "length", "length", PARAM_CANOMITNAME, 0, -1);
+	stick->tab = ParamObject::makeParamTab((ParamInterface *)&stick->mut, 0, 0, stick->mut.firstMutableIndex());
+	words["S"] = stick;
+
+	// neuron N
+	fL_Word *neuron = new fL_Word(true);
+	neuron->name = "N";
+	neuron->npar = 1;
+	neuron->mut.addProperty(NULL, "d", "s", "details", "details", PARAM_CANOMITNAME, 0, -1);
+	neuron->tab = ParamObject::makeParamTab((ParamInterface *)&neuron->mut, 0, 0, neuron->mut.firstMutableIndex());
+	words["N"] = neuron;
+
+	// connection C
+	fL_Word *connection = new fL_Word(true);
+	connection->name = "C";
+	connection->npar = 2;
+	connection->mut.addProperty(NULL, "w", "s", "weight", "weight", PARAM_CANOMITNAME, 0, -1);
+	connection->mut.addProperty(NULL, "attr", "s", "attractor", "connection attractor", PARAM_CANOMITNAME, 0, -1);
+	connection->tab = ParamObject::makeParamTab((ParamInterface *)&connection->mut, 0, 0, connection->mut.firstMutableIndex());
+	words["C"] = connection;
+
+	// rotation objects
+	fL_Word *rotx = new fL_Word(true);
+	rotx->name = "rotX";
+	rotx->npar = 1;
+	rotx->processDefinition(this);
+
+	fL_Word *roty = new fL_Word(true);
+	roty->name = "rotY";
+	roty->npar = 1;
+	roty->processDefinition(this);
+
+	fL_Word *rotz = new fL_Word(true);
+	rotz->name = "rotZ";
+	rotz->npar = 1;
+	rotz->processDefinition(this);
+}
+
+int fL_Builder::parseGenotype(SString genotype)
+{
+	int pos = 0;
+	int lastpos = 0;
+	SString line;
+	int linenumber = 0;
+
+	fLElementType type = fLElementType::TERM;
+
+	// add default words first to prevent redefinitions
+	addModelWords();
+
+	while (genotype.getNextToken(pos, line, '\n'))
+	{
+		if (line.len() > 0)
+		{
+			// words can be defined in the beginning of genotype
+			if (line.startsWith("w:") && type != fLElementType::TERM)
+			{
+				logMessage("fL_Builder", "parseGenotype", LOG_ERROR, "All words should be defined in the beginning of genotype");
+				return lastpos + 1;
+			}
+			else if (line.startsWith("i:"))
+			{
+				// after all words are defined, next definition should be information
+				if (type == fLElementType::TERM)
+				{
+					type = fLElementType::INFO;
+				}
+				else
+				{
+					logMessage("fL_Builder", "parseGenotype", LOG_ERROR, "Axioms and iteration number should be defined after word definitions");
+					return lastpos + 1;
+				}
+			}
+			else if (line.startsWith("r:"))
+			{
+				// after information definition, the last thing is rule definitions
+				if (type == fLElementType::TERM)
+				{
+					logMessage("fL_Builder", "parseGenotype", LOG_ERROR, "Axiom is not defined - define it after words definition");
+					return lastpos + 1;
+				}
+				else if (type == fLElementType::INFO)
+				{
+					type = fLElementType::RULE;
+				}
+			}
+			// create object
+			fL_Element *obj = NULL;
+			int res = processLine(type, line.substr(2), obj, linenumber, lastpos, pos - 1);
+			if (res != 0)
+			{
+				if (obj && obj != this) delete obj;
+				return res;
+			}
+			res = obj->processDefinition(this);
+			if (res != 0)
+			{
+				if (obj && obj != this) delete obj;
+				return res;
+			}
+		}
+		lastpos = pos;
+	}
+	if (type == fLElementType::TERM)
+	{
+		logMessage("fL_Builder", "parseGenotype", LOG_ERROR, "Info line was not declared");
+		return 1;
+	}
+	return 0;
+}
+
+int fL_Word::saveEvals(bool keepformulas)
+{
+	if (npar > 0)
+	{
+		Param par(tab);
+		par.select(data);
+		for (int i = 0; i < npar; i++)
+		{
+			if (parevals[i] != NULL)
+			{
+				double val;
+				if (parevals[i]->evaluateRPN(val) != 0)
+				{
+					logMessage("fL_Word", "saveEvals", LOG_ERROR, "Could not stringify mathematical expression in Word");
+					return 1;
+				}
+				if (val == 0)
+				{
+					par.setString(i, "");
+				}
+				else
+				{
+					if (keepformulas)
+					{
+						std::string res;
+						if (parevals[i]->RPNToInfix(res) != 0)
+						{
+							logMessage("fL_Word", "saveEvals", LOG_ERROR, "Could not stringify mathematical expression in Word");
+							return 1;
+						}
+						par.setString(i, res.c_str());
+					}
+					else
+					{
+						SString r = SString::valueOf(val);
+						par.setString(i, r);
+					}
+				}
+			}
+		}
+	}
+	return 0;
+}
+
+// Methods for converting L-System objects to string
+
+SString fL_Word::toString()
+{
+	Param par(fL_word_paramtab);
+	fL_Word *obj = new fL_Word();
+	par.select(this);
+	SString res;
+	par.saveSingleLine(res, obj, true, false);
+	res = SString("w:") + res;
+	delete obj;
+	return res;
+}
+
+SString fL_Word::stringify(bool keepformulas)
+{
+	SString res = name;
+	SString params = "";
+	if (npar > 0)
+	{
+		saveEvals(keepformulas);
+		Param par(tab);
+		void *obj = ParamObject::makeObject(tab);
+		par.select(obj);
+		par.setDefault();
+		par.select(data);
+		par.saveSingleLine(params, obj, false, false);
+		ParamObject::freeObject(obj);
+	}
+	res += "(";
+	res += params + ")";
+	return res;
+}
+
+SString fL_Rule::toString()
+{
+	predecessor = objpred->name;
+	std::string tmp;
+	if (condeval)
+	{
+		condeval->RPNToInfix(tmp);
+		condition = tmp.c_str();
+	}
+	else
+	{
+		condition = "";
+	}
+	successor = "";
+	std::list<fL_Word *>::iterator i;
+	for (i = objsucc.begin(); i != objsucc.end(); i++)
+	{
+		successor += (*i)->stringify();
+	}
+	Param par(fL_rule_paramtab);
+	fL_Rule *obj = new fL_Rule(0, 0);
+	par.select(this);
+	SString res;
+	par.saveSingleLine(res, obj, true, false);
+	res = SString("r:") + res;
+	delete obj;
+	return res;
+}
+
+SString fL_Builder::getStringifiedProducts()
+{
+	axiom = "";
+	std::list<fL_Word *>::iterator i;
+	for (i = genotype.begin(); i != genotype.end(); i++)
+	{
+		axiom += (*i)->stringify(false);
+	}
+	return axiom;
+}
+
+SString fL_Builder::toString()
+{
+	SString res;
+	for (std::unordered_map<std::string, fL_Word *>::iterator it = words.begin(); it != words.end(); it++)
+	{
+		if (!it->second->builtin)
+		{
+			res += it->second->toString();
+		}
+	}
+	getStringifiedProducts();
+	Param par(fL_builder_paramtab);
+	fL_Builder *obj = new fL_Builder();
+	par.select(this);
+	SString tmp;
+	par.saveSingleLine(tmp, obj, true, false);
+	res += SString("i:") + tmp;
+	delete obj;
+	for (fL_Rule * rule : rules)
+	{
+		res += rule->toString();
+	}
+	return res;
+}
+
+int fL_Rule::deploy(fL_Word *in, std::list<fL_Word *>::iterator &it, std::list<fL_Word *> &genotype, double currtime)
+{
+	// if predecessor and given word differ, then rule is not applicable
+	if (in->name != objpred->name || in->npar != objpred->npar)
+	{
+		return 1;
+	}
+	// store predecessor values in separate array
+	double *inwordvalues = new double[in->npar];
+	for (int i = 0; i < in->npar; i++)
+	{
+		if (in->parevals[i] != NULL)
+		{
+			in->parevals[i]->modifyVariable(-1, currtime == in->creationiter + 1.0 ? 1.0 : currtime - floor(currtime));
+			in->parevals[i]->evaluateRPN(inwordvalues[i]);
+		}
+		else
+		{
+			inwordvalues[i] = 0;
+		}
+	}
+	// if condition exists
+	if (condeval)
+	{
+		// check if condition is satisfied. If not, rule is not applicable
+		for (int i = 0; i < in->npar; i++)
+		{
+			condeval->modifyVariable(i, inwordvalues[i]);
+		}
+		double condvalue;
+		condeval->evaluateRPN(condvalue);
+		if (condvalue == 0)
+		{
+			delete[] inwordvalues;
+			return 1;
+		}
+	}
+
+	// remove predecessor word from genotype and replace it with successor
+	it = genotype.erase(it);
+	for (std::list<fL_Word *>::iterator word = objsucc.begin(); word != objsucc.end(); word++)
+	{
+		// create new word and copy properties from word definition
+		fL_Word *nword = new fL_Word();
+		*nword = **word;
+		// store information about when word has been created
+		nword->creationiter = currtime;
+		nword->parevals.clear();
+		if (nword->npar > 0)
+		{
+			nword->data = ParamObject::makeObject(nword->tab);
+		}
+		// calculate word parameters and store MathEvaluation objects for further
+		// time manipulations.
+		for (int q = 0; q < nword->npar; q++)
+		{
+			if ((*word)->parevals[q] == NULL)
+			{
+				MathEvaluation *ev = new MathEvaluation(0);
+				ev->convertString("0");
+				nword->parevals.push_back(ev);
+			}
+			else
+			{
+				std::string tmp;
+				(*word)->parevals[q]->RPNToInfix(tmp);
+				MathEvaluation *ev = new MathEvaluation(in->npar);
+				for (int i = 0; i < in->npar; i++)
+				{
+					ev->modifyVariable(i, inwordvalues[i]);
+				}
+				ev->modifyVariable(-1, currtime == (*word)->creationiter + 1.0 ? 1.0 : currtime - floor(currtime));
+				ev->convertString(tmp);
+				nword->parevals.push_back(ev);
+			}
+		}
+		genotype.insert(it, nword);
+	}
+	delete[] inwordvalues;
+	delete in;
+	return 0;
+}
+
+int fL_Builder::iterate(double currtime)
+{
+	// deploy proper rules for all words in current genotype
+	std::list<fL_Word *>::iterator word = genotype.begin();
+	while (word != genotype.end())
+	{
+		bool deployed = false;
+		for (fL_Rule * rule : rules)
+		{
+			if (rule->deploy((*word), word, genotype, currtime) == 0)
+			{
+				deployed = true;
+				break;
+			}
+		}
+		if (!deployed) word++;
+	}
+	return 0;
+}
+
+int fL_Builder::alterTimedProperties(double currtime)
+{
+	// alter parameters of all words, if they are time-dependent
+	std::list<fL_Word *>::iterator word = genotype.begin();
+	while (word != genotype.end())
+	{
+		if (currtime - (*word)->creationiter <= 1.0)
+		{
+			for (MathEvaluation *ev : (*word)->parevals)
+			{
+				if (ev) ev->modifyVariable(-1, currtime == (*word)->creationiter + 1.0 ? 1.0 : currtime - floor(currtime));
+			}
+		}
+		word++;
+	}
+	return 0;
+}
+
+int fL_Builder::alterPartProperties(Part *part, fL_Word *stickword, double &alterationcount)
+{
+	Param par(stickword->tab, stickword->data);
+	Param ppar = part->properties();
+	for (int i = 0; i < PART_PROPS_COUNT; i++)
+	{
+		double partprop;
+		double currval;
+		if (!ExtValue::parseDouble(par.getStringById(fL_part_names[i]).c_str(), currval, false))
+		{
+			logMessage("fL_Builder", "alterPartProperties", LOG_ERROR,
+				"Error parsing word parameter");
+			return 1;
+		}
+		partprop = (ppar.getDoubleById(fL_part_names[i]) * alterationcount +
+			currval) / (alterationcount + 1.0);
+		ppar.setDoubleById(fL_part_names[i], partprop);
+	}
+	return 0;
+}
+
+bool fL_Word::operator==(const fL_Word& other) const
+{
+	if (name == other.name) return false;
+	if (npar == other.npar) return false;
+	for (int i = 0; i < npar; i++)
+	{
+		if (parevals[i] && other.parevals[i])
+		{
+			double first;
+			double second;
+			parevals[i]->evaluateRPN(first);
+			other.parevals[i]->evaluateRPN(second);
+			if (first != second)
+			{
+				return false;
+			}
+		}
+		else
+		{
+			return false;
+		}
+	}
+	return true;
+}
+
+void fL_Builder::findNext(fL_Word *word, std::list<fL_Word *> genotype, std::list<fL_Word *>::iterator &it)
+{
+	int rightdist = 0;
+	std::list<fL_Word *>::iterator iter(it);
+	for (; iter != genotype.end(); iter++)
+	{
+		if (*word == **iter)
+		{
+			break;
+		}
+		rightdist++;
+	}
+	int leftdist = 0;
+	std::list<fL_Word *>::reverse_iterator riter(it);
+	for (; riter != genotype.rend(); riter++)
+	{
+		if (*word == **riter)
+		{
+			break;
+		}
+		leftdist++;
+	}
+	if (iter == genotype.end())
+	{
+		it = riter.base();
+	}
+	else if (riter == genotype.rend())
+	{
+		it = iter;
+	}
+	else if (leftdist < rightdist)
+	{
+		it = riter.base();
+	}
+	else
+	{
+		it = iter;
+	}
+}
+
+Neuro *fL_Builder::findInputNeuron(std::list<fL_Word *> genotype, std::list<fL_Word *>::iterator it, fL_Word *attractor)
+{
+	if (!attractor)
+	{
+		attractor = new fL_Word();
+		*attractor = *(*it);
+		attractor->data = NULL;
+		// TODO implement
+	}
+	return NULL;
+}
+
+int fL_Builder::developModel(Model &model)
+{
+	// TODO implement
+	fL_State currstate;
+	std::unordered_map<Part *, double> counters;
+	std::stack<fL_State> statestack;
+	std::vector<std::pair<std::list<fL_Word *>::iterator, Neuro *>> connsbuffer;
+	Part *firstpart = NULL;
+
+	for (std::list<fL_Word *>::iterator w = genotype.begin(); w != genotype.end(); w++)
+	{
+		fL_Word *word = (*w);
+		if (word->builtin)
+		{
+			if (word->name == "S")
+			{
+				if (!currstate.currpart)
+				{
+					if (!firstpart)
+					{
+						firstpart = new Part();
+						firstpart->p = Pt3D_0;
+						counters[firstpart] = 0;
+						model.addPart(firstpart);
+					}
+					currstate.currpart = firstpart;
+				}
+				if (alterPartProperties(currstate.currpart, word, counters[currstate.currpart]) != 0)
+				{
+					return 1;
+				}
+				counters[currstate.currpart] += 1;
+				Part *newpart = new Part();
+				counters[newpart] = 0;
+				if (alterPartProperties(newpart, word, counters[newpart]) != 0)
+				{
+					delete newpart;
+					return 1;
+				}
+				Param par(word->tab, word->data);
+				double length;
+				if (!ExtValue::parseDouble(par.getStringById("l").c_str(), length, false))
+				{
+					delete newpart;
+					logMessage("fL_Builder", "alterPartProperties", LOG_ERROR,
+						"Error parsing word parameter");
+					return 1;
+				}
+				newpart->p = currstate.currpart->p + currstate.direction * length;
+				counters[newpart] += 1;
+				model.addPart(newpart);
+
+				Joint *newjoint = new Joint();
+				newjoint->attachToParts(currstate.currpart, newpart);
+
+				Param jpar = newjoint->properties();
+				for (int i = 0; i < JOINT_PROPS_COUNT; i++)
+				{
+					double jointprop;
+					if (!ExtValue::parseDouble(par.getStringById(fL_joint_names[i]).c_str(), jointprop, false))
+					{
+						logMessage("fL_Builder", "developModel", LOG_ERROR,
+							"Error parsing word parameter");
+						delete newjoint;
+						return 1;
+					}
+					jpar.setDoubleById(fL_joint_names[i], jointprop);
+				}
+				model.addJoint(newjoint);
+				currstate.currpart = newpart;
+			}
+			else if (word->name == "N")
+			{
+				Param npar(word->tab, word->data);
+				Neuro *neu = new Neuro();
+				neu->setDetails(npar.getStringById("d"));
+				if (!neu->getClass())
+				{
+					logMessage("fL_Builder", "developModel", LOG_ERROR, "Error parsing neuron class");
+					delete neu;
+					return 1;
+				}
+				model.addNeuro(neu);
+				currstate.currneuron = neu;
+			}
+			else if (word->name == "C")
+			{
+				connsbuffer.push_back({ w, currstate.currneuron });
+			}
+			else if (word->name.startsWith("rot"))
+			{
+				Orient rotmatrix;
+				double rot;
+				if (word->parevals[0]->evaluateRPN(rot) != 0)
+				{
+					logMessage("fL_Builder", "developModel", LOG_ERROR, "Error parsing neuron class");
+					return 1;
+				}
+				if (word->name == "rotX")
+				{
+					rotmatrix.rotate(Pt3D(rot, 0.0, 0.0));
+				}
+				else if (word->name == "rotY")
+				{
+					rotmatrix.rotate(Pt3D(0.0, rot, 0.0));
+				}
+				else if (word->name == "rotZ")
+				{
+					rotmatrix.rotate(Pt3D(0.0, 0.0, rot));
+				}
+				currstate.direction = rotmatrix.transform(currstate.direction);
+			}
+			else if (word->name == "[")
+			{
+				statestack.push(currstate);
+			}
+			else if (word->name == "]")
+			{
+				currstate = statestack.top();
+				statestack.pop();
+			}
+		}
+	}
+
+	// connections need
+	//	for (std::pair<std::list<fL_Word *>::iterator, Neuro *> conndata : connsbuffer)
+	//	{
+	//
+	//	}
+	return 0;
+}
+
+int fL_Builder::develop()
+{
+	Model m;
+	double curriter = 0;
+	double timestamp = 1.0 / numckp;
+	double t = 0;
+	for (; t <= time; t += timestamp)
+	{
+		alterTimedProperties(t); // always alter timed properties in the beginning
+		// if iteration exceeds integer value, then deploy rules
+		if (floor(t) > curriter)
+		{
+			iterate(t);
+			curriter += 1.0;
+		}
+	}
+	// if exact time of development was not reached due to floating point errors,
+	// then alter timed properties
+	if (time < t)
+	{
+		alterTimedProperties(time);
+	}
+	return 0;
+}
Index: cpp/frams/genetics/fL/fL_general.h
===================================================================
--- cpp/frams/genetics/fL/fL_general.h	(revision 780)
+++ cpp/frams/genetics/fL/fL_general.h	(revision 780)
@@ -0,0 +1,403 @@
+#ifndef _FL_GENERAL_
+
+#define _FL_GENERAL_
+
+#include <frams/util/sstring.h>
+#include <frams/param/mutableparam.h>
+#include <frams/param/paramobj.h>
+#include <vector>
+#include <list>
+#include <unordered_map>
+#include <frams/model/model.h>
+#include "fL_matheval.h"
+
+/// determines to which class fL element belongs
+enum fLElementType {
+	TERM, ///< word of L-System
+	INFO, ///< fL_Builder object
+	RULE, ///< rule of L-System
+	BRANCH ///< special type of fL word, which represents branch
+};
+
+/** @name Constants used in fL methods */
+//@{
+#define PART_PROPS_COUNT   4 ///<Count of part properties
+#define JOINT_PROPS_COUNT  3 ///<Count of joint properties
+#define PE_NEURO_DET       "d" ///<Id of details type definition in f0_neuro_paramtab
+#define PE_CONN_WEIGHT     "w" ///<Id of weight type definition in f0_neuroconn_paramtab
+//@}
+
+extern const char *fL_part_names[];
+extern const char *fL_joint_names[];
+extern const char *fL_joint_fullnames[JOINT_PROPS_COUNT];
+extern const char *fL_part_fullnames[PART_PROPS_COUNT];
+
+#define LSYSTEM_PARAM_TYPE "s" ///< standard type of L-System elements
+
+class fL_Builder;
+
+/**
+ * Most abstract class of L-System. It requires from inheriting classes to implement
+ * methods processDefinition and toString.
+ */
+class fL_Element
+{
+public:
+	fLElementType type; ///< type of fL_Element
+
+	fL_Element(fLElementType type) : type(type) {}
+	virtual ~fL_Element() { }
+
+	/**
+	 * Performs connecting current element to fL_Builder and parsing of input
+	 * with respect of builder.
+	 * @param builder fL_Builder object responsible for creating this element
+	 * @return 0 if processing went successfully, other values otherwise
+	 */
+	virtual int processDefinition(fL_Builder *builder) = 0;
+
+	/**
+	 * Creates string line for current element. This method is used by Builder
+	 * to create string representation of words, rules and informations of L-System.
+	 * @return stringified element
+	 */
+	virtual SString toString() = 0;
+};
+
+/**
+ * Represents word objects of L-System representation. They are used in axiom,
+ * produced sequences and rules.
+ */
+class fL_Word : public fL_Element
+{
+public:
+	SString name; ///<name of word
+	int npar; ///<number of word parameters
+	MutableParam mut; ///<MutableParam for word parameters
+	ParamEntry *tab; ///<ParamTab used for loading and saving properties of word
+	void *data; ///<pointer to properties of word
+	bool builtin; ///<determines if word is built-in (true) or not (false).
+	std::vector<MathEvaluation *> parevals; ///<stores MathEvaluation objects with parameter functions
+	double creationiter; ///<this helper field is used during L-System iterations and determines when word was created
+	fL_Word(bool builtin = false) :
+		fL_Element(fLElementType::TERM), mut("Word", "Properties"), //TODO change Word to Term everywhere
+		builtin(builtin)
+	{
+		name = "";
+		npar = 0;
+		tab = NULL;
+		data = NULL;
+		creationiter = 0;
+	}
+
+	/**
+	 * Destroys data ParamObject and MathEvaluation objects. ParamTab for Word
+	 * should be deleted separately, because all words with same name share same
+	 * pointer to ParamTab.
+	 */
+	~fL_Word()
+	{
+		if (data)
+			ParamObject::freeObject(data);
+		for (MathEvaluation *ev : parevals)
+		{
+			delete ev;
+		}
+		parevals.clear();
+	}
+
+	/**
+	 * Checks if there is no other word stored in the builder with the same name,
+	 * prepares ParamTab for defined word and adds created word definition to the
+	 * builder.
+	 * @param builder pointer to the builder that process this word definition
+	 * @return 0 if word is added, 1 if word is redefined
+	 */
+	int processDefinition(fL_Builder *builder);
+
+	/**
+	 * Operator copies name string, npar value, pointer to ParamTab and pointers
+	 * to MathEvaluation objects for parameters. It sets data of this word to
+	 * NULL.
+	 * @param src source word
+	 */
+	void operator=(const fL_Word& src);
+
+	/**
+	 * TODO
+	 */
+	bool operator==(const fL_Word& other) const;
+
+	/**
+	 * Returns 'w:' line defining word in genotype.
+	 * @return string representation of word definition
+	 */
+	virtual SString toString();
+
+	/**
+	 * Returns token version of this word. It is used during converting successor's
+	 * list or axiom list into strings. Flag 'keepformulas' should be set to true
+	 * if word parameters should be represented as formulas, and set to false if
+	 * word parameters should contain the result of evaluation.
+	 * @param keepformulas true if parameters should have mathematical formula, false if it should have result of evaluation
+	 */
+	virtual SString stringify(bool keepformulas = true);
+
+	/**
+	 * Saves formulas or evaluations of parameters in ParamObject.
+	 * @param keepformulas true if parameters should have mathematical formula, false if it should have result of evaluation
+	 * @return 0 if method successfully managed to save data, 1 if an error occured
+	 */
+	int saveEvals(bool keepformulas);
+};
+
+/**
+ * Represents special branching word in L-System genotype.
+ */
+class fL_Branch : public fL_Word
+{
+public:
+	/// Determines if branching parenthesis is opened or closed
+	enum BranchType {
+		OPEN,
+		CLOSE
+	};
+	BranchType btype; ///< branch parenthesis type
+	fL_Branch(BranchType branchtype) : fL_Word()
+	{
+		type = fLElementType::BRANCH;
+		btype = branchtype;
+		name = stringify();
+	}
+	SString toString() { return ""; };
+	SString stringify(bool keepformulas = false) { return btype == BranchType::OPEN ? "[" : "]"; }
+};
+
+/**
+ * Represents rules in L-System genotype. Every rule has predecessor and successors.
+ * The optional argument is a condition of deploying rule. Every rule is ran
+ * synchronously for every letter of the current genotype. If condition and
+ * predecessor are satisfied, then predecessor is replaced by successors.
+ */
+class fL_Rule : public fL_Element
+{
+public:
+	SString predecessor; ///<string representation of the predecessor
+	SString condition; ///<string representation of the condition
+	SString successor; ///<string representation of the successor
+
+	fL_Word *objpred; ///<object representation of the predecessor
+	MathEvaluation *condeval; ///<object representation of the condition
+
+	std::list<fL_Word *> objsucc; ///<objec representation of successors
+
+	int start; ///<beginning of the rule definition in genotype
+	int end; ///<end of the rule definition in genotype
+
+	fL_Rule(int start, int end) : fL_Element(fLElementType::RULE),
+		start(start), end(end)
+	{
+		predecessor = "";
+		condition = "";
+		successor = "";
+		objpred = NULL;
+		condeval = NULL;
+	}
+
+	~fL_Rule()
+	{
+		if (objpred) delete objpred;
+		if (condeval) delete condeval;
+		for (fL_Word *word : objsucc)
+		{
+			delete word;
+		}
+		objsucc.clear();
+	}
+
+	/**
+	 * Loads rule definition from the genotype, checks if word defined in
+	 * predecessor does exist, tokenizes successor and condition.
+	 * @param builder pointer to the builder that process this word definition
+	 * @return 0 if word is added, 1 if an error occured during parsing
+	 */
+	int processDefinition(fL_Builder *builder);
+
+	SString toString();
+
+	/**
+	 * Runs rule for a given word, if all conditions and starting rules are satisfied.
+	 * Method alters given list of tokens by removing matching word pointed by
+	 * pointer and iterator of list and inserting successor sequence into list.
+	 * Final iterator value points to the first word after processed word.
+	 * @param in word that is currently processed
+	 * @param it iterator of genotype list which determines position of current analysis
+	 * @param genotype current genotype. Words on the left of genotype are processed and possibly replaced by previous rules
+	 * @param currtime value representing continuous time value for rule
+	 * @return 0 if rule processed current word, 1 if rule is no applicable
+	 */
+	int deploy(fL_Word *in, std::list<fL_Word *>::iterator &it, std::list<fL_Word *> &genotype, double currtime);
+};
+
+struct fL_State
+{
+	Pt3D direction; ///<Direction of turtle
+	Part *currpart; ///<Latest created part
+	Neuro *currneuron; ///<Latest created neuron
+	fL_State() : direction(1, 0, 0), currpart(NULL), currneuron(NULL)
+	{ }
+};
+
+/**
+ * Main class of L-System processing. It holds all information required to perform
+ * steps of development of a creature. It allows to create Timed D0L-Systems with
+ * following limitations:
+ *
+ *  - fractions of time affect only parameters of currently produced words,
+ *  - integer steps deploy rules in order to develop new elements of body,
+ *  - if parameter should use time fraction, then $t variable must be used,
+ *  - $t variable always contain values from 0 to 1 that represent current fraction
+ *    of step.
+ */
+class fL_Builder : public fL_Element
+{
+public:
+	SString axiom; ///<starting sequence of genotype
+	double time; ///<time of creature development
+	int numckp; ///<number of checkpoints per growth step - checkpoints are always created after rules deployment in integer steps, numckp determines how many checkpoints should be created within single step (to watch changes of parameters)
+
+	std::list<fL_Word *> genotype; ///<list of current words of genotype
+	std::unordered_map<std::string, fL_Word *> words; ///<map from string to words existing in L-System
+	std::vector<fL_Rule *> rules; ///<rules available in system
+
+	fL_Builder() : fL_Element(fLElementType::INFO)
+	{
+		axiom = "";
+		time = 1.0;
+		numckp = 1;
+	}
+	~fL_Builder();
+
+	/**
+	 * Helper function for trimming leading and trailing spaces from sequence.
+	 * @param data input string
+	 * @return string with trimmed spaces
+	 */
+	static std::string trimSpaces(std::string data);
+
+	/**
+	 * Processes single line of input sequence and load line properties with use
+	 * of proper ParamTab.
+	 * @param type which type of line is this
+	 * @param line line to be processed
+	 * @param obj variable storing pointer to created L-System element
+	 * @param linenumber for error messages
+	 * @param begin index of first character of line
+	 * @param end index of last character of line
+	 * @return 0 if processing ended successfully, 1-based position of error otherwise
+	 */
+	int processLine(fLElementType type, SString line, fL_Element *&obj, int linenumber, int begin, int end);
+
+	/**
+	 * Parses input genotype with words, information and rules. First of all,
+	 * model-specific words defined in addModelWords method are added to words map.
+	 * Every genotype should start with words definitions. They cannot collide
+	 * with model words and with each other. Secondly, information line, containing
+	 * axiom and number of iteration must be processed. In the end, all rules
+	 * have to be processed by builder. After determining line type and creating
+	 * fL_Element specialized object, the builder runs object's processDefinition
+	 * method to generate all important objects and register element in builder
+	 * structures.
+	 * @param genotype input genotype
+	 * @return 0 if processing finished successfully, 1-based position of error if it occured
+	 */
+	int parseGenotype(SString genotype);
+
+	/**
+	 * Prepares structures and tokenizes axiom.
+	 * @param builder this method should receive pointer to itself
+	 * @return 0 if processing went successfully, 1 otherwise
+	 */
+	int processDefinition(fL_Builder *builder);
+
+	/**
+	 * Adds words used for Framsticks body and brain development.
+	 */
+	void addModelWords();
+
+	/**
+	 * Helper method that tokenizes string sequence by closing parenthesis
+	 * with respect to parenthesis nesting.
+	 * @param pos index of character, from which next token needs to be extracted. Method replaces this parameter with next starting position, or -1 if there was an error during parsing, like parenthesis mismatch
+	 * @param src original sequence
+	 * @param token reference to variable holding new token
+	 * @return true if new token is found, false if there is no more tokens or when there was parenthesis mismatch (if pos == -1, then it is parenthesis mismatch)
+	 */
+	bool getNextObject(int &pos, SString src, SString &token);
+
+	/**
+	 * Helper function that converts input sequence into list of L-System words.
+	 * @param sequence input sequence of stringified word objects
+	 * @param result reference to list holding generated words
+	 * @param numparams number of parameters that can be used for words stored in result list
+	 * @return 0 if tokenizing finished successfully, 1 otherwise
+	 */
+	int tokenize(SString sequence, std::list<fL_Word *> &result, int numparams);
+
+	/**
+	 * Uses rules to process current genotype and make next iteration step for
+	 * L-System development.
+	 * @param currtime current time of genotype processing
+	 * @return always 0
+	 */
+	int iterate(double currtime);
+
+	/**
+	 * Alters only parameters that depend on time. Should be used if only fraction
+	 * of iteration has changed, not integer part.
+	 * @param currtime current time of processing
+	 * @return always 0
+	 */
+	int alterTimedProperties(double currtime);
+
+	/**
+	 * Developes L-System from given genotype and builds Framsticks Model from it.
+	 */
+	int develop();
+
+	/**
+	 * Creates new checkpoint for a given model based on current state of genotype.
+	 * @param model reference to model
+	 * @return 0 if developing went successfully, 1 otherwise
+	 */
+	int developModel(Model &model);
+
+	/**
+	 * Returns stringified product of L-System development.
+	 * @return stringified words of developed L-System
+	 */
+	SString getStringifiedProducts();
+
+	/**
+	 * Returns genotype stored by objects in fL_Builder.
+	 * @return genotype converted from L-System objects
+	 */
+	SString toString();
+
+	/**
+	 * TODO
+	 */
+	int alterPartProperties(Part *part, fL_Word *stickword, double &alterationcount);
+
+	/**
+	 * TODO
+	 */
+	Neuro *findInputNeuron(std::list<fL_Word *> genotype, std::list<fL_Word *>::iterator it, fL_Word *attractor);
+
+	/**
+	 * TODO
+	 */
+	void findNext(fL_Word *word, std::list<fL_Word *> genotype, std::list<fL_Word *>::iterator &it);
+};
+
+#endif // _FL_GENERAL_
Index: cpp/frams/genetics/fL/fL_matheval.cpp
===================================================================
--- cpp/frams/genetics/fL/fL_matheval.cpp	(revision 780)
+++ cpp/frams/genetics/fL/fL_matheval.cpp	(revision 780)
@@ -0,0 +1,593 @@
+#include <frams/util/extvalue.h>
+#include <frams/util/sstring.h>
+#include <stack>
+#include "fL_matheval.h"
+
+// Used available operators in MathEvaluation
+
+double madd(double left, double right)
+{
+	return left + right;
+}
+
+double msub(double left, double right)
+{
+	return left - right;
+}
+
+double mmul(double left, double right)
+{
+	return left * right;
+}
+
+double mand(double left, double right)
+{
+	return left && right;
+}
+
+double mor(double left, double right)
+{
+	return left || right;
+}
+
+double mgreater(double left, double right)
+{
+	return left > right;
+}
+
+double mless(double left, double right)
+{
+	return left < right;
+}
+
+double mequal(double left, double right)
+{
+	return left == right;
+}
+
+double mnotequal(double left, double right)
+{
+	return left != right;
+}
+
+double meqless(double left, double right)
+{
+	return left <= right;
+}
+
+double meqgreater(double left, double right)
+{
+	return left >= right;
+}
+
+// Methods for converting evaluation tokens to string
+
+std::string MathEvaluation::Number::toString()
+{
+	return std::string(SString::valueOf(value).c_str());
+}
+
+std::string MathEvaluation::Variable::toString()
+{
+	if (id == -1) return std::string(1, VARIABLEPREFIX) + "t";
+	return std::string(1, VARIABLEPREFIX) + std::to_string(id);
+}
+
+std::string MathEvaluation::Parenthesis::toString()
+{
+	return ptype == ParenthesisType::OPEN ? "(" : ")";
+}
+
+std::string MathEvaluation::Operator::toString()
+{
+	return opname;
+}
+
+void MathEvaluation::Number::operator=(const Number& src)
+{
+	value = src.value;
+}
+
+double MathEvaluation::Operator::execute(double left, double right)
+{
+	return operation(left, right);
+}
+
+void MathEvaluation::registerOperators()
+{
+	// list of available operators in MathEvaluation
+	operators["+"] = new Operator(madd, 2, Associativity::LEFT, "+");
+	operators["-"] = new Operator(msub, 2, Associativity::LEFT, "-");
+	operators["*"] = new Operator(mmul, 3, Associativity::LEFT, "*");
+	operators["&"] = new Operator(mand, 0, Associativity::LEFT, "&");
+	operators["|"] = new Operator(mor, 0, Associativity::LEFT, "|");
+	operators[">"] = new Operator(mgreater, 1, Associativity::LEFT, ">");
+	operators["<"] = new Operator(mless, 1, Associativity::LEFT, "<");
+	operators[">="] = new Operator(meqgreater, 1, Associativity::LEFT, ">=");
+	operators["<="] = new Operator(meqless, 1, Associativity::LEFT, "<=");
+	operators["="] = new Operator(mequal, 1, Associativity::RIGHT, "=");
+	operators["~"] = new Operator(mnotequal, 1, Associativity::RIGHT, "~");
+}
+
+void MathEvaluation::clearPostfix()
+{
+	if (!postfixlist.empty())
+	{
+		for (Token *el : postfixlist)
+		{
+			// only numbers or parenthesis should be removed - operators and
+			// variables are removed later during destruction of the
+			// MathEvaluation object
+			if (el->type == TokenType::NUMBER ||
+				el->type == TokenType::PARENTHESIS)
+				delete el;
+		}
+		postfixlist.clear();
+	}
+}
+
+MathEvaluation::MathEvaluation(int varcount) : varcount(varcount), vars(varcount, NULL)
+{
+	registerOperators();
+	for (int i = 0; i < varcount; i++)
+	{
+		vars[i] = new Variable(i);
+	}
+	t = new Variable(-1);
+	t->value = 0;
+}
+
+MathEvaluation::~MathEvaluation()
+{
+	clearPostfix();
+
+	std::unordered_map<std::string, Operator *>::iterator it;
+	for (it = operators.begin(); it != operators.end(); it++)
+	{
+		delete it->second;
+	}
+	operators.clear();
+
+	for (Variable *var : vars)
+	{
+		delete var;
+	}
+	vars.clear();
+	delete t;
+}
+
+int MathEvaluation::convertString(std::string expression)
+{
+	clearPostfix(); //clear previous objects
+	ExtValue val;
+
+	unsigned int it = 0;
+
+	std::list<Token*> operatorstack; // stores operators for later
+
+	bool canbeunary = true; // used to determine if -/+ operators should be unary
+	while (it < expression.size())
+	{
+		bool parsenumber = false;
+		int oplen = 2; // first method checks if 2-character operators match, then 1-character
+
+		// if following letters describe variable
+		if (expression[it] == VARIABLEPREFIX ||
+			(canbeunary && strchr("+-", expression[it]) &&
+			it + 1 < expression.size() &&
+			expression[it + 1] == VARIABLEPREFIX))
+		{
+			// determine if before variable there is an unary operator '-'
+			// if yes, the variable will be negated
+			double mult = expression[it] == '-' ? -1 : 1;
+			it += expression[it] == VARIABLEPREFIX ? 1 : 2;
+			// if there is no space after '$' character, return error
+			if (it >= expression.size())
+			{
+				std::string message = "Evaluation error: Invalid variable '";
+				message += expression.substr(it) + "'";
+				logMessage("MathEvaluation", "convertString", LOG_ERROR, message.c_str());
+				while (!operatorstack.empty())
+				{
+					if (operatorstack.back()->type != TokenType::OPERATOR)
+					{
+						delete operatorstack.back();
+						operatorstack.pop_back();
+					}
+				}
+				return -1;
+			}
+
+			//determine id of variable
+			const char *ptr = expression[it] == 't' ? expression.c_str() + it + 1 : val.parseNumber(expression.c_str() + it, ExtPType::TInt);
+			int index = expression[it] == 't' ? -1 : val.getInt();
+			bool invalidid = false;
+			// if id is parsed properly
+			if (ptr) // if current element is number, then add it to RPN
+			{
+				// if id is exceeding available amount of variables, then variable
+				// is invalid
+				if (index >= varcount)
+				{
+					invalidid = true;
+				}
+				else
+				{
+					Variable *v = index == -1 ? t : vars[index];
+					// if variable had unary '-', then is multiplied by -1
+					// multiplying value stored in variable would change value
+					// in every occurrence of variable
+					if (mult == -1)
+					{
+						postfixlist.push_back(new Number(-1));
+						postfixlist.push_back(v);
+						postfixlist.push_back(operators["*"]);
+					}
+					// push pointer to a variable in order to make evaluation
+					// reusable for other values of variables
+					else
+					{
+						postfixlist.push_back(v);
+					}
+					int offset = ptr - (expression.c_str() + it);
+					it += offset;
+					// after variable there cannot be unary operator
+					canbeunary = false;
+				}
+			}
+			// if parsing of variable went wrong, then return error message
+			if (!ptr || invalidid)
+			{
+				std::string message = "Evaluation error: Invalid variable '";
+				message += expression.substr(it) + "'";
+				logMessage("MathEvaluation", "convertString", LOG_ERROR, message.c_str());
+				while (!operatorstack.empty())
+				{
+					if (operatorstack.back()->type != TokenType::OPERATOR)
+					{
+						delete operatorstack.back();
+						operatorstack.pop_back();
+					}
+				}
+				return -1;
+			}
+		}
+		// if current characters describe operators
+		else if ((it + 1 < expression.size() && operators.find(expression.substr(it, oplen)) != operators.end())
+			|| operators.find(expression.substr(it, --oplen)) != operators.end())
+		{
+			// if operator is + or - and from context it is known that it is
+			// unary version of one of those operators, then move control to
+			// number parsing
+			if (canbeunary && strchr("+-", expression[it]) &&
+				it + 1 < expression.size() && isdigit(expression[it + 1]))
+			{
+				parsenumber = true;
+			}
+			else
+			{
+				// otherwise prepare pointer to a given operator
+				Operator *newop = operators[expression.substr(it, oplen)];
+
+				bool finished = operatorstack.empty();
+
+				// before operator will be put onto the operator stack, all operators
+				// with higher precedence than the current operator should be popped
+				// from the stack and added to postfix list
+				while (!finished)
+				{
+
+					Token *curr = operatorstack.back();
+					// when token in the operator stack is opened parenthesis,
+					// then the process of taking operators from stack stops.
+					if (curr->type == TokenType::PARENTHESIS)
+					{
+						Parenthesis *par = (Parenthesis *)curr;
+						if (par->ptype == ParenthesisType::OPEN)
+						{
+							finished = true;
+						}
+					}
+					else
+					{
+						// if current operator in stack is left-associated and
+						// its precedence is equal or greater than precedence of
+						// new operator than current operator is taken from stack
+						// and added to postfixlist. If current operator is
+						// right-associated, then its precedence must be strictly
+						// higher than new operator precedence
+						Operator *op = (Operator *)curr;
+						if (newop->assoc == Associativity::LEFT && newop->precedence <= op->precedence)
+						{
+							postfixlist.push_back(op);
+							operatorstack.pop_back();
+						}
+						else if (newop->assoc == Associativity::RIGHT && newop->precedence < op->precedence)
+						{
+							postfixlist.push_back(op);
+							operatorstack.pop_back();
+						}
+						else
+						{
+							finished = true;
+						}
+					}
+					finished = finished || operatorstack.empty();
+				}
+				// after operator there cannot be unary operator - wrap it in
+				// parenthesis
+				canbeunary = false;
+				// add new operator to stack
+				operatorstack.push_back(newop);
+				it += oplen;
+			}
+		}
+		else if (expression[it] == '(' || expression[it] == ')')
+		{
+			// if current character is open parenthesis, then add it to
+			// the operator stack
+			if (expression[it] == '(')
+			{
+				Parenthesis *par = new Parenthesis(ParenthesisType::OPEN);
+				// after open parenthesis there can be unary operator
+				canbeunary = true;
+				operatorstack.push_back(par);
+			}
+			else
+			{
+				// if current character is closed parenthesis, then all operators
+				// are popped from stack into postfix list until first open
+				// parenthesis is found
+				bool finpop = false;
+				while (!finpop)
+				{
+					// if there is no more operators in the stack, then parenthesis
+					// is mismatched
+					if (operatorstack.empty())
+					{
+						logMessage("MathEvaluation", "convertString", LOG_ERROR, "Evaluation error: Parenthesis mismatch");
+						return -1;
+					}
+					Token *curr = operatorstack.back();
+					if (curr->type == TokenType::PARENTHESIS)
+					{
+						// if corresponding parenthesis is found, then opening
+						// parenthesis is deleted and removed from stack - postfix
+						// notation does not have parenthesis
+						Parenthesis *par = (Parenthesis *)curr;
+						if (par->ptype == ParenthesisType::OPEN)
+						{
+							delete par;
+							operatorstack.pop_back();
+							finpop = true;
+						}
+					}
+					else
+					{
+						postfixlist.push_back(curr);
+						operatorstack.pop_back();
+					}
+				}
+				// after closed parenthesis unary operators does not exist
+				canbeunary = false;
+			}
+			it++;
+		}
+		else if (isspace(expression[it])) // all whitespaces are skipped
+		{
+			it++;
+		}
+		else // if above conditions are not satisfied, then method assumes that
+		{    // characters describe number
+			parsenumber = true;
+		}
+		if (parsenumber)
+		{
+			// if parsing went successfully, then push number to postfix list
+			const char *ptr = val.parseNumber(expression.c_str() + it, ExtPType::TDouble);
+			if (ptr) // if current element is number, then add it to RPN
+			{
+				Number *num = new Number(val.getDouble());
+				postfixlist.push_back(num);
+				int offset = ptr - (expression.c_str() + it);
+				it += offset;
+				// There are no unary operators after number
+				canbeunary = false;
+			}
+			else
+			{
+				// otherwise return error
+				std::string message = "Evaluation error: Invalid letter '";
+				message += expression[it];
+				message += "'";
+				logMessage("MathEvaluation", "convertString", LOG_ERROR, message.c_str());
+				while (!operatorstack.empty())
+				{
+					if (operatorstack.back()->type != TokenType::OPERATOR)
+					{
+						delete operatorstack.back();
+						operatorstack.pop_back();
+					}
+				}
+				return -1;
+			}
+		}
+	}
+
+	// Pop remaining operators from stack and add them to the postfix list
+	while (!operatorstack.empty())
+	{
+		Token *curr = operatorstack.back();
+		if (curr->type == TokenType::OPERATOR)
+		{
+			postfixlist.push_back(curr);
+			operatorstack.pop_back();
+		}
+		else
+		{
+			// if current token in the stack is open parenthesis, then mismatch
+			// occured
+			logMessage("MathEvaluation", "convertString", LOG_ERROR, "Evaluation error: Parenthesis mismatch");
+			while (!operatorstack.empty())
+			{
+				if (operatorstack.back()->type != TokenType::OPERATOR)
+				{
+					delete operatorstack.back();
+					operatorstack.pop_back();
+				}
+			}
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+int MathEvaluation::evaluateRPN(double &res)
+{
+	// stack holds number used during operator execution
+	std::stack<Number *> numberstack;
+
+	for (std::list<Token *>::iterator it = postfixlist.begin(); it != postfixlist.end(); it++)
+	{
+		Token *tok = (*it);
+		// if token is number or variable - add it to number stack
+		if (tok->type == TokenType::NUMBER || tok->type == TokenType::VARIABLE)
+		{
+			Number *num = new Number(((Number *)tok)->value);
+			numberstack.push(num);
+		}
+		else
+		{
+			// the token is an operator
+			Operator *op = (Operator *)tok;
+			// if there isn't at least 2 elements in number stack, then return error
+			if (numberstack.size() < 2)
+			{
+				logMessage("MathEvaluation", "convertString", LOG_ERROR, "Evaluation error: The math expression is not complete");
+				while (!numberstack.empty())
+				{
+					if (numberstack.top()->type == TokenType::NUMBER) delete numberstack.top();
+					numberstack.pop();
+				}
+				return -1;
+			}
+			// otherwise, pop two top elements from number stack and use them
+			// with current operator
+			double right = numberstack.top()->value;
+			if (numberstack.top()->type == TokenType::NUMBER) delete numberstack.top();
+			numberstack.pop();
+			double left = numberstack.top()->value;
+			if (numberstack.top()->type == TokenType::NUMBER) delete numberstack.top();
+			numberstack.pop();
+			double result = op->execute(left, right);
+			Number *newnum = new Number(result);
+			// Push operation result to number stack
+			numberstack.push(newnum);
+		}
+	}
+
+	// in the end of processing, only 1 element should be available in number stack.
+	// Otherwise expression was not complete and error will be returned
+	if (numberstack.size() != 1)
+	{
+		logMessage("MathEvaluation", "convertString", LOG_ERROR, "Evaluation error: The math expression is not complete");
+		while (!numberstack.empty())
+		{
+			if (numberstack.top()->type == TokenType::NUMBER) delete numberstack.top();
+			numberstack.pop();
+		}
+		return -1;
+	}
+
+	res = numberstack.top()->value;
+	if (numberstack.top()->type == TokenType::NUMBER) delete numberstack.top();
+	numberstack.pop();
+	return 0;
+}
+
+void MathEvaluation::modifyVariable(int i, double val)
+{
+	if (i == -1)
+	{
+		t->value = val;
+	}
+	else
+	{
+		if (!vars[i])
+		{
+			vars[i] = new Variable(i);
+		}
+		vars[i]->value = val;
+	}
+}
+
+int MathEvaluation::evaluate(std::string expression, double &result)
+{
+	int res = convertString(expression);
+	if (res != 0) return res;
+	return evaluateRPN(result);
+}
+
+int MathEvaluation::RPNToInfix(std::string &result)
+{
+	// stack holds stringified chunk and its precedence
+	std::stack<std::pair<std::string, int>> chunks;
+	// foreach token in postfix list
+	for (Token *tok : postfixlist)
+	{
+		// if token is not an operator, push stringified variable or number
+		// on top of stack
+		if (tok->type != TokenType::OPERATOR)
+		{
+			// number or variable has no precedence
+			chunks.push({ tok->toString(), -1 });
+		}
+		else // if token is an operator
+		{
+			Operator *op = (Operator *)tok;
+			int prec = op->precedence;
+			// if there are not at least two stringified chunks in stack, return error
+			if (chunks.size() < 2)
+			{
+				logMessage("MathEvaluation", "RPNToInfix", LOG_ERROR,
+					"Could not convert RPN notation to infix notation");
+				return -1;
+			}
+			// pop first chunk
+			std::pair<std::string, int> right = chunks.top();
+			chunks.pop();
+			if (right.second != -1 && right.second < op->precedence)
+			{
+				// if chunk on the right of operator has lower precedence than
+				// this operator, then wrap it with parenthesis
+				right.first = std::string(1, '(') + right.first + std::string(1, ')');
+			}
+			else if (right.second >= op->precedence)
+			{
+				prec = right.second;
+			}
+			std::pair<std::string, int> left = chunks.top();
+			chunks.pop();
+			if (left.second != -1 && left.second < op->precedence)
+			{
+				// if chunk on the left of operator has lower precedence than
+				// this operator, then wrap it with parenthesis
+				left.first = std::string(1, '(') + left.first + std::string(1, ')');
+			}
+			std::string res = left.first + op->toString() + right.first;
+			// add summed chunk
+			chunks.push({ res, prec });
+		}
+	}
+	// if there is more than one chunk then return error
+	if (chunks.size() != 1)
+	{
+		logMessage("MathEvaluation", "RPNToInfix", LOG_ERROR,
+			"Could not convert RPN notation to infix notation");
+		return -1;
+	}
+	result = chunks.top().first;
+	chunks.pop();
+	return 0;
+}
Index: cpp/frams/genetics/fL/fL_matheval.h
===================================================================
--- cpp/frams/genetics/fL/fL_matheval.h	(revision 780)
+++ cpp/frams/genetics/fL/fL_matheval.h	(revision 780)
@@ -0,0 +1,235 @@
+#ifndef _FL_MATHEVAL_H_
+#define _FL_MATHEVAL_H_
+
+#include <string>
+#include <unordered_map>
+#include <list>
+#include <vector>
+
+#define VARIABLEPREFIX '$'
+
+/** @name Available operators for MathEvaluation */
+//@{
+double madd(double left, double right); ///<add
+double msub(double left, double right); ///<subtract
+double mmul(double left, double right); ///<multiply
+double mand(double left, double right); ///<and
+double mor(double left, double right); ///<or
+double mgreater(double left, double right); ///<greater than
+double mless(double left, double right); ///<less than
+double mequal(double left, double right); ///<equal to
+double mnotequal(double left, double right); ///<not equal to
+double meqless(double left, double right); ///<less or equal
+double meqgreater(double left, double right); ///<greater or equal
+//@}
+
+/**
+ * Class for performing simple mathematical parsing and evaluations of expressions
+ * stored in strings. At first, the class object converts given string into list
+ * of objects that can be described as Reverse Polish Notation, or suffix notation.
+ * From this notation object can efficiently perform calculations for different
+ * values of variables, without re-tokenizing of a string.
+ */
+class MathEvaluation
+{
+	/// determines to whih class token belongs
+	enum TokenType {
+		NUMBER, ///<Number token
+		PARENTHESIS, ///<Parenthesis token
+		OPERATOR,  ///<Operator token
+		VARIABLE ///<Variable token
+	};
+	/// associativity of operator
+	enum Associativity {
+		RIGHT,
+		LEFT
+	};
+	/// determines if parenthesis is opening of closing
+	enum ParenthesisType {
+		OPEN,
+		CLOSE
+	};
+
+	/**
+	 * Simplest token of MathEvaluation Reverse Polish Notation. Every class used
+	 * in RPN notation should inherit from this class.
+	 */
+	class Token
+	{
+	public:
+		TokenType type; ///<type of token
+		/**
+		 * Method is used during converting list of token objects into infix
+		 * notation. Every class should implement this method and provide useful
+		 * and valid information for infix notation.
+		 * @return stringified token
+		 */
+		virtual std::string toString() = 0;
+		Token(TokenType type) : type(type) {}
+		virtual ~Token() {}
+	};
+
+	/**
+	 * Describes all numbers available in object infix notation.
+	 */
+	class Number : public Token
+	{
+	public:
+		double value; ///<value of stored number
+		Number(double value) : Token(TokenType::NUMBER), value(value)
+		{ }
+		~Number() {}
+		std::string toString();
+		/**
+		 * Copies value field from given source.
+		 * @param src other Number object
+		 */
+		void operator=(const Number& src);
+	};
+
+	/**
+	 * Special type of Number object, which holds external variables, represented
+	 * as $id, where id is a number.
+	 */
+	class Variable : public Number
+	{
+	public:
+		int id; ///<id of Variable object. Object is accessed via $id
+		Variable(int id) : Number(0), id(id)
+		{
+			type = TokenType::VARIABLE;
+		}
+		~Variable() {}
+		std::string toString();
+	};
+
+	/**
+	 * Class describing operator in RPN objects. It holds informations about
+	 * precedence, associativity and symbol of the operator. Operator can have 1
+	 * or 2 characters, not more or less. Operator requires function that takes
+	 * two doubles and returns double value -- the result of this function is the
+	 * result of operator execution.
+	 */
+	class Operator : public Token
+	{
+		double(*operation)(double left, double right); ///<field holding pointer to operator function
+	public:
+		int precedence; ///<precedence of the operator
+		Associativity assoc; ///<associativity of the operator
+		std::string opname; ///<symbol of the operator, can have 1 or 2 characters
+
+		/**
+		 * Uses method pointed by 'operation' pointer to return operator result
+		 * for a given numbers.
+		 * @param left number on the left side of the operator
+		 * @param right number on the right side of the operator
+		 * @return operator result
+		 */
+		double execute(double left, double right);
+
+		Operator(double(*operation)(double left, double right), int precedence,
+			Associativity assoc, std::string opname) :
+			Token(TokenType::OPERATOR),
+			operation(operation),
+			precedence(precedence),
+			assoc(assoc),
+			opname(opname)
+		{ }
+		~Operator() {}
+		std::string toString();
+	};
+
+	/**
+	 * Class represents parenthesis token. Parenthesis are considered only during
+	 * creation of RPN notation - the notation itself does not contain any
+	 * parenthesis, because the order of calculation is determined directly by
+	 * operators and numbers order.
+	 */
+	class Parenthesis : public Token
+	{
+	public:
+		ParenthesisType ptype; ///<determines if parenthesis is open or closed
+		Parenthesis(ParenthesisType ptype) :
+			Token(TokenType::PARENTHESIS),
+			ptype(ptype)
+		{ }
+		~Parenthesis() { }
+		std::string toString();
+	};
+
+	/**
+	 * Clears postfix objects stored in MathEvaluation object.
+	 */
+	void clearPostfix();
+
+	/**
+	 * Registers operators available in MathEvaluation object. Default operators
+	 * are +, -, *, &, |, >, <, >=, <=, =, ~, where ~ is inequality.
+	 * Registered operators can have maximally two characters, otherwise they are
+	 * ignored.
+	 */
+	void registerOperators();
+
+	std::unordered_map<std::string, Operator *> operators; ///<map containing available operators for MathEvaluation
+	std::list<Token *> postfixlist; ///<list with tokens ordered as postfix (RPN) notation of the given string
+	int varcount; ///<amount of variables declared for this MathEvaluation object
+	std::vector<Variable *> vars; ///<vector of variables, default values are 0
+	Variable *t; ///<additional t variable, that can act as time for evaluation
+public:
+
+	/**
+	 * Default constructor. It registers operators for MathEvaluation and prepares
+	 * vector of variables.
+	 */
+	MathEvaluation(int varcount);
+
+	/**
+	 * Destructor is responsible for clearing all objects in postfix, all operator
+	 * objects and all variables.
+	 */
+	~MathEvaluation();
+
+	/**
+	 * Converts string to std::list of tokens in postfix order that can be later
+	 * evaluated. Detailed description of algorithm can be found in source of
+	 * method.
+	 * @param expression infix mathematical expression
+	 * @return 0 if conversion is successful, or -1 if an error occurred
+	 */
+	int convertString(std::string expression);
+
+	/**
+	 * Evaluates expression stored in postfix list. It takes into account changes
+	 * made by modifyVariable method. This method should be called if the only
+	 * thing changed in expression are variable values - it saves time because
+	 * it uses objects created during convertString or evaluate method.
+	 * @param res reference to the variable, in which result will be stored
+	 * @return 0 if evaluation went successful, or -1 if an error occurred
+	 */
+	int evaluateRPN(double &res);
+
+	/**
+	 * Performs convertString and evaluateRPN methods respectively. It holds
+	 * objects created by convertString method.
+	 * @param expression infix mathematical expression
+	 * @param result reference to the variable, in which result will be stored
+	 * @return 0 if evaluation went successful, otherwise it returns the error of previous functions
+	 */
+	int evaluate(std::string expression, double &result);
+
+	/**
+	 * Sets variable with index i with value val.
+	 * @param i id of variable, -1 if changed variable should be variable 't' (time)
+	 * @param val new value
+	 */
+	void modifyVariable(int i, double val);
+
+	/**
+	 * Converts stored RPN list to infix string.
+	 * @param result reference to variable that will hold the result
+	 * @return 0 if method went successful, or -1 if an error occurred
+	 */
+	int RPNToInfix(std::string &result);
+};
+
+#endif // _FL_MATHEVAL_H_
Index: cpp/frams/genetics/fL/fL_oper.cpp
===================================================================
--- cpp/frams/genetics/fL/fL_oper.cpp	(revision 780)
+++ cpp/frams/genetics/fL/fL_oper.cpp	(revision 780)
@@ -0,0 +1,9 @@
+#include "fL_oper.h"
+
+Geno_fL::Geno_fL()
+{
+	//	par.setParamTab(GENOfHparam_tab);
+	//	par.select(this);
+	//	par.setDefault();
+	supported_format = 'H';
+}
Index: cpp/frams/genetics/fL/fL_oper.h
===================================================================
--- cpp/frams/genetics/fL/fL_oper.h	(revision 780)
+++ cpp/frams/genetics/fL/fL_oper.h	(revision 780)
@@ -0,0 +1,24 @@
+#ifndef _FL_OPER_
+#define _FL_OPER_
+
+#include "../genooperators.h"
+
+class Geno_fL : public GenoOperators
+{
+public:
+	Geno_fL();
+
+	//	int checkValidity(const char *geno, const char *genoname);
+
+	//	int validate(char *&geno, const char *genoname);
+
+	//	int mutate(char *&geno, float& chg, int &method);
+
+	//	int crossOver(char *&g1, char *&g2, float& chg1, float& chg2);
+
+	//	virtual const char* getSimplest() { return "5\naaazz"; }
+
+	//	uint32_t style(const char *geno, int pos);
+};
+
+#endif // _FL_OPER_
Index: cpp/frams/genetics/gen-config-SDK.h
===================================================================
--- cpp/frams/genetics/gen-config-SDK.h	(revision 779)
+++ cpp/frams/genetics/gen-config-SDK.h	(revision 780)
@@ -21,4 +21,7 @@
 #define USE_GENCONV_fF0
 #define USE_GENCONV_fn0
+#define USE_GENCONV_fBH
+#define USE_GENCONV_fH0
+#define USE_GENCONV_fL0
 
 //#define USE_GENMAN_f0
@@ -32,2 +35,5 @@
 #define USE_GENMAN_fT
 #define USE_GENMAN_fn
+#define USE_GENMAN_fB
+#define USE_GENMAN_fH
+#define USE_GENMAN_fL
Index: cpp/frams/genetics/genman.cpp
===================================================================
--- cpp/frams/genetics/genman.cpp	(revision 779)
+++ cpp/frams/genetics/genman.cpp	(revision 780)
@@ -59,4 +59,13 @@
 #ifdef USE_GENMAN_fT
 #include "fT/fTest_oper.h"
+#endif
+#ifdef USE_GENMAN_fB
+#include "fB/fB_oper.h"
+#endif
+#ifdef USE_GENMAN_fH
+#include "fH/fH_oper.h"
+#endif
+#ifdef USE_GENMAN_fL
+#include "fL/fL_oper.h"
 #endif
 
@@ -158,4 +167,13 @@
 #ifdef USE_GENMAN_fT
 	oper_fx_list.push_back(new GenoOper_fTest);
+#endif
+#ifdef USE_GENMAN_fB
+	oper_fx_list.push_back(new Geno_fB);
+#endif
+#ifdef USE_GENMAN_fH
+	oper_fx_list.push_back(new Geno_fH);
+#endif
+#ifdef USE_GENMAN_fL
+	oper_fx_list.push_back(new Geno_fL);
 #endif
 
