Index: /cpp/README.txt
===================================================================
--- /cpp/README.txt	(revision 193)
+++ /cpp/README.txt	(revision 194)
@@ -17,7 +17,8 @@
       +- errmgr      - error manager (logging/messaging)
       +- genetics    - genetic operators and converters between formats
-         +- f1       - ...for genetic format f1
-         +- f9       - ...for genetic format f9
-         +- fF       - ...for genetic format fF
+         +- f1       - ...for genetic format f1 (recurrent encoding)
+         +- f9       - ...for genetic format f9 (3D turtle)
+         +- fF       - ...for genetic format fF (Foraminifera)
+         +- fT       - ...for genetic format fT (educational: ATGC sequences)
       +- model       - parts, joints, neurons, connections
          +- geometry - compute dimensions, volume, surface area
Index: /cpp/frams/Makefile-GDK
===================================================================
--- /cpp/frams/Makefile-GDK	(revision 193)
+++ /cpp/frams/Makefile-GDK	(revision 194)
@@ -5,5 +5,5 @@
 include frams/Makefile-GDK-files
 
-GDK_TESTS=genoconv_test gdk_test geno_test neuro_test loader_test serial_test multiline_f0_test f0_variants_test full_props part_shapes neuro_layout_test genooper_test geometry_apices_test geometry_info_test geometry_surface_test geometry_volume_test
+GDK_TESTS=genoconv_test gdk_test geno_test genooper_test genooper_test_fTest neuro_test loader_test serial_test multiline_f0_test f0_variants_test full_props part_shapes neuro_layout_test geometry_apices_test geometry_info_test geometry_surface_test geometry_volume_test
 
 gdk_tests: $(GDK_TESTS)
@@ -22,4 +22,10 @@
 geno_test: $(GENO_TEST_OBJS)
 	$(CXX) $(GENO_TEST_OBJS) -o $@
+
+genooper_test: $(GENOOPER_TEST_OBJS)
+	$(CXX) $(GENOOPER_TEST_OBJS) -o $@
+
+genooper_test_fTest: $(GENOOPER_TEST_FTEST_OBJS)
+	$(CXX) $(GENOOPER_TEST_FTEST_OBJS) -o $@
 
 neuro_test: $(NEURO_TEST_OBJS)
@@ -47,6 +53,4 @@
 	$(CXX) $(NEURO_LAYOUT_TEST_OBJS) -o $@
 
-genooper_test: $(GENOOPER_TEST_OBJS)
-	$(CXX) $(GENOOPER_TEST_OBJS) -o $@
 
 geometry_apices_test: $(GEOMETRY_APICES_TEST_OBJS)
@@ -62,4 +66,5 @@
 	$(CXX) $(GEOMETRY_VOLUME_TEST_OBJS) -o $@
 
+
 #############################################
 
Index: /cpp/frams/Makefile-GDK-files
===================================================================
--- /cpp/frams/Makefile-GDK-files	(revision 193)
+++ /cpp/frams/Makefile-GDK-files	(revision 194)
@@ -2,8 +2,9 @@
 
 # ALL_DIRS is later expanded by the shell, no spaces/newlines allowed, or it breaks
-ALL_DIRS={common,frams,frams/canvas,frams/config,frams/errmgr,frams/genetics,frams/genetics/f0,frams/genetics/f1,frams/genetics/f2,frams/genetics/f3,frams/genetics/f4,frams/genetics/f5,frams/genetics/f6,frams/genetics/f7,frams/genetics/f8,frams/genetics/f9,frams/genetics/fF,frams/model,frams/neuro,frams/neuro/impl,frams/param,frams/test,frams/util,frams/vm/classes,frams/virtfile,frams/_demos,frams/model/geometry,frams/_demos/geometry}
+ALL_DIRS={common,frams,frams/canvas,frams/config,frams/errmgr,frams/genetics,frams/genetics/f0,frams/genetics/f1,frams/genetics/f2,frams/genetics/f3,frams/genetics/f4,frams/genetics/f5,frams/genetics/f6,frams/genetics/f7,frams/genetics/f8,frams/genetics/f9,frams/genetics/fF,frams/genetics/fT,frams/model,frams/neuro,frams/neuro/impl,frams/param,frams/test,frams/util,frams/vm/classes,frams/virtfile,frams/_demos,frams/model/geometry,frams/_demos/geometry}
 
 GENMANF9=frams/genetics/f9/oper_f9.o
 GENMANFF=frams/genetics/fF/oper_fF.o
