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 797)
@@ -1,2 +1,6 @@
+// This file is a part of Framsticks SDK.  http://www.framsticks.com/
+// Copyright (C) 1999-2018  Maciej Komosinski and Szymon Ulatowski.
+// See LICENSE.txt for details.
+
 #include "fB_conv.h"
 
@@ -89,5 +93,14 @@
 			continue;
 		}
-		fH_Handle *handle = convertCharacterToHandle(gene[2], dims, start, end, ranges);
+		int hclasspos = 2;
+		if (gene[2] == '"')
+		{
+			hclasspos--;
+			if (!getNextCharId(gene, hclasspos))
+			{
+				return "";
+			}
+		}
+		fH_Handle *handle = convertCharacterToHandle(gene[hclasspos], dims, start, end, ranges);
 		ParamEntry *tab = creature.getParamTab(handle->type);
 		void *obj = ParamObject::makeObject(tab);
@@ -97,13 +110,38 @@
 
 		int propindex = 0;
-		int z = 3;
+		int z = hclasspos;
+		if (gene[z] == '"')
+		{
+			z--;
+			if (!getNextCharId(gene, z))
+			{
+				delete handle;
+				ParamObject::freeObject(obj);
+				return "";
+			}
+		}
 		endoffset = 0;
 		if (gene.indexOf("zz", 0) != -1) endoffset = 2;
+		int nclassdefcount = 1;
 		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");
-			}
+			if (processNextLetter(creature, handle, par, gene, propindex, z, ranges, nclassdefcount) == -1)
+			{
+				logMessage("GenoConv_fBH", "convert", LOG_ERROR, "Property of fH could not be parsed");
+				delete handle;
+				ParamObject::freeObject(obj);
+				return "";
+			}
+		}
+		if (handle->type == fHBodyType::NEURON && propindex < par.getPropCount())
+		{
+			SString nclass;
+			if (!getNeuroClass(gene, nclass, nclassdefcount))
+			{
+				delete handle;
+				ParamObject::freeObject(obj);
+				return "";
+			}
+			par.setStringById(FH_PE_NEURO_DET, nclass);
 		}
 		handle->loadProperties(par);
@@ -132,5 +170,53 @@
 }
 
-int GenoConv_fBH::processNextLetter(fH_Builder &creature, fH_Handle *&currhandle, Param &par, SString gene, int &propindex, int &i, std::vector<IRange> ranges[3])
+bool GenoConv_fBH::getNextCharId(SString genotype, int &i)
+{
+	i++;
+	if (genotype[i] == '"')
+	{
+		int nextid = i + 1;
+		do
+		{
+			nextid = genotype.indexOf('"', nextid);
+			if (nextid == -1)
+			{
+				return false;
+			}
+			nextid++;
+		}
+		while (genotype[nextid] == '"');
+		i = nextid;
+	}
+	return true;
+}
+
+bool GenoConv_fBH::getNeuroClass(SString gene, SString &def, int nclassdefcount)
+{
+	SString lastdef = "N";
+	int nclass = 0;
+	int pos = 0;
+	while (nclass < nclassdefcount)
+	{
+		pos = gene.indexOf('\"', pos);
+		if (pos == -1)
+		{
+			def = lastdef;
+			return true;
+		}
+		pos++;
+		SString currdef;
+		if (gene.indexOf('\"', pos) == -1 || !gene.getNextToken(pos, currdef, '\"'))
+		{
+			def = lastdef;
+			return false;
+		}
+		lastdef = currdef;
+		nclass++;
+	}
+	def = lastdef;
+	return true;
+}
+
+int GenoConv_fBH::processNextLetter(fH_Builder &creature, fH_Handle *&currhandle, Param &par, SString gene, int &propindex, int &i, std::vector<IRange> ranges[3], int &nclassdefcount)
 {
 	if (propindex >= par.getPropCount())
@@ -147,5 +233,6 @@
 		par.setDefault();
 		propindex = 0;
-		i++;
+		if (!getNextCharId(gene, i))
+			return -1;
 		return 0;
 	}
@@ -166,12 +253,19 @@
 			}
 			propindex++;