+GENMANFT=frams/genetics/fT/oper_fTest.o
 
 CONVF1=frams/genetics/f1/conv_f1.o
@@ -12,5 +13,5 @@
 
 GENOCONV_GDK_OBJS=frams/genetics/defgenoconv.o $(CONVF1) $(CONVF9) $(CONVFF)
-GENMAN_GDK_OBJS=$(GENMAN_COMMON_OBJS) $(GENMANF9) $(GENMANFF)
+GENMAN_GDK_OBJS=$(GENMAN_COMMON_OBJS) $(GENMANF9) $(GENMANFF) $(GENMANFT)
 
 GENMAN_COMMON_OBJS=frams/genetics/genman.o frams/param/mutableparam.o frams/param/mutparamlist.o frams/neuro/geneticneuroparam.o frams/neuro/neurolibparam.o frams/vm/classes/genoobj.o frams/model/autoname.o
@@ -34,4 +35,8 @@
 GENO_TEST_OBJS= frams/_demos/geno_test.o frams/virtfile/virtfile.o   $(GDK_OBJS) $(GENOCONV_GDK_OBJS) $(GENMAN_GDK_OBJS)
 
+GENOOPER_TEST_OBJS=frams/_demos/genooper_test.o frams/virtfile/virtfile.o frams/errmgr/stdouterr.o $(GDK_OBJS) $(GENOCONV_GDK_OBJS) $(GENMAN_GDK_OBJS)
+
+GENOOPER_TEST_FTEST_OBJS=frams/_demos/genooper_test_fTest.o frams/virtfile/virtfile.o $(GDK_OBJS) $(GENOCONV_GDK_OBJS) $(GENMAN_GDK_OBJS)
+
 NEURO_TEST_OBJS= frams/_demos/neuro_test.o frams/errmgr/stdouterr.o frams/virtfile/virtfile.o \
 	frams/neuro/neuroimpl.o frams/neuro/neurofactory.o frams/neuro/impl/neuroimpl-simple.o frams/neuro/impl/neuroimpl-channels.o \
@@ -46,6 +51,4 @@
 NEURO_LAYOUT_TEST_OBJS= frams/_demos/neuro_layout_test.o frams/virtfile/virtfile.o frams/errmgr/stdouterr.o $(GDK_OBJS) $(GENOCONV_GDK_OBJS) $(GENMAN_GDK_OBJS) frams/canvas/nn_layout_model.o frams/canvas/nn_simple_layout.o frams/canvas/nn_smart_layout.o
 
-GENOOPER_TEST_OBJS=frams/_demos/genooper_test.o frams/virtfile/virtfile.o frams/errmgr/stdouterr.o $(GDK_OBJS) $(GENOCONV_GDK_OBJS) $(GENMAN_GDK_OBJS)
-
 GEOMETRY_APICES_TEST_OBJS=frams/_demos/geometry/apices_test.o frams/_demos/geometry/geometrytestutils.o frams/_demos/genotypeloader.o frams/virtfile/virtfile.o frams/param/multiparamload.o frams/virtfile/stdiofile-autoinit.o frams/virtfile/stdiofile.o common/nonstd_stdio.o $(GDK_OBJS) $(GENOCONV_GDK_OBJS) $(GEOMETRY_OBJS)
 