-			i++;
+			if (!getNextCharId(gene, i))
+				return -1;
 			return 0;
 		}
 		else if (currhandle->type == fHBodyType::NEURON && *par.id(propindex) == 'd')
 		{
-			//TODO: handle neuron classes and properties
+			//When 'd' property appears for i-th element in gene, the method
+			//looks for i-th neuron definition
+			SString nclass;
+			if (!getNeuroClass(gene, nclass, nclassdefcount)) return -1;
+			par.setString(propindex, nclass);
 			propindex++;
-			i++;
+			nclassdefcount++;
+			if (!getNextCharId(gene, i))
+				return -1;
 			return 0;
 		}
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 797)
@@ -1,2 +1,6 @@
+// This file is a part of Framsticks SDK.  http://www.framsticks.com/
+// Copyright (C) 1999-2018  Maciej Komosinski and Szymon Ulatowski.
+// See LICENSE.txt for details.
+
 #ifndef _FB_CONV_H_
 #define _FB_CONV_H_
@@ -8,8 +12,10 @@
 {
 private:
+	bool getNextCharId(SString genotype, int &i);
 	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]);
+	int processNextLetter(fH_Builder &creature, fH_Handle *&currhandle, Param &par, SString gene, int &propindex, int &i, std::vector<IRange> ranges[3], int &nclassdefcount);
+	bool getNeuroClass(SString gene, SString &def, int nclassdefcount);
 
 public:
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 797)
@@ -1,2 +1,6 @@
+// This file is a part of Framsticks SDK.  http://www.framsticks.com/
+// Copyright (C) 1999-2018  Maciej Komosinski and Szymon Ulatowski.
+// See LICENSE.txt for details.
+
 #ifndef _FB_GENERAL_H_
 #define _FB_GENERAL_H_
@@ -10,8 +14,13 @@
 	{
 		int start = 0;
+		int prev = 0;
 		int count = -1;
 		do {
 			count++;
 			start = geno.indexOf("aa", start) + 1; // +1 is for progress, starting codons can overlap
+			int quotecount = 0;
+			for (int q = prev; q < start; q++) if (geno[q] == '\"') quotecount++;
+			prev = start;
+			if (quotecount % 2 != 0) count--; // 'aa' sequence is within quotes
 		} while (start - 1 != -1);
 		return count;
@@ -25,4 +34,7 @@
 			count++;
 			start = genotype.indexOf("aa", start) + 1;
+			int quotecount = 0;
+			for (int q = 0; q < start; q++) if (genotype[q] == '\"') quotecount++;
+			if (quotecount % 2 != 0) count--; // 'aa' sequence is within quotes
 		} while (start - 1 != -1 && count != i);
 		if (start - 1 == -1) // there is no gene with a given "i"
@@ -33,5 +45,15 @@
 		}
 		end = start;
-		end = genotype.indexOf("zz", end);
+		int quotecount = 0;
+		do {
+			quotecount = 0;
+			end = genotype.indexOf("zz", end);
+			if (end != -1)
+			{
+				for (int q = start; q < end; q++) if (genotype[q] == '\"') quotecount++;
+				if (quotecount % 2 != 0) end++;
+			}
+		} while (quotecount % 2 != 0 && end != -1);
+
 		if (end == -1) end = genotype.len();
 		else end += 2;
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 797)
@@ -1,2 +1,6 @@
+// This file is a part of Framsticks SDK.  http://www.framsticks.com/
+// Copyright (C) 1999-2018  Maciej Komosinski and Szymon Ulatowski.
+// See LICENSE.txt for details.
+
 #include <frams/util/sstring.h>
 #include <vector>
@@ -5,4 +9,5 @@
 #include "fB_general.h"
 #include "fB_oper.h"
+#include "../fH/fH_oper.h"
 
 #define FIELDSTRUCT Geno_fB
@@ -10,9 +15,10 @@
 static ParamEntry GENOfBparam_tab[] =
 {
-	{ "Genetics: fB", 3, FB_MUT_COUNT + FB_XOVER_COUNT, }, // ask about it
+	{ "Genetics: fB", 3, FB_MUT_COUNT + FB_XOVER_COUNT, },
 	{ "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_insertion", 1, 0, "Insertion", "f 0 1 0.95", FIELD(mutationprobs[FB_INSERTION]), "Probability of mutation by inserting characters in random place of genotype", },
+	{ "fB_mut_nclassins", 1, 0, "Insertion of neuron class definition", "f 0 1 0.05", FIELD(mutationprobs[FB_NCLASSINS]), "Probability of mutation by inserting neuron class definition 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", },
@@ -81,5 +87,27 @@
 		if (!islower(genotype[i]))
 		{
-			return i + 1;
+			if (genotype[i] == '"')
+			{
+				SString neuclassdef;
+				int nextid = i + 1;
+				if (!genotype.getNextToken(nextid, neuclassdef, '"'))
+				{
+					return i + 1;
+				}
+				Neuro *neu = new Neuro();
+				neu->setDetails(neuclassdef);
+
+				bool isclass = neu->getClass() ? true : false;
+				delete neu;
+				if (!isclass)
+				{
+					return i + 1;
+				}
+				i = nextid;
+			}
+			else
+			{
+				return i + 1;
+			}
 		}
 	}
@@ -121,8 +149,30 @@
 		if (!isalpha(genotype[i]))
 		{
-			return GENOPER_OPFAIL;
+			if (genotype[i] == '"')
+			{
+				SString neuclassdef;
+				int nextid = i + 1;
+				if (!genotype.getNextToken(nextid, neuclassdef, '"'))
+				{
+					return i + 1;
+				}
+				Neuro *neu = new Neuro();
+				neu->setDetails(neuclassdef);
+
+				bool isclass = neu->getClass() ? true : false;
+				delete neu;
+				if (!isclass)
+				{
+					return i + 1;
+				}
+				i = nextid;
+			}
+			else
+			{
+				return GENOPER_OPFAIL;
+			}
 		}
 		// if character is uppercase, then convert it to lowercase
-		if (isupper(genotype[i]))
+		else if (isupper(genotype[i]))
 		{
 			genotype.directWrite()[i] = tolower(genotype[i]);
@@ -142,4 +192,42 @@
 	}
 	return GENOPER_OK;
+}
+
+SString Geno_fB::detokenizeSequence(std::list<SString> tokenlist)
+{
+	SString res = "";
+	for (std::list<SString>::iterator it = tokenlist.begin(); it != tokenlist.end(); it++)
+	{
+		res += (*it);
+	}
+	return res;
+}
+
+std::list<SString> Geno_fB::tokenizeSequence(SString genotype)
+{
+	std::list<SString> res;
+	int i = 0;
+	while (i < genotype.len())
+	{
+		// if character is not alphabetic - error
+		if (isalpha(genotype[i]))
+		{
+			SString el = "";
+			el += genotype[i];
+			res.push_back(el);
+			i++;
+		}
+		else
+		{
+			SString neuclassdef;
+			i++;
+			genotype.getNextToken(i, neuclassdef, '"');
+			SString ndef = "\"";
+			ndef += neuclassdef;
+			ndef += "\"";
+			res.push_back(ndef);
+		}
+	}
+	return res;
 }
 