Index: /cpp/frams/_demos/genooper_test_fTest.cpp
===================================================================
--- /cpp/frams/_demos/genooper_test_fTest.cpp	(revision 194)
+++ /cpp/frams/_demos/genooper_test_fTest.cpp	(revision 194)
@@ -0,0 +1,38 @@
+// This file is a part of the Framsticks GDK.
+// Copyright (C) 2002-2014  Maciej Komosinski and Szymon Ulatowski.  See LICENSE.txt for details.
+// Refer to http://www.framsticks.com/ for further information.
+
+#include <frams/genetics/fT/oper_fTest.h>
+
+GenoOper_fTest gft;
+
+//A demonstration of genetic operations on the "T" (fTest) genetic format:
+int main()
+{
+	float chg;
+	char *g = strdup(gft.getSimplest());
+	for (int i = 0; i < 10; i++)
+	{
+		int _method; //unused
+		int result = gft.mutate(g, chg, _method);
+		printf("%s   [mutated %.1f%%]\n", g, chg * 100);
+	}
+
+	char *g2 = strdup(gft.getSimplest());
+	float chg2;
+	printf("\nCrossing over the last mutant, \n\t%s\nand the simplest genotype\n\t%s\n:\n", g, g2);
+	gft.crossOver(g, g2, chg, chg2);
+	printf("Offspring 1:\n\t%s  (%.1f%% genes from parent1)\n", g, chg * 100);
+	printf("Offspring 2:\n\t%s  (%.1f%% genes from parent2)\n", g2, chg2 * 100);
+	free(g);
+	free(g2);
+
+	g = strdup("ATGsomethingCG");
+	printf("\nChecking genotype:\n\t%s... error at position %d.\n", g, gft.checkValidity(g));
+	gft.validate(g);
+	printf("After validation:\n\t%s\n", g);
+	free(g);
+	printf("...and how about YOUR genotype?\n\n");
+
+	return 0;
+}
Index: /cpp/frams/genetics/fT/oper_fTest.cpp
===================================================================
--- /cpp/frams/genetics/fT/oper_fTest.cpp	(revision 194)
+++ /cpp/frams/genetics/fT/oper_fTest.cpp	(revision 194)
@@ -0,0 +1,126 @@
+// This file is a part of the Framsticks GDK.
+// Copyright (C) 2002-2014  Maciej Komosinski and Szymon Ulatowski.  See LICENSE.txt for details.
+// Refer to http://www.framsticks.com/ for further information.
+
+#include "oper_fTest.h"
+#include <common/nonstd.h> //randomN, rnd01
+
+/**
+Sample output (simple examples of various genetic operations) produced by genooper_test_fTest.cpp:
+$ ./genooper_test_fTest.exe
+GATCGATTACA   [mutated 0.0%]
+GATCCATTACA   [mutated 9.1%]
+GATCCTGTACA   [mutated 27.3%]
+GATCCTGTACA   [mutated 0.0%]
+GATCCTGTACA   [mutated 0.0%]
+GATCCTGTATA   [mutated 9.1%]
+GATCCTGTATA   [mutated 0.0%]
+GATACTGTATA   [mutated 9.1%]
+GATACTGTATA   [mutated 9.1%]
+GATACTGTATA   [mutated 0.0%]
+
+Crossing over the last mutant,
+GATACTGTATA
+and the simplest genotype
+GATCGATTACA
+:
+Offspring 1:
+GATACTCGATTACA  (35.7% genes from parent1)
+Offspring 2:
+GATGTATA  (25.0% genes from parent2)
+
+Checking genotype:
+ATGsomethingCG... error at position 4.
+After validation:
+ATGCG
+...and how about YOUR genotype?
+*/
+
+
+// To test this genetic format, you can also use the general genooper_test app that supports all genetic formats:
+// $ ./genooper_test.exe /*T*/AAAAAAAAAAA
+
+
+
+#define FIELDSTRUCT GenoOper_fTest
+static ParamEntry GENOtestparam_tab[] =   //external access to ftest genetic parameters
+{
+	{ "Genetics: fTest", 1, 1, },
+	{ "fTest_mut", 0, 0, "Mutation probability", "f 0 1", FIELD(prob), "How many genes should be mutated during single mutation (1=all genes, 0.1=ten percent)", },
+	{ 0, },
+};
+#undef FIELDSTRUCT
+
+GenoOper_fTest::GenoOper_fTest()
+{
+	par.setParamTab(GENOtestparam_tab);
+	par.select(this);
+	supported_format = 'T'; //'0' for f0, '1' for f1, 'F' for fF, etc.
+	prob = 0.1;
+}
+
+///The only letters allowed are A,T,G,C
+int GenoOper_fTest::checkValidity(const char* gene)
+{
+	if (!gene[0]) return 1; //empty is not valid
+	bool ok = true;
+	int i;
+	for (i = 0; i < strlen(gene); i++) if (!strchr("ATGC", gene[i])) { ok = false; break; }
+	return ok ? GENOPER_OK : i + 1;
+}
+
+///Remove all invalid letters from the genotype
+int GenoOper_fTest::validate(char *&gene)
+{
+	SString validated; //new genotype (everything except ATGC is skipped)
+	for (int i = 0; i < strlen(gene); i++)
+		if (strchr("ATGC", gene[i])) validated += gene[i];  //validated contains only ATGC
+	free(gene);
+	gene = strdup(validated); //reallocate
+	return GENOPER_OK;
+}
+
+///Very simple mutation; should be improved to guarantee at least one gene changed
+int GenoOper_fTest::mutate(char *&geno, float &chg, int &method)
+{
+	static char a[] = "ATGC";
+	method = 0;
+	int changes = 0, len = strlen(geno);
+	for (int i = 0; i < len; i++)
+		if (rnd01 < prob) //normalize prob with length of genotype
+		{
+			geno[i] = a[randomN(4)];
+			changes++;
+		}
+	chg = (float)changes / len;
+	return GENOPER_OK;
+}
+
+///A simple one-point crossover
+int GenoOper_fTest::crossOver(char *&g1, char *&g2, float& chg1, float& chg2)
+{
+	int len1 = strlen(g1), len2 = strlen(g2);
+	int p1 = randomN(len1);  //random cut point for first genotype
+	int p2 = randomN(len2);  //random cut point for second genotype
+	char *child1 = (char*)malloc(p1 + len2 - p2 + 1);
+	char *child2 = (char*)malloc(p2 + len1 - p1 + 1);
+	strncpy(child1, g1, p1);   strcpy(child1 + p1, g2 + p2);
+	strncpy(child2, g2, p2);   strcpy(child2 + p2, g1 + p1);
+	free(g1); g1 = child1;
+	free(g2); g2 = child2;
+	chg1 = (float)p1 / strlen(child1);
+	chg2 = (float)p2 / strlen(child2);
+	return GENOPER_OK;
+}
+
+///Applying some colors and font styles...
+unsigned long GenoOper_fTest::style(const char *g, int pos)
+{
+	char ch = g[pos];
+	unsigned long style = GENSTYLE_CS(0, GENSTYLE_INVALID); //default, should be changed below
+	if (ch == 'A') style = GENSTYLE_RGBS(200, 0, 0, GENSTYLE_BOLD);
+	if (ch == 'T') style = GENSTYLE_RGBS(0, 200, 0, GENSTYLE_BOLD);
+	if (ch == 'G') style = GENSTYLE_RGBS(0, 0, 200, GENSTYLE_NONE);
+	if (ch == 'C') style = GENSTYLE_RGBS(200, 200, 0, GENSTYLE_NONE);
+	return style;
+}
Index: /cpp/frams/genetics/fT/oper_fTest.h
===================================================================
--- /cpp/frams/genetics/fT/oper_fTest.h	(revision 194)
+++ /cpp/frams/genetics/fT/oper_fTest.h	(revision 194)
@@ -0,0 +1,37 @@
+// This file is a part of the Framsticks GDK.
+// Copyright (C) 2002-2014  Maciej Komosinski and Szymon Ulatowski.  See LICENSE.txt for details.
+// Refer to http://www.framsticks.com/ for further information.
+
+#ifndef _GENOOPER_FTEST_H_
+#define _GENOOPER_FTEST_H_
+
+#include "../oper_fx.h"
+
+/** \file */
+
+///A sample class for genetic operations on DNA-like genotypes
+/**
+\author Maciej Komosinski
+
+This is a very simple class that illustrates basic genetic operations performed on ATGC sequences.
+For a more sophisticated and realistic examples of genetic formats and operators derived from GenoOperators,
+refer to the available source for genetic formats f9, fF, and f4.
+
+\sa \ref geno_ftest_example
+*/
+
+class GenoOper_fTest : public GenoOperators
+{
+public:
+	GenoOper_fTest();
+	int checkValidity(const char *);
+	int validate(char *&);
+	int mutate(char *&geno, float& chg, int &method);
+	int crossOver(char *&g1, char *&g2, float& chg1, float& chg2);
+	unsigned long style(const char *g, int pos);
+	const char* getSimplest() { return "GATCGATTACA"; }
+
+	double prob;
+};
+
+#endif
Index: /cpp/frams/genetics/gen-config-GDK.h
===================================================================
--- /cpp/frams/genetics/gen-config-GDK.h	(revision 193)
+++ /cpp/frams/genetics/gen-config-GDK.h	(revision 194)
@@ -29,2 +29,4 @@
 #define USE_GENMAN_f9
 #define USE_GENMAN_fF
+#define USE_GENMAN_fT
+
Index: /cpp/frams/genetics/genman.cpp
===================================================================
--- /cpp/frams/genetics/genman.cpp	(revision 193)
+++ /cpp/frams/genetics/genman.cpp	(revision 194)
@@ -46,4 +46,7 @@
 #ifdef USE_GENMAN_fF
 #include "fF/oper_fF.h"
+#endif
+#ifdef USE_GENMAN_fT
+#include "fT/oper_fTest.h"
 #endif
 
@@ -139,4 +142,7 @@
 #ifdef USE_GENMAN_fF
 	oper_fx_list.push_back(new GenoOper_fF);
+#endif
+#ifdef USE_GENMAN_fT
+	oper_fx_list.push_back(new GenoOper_fTest);
 #endif
 