@@ -157,43 +245,79 @@
 	case FB_SUBSTITUTION:
 	{
-		int rndid = randomN(line.len()); // select random letter from genotype
+		std::list<SString> tokenized = tokenizeSequence(line);
+		int rndid = randomN(tokenized.size()); // 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;
+		std::list<SString>::iterator it = tokenized.begin();
+		std::advance(it, rndid);
+		SString t = (*it);
+		if ((*it).len() == 1)
+		{
+			if (randomN(2) == 0)
+			{
+				if ((*it)[0] == 'a') (*it).directWrite()[0] = 'b';
+				else (*it).directWrite()[0] = (*it)[0] - 1;
+			}
+			else
+			{
+				if ((*it)[0] == 'z') (*it).directWrite()[0] = 'y';
+				else (*it).directWrite()[0] = (*it)[0] + 1;
+			}
+			chg = 1.0 / line.len();
 		}
 		else
 		{
-			if (line[rndid] == 'z') line.directWrite()[rndid] = 'y';
-			else line.directWrite()[rndid] = line[rndid] + 1;
-		}
+			// first method needs to extract quotes
+			SString def = (*it);
+			def = def.substr(1, def.len() - 2);
+			Geno_fH::mutateNeuronProperties(def);
+			SString res = "\"";
+			res += def;
+			res += "\"";
+			(*it) = res;
+			chg = (double)def.len() / line.len();
+		}
+		line = detokenizeSequence(tokenized);
+		break;
+	}
+	case FB_INSERTION:
+	{
 		chg = 1.0 / line.len();
-		break;
-	}
-	case FB_INSERTION:
+		std::list<SString> tokenized = tokenizeSequence(line);
+		int rndid = randomN(tokenized.size()); // select random insertion point
+		std::list<SString>::iterator it = tokenized.begin();
+		std::advance(it, rndid);
+		SString letter = "a";
+		letter.directWrite()[0] = 'a' + randomN(26);
+		tokenized.insert(it, letter);
+		line = detokenizeSequence(tokenized);
+		break;
+	}
+	case FB_NCLASSINS:
+	{
+		std::list<SString> tokenized = tokenizeSequence(line);
+		std::list<SString>::iterator it = tokenized.begin();
+		int rndid = randomN(tokenized.size()); // select random insertion point
+		std::advance(it, rndid);
+		NeuroClass *cls = getRandomNeuroClass();
+		SString classdef = cls->getName();
+		Geno_fH::mutateNeuronProperties(classdef);
+		SString res = "\"";
+		res += classdef;
+		res += "\"";
+		tokenized.insert(it, res);
+		chg = (double)classdef.len() / line.len();
+		line = detokenizeSequence(tokenized);
+		break;
+	}
+	case FB_DELETION:
 	{
 		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);
-		}
+		std::list<SString> tokenized = tokenizeSequence(line);
+		std::list<SString>::iterator it = tokenized.begin();
+		int rndid = randomN(tokenized.size()); // select random deletion point
+		std::advance(it, rndid);
+		tokenized.erase(it);
+		line = detokenizeSequence(tokenized);
 		break;
 	}
@@ -210,15 +334,30 @@
 	case FB_TRANSLOCATION:
 	{
-		std::vector<int> cuts(4);
+		std::list<SString> tokenized = tokenizeSequence(line);
+		std::vector<unsigned int> cuts(4);
 		for (int i = 0; i < 4; i++)
 		{
-			cuts[i] = randomN(line.len());
+			cuts[i] = randomN(tokenized.size());
 		}
 		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;
+		std::vector<std::list<SString>::iterator> iters(4);
+		for (int i = 0; i < 4; i++)
+		{
+			iters[i] = tokenized.begin();
+			std::advance(iters[i], cuts[i]);
+		}
+
+		std::list<SString> res;
+		res.insert(res.end(), tokenized.begin(), iters[0]);
+		res.insert(res.end(), iters[2], iters[3]);
+		res.insert(res.end(), iters[1], iters[2]);
+		res.insert(res.end(), iters[0], iters[1]);
+		res.insert(res.end(), iters[3], tokenized.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 = detokenizeSequence(res);
 		chg = (float)(cuts[3] - cuts[2] + cuts[1] - cuts[0]) / line.len();
 		break;
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 797)
@@ -1,6 +1,11 @@
+// This file is a part of Framsticks SDK.  http://www.framsticks.com/
+// Copyright (C) 1999-2018  Maciej Komosinski and Szymon Ulatowski.
+// See LICENSE.txt for details.
+
 #ifndef _FB_OPER_H_
 #define _FB_OPER_H_
 
 #include "../genooperators.h"
+#include <list>
 
 /** @name Codes for general fB mutation types */
@@ -8,8 +13,9 @@
 #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
+#define FB_NCLASSINS     2 ///<Relative probability of mutation by inserting neuron class definition in random place of genotype
+#define FB_DELETION      3 ///<Relative probability of mutation by deleting random characters in genotype
+#define FB_DUPLICATION   4 ///<Relative probability of mutation by copying single *gene* of genotype and appending it to the beginning of this genotype
+#define FB_TRANSLOCATION 5 ///<Relative probability of mutation by replacing two substrings in genotype
+#define FB_MUT_COUNT     6 ///<Count of mutation types
 //@}
 
@@ -25,4 +31,6 @@
 private:
 	bool hasStick(SString genotype);
+	SString detokenizeSequence(std::list<SString> tokenlist);
+	std::list<SString> tokenizeSequence(SString genotype);
 
 public:
