diff --git a/.gitignore b/.gitignore
index ae5f085df619e4faf11263c8af42121396ec16d9..cddf03602a35709c94e0d191f9fe37af69e5757e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,6 @@
 .gradle/
 .idea/
 build/dependencyUpdates/
+venv/
+*/out/
+logs/
diff --git a/benchmark/.gitignore b/benchmark/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..54c5c0b024dab04da2a43d4135ed67ed2a670b46
--- /dev/null
+++ b/benchmark/.gitignore
@@ -0,0 +1,2 @@
+/build/
+logs/
diff --git a/benchmark/build.gradle b/benchmark/build.gradle
new file mode 100644
index 0000000000000000000000000000000000000000..dfcc1d42edbaf81885917bd8b31573056ba29dbb
--- /dev/null
+++ b/benchmark/build.gradle
@@ -0,0 +1,36 @@
+apply plugin: 'application'
+
+dependencies {
+    compile project(':eraser-base')
+    compile project(':feedbackloop.learner_backup')
+    compile project(':datasets')
+    testImplementation 'junit:junit:4.12'
+    // https://mvnrepository.com/artifact/org.hamcrest/java-hamcrest
+    // https://mvnrepository.com/artifact/org.hamcrest/hamcrest-core
+    testCompile group: 'org.hamcrest', name: 'hamcrest-core', version: '1.3'
+    implementation group: 'com.opencsv', name: 'opencsv', version: '4.1'
+    // https://mvnrepository.com/artifact/org.apache.httpcomponents/httpclient
+    compile group: 'org.apache.httpcomponents', name: 'httpclient', version: '4.0-alpha4'
+    testCompile group: 'org.apache.logging.log4j', name: 'log4j-slf4j-impl', version: '2.11.2'
+    // https://mvnrepository.com/artifact/org.apache.httpcomponents/fluent-hc
+    compile group: 'org.apache.httpcomponents', name: 'fluent-hc', version: '4.2.1'
+    // https://mvnrepository.com/artifact/junit/junit
+    testCompile group: 'junit', name: 'junit', version: '4.4'
+    
+}
+
+run {
+    mainClassName = 'de.tudresden.inf.st.eraser.benchmark.Main'
+    standardInput = System.in
+    if (project.hasProperty("appArgs")) {
+        args Eval.me(appArgs)
+    }
+}
+
+sourceSets {
+    main {
+        java {
+            srcDir 'src/main/java'
+        }
+    }
+}
diff --git a/benchmark/src/main/java/de/tudresden/inf/st/eraser/benchmark/Benchmark.java b/benchmark/src/main/java/de/tudresden/inf/st/eraser/benchmark/Benchmark.java
new file mode 100644
index 0000000000000000000000000000000000000000..2c1d64d5be93238589167e0c474218d3b22a952f
--- /dev/null
+++ b/benchmark/src/main/java/de/tudresden/inf/st/eraser/benchmark/Benchmark.java
@@ -0,0 +1,146 @@
+package de.tudresden.inf.st.eraser.benchmark;
+
+import com.opencsv.CSVReader;
+import org.apache.http.HttpResponse;
+import org.apache.http.client.fluent.Request;
+import org.apache.http.entity.ContentType;
+import org.apache.http.util.EntityUtils;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import java.io.File;
+import java.io.FileReader;
+import java.util.Arrays;
+
+public class Benchmark {
+
+    //read every 5 s from csv
+    //activity CSV
+    /**
+     * Col 1: smartphone acceleration x
+     * Col 2: smartphone acceleration y
+     * Col 3: smartphone acceleration z
+     * Col 4: smartphone rotation x
+     * Col 5: smartphone rotation y
+     * Col 6: smartphone rotation z
+     * Col 7: watch acceleration x
+     * Col 8: watch acceleration y
+     * Col 9: watch acceleration z
+     * Col 10: watch rotation x
+     * Col 11: watch rotation y
+     * Col 12: watch rotation z/*/
+    //preference CSV
+    /**
+     * Col 1: Activity
+     * Col 2: watch brightness range "bright, medium, dimmer, dark"*/
+
+    private String a_csv_file_path;
+    private String p_csv_file_path;
+    private static final Logger logger = LogManager.getLogger(Benchmark.class);
+    private static final String ERASER_ITEM_URI = "http://localhost:4567/model/items/";
+    //TODO ITEM_NAME HAS TO BE DISCUSSED
+    private static final String[] ACTIVITY_ITEM_NAME = {
+            "m_accel_x", "m_accel_y", "m_accel_z", "m_rotation_x",
+            "m_rotation_y", "m_rotation_z", "w_accel_x", "w_accel_y",
+            "w_accel_z", "w_rotation_x", "w_rotation_y", "w_rotation_z"};
+    private static final String[] PREFERENCE_ITEM_NAME = {
+           "w_brightness"
+    };
+    private static boolean flag2 = true;
+    //csv_type is activity or preference
+    Benchmark(String a_csv_file_path, String p_csv_file_path) {
+        this.a_csv_file_path = a_csv_file_path;
+        this.p_csv_file_path = p_csv_file_path;
+    }
+
+    void start(){
+        String PREFERENCE_URL = "http://localhost:4567/model/items/iris1_item/state";
+        String ACTIVITY_URL = "http://localhost:4567/activity/current";
+        int TIME_PERIOD = 5000;
+        File a_file;
+        File p_file;
+        FileReader a_file_reader;
+        FileReader p_file_reader;
+        CSVReader a_csv_reader;
+        CSVReader p_csv_reader;
+        String[] a_next_record;
+        String[] p_next_record;
+        boolean flag1;
+        a_file=new File(a_csv_file_path);
+        p_file= new File(p_csv_file_path);
+        try {
+            a_file_reader =new FileReader(a_file);
+            p_file_reader=new FileReader(p_file);
+            a_csv_reader = new CSVReader(a_file_reader);
+            p_csv_reader = new CSVReader(p_file_reader);
+            while ((((a_next_record = a_csv_reader.readNext())!= null) && flag2)){
+                try{Thread.sleep(TIME_PERIOD);}catch (InterruptedException e){e.printStackTrace();}
+                String[] values = Arrays.copyOf(a_next_record,12);
+                setNewValue(values, ACTIVITY_ITEM_NAME,"activity");
+                HttpResponse response= Request.Get(ACTIVITY_URL).execute().returnResponse();
+                String status = response.getStatusLine().toString();
+                if(status.contains("200")){
+                    flag1 = true;
+                    logger.info("activity should be (read direct from CSV): " + a_next_record[12]);
+                    logger.info(EntityUtils.toString(response.getEntity()));
+                    logger.info("get activity from web server: response 200 ok");
+                }else{
+                    flag1 = false;
+                    flag2 = false;
+                    logger.info("can not get the activity from the web server");
+                }
+                while((((p_next_record = p_csv_reader.readNext()) != null) && flag1)) {
+                    try{Thread.sleep(TIME_PERIOD);}catch (InterruptedException e){e.printStackTrace();}
+                    String[] values1 = Arrays.copyOf(p_next_record,2);
+                    setNewValue(values1, PREFERENCE_ITEM_NAME,"preference");
+                    HttpResponse response1= Request.Get(PREFERENCE_URL).execute().returnResponse();
+                    String status1=response1.getStatusLine().toString();
+                    if(status1.contains("200")){
+                        flag2 = true;
+                        logger.info("get the iris1_item preference from web server: response 200 ok, value is: "+EntityUtils.toString(response1.getEntity()));
+                    }else {flag2 = false;
+                    logger.info("can not get the iris1_item from the web server");}
+                    break;
+                }
+            }
+        }
+        catch (Exception e){
+            e.printStackTrace();
+        }
+    }
+    private void setNewValue(String[] values, String[] name, String file_typ){
+        if(file_typ.equals("activity"))
+        {
+            int i = 0;
+            for(String value : values){
+                String uri = ERASER_ITEM_URI + name[i] + "/state";
+                try {
+                    HttpResponse httpResponse = Request.Put(uri)
+                            .bodyString(value, ContentType.TEXT_PLAIN)
+                            .execute().returnResponse();
+                    String status=httpResponse.getStatusLine().toString();
+                    if(status.contains("200")){
+                        logger.info("put activity input name: "+name[i]+", value: "+value+"to web server: response 200 ok");
+                    }else{
+                        logger.info("can not put activity inputs to rest server");
+                    }
+                }catch (Exception e){
+                    e.printStackTrace();
+                }
+                i+=1;
+            }
+        }else{
+            String uri= ERASER_ITEM_URI + "w_brightness" +"/state";
+            try {
+                HttpResponse httpResponse = Request.Put(uri)
+                        .bodyString(values[1], ContentType.TEXT_PLAIN)
+                        .execute().returnResponse();
+                String put_response=httpResponse.getStatusLine().toString();
+                if (put_response.contains("200")){logger.info("put w_brightness to web server: response 200 ok");}else{
+                    logger.info("can not put w_brightness to rest server");
+                }
+            }catch (Exception e){
+                e.printStackTrace();
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/benchmark/src/main/java/de/tudresden/inf/st/eraser/benchmark/Main.java b/benchmark/src/main/java/de/tudresden/inf/st/eraser/benchmark/Main.java
new file mode 100644
index 0000000000000000000000000000000000000000..ac7536cae53749132be31ebe028e5ec0e55c30f4
--- /dev/null
+++ b/benchmark/src/main/java/de/tudresden/inf/st/eraser/benchmark/Main.java
@@ -0,0 +1,12 @@
+package de.tudresden.inf.st.eraser.benchmark;
+
+public class Main {
+
+    public static void main(String[] args) {
+        String A_CSV_FILE_PATH = "../datasets/backup/activity_data.csv";
+        String P_CSV_FILE_PATH = "../datasets/backup/preference_data.csv";
+        Benchmark benchmark=new Benchmark(A_CSV_FILE_PATH,P_CSV_FILE_PATH);
+        benchmark.start();
+    }
+}
+
diff --git a/feedbackloop.learner_backup/out/production/resources/log4j2.xml b/benchmark/src/main/resources/log4j2.xml
similarity index 100%
rename from feedbackloop.learner_backup/out/production/resources/log4j2.xml
rename to benchmark/src/main/resources/log4j2.xml
diff --git a/eraser-base/build.gradle b/eraser-base/build.gradle
index 2d0b1f8e78a2333cf594e8732e9ba30657a78db2..fbe5f76ec7b7097ca4ef1ca48181b4c26eb71433 100644
--- a/eraser-base/build.gradle
+++ b/eraser-base/build.gradle
@@ -118,6 +118,7 @@ task copyRagdoc(type: Copy, dependsOn: cleanRagdoc) {
 }
 
 generateAst.dependsOn preprocess
+generateAst.inputs.files file("./src/main/jastadd/mainGen.ast"), file("./src/main/jastadd/mainGen.jadd")
 //compileJava.dependsOn jastadd
 //
 //// always run jastadd
diff --git a/eraser-base/src/main/jastadd/Item.jrag b/eraser-base/src/main/jastadd/Item.jrag
index c143c2bbdc23e9a0a3035f7293af1700baee740c..0b370142cf57c377775294bb6c758dafa7db036f 100644
--- a/eraser-base/src/main/jastadd/Item.jrag
+++ b/eraser-base/src/main/jastadd/Item.jrag
@@ -10,12 +10,19 @@ aspect ItemHandling {
   public void Item.enableSendState() { sendState = true; }
   public final boolean Item.isSendState() { return sendState; }
 
+  //--- DateTimeItem.ALTERNATIVE_FORMAT ---
+  private static final java.time.format.DateTimeFormatter DateTimeItem.ALTERNATIVE_FORMAT = new java.time.format.DateTimeFormatterBuilder()
+    .appendPattern("yyyy-MM-dd'T'HH:mm:ss.SSSZ")
+    .toFormatter()
+    .withZone(java.time.ZoneId.of("UTC"));
+
   //--- getStateAsString ---
   syn String Item.getStateAsString();
   eq ColorItem.getStateAsString() = getState().toString();
   eq DateTimeItem.getStateAsString() = getState().toString();
   eq ItemWithBooleanState.getStateAsString() = Boolean.toString(getState());
   eq SwitchItem.getStateAsString() = getState() ? "ON" : "OFF";
+  eq ContactItem.getStateAsString() = getState() ? "OPEN" : "CLOSED";
   eq ItemWithDoubleState.getStateAsString() = Double.toString(getState());
   eq ItemWithStringState.getStateAsString() = getState();
 
@@ -50,19 +57,24 @@ aspect ItemHandling {
     }
   }
   public void DateTimeItem.setStateFromString(String value) {
-    try{
+    Exception exception = null;
+    // try normal instant parsing. Format example: 2019-07-22T12:58:08.960Z
+    try {
       this.setState(Instant.parse(value));
-    } catch (java.time.format.DateTimeParseException e1) {
-      // try to read input as number and use that
-      try {
-        long time = Long.parseLong(value);
-        this.setStateFromLong(time);
-        // exit the method to avoid printing the error message for e1
-        return;
-      } catch (NumberFormatException e2) {
-        logger.catching(e2);
-      }
-      logger.catching(e1);
+      return;
+    } catch (java.time.format.DateTimeParseException e) { /* empty */ }
+    // try openHAB parsing. Format example: 2019-07-22T12:58:08.960+0000
+    try {
+      this.setState(ALTERNATIVE_FORMAT.parse(value, Instant::from));
+      return;
+    } catch (java.time.format.DateTimeParseException e) { /* empty */ }
+    // try to read input as number and use that
+    try {
+      long time = Long.parseLong(value);
+      this.setStateFromLong(time);
+      return;
+    } catch (NumberFormatException e) {
+      logger.warn("Could not parse date value from {}", value);
     }
   }
   public void ItemWithBooleanState.setStateFromString(String value) {
@@ -75,6 +87,20 @@ aspect ItemHandling {
       default: super.setStateFromString(value);
     }
   }
+  public void ContactItem.setStateFromString(String value) {
+    switch (value) {
+      case "OPEN": this.setState(true); break;
+      case "CLOSED": this.setState(false); break;
+      default: super.setStateFromString(value);
+    }
+  }
+  public void RollerShutterItem.setStateFromString(String value) {
+    switch (value) {
+      case "UP": this.setState(0); break;
+      case "DOWN": this.setState(100); break;
+      default: super.setStateFromString(value);
+    }
+  }
   public void ItemWithDoubleState.setStateFromString(String value) {
     this.setState(Double.parseDouble(value));
   }
@@ -288,7 +314,7 @@ aspect ItemHandling {
   //--- sendState ---
   protected void Item.sendState() throws Exception {
     for (MachineLearningModel model : getRelevantInMachineLearningModels()) {
-      model.getEncoder().newData(getRoot(), java.util.Collections.singletonList(this));
+      model.getEncoder().newData(Collections.singletonList(this));
     }
   }
 
diff --git a/eraser-base/src/main/jastadd/Logging.jadd b/eraser-base/src/main/jastadd/Logging.jadd
index dd41bc70f125081ea2ab6291ae48fa0272eea4c4..710bd79a7bce048213ce0d52bb42cae5176b832a 100644
--- a/eraser-base/src/main/jastadd/Logging.jadd
+++ b/eraser-base/src/main/jastadd/Logging.jadd
@@ -1,12 +1,21 @@
 aspect Logging {
+  // Base
   protected org.apache.logging.log4j.Logger Item.logger = org.apache.logging.log4j.LogManager.getLogger(Item.class);
   protected org.apache.logging.log4j.Logger ItemPreference.logger = org.apache.logging.log4j.LogManager.getLogger(ItemPreference.class);
-  protected org.apache.logging.log4j.Logger Neuron.logger = org.apache.logging.log4j.LogManager.getLogger(Neuron.class);
 
+  // MachineLearning
   private org.apache.logging.log4j.Logger DummyMachineLearningModel.logger = org.apache.logging.log4j.LogManager.getLogger(DummyMachineLearningModel.class);
-  private org.apache.logging.log4j.Logger Rule.logger = org.apache.logging.log4j.LogManager.getLogger(Rule.class);
-  private org.apache.logging.log4j.Logger MqttRoot.logger = org.apache.logging.log4j.LogManager.getLogger(MqttRoot.class);
-  private org.apache.logging.log4j.Logger InternalMachineLearningModel.logger = org.apache.logging.log4j.LogManager.getLogger(MachineLearningModel.class);
+  private org.apache.logging.log4j.Logger InternalMachineLearningModel.logger = org.apache.logging.log4j.LogManager.getLogger(InternalMachineLearningModel.class);
+  private org.apache.logging.log4j.Logger ExternalMachineLearningModel.logger = org.apache.logging.log4j.LogManager.getLogger(ExternalMachineLearningModel.class);
+
+  // NeuralNetwork
   private org.apache.logging.log4j.Logger NeuralNetworkRoot.logger = org.apache.logging.log4j.LogManager.getLogger(NeuralNetworkRoot.class);
   private org.apache.logging.log4j.Logger OutputLayer.logger = org.apache.logging.log4j.LogManager.getLogger(OutputLayer.class);
+  protected org.apache.logging.log4j.Logger Neuron.logger = org.apache.logging.log4j.LogManager.getLogger(Neuron.class);
+
+  // Rules
+  private org.apache.logging.log4j.Logger Rule.logger = org.apache.logging.log4j.LogManager.getLogger(Rule.class);
+
+  // MQTT
+  private org.apache.logging.log4j.Logger MqttRoot.logger = org.apache.logging.log4j.LogManager.getLogger(MqttRoot.class);
 }
diff --git a/eraser-base/src/main/jastadd/MachineLearning.jrag b/eraser-base/src/main/jastadd/MachineLearning.jrag
index e5fc2f6f3e8c2dd8e9cb17c38d1dfd2c88f4a465..e584d8f2f6b9f1b2b0ce140a46c005b32887e1dd 100644
--- a/eraser-base/src/main/jastadd/MachineLearning.jrag
+++ b/eraser-base/src/main/jastadd/MachineLearning.jrag
@@ -112,7 +112,8 @@ aspect MachineLearning {
 
   @Override
   public boolean ExternalMachineLearningModel.check() {
-    throw new UnsupportedOperationException("check not available for external ML models (yet)!");
+    logger.warn("check not available for external ML models (yet)!");
+    return true;
   }
 
   //--- mlKind ---
@@ -160,7 +161,33 @@ aspect MachineLearning {
     return this.decoder;
   }
 
-  // refine Item.stateUpdated
+}
+
+aspect ChangeEvents {
+  private static final java.util.concurrent.atomic.AtomicInteger ChangeEvent.idCounter = new java.util.concurrent.atomic.AtomicInteger(0);
+
+  //--- createRecognitionEvent ---
+  public static RecognitionEvent RecognitionEvent.createRecognitionEvent(MachineLearningModel modelOfRecognition) {
+    RecognitionEvent result = new RecognitionEvent();
+    result.initChangeEvent();
+    for (Item relevantItem : modelOfRecognition.getRelevantItems()) {
+      result.addChangedItem(ChangedItem.newFromItem(relevantItem));
+    }
+    return result;
+  }
 
+  //--- newFromItem ---
+  public static ChangedItem ChangedItem.newFromItem(Item source) {
+    ChangedItem result = new ChangedItem();
+    result.setItem(source);
+    result.setNewStateAsString(source.getStateAsString());
+    return result;
+  }
+
+  //--- initChangeEvent ---
+  protected void ChangeEvent.initChangeEvent() {
+    this.setCreated(Instant.now());
+    this.setIdentifier(idCounter.incrementAndGet());
+  }
 
 }
diff --git a/eraser-base/src/main/jastadd/MachineLearning.relast b/eraser-base/src/main/jastadd/MachineLearning.relast
index b31dacb02aea2143c22828f9d6fa15d24ad9c545..906d344b8f123fca5d617b174078dcfa56f7f4c8 100644
--- a/eraser-base/src/main/jastadd/MachineLearning.relast
+++ b/eraser-base/src/main/jastadd/MachineLearning.relast
@@ -3,7 +3,7 @@ MachineLearningRoot ::= [ActivityRecognition:MachineLearningModel] [PreferenceLe
 
 Activity ::= <Identifier:int> <Label:String> ;
 
-abstract ChangeEvent ::= <Identifier:int> <Timestamp:long> ChangedItem* ;
+abstract ChangeEvent ::= <Identifier:int> <Created:Instant> ChangedItem* ;
 
 ChangedItem ::= <NewStateAsString:String> ;
 rel ChangedItem.Item -> Item ;
diff --git a/eraser-base/src/main/jastadd/Printing.jrag b/eraser-base/src/main/jastadd/Printing.jrag
index 53206bc16b2a09708a33386393ade1f3310e1666..7402973f563eb21924f1f54a54ae8dc6d2bea848 100644
--- a/eraser-base/src/main/jastadd/Printing.jrag
+++ b/eraser-base/src/main/jastadd/Printing.jrag
@@ -207,4 +207,29 @@ aspect Printing {
         .build();
   }
 
+// Expressions
+  syn String ParenthesizedNumberExpression.prettyPrint() = "(" + getOperand().prettyPrint() + ")";
+  syn String NumberLiteralExpression.prettyPrint() = Double.toString(getValue());
+  syn String AddExpression.prettyPrint() = "(" + getLeftOperand().prettyPrint() + " + " + getRightOperand().prettyPrint() + ")";
+  syn String SubExpression.prettyPrint() = "(" + getLeftOperand().prettyPrint() + " - " + getRightOperand().prettyPrint() + ")";
+  syn String MultExpression.prettyPrint() = "(" + getLeftOperand().prettyPrint() + " * " + getRightOperand().prettyPrint() + ")";
+  syn String DivExpression.prettyPrint() = "(" + getLeftOperand().prettyPrint() + " / " + getRightOperand().prettyPrint() + ")";
+  syn String PowerExpression.prettyPrint() = "(" + getLeftOperand().prettyPrint() + " ^ " + getRightOperand().prettyPrint() + ")";
+  syn String ParenthesizedLogicalExpression.prettyPrint()  = "(" + getOperand().prettyPrint() + ")";
+  syn String NotExpression.prettyPrint()  = "!" + getOperand().prettyPrint();
+  syn String ComparingExpression.prettyPrint() {
+    switch (getComparator()) {
+      case NotEquals: return "(" + getLeftOperand().prettyPrint() + " != " + getRightOperand().prettyPrint() + ")";
+      case Equals: return "(" + getLeftOperand().prettyPrint() + " == " + getRightOperand().prettyPrint() + ")";
+      case LessThan: return "(" + getLeftOperand().prettyPrint() + " < " + getRightOperand().prettyPrint() + ")";
+      case GreaterThan: return "(" + getLeftOperand().prettyPrint() + " > " + getRightOperand().prettyPrint() + ")";
+      case LessOrEqualThan: return "(" + getLeftOperand().prettyPrint() + " <= " + getRightOperand().prettyPrint() + ")";
+      case GreaterOrEqualThan: return "(" + getLeftOperand().prettyPrint() + " >= " + getRightOperand().prettyPrint() + ")";
+      default: throw new IllegalArgumentException("Unknown compartor type: " + getComparator());
+    }
+  }
+  syn String AndExpression.prettyPrint() = "(" + getLeftOperand().prettyPrint() + " & " + getRightOperand().prettyPrint() + ")";
+  syn String OrExpression.prettyPrint() = "(" + getLeftOperand().prettyPrint() + " | " + getRightOperand().prettyPrint() + ")";
+  syn String Designator.prettyPrint() = getItem().getID();
+
 }
diff --git a/eraser-base/src/main/jastadd/Util.jrag b/eraser-base/src/main/jastadd/Util.jrag
index 282a44413c80ee2b5c5d71dca179ce4cf45c1fde..b038ca0dfae51d7bbea748086965b78e40f0c3e6 100644
--- a/eraser-base/src/main/jastadd/Util.jrag
+++ b/eraser-base/src/main/jastadd/Util.jrag
@@ -6,6 +6,7 @@ aspect Util {
 //  }
   public void MqttRoot.setHostByName(String hostName) {
     setHost(ExternalHost.of(hostName, DEFAULT_PORT));
+    flushCache();
   }
 
   public void InfluxRoot.setHostByName(String hostName) {
diff --git a/eraser-base/src/main/jastadd/eraser.flex b/eraser-base/src/main/jastadd/eraser.flex
index 2bd49e50fdfadebce430f728fa056be76573e8d6..bc9b3e8d9a41c9bd4cc51d1879f081b32538f103 100644
--- a/eraser-base/src/main/jastadd/eraser.flex
+++ b/eraser-base/src/main/jastadd/eraser.flex
@@ -106,7 +106,7 @@ Comment = "//" [^\n\r]+
 "<="           { return sym(Terminals.LE); }
 "=="           { return sym(Terminals.EQ); }
 "!="           { return sym(Terminals.NE); }
-"=>"           { return sym(Terminals.GE); }
+">="           { return sym(Terminals.GE); }
 ">"            { return sym(Terminals.GT); }
 "+"            { return sym(Terminals.PLUS); }
 "*"            { return sym(Terminals.MULT); }
diff --git a/eraser-base/src/main/jastadd/mqtt.jrag b/eraser-base/src/main/jastadd/mqtt.jrag
index ee7e06e00e5979a416ab300cf5163cc731af2072..b3f9c2a24a0a62ccc1f360fdadaad4cd7bafe3b5 100644
--- a/eraser-base/src/main/jastadd/mqtt.jrag
+++ b/eraser-base/src/main/jastadd/mqtt.jrag
@@ -74,4 +74,14 @@ aspect MQTT {
     getMqttRoot().getMqttSender().publish(getOutgoingTopic(), message);
   }
 
+  refine OpenHAB2 public void OpenHAB2Model.addNewItem(Item item) {
+    refined(item);
+    // update mqtt-topic to new mqtt-root
+    JavaUtils.ifPresentOrElse(
+        getRoot().getMqttRoot().resolveTopicSuffix(item.getTopic().getTopicString()),
+        topic -> item.setTopic(topic),
+        () -> de.tudresden.inf.st.eraser.util.ParserUtils.createMqttTopic(item, item.getTopic().getTopicString(), getRoot())
+    );
+  }
+
 }
diff --git a/eraser-base/src/main/jastadd/openhab.jrag b/eraser-base/src/main/jastadd/openhab.jrag
index 6d30e4b3e0fb91225c9e8ea08bfdf3ab1afb1357..56aa89f36ac62aa817352f45a639ae7c4aa62206 100644
--- a/eraser-base/src/main/jastadd/openhab.jrag
+++ b/eraser-base/src/main/jastadd/openhab.jrag
@@ -2,4 +2,12 @@ aspect OpenHAB2 {
   syn ActivityItem OpenHAB2Model.getActivityItem() {
     return new ActivityItem();
   }
+
+  public void OpenHAB2Model.addNewItem(Item item) {
+    JavaUtils.ifPresentOrElse(
+        resolveGroup(de.tudresden.inf.st.eraser.util.ParserUtils.UNKNOWN_GROUP_NAME),
+        group -> group.addItem(item),
+        () -> de.tudresden.inf.st.eraser.util.ParserUtils.createUnknownGroup(this, Collections.singletonList(item)));
+  }
+
 }
diff --git a/eraser-base/src/main/jastadd/openhab.relast b/eraser-base/src/main/jastadd/openhab.relast
index 7d7d9afa27f9f9998f6c5bd4b9822f0dfa774e8d..575f875734994ee52ba5259e5cfe570aa488c139 100644
--- a/eraser-base/src/main/jastadd/openhab.relast
+++ b/eraser-base/src/main/jastadd/openhab.relast
@@ -40,7 +40,7 @@ ImageItem : ItemWithStringState ;
 LocationItem : ItemWithStringState ;
 NumberItem : ItemWithDoubleState ;
 PlayerItem : ItemWithStringState ;
-RollerShutterItem : ItemWithBooleanState ;
+RollerShutterItem : ItemWithDoubleState ;
 StringItem : ItemWithStringState ;
 SwitchItem : ItemWithBooleanState ;
 DefaultItem : ItemWithStringState ;
diff --git a/eraser-base/src/main/java/de/tudresden/inf/st/eraser/jastadd/model/InternalMachineLearningHandler.java b/eraser-base/src/main/java/de/tudresden/inf/st/eraser/jastadd/model/InternalMachineLearningHandler.java
index 2c59f46ca48fc18afa7aa096571a19ef9bef4b44..75d2a1d8cfc28c0293f1d55cc4e6714a6e37818a 100644
--- a/eraser-base/src/main/java/de/tudresden/inf/st/eraser/jastadd/model/InternalMachineLearningHandler.java
+++ b/eraser-base/src/main/java/de/tudresden/inf/st/eraser/jastadd/model/InternalMachineLearningHandler.java
@@ -22,7 +22,12 @@ public class InternalMachineLearningHandler implements MachineLearningEncoder, M
   }
 
   @Override
-  public void newData(Root model, List<Item> changedItems) {
+  public void setKnowledgeBaseRoot(Root root) {
+    // ignored
+  }
+
+  @Override
+  public void newData(List<Item> changedItems) {
     logger.debug("Ignored new data of {}", changedItems);
   }
 
diff --git a/eraser-base/src/main/java/de/tudresden/inf/st/eraser/jastadd/model/MachineLearningDecoder.java b/eraser-base/src/main/java/de/tudresden/inf/st/eraser/jastadd/model/MachineLearningDecoder.java
index a6e01fb945226bcf91e4bc94663c24b561f7cd6f..045c7695ba325429a3ba82a4e1319e0926aa043b 100644
--- a/eraser-base/src/main/java/de/tudresden/inf/st/eraser/jastadd/model/MachineLearningDecoder.java
+++ b/eraser-base/src/main/java/de/tudresden/inf/st/eraser/jastadd/model/MachineLearningDecoder.java
@@ -9,7 +9,7 @@ import java.time.Instant;
  * @author rschoene - Initial contribution
  */
 @SuppressWarnings("unused")
-public interface MachineLearningDecoder {
+public interface MachineLearningDecoder extends MachineLearningSetRoot {
 
   /**
    * Execute the machine learning model and returns the classification result.
diff --git a/eraser-base/src/main/java/de/tudresden/inf/st/eraser/jastadd/model/MachineLearningEncoder.java b/eraser-base/src/main/java/de/tudresden/inf/st/eraser/jastadd/model/MachineLearningEncoder.java
index 8cf4d78fd92a2c18bd4914ab5b805db63995be85..23ca8959f468b8210c287b163a217a0224f7d283 100644
--- a/eraser-base/src/main/java/de/tudresden/inf/st/eraser/jastadd/model/MachineLearningEncoder.java
+++ b/eraser-base/src/main/java/de/tudresden/inf/st/eraser/jastadd/model/MachineLearningEncoder.java
@@ -1,8 +1,5 @@
 package de.tudresden.inf.st.eraser.jastadd.model;
 
-import de.tudresden.inf.st.eraser.jastadd.model.Item;
-import de.tudresden.inf.st.eraser.jastadd.model.Root;
-
 import java.util.List;
 
 /**
@@ -13,14 +10,13 @@ import java.util.List;
  * @author rschoene - Initial contribution
  */
 @SuppressWarnings("unused")
-public interface MachineLearningEncoder {
+public interface MachineLearningEncoder extends MachineLearningSetRoot {
 
   /**
    * Update when new data is available.
-   * @param model        The underlying model
    * @param changedItems A list of items whose state has changed
    */
-  void newData(Root model, List<Item> changedItems);
+  void newData(List<Item> changedItems);
 
   // to be discussed, in which form this is specified
 
diff --git a/eraser-base/src/main/java/de/tudresden/inf/st/eraser/jastadd/model/MachineLearningSetRoot.java b/eraser-base/src/main/java/de/tudresden/inf/st/eraser/jastadd/model/MachineLearningSetRoot.java
new file mode 100644
index 0000000000000000000000000000000000000000..13fec09c243d0d15c4f5e41a8c8851321c26d5d5
--- /dev/null
+++ b/eraser-base/src/main/java/de/tudresden/inf/st/eraser/jastadd/model/MachineLearningSetRoot.java
@@ -0,0 +1,17 @@
+package de.tudresden.inf.st.eraser.jastadd.model;
+
+/**
+ * Common interface for both {@link MachineLearningDecoder} and {@link MachineLearningEncoder}.
+ *
+ * @author rschoene - Initial contribution
+ */
+public interface MachineLearningSetRoot {
+
+  /**
+   * Informs this handler of the knowledge base.
+   * This method is called before any other of the interface methods.
+   * @param root The root node of the knowledge base
+   */
+  void setKnowledgeBaseRoot(Root root);
+
+}
diff --git a/eraser-base/src/main/java/de/tudresden/inf/st/eraser/parser/EraserParserHelper.java b/eraser-base/src/main/java/de/tudresden/inf/st/eraser/parser/EraserParserHelper.java
index fe88455606c2bb7b6d78a877059077686edf12fc..5d1b1af27c4bf36e15768bd12facc02ca3a1e773 100644
--- a/eraser-base/src/main/java/de/tudresden/inf/st/eraser/parser/EraserParserHelper.java
+++ b/eraser-base/src/main/java/de/tudresden/inf/st/eraser/parser/EraserParserHelper.java
@@ -7,7 +7,6 @@ import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
 
 import java.util.*;
-import java.util.Comparator;
 import java.util.function.BiConsumer;
 
 /**
diff --git a/eraser-base/src/main/java/de/tudresden/inf/st/eraser/util/MqttReceiver.java b/eraser-base/src/main/java/de/tudresden/inf/st/eraser/util/MqttReceiver.java
index 1f013ea25872e57e452a603616e95126bdd69e11..5fa9ad6800b3964369d0a1f140db6a4c3e0d164f 100644
--- a/eraser-base/src/main/java/de/tudresden/inf/st/eraser/util/MqttReceiver.java
+++ b/eraser-base/src/main/java/de/tudresden/inf/st/eraser/util/MqttReceiver.java
@@ -133,6 +133,17 @@ public class MqttReceiver implements AutoCloseable {
     connection.connect(new Callback<Void>() {
       @Override
       public void onSuccess(Void value) {
+        connection.publish("components", "Eraser is listening".getBytes(), QoS.AT_LEAST_ONCE, false, new Callback<Void>() {
+          @Override
+          public void onSuccess(Void value) {
+            logger.debug("success sending welcome message");
+          }
+
+          @Override
+          public void onFailure(Throwable value) {
+            logger.debug("failure sending welcome message", value);
+          }
+        });
         Topic[] topicArray = Arrays.stream(topics).map(topicName -> new Topic(topicName, qos)).toArray(Topic[]::new);
         logger.info("Connected, subscribing to {} topic(s) now.", topicArray.length);
         connection.subscribe(topicArray, new Callback<byte[]>() {
@@ -150,7 +161,7 @@ public class MqttReceiver implements AutoCloseable {
 
           @Override
           public void onFailure(Throwable cause) {
-            logger.error("Could not subscribe, because {}", cause);
+            logger.error("Could not subscribe", cause);
           }
         });
       }
diff --git a/eraser-base/src/main/java/de/tudresden/inf/st/eraser/util/ParserUtils.java b/eraser-base/src/main/java/de/tudresden/inf/st/eraser/util/ParserUtils.java
index c45f02562fa72036b24749ab4fdca47fbf87ed41..716f63f9caa9462665b8819c9347aef466637a76 100644
--- a/eraser-base/src/main/java/de/tudresden/inf/st/eraser/util/ParserUtils.java
+++ b/eraser-base/src/main/java/de/tudresden/inf/st/eraser/util/ParserUtils.java
@@ -241,6 +241,7 @@ public class ParserUtils {
     EraserScanner scanner = new EraserScanner(reader);
     EraserParser parser = new EraserParser();
     Root root = (Root) parser.parse(scanner);
+    parser.resolveReferences();
     reader.close();
     int size = root.getOpenHAB2Model().items().size();
     if (size == 0) {
diff --git a/eraser-base/src/test/java/de/tudresden/inf/st/eraser/ExpressionEvalTest.java b/eraser-base/src/test/java/de/tudresden/inf/st/eraser/ExpressionEvalTest.java
index d9c64c57553133162dc2a355360f50fc3716cf33..1758931346632a63c9f3297912b1fb7d1430da46 100644
--- a/eraser-base/src/test/java/de/tudresden/inf/st/eraser/ExpressionEvalTest.java
+++ b/eraser-base/src/test/java/de/tudresden/inf/st/eraser/ExpressionEvalTest.java
@@ -73,6 +73,19 @@ public class ExpressionEvalTest {
     assertThat(divExpression.getRightOperand().eval(), equalTo(4.0));
   }
 
+  @Test
+  public void expressionWithItem() throws IOException, Parser.Exception {
+    double itemValue = 5.3;
+    Item referenceItem = ParserUtils.parseItem("Number Item: id=\"myItem\" state=\"" + itemValue + "\";");
+    NumberExpression sut = ParserUtils.parseNumberExpression("(myItem * 3)", referenceItem.getRoot());
+    assertThat(sut.eval(), equalTo(itemValue * 3));
+
+    // set item state to new value
+    itemValue = 17;
+    referenceItem.setStateFromDouble(itemValue);
+    assertThat(sut.eval(), equalTo(itemValue * 3));
+  }
+
   @Test
   public void comparingExpressions() throws IOException, Parser.Exception {
     comparingExpression(1, "<",  2, true);
@@ -89,9 +102,9 @@ public class ExpressionEvalTest {
     comparingExpression(7, "!=", 8, true);
     comparingExpression(8, "!=", 8, false);
 
-    comparingExpression(9, "=>", 10, false);
-    comparingExpression(10, "=>", 10, true);
-    comparingExpression(11, "=>", 10, true);
+    comparingExpression(9, ">=", 10, false);
+    comparingExpression(10, ">=", 10, true);
+    comparingExpression(11, ">=", 10, true);
 
     comparingExpression(11,">",   12, false);
     comparingExpression(12,">",   12, false);
@@ -99,7 +112,8 @@ public class ExpressionEvalTest {
   }
 
   private void comparingExpression(double left, String actualComparatorString, double right, boolean expectedResult) throws IOException, Parser.Exception {
-    LogicalExpression sut = ParserUtils.parseLogicalExpression(String.format("(%f %s %f)", left, actualComparatorString, right));
+    String expression = String.format("(%s %s %s)", Double.toString(left), actualComparatorString, Double.toString(right));
+    LogicalExpression sut = ParserUtils.parseLogicalExpression(expression);
     assertThat(sut.eval(), equalTo(expectedResult));
   }
 
diff --git a/eraser-base/src/test/java/de/tudresden/inf/st/eraser/ExpressionParserTest.java b/eraser-base/src/test/java/de/tudresden/inf/st/eraser/ExpressionParserTest.java
index c01d93df0fe1e259b3be5d7f27e0c80a6e3ba2f6..a034d3c8f8699046c9c89d2f139f14880a80b704 100644
--- a/eraser-base/src/test/java/de/tudresden/inf/st/eraser/ExpressionParserTest.java
+++ b/eraser-base/src/test/java/de/tudresden/inf/st/eraser/ExpressionParserTest.java
@@ -19,9 +19,11 @@ import static org.junit.Assert.assertThat;
  */
 public class ExpressionParserTest {
 
+  private static final String TRUE_EXPRESSION = "(0.0==0.0)";
+
   @Test
   public void plusExpression() throws IOException, Parser.Exception {
-    NumberExpression sut = ParserUtils.parseNumberExpression("(3 + 4)");
+    NumberExpression sut = parseWithRoundTripNumberExpression("(3 + 4)");
     assertThat(sut, instanceOf(AddExpression.class));
     AddExpression addExpression = (AddExpression) sut;
     assertThat(addExpression.getLeftOperand(), instanceOf(NumberLiteralExpression.class));
@@ -34,7 +36,7 @@ public class ExpressionParserTest {
 
   @Test
   public void minusExpression() throws IOException, Parser.Exception {
-    NumberExpression sut = ParserUtils.parseNumberExpression("(12.5 - 4.1)");
+    NumberExpression sut = parseWithRoundTripNumberExpression("(12.5 - 4.1)");
     assertThat(sut, instanceOf(SubExpression.class));
     SubExpression subExpression = (SubExpression) sut;
     assertThat(subExpression.getLeftOperand(), instanceOf(NumberLiteralExpression.class));
@@ -47,7 +49,7 @@ public class ExpressionParserTest {
 
   @Test
   public void multExpression() throws IOException, Parser.Exception {
-    NumberExpression sut = ParserUtils.parseNumberExpression("(0 * 0)");
+    NumberExpression sut = parseWithRoundTripNumberExpression("(0 * 0)");
     assertThat(sut, instanceOf(MultExpression.class));
     MultExpression multExpression = (MultExpression) sut;
     assertThat(multExpression.getLeftOperand(), instanceOf(NumberLiteralExpression.class));
@@ -60,7 +62,7 @@ public class ExpressionParserTest {
 
   @Test
   public void divExpression() throws IOException, Parser.Exception {
-    NumberExpression sut = ParserUtils.parseNumberExpression("(1.1 / 0.0)");
+    NumberExpression sut = parseWithRoundTripNumberExpression("(1.1 / 0.0)");
     assertThat(sut, instanceOf(DivExpression.class));
     DivExpression divExpression = (DivExpression) sut;
     assertThat(divExpression.getLeftOperand(), instanceOf(NumberLiteralExpression.class));
@@ -73,7 +75,7 @@ public class ExpressionParserTest {
 
   @Test
   public void powerExpression() throws IOException, Parser.Exception {
-    NumberExpression sut = ParserUtils.parseNumberExpression("(3 ^ 0.5)");
+    NumberExpression sut = parseWithRoundTripNumberExpression("(3 ^ 0.5)");
     assertThat(sut, instanceOf(PowerExpression.class));
     PowerExpression powExpression = (PowerExpression) sut;
     assertThat(powExpression.getLeftOperand(), instanceOf(NumberLiteralExpression.class));
@@ -86,7 +88,7 @@ public class ExpressionParserTest {
 
   @Test
   public void parenthesizedExpression() throws IOException, Parser.Exception {
-    NumberExpression sut = ParserUtils.parseNumberExpression("(3)");
+    NumberExpression sut = parseWithRoundTripNumberExpression("(3)");
     assertThat(sut, instanceOf(ParenthesizedNumberExpression.class));
     ParenthesizedNumberExpression parenExpression = (ParenthesizedNumberExpression) sut;
     assertThat(parenExpression.getOperand(), instanceOf(NumberLiteralExpression.class));
@@ -96,7 +98,7 @@ public class ExpressionParserTest {
 
   @Test
   public void complexExpression() throws IOException, Parser.Exception {
-    NumberExpression sut = ParserUtils.parseNumberExpression("((3 + 4) * (1 / (12 - 8)))");
+    NumberExpression sut = parseWithRoundTripNumberExpression("((3 + 4) * (1 / (12 - 8)))");
     assertThat(sut, instanceOf(MultExpression.class));
     MultExpression multExpression = (MultExpression) sut;
 
@@ -130,13 +132,17 @@ public class ExpressionParserTest {
   }
 
   @Test
-  public void expressionWithItem() {
-    try {
-      ParserUtils.parseNumberExpression("(myItem * 3)");
-    } catch (IOException | Parser.Exception e) {
-      e.printStackTrace();
-      Assert.fail(e.getMessage());
-    }
+  public void expressionWithItem() throws IOException, Parser.Exception {
+    Item referenceItem = ParserUtils.parseItem("Number Item: id=\"myItem\";");
+    NumberExpression sut = parseWithRoundTripNumberExpression("(myItem * 3)", referenceItem.getRoot());
+    assertThat(sut, instanceOf(MultExpression.class));
+    MultExpression multExpression = (MultExpression) sut;
+    assertThat(multExpression.getLeftOperand(), instanceOf(Designator.class));
+    Designator left = (Designator) multExpression.getLeftOperand();
+    assertThat(left.getItem(), equalTo(referenceItem));
+    assertThat(multExpression.getRightOperand(), instanceOf(NumberLiteralExpression.class));
+    NumberLiteralExpression right = (NumberLiteralExpression) multExpression.getRightOperand();
+    assertThat(right.getValue(), equalTo(3.0));
   }
 
   @Test
@@ -145,12 +151,13 @@ public class ExpressionParserTest {
     comparingExpression("<=", ComparatorType.LessOrEqualThan, 3, 4);
     comparingExpression("==", ComparatorType.Equals, 5, 6);
     comparingExpression("!=", ComparatorType.NotEquals, 7, 8);
-    comparingExpression("=>", ComparatorType.GreaterOrEqualThan, 9, 10);
+    comparingExpression(">=", ComparatorType.GreaterOrEqualThan, 9, 10);
     comparingExpression(">",  ComparatorType.GreaterThan, 11, 12);
   }
 
   private void comparingExpression(String actualComparatorString, ComparatorType expectedComparatorType, double left, double right) throws IOException, Parser.Exception {
-    LogicalExpression sut = ParserUtils.parseLogicalExpression(String.format("(%f %s %f)", left, actualComparatorString, right));
+    String expression = String.format("(%s %s %s)", Double.toString(left), actualComparatorString, Double.toString(right));
+    LogicalExpression sut = parseWithRoundTripLogicalExpression(expression);
     assertThat(sut, instanceOf(ComparingExpression.class));
     ComparingExpression comparingExpression = (ComparingExpression) sut;
     assertThat(comparingExpression.getLeftOperand(), instanceOf(NumberLiteralExpression.class));
@@ -164,7 +171,7 @@ public class ExpressionParserTest {
 
   @Test
   public void notExpression() throws IOException, Parser.Exception {
-    LogicalExpression sut = ParserUtils.parseLogicalExpression("!(0==0)");
+    LogicalExpression sut = parseWithRoundTripLogicalExpression("!" + TRUE_EXPRESSION);
     assertThat(sut, instanceOf(NotExpression.class));
     NotExpression notExpression = (NotExpression) sut;
     checkZeroEqualsZero(notExpression.getOperand());
@@ -172,7 +179,7 @@ public class ExpressionParserTest {
 
   @Test
   public void andExpression() throws IOException, Parser.Exception {
-    LogicalExpression sut = ParserUtils.parseLogicalExpression("((0==0) & (0==0))");
+    LogicalExpression sut = parseWithRoundTripLogicalExpression("(" + TRUE_EXPRESSION + " & " + TRUE_EXPRESSION + ")");
     assertThat(sut, instanceOf(AndExpression.class));
     AndExpression notExpression = (AndExpression) sut;
     checkZeroEqualsZero(notExpression.getLeftOperand());
@@ -181,7 +188,7 @@ public class ExpressionParserTest {
 
   @Test
   public void orExpression() throws IOException, Parser.Exception {
-    LogicalExpression sut = ParserUtils.parseLogicalExpression("((0==0) | (0==0))");
+    LogicalExpression sut = parseWithRoundTripLogicalExpression("(" + TRUE_EXPRESSION + " | " + TRUE_EXPRESSION + ")");
     assertThat(sut, instanceOf(OrExpression.class));
     OrExpression notExpression = (OrExpression) sut;
     checkZeroEqualsZero(notExpression.getLeftOperand());
@@ -190,12 +197,34 @@ public class ExpressionParserTest {
 
   @Test
   public void parenthesizedLogicalExpression() throws IOException, Parser.Exception {
-    LogicalExpression sut = ParserUtils.parseLogicalExpression("((0==0))");
+    LogicalExpression sut = parseWithRoundTripLogicalExpression("(" + TRUE_EXPRESSION + ")");
     assertThat(sut, instanceOf(ParenthesizedLogicalExpression.class));
     ParenthesizedLogicalExpression parenthesizedLogicalExpression = (ParenthesizedLogicalExpression) sut;
     checkZeroEqualsZero(parenthesizedLogicalExpression.getOperand());
   }
 
+  private NumberExpression parseWithRoundTripNumberExpression(String numberExpression) throws IOException, Parser.Exception {
+    return parseWithRoundTripNumberExpression(numberExpression, null);
+  }
+
+  private NumberExpression parseWithRoundTripNumberExpression(String numberExpression, Root root) throws IOException, Parser.Exception {
+    NumberExpression sut = ParserUtils.parseNumberExpression(numberExpression, root);
+    String first = sut.prettyPrint();
+    NumberExpression reParsed = ParserUtils.parseNumberExpression(first, root);
+    String second = reParsed.prettyPrint();
+    assertThat(first, equalTo(second));
+    return sut;
+  }
+
+  private LogicalExpression parseWithRoundTripLogicalExpression(String logicalExpression) throws IOException, Parser.Exception {
+    LogicalExpression sut = ParserUtils.parseLogicalExpression(logicalExpression);
+    String first = sut.prettyPrint();
+    LogicalExpression reParsed = ParserUtils.parseLogicalExpression(first);
+    String second = reParsed.prettyPrint();
+    assertThat(first, equalTo(second));
+    return sut;
+  }
+
   private void checkZeroEqualsZero(LogicalExpression logicalExpression) {
     assertThat(logicalExpression, instanceOf(ComparingExpression.class));
     ComparingExpression comparingExpression = (ComparingExpression) logicalExpression;
diff --git a/eraser-base/src/test/java/de/tudresden/inf/st/eraser/InfluxTest.java b/eraser-base/src/test/java/de/tudresden/inf/st/eraser/InfluxTest.java
index a7d76202ffc30da22280f9a5ec95c643cb4aee42..9526a4db04802684261f820e807db35d6a47c24f 100644
--- a/eraser-base/src/test/java/de/tudresden/inf/st/eraser/InfluxTest.java
+++ b/eraser-base/src/test/java/de/tudresden/inf/st/eraser/InfluxTest.java
@@ -33,8 +33,8 @@ public class InfluxTest {
   @ClassRule
   public static InfluxDBContainer influxDbContainer = new InfluxDBContainer()
       .withDatabase(InfluxRoot.createDefault().getDbName())
-      .withUsername(InfluxRoot.createDefault().getUser())
-      .withPassword(InfluxRoot.createDefault().getPassword());
+      .withAdmin(InfluxRoot.createDefault().getUser())
+      .withAdminPassword(InfluxRoot.createDefault().getPassword());
 
   @Test
   public void oneItem() {
@@ -154,9 +154,10 @@ public class InfluxTest {
           point -> points.add((DoubleStatePoint) point));
     } else {
       influxRoot = InfluxRoot.createDefault();
-      // use zih vm2098 running influx
+      // use container running influx
       influxRoot.setDbName(InfluxTest.class.getSimpleName());
-      influxRoot.setHostByName("vm2098.zih.tu-dresden.de");
+      System.out.println("ports: " + influxDbContainer.getPortBindings() + " url: '" + influxDbContainer.getUrl() + "'");
+      influxRoot.setHostByName(influxDbContainer.getUrl().replaceAll("^http://", ""));
     }
     mai.model.getRoot().setInfluxRoot(influxRoot);
     Assume.assumeTrue(influxRoot.influxAdapter().isConnected());
diff --git a/eraser-base/src/test/resources/tests/ppc3/input.eraser b/eraser-base/src/test/resources/tests/ppc3/input.eraser
index 5fad695027d88ad41935092e7a3175206a3dfb2d..9a8a80d0d47d21df28a233b13135c43a98be3f8a 100644
--- a/eraser-base/src/test/resources/tests/ppc3/input.eraser
+++ b/eraser-base/src/test/resources/tests/ppc3/input.eraser
@@ -14,7 +14,7 @@ Image Item : id="image1" label="an Image Item" state="def" topic="item/str/image
 Location Item : id="location1" label="a Location Item" state="ghi" topic="item/str/location1/state";
 Number Item : id="number1" label="a Number Item" state="456" topic="item/double/number1/state";
 Player Item : id="player1" label="a Player Item" state="jkl" topic="item/str/player1/state";
-RollerShutter Item : id="rollerShutter1" label="a RollerShutter Item" state="false" topic="item/str/rs1/state";
+RollerShutter Item : id="rollerShutter1" label="a RollerShutter Item" state="32" topic="item/str/rs1/state";
 String Item : id="string1" label="a String Item" state="mno" topic="item/str/string1/state";
 Switch Item : id="switch1" label="a Switch Item" state="true" topic="item/bool/switch1/state";
 Switch Item : id="switch2" label="a second Switch Item" state="OFF" topic="item/bool/switch2/state";
diff --git a/eraser-base/src/test/resources/tests/ppc3/output.eraser b/eraser-base/src/test/resources/tests/ppc3/output.eraser
index 9f209db2cbcac9ee3d862a7d005cfc159432a0a3..f480a5d4ecb8144e53e02334acf39b7e6b629868 100644
--- a/eraser-base/src/test/resources/tests/ppc3/output.eraser
+++ b/eraser-base/src/test/resources/tests/ppc3/output.eraser
@@ -1,5 +1,5 @@
 Color Item: id="color1" label="a Color Item" state="1,2,3" topic="item/hsb/color1/state" ;
-Contact Item: id="contact1" label="a Contact Item" state="true" topic="item/bool/contact1/state" ;
+Contact Item: id="contact1" label="a Contact Item" state="OPEN" topic="item/bool/contact1/state" ;
 Image Item: id="image1" label="an Image Item" state="def" topic="item/str/image1/state" ;
 Location Item: id="location1" label="a Location Item" state="ghi" topic="item/str/location1/state" ;
 DateTime Item: id="datetime1" label="a DateTime Item" state="1970-01-18T20:43:35.826Z" topic="item/date/datetime1/state" ;
@@ -7,7 +7,7 @@ Item: id="default1" label="a Default Item" state="pqr" topic="item/str/default1/
 Dimmer Item: id="dimmer1" label="a Dimmer Item" state="123.0" topic="item/double/dimmer1/state" ;
 Player Item: id="player1" label="a Player Item" state="jkl" topic="item/str/player1/state" ;
 Number Item: id="number1" label="a Number Item" state="456.0" topic="item/double/number1/state" ;
-RollerShutter Item: id="rollerShutter1" label="a RollerShutter Item" state="false" topic="item/str/rs1/state" ;
+RollerShutter Item: id="rollerShutter1" label="a RollerShutter Item" state="32.0" topic="item/str/rs1/state" ;
 String Item: id="string1" label="a String Item" state="mno" topic="item/str/string1/state" ;
 Switch Item: id="switch1" label="a Switch Item" state="ON" topic="item/bool/switch1/state" ;
 Switch Item: id="switch2" label="a second Switch Item" state="OFF" topic="item/bool/switch2/state" ;
diff --git a/eraser-base/src/test/resources/tests/ppc4/input.eraser b/eraser-base/src/test/resources/tests/ppc4/input.eraser
index f5c7afff39c0a2d617f293076a86a794fa24263f..8687f881951aa3bc8766e209a87432a235e2a72a 100644
--- a/eraser-base/src/test/resources/tests/ppc4/input.eraser
+++ b/eraser-base/src/test/resources/tests/ppc4/input.eraser
@@ -8,13 +8,13 @@ Group: id="my-empty-group" ;
 
 Color Item : id="color1" label="a Color Item" state="1,2,3" topic="item/hsb/color1/state";
 DateTime Item : id="datetime1" label="a DateTime Item" state="1543415826" topic="item/date/datetime1/state";
-Contact Item : id="contact1" label="a Contact Item" state="true" topic="item/bool/contact1/state";
+Contact Item : id="contact1" label="a Contact Item" state="CLOSED" topic="item/bool/contact1/state";
 Dimmer Item : id="dimmer1" label="a Dimmer Item" state="123" topic="item/double/dimmer1/state" controls=["color1", "datetime1"];
 Image Item : id="image1" label="an Image Item" state="def" topic="item/str/image1/state" controls=[];
 Location Item : id="location1" label="a Location Item" state="ghi" topic="item/str/location1/state";
 Number Item : id="number1" label="a Number Item" state="456" topic="item/double/number1/state" controls=["string1"];
 Player Item : id="player1" label="a Player Item" state="jkl" topic="item/str/player1/state";
-RollerShutter Item : id="rollerShutter1" label="a RollerShutter Item" state="false" topic="item/str/rs1/state";
+RollerShutter Item : id="rollerShutter1" label="a RollerShutter Item" state="0" topic="item/str/rs1/state";
 Activity Item: id="activity";
 String Item : id="string1" label="a String Item" state="mno" topic="item/str/string1/state";
 Switch Item : id="switch1" label="a Switch Item" state="true" topic="item/bool/switch1/state" controls=["rollerShutter1"];
diff --git a/eraser-base/src/test/resources/tests/ppc4/output.eraser b/eraser-base/src/test/resources/tests/ppc4/output.eraser
index 651bf7220435c60edee891b3a244a42cce706261..d4934300c2f7e3c0c8be65bf4f4932bbc4b7be52 100644
--- a/eraser-base/src/test/resources/tests/ppc4/output.eraser
+++ b/eraser-base/src/test/resources/tests/ppc4/output.eraser
@@ -1,5 +1,5 @@
 Color Item: id="color1" label="a Color Item" state="1,2,3" topic="item/hsb/color1/state" ;
-Contact Item: id="contact1" label="a Contact Item" state="true" topic="item/bool/contact1/state" ;
+Contact Item: id="contact1" label="a Contact Item" state="CLOSED" topic="item/bool/contact1/state" ;
 Image Item: id="image1" label="an Image Item" state="def" topic="item/str/image1/state" ;
 Location Item: id="location1" label="a Location Item" state="ghi" topic="item/str/location1/state" ;
 DateTime Item: id="datetime1" label="a DateTime Item" state="1970-01-18T20:43:35.826Z" topic="item/date/datetime1/state" ;
@@ -7,7 +7,7 @@ Item: id="default1" label="a Default Item" state="pqr" topic="item/str/default1/
 Dimmer Item: id="dimmer1" label="a Dimmer Item" state="123.0" topic="item/double/dimmer1/state" controls=["color1", "datetime1"] ;
 Player Item: id="player1" label="a Player Item" state="jkl" topic="item/str/player1/state" ;
 Number Item: id="number1" label="a Number Item" state="456.0" topic="item/double/number1/state" controls=["string1"] ;
-RollerShutter Item: id="rollerShutter1" label="a RollerShutter Item" state="false" topic="item/str/rs1/state" ;
+RollerShutter Item: id="rollerShutter1" label="a RollerShutter Item" state="0.0" topic="item/str/rs1/state" ;
 Activity Item: id="activity" ;
 String Item: id="string1" label="a String Item" state="mno" topic="item/str/string1/state" ;
 Switch Item: id="switch1" label="a Switch Item" state="ON" topic="item/bool/switch1/state" controls=["rollerShutter1"] ;
diff --git a/eraser.spark/src/main/java/de/tudresden/inf/st/eraser/spark/Application.java b/eraser.spark/src/main/java/de/tudresden/inf/st/eraser/spark/Application.java
index c1c8c2f40e4a3847e4dbfa7ea4b95a406df4d1d2..4d8df7dfaa448fe34c6cef1ed51a30d4dd2bc1ae 100644
--- a/eraser.spark/src/main/java/de/tudresden/inf/st/eraser/spark/Application.java
+++ b/eraser.spark/src/main/java/de/tudresden/inf/st/eraser/spark/Application.java
@@ -6,12 +6,10 @@ import de.tudresden.inf.st.eraser.util.JavaUtils;
 import de.tudresden.inf.st.eraser.util.ParserUtils;
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
-import org.eclipse.jetty.http.HttpStatus;
 import spark.Request;
 import spark.Response;
 import spark.Spark;
 
-import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -41,7 +39,7 @@ public class Application {
   private void createRules() {
     ObjectMapper mapper = new ObjectMapper();
 
-    Spark.path("/", () -> Spark.before((request, response) -> logger.debug(request.pathInfo())));
+    Spark.path("/", () -> Spark.before((request, response) -> logger.debug("{}: {}", request.pathInfo(), request.body())));
 
     Spark.path("/activity", () -> {
 
@@ -116,13 +114,12 @@ public class Application {
             OpenHAB2Model openHAB2Model = root.getOpenHAB2Model();
             Item item = ParserUtils.parseItem(request.body());
             if (!openHAB2Model.resolveItem(item.getID()).isPresent()) {
-              JavaUtils.ifPresentOrElse(
-                  root.getOpenHAB2Model().resolveGroup(ParserUtils.UNKNOWN_GROUP_NAME),
-                  group -> group.addItem(item),
-                  () -> ParserUtils.createUnknownGroup(root.getOpenHAB2Model(), Collections.singletonList(item)));
+              root.getOpenHAB2Model().addNewItem(item);
               response.status(201);
+              return "OK";
+            } else {
+              return makeError(response, 409, "Item already exists.");
             }
-            return "OK";
           });
 
           //--- GET /model/items/:identifier/state ---
@@ -169,7 +166,7 @@ public class Application {
 
   private Object safeItemRoute(Request request, Response response, Function<Item, String> action) {
     return JavaUtils.ifPresentOrElseReturn(root.getOpenHAB2Model().resolveItem(request.params("identifier")), action,
-        () -> makeError(response, 404, "Item '" + request.body() + "' not found"));
+        () -> makeError(response, 404, "Item '" + request.params("identifier") + "' not found"));
   }
 
   private String makeHistory(Item item, Response response) {
diff --git a/eraser.spark/src/main/java/de/tudresden/inf/st/eraser/spark/DummyDataCreator.java b/eraser.spark/src/main/java/de/tudresden/inf/st/eraser/spark/DummyDataCreator.java
index e548a6bc95012ba72675131395b9956f4a84466f..65885823f7960465adadf30bbda4f82744c54903 100644
--- a/eraser.spark/src/main/java/de/tudresden/inf/st/eraser/spark/DummyDataCreator.java
+++ b/eraser.spark/src/main/java/de/tudresden/inf/st/eraser/spark/DummyDataCreator.java
@@ -3,6 +3,9 @@ package de.tudresden.inf.st.eraser.spark;
 import de.tudresden.inf.st.eraser.jastadd.model.*;
 import de.tudresden.inf.st.eraser.util.JavaUtils;
 
+import java.time.Duration;
+import java.time.Instant;
+
 /**
  * Creates some activities and change events.
  *
@@ -28,12 +31,13 @@ class DummyDataCreator {
     Item iris1 = getOrCreateColorItem("iris1", "Hue Iris 1");
     Item go1 = getOrCreateColorItem("go1", "Hue Go 1");
     Item go2 = getOrCreateColorItem("go2", "Hue Go 2");
-    mlRoot.addChangeEvent(newRecognitionEvent(1, 1547637740, 1,
+    Instant now = Instant.now();
+    mlRoot.addChangeEvent(newRecognitionEvent(1, now, 1,
         new ChangedItem("green", iris1), new ChangedItem("green", go1)));
-    mlRoot.addChangeEvent(newRecognitionEvent(2, 1547637750, 1));
-    mlRoot.addChangeEvent(newRecognitionEvent(4, 1547623460, 2,
+    mlRoot.addChangeEvent(newRecognitionEvent(2, now.plusSeconds(1), 1));
+    mlRoot.addChangeEvent(newRecognitionEvent(3, now.plusSeconds(3), 2,
         new ChangedItem("off", go2)));
-    mlRoot.addChangeEvent(newManualChangeEvent(1501146256, 5,
+    mlRoot.addChangeEvent(newManualChangeEvent(4, now.plusSeconds(17),
         new ChangedItem("green", iris1),
         new ChangedItem("red", go1),
         new ChangedItem("#EE7F00", go2)));
@@ -51,23 +55,23 @@ class DummyDataCreator {
     });
   }
 
-  private RecognitionEvent newRecognitionEvent(int identifier, long timestamp, int activityIdentifier, ChangedItem... changedItems) {
+  private RecognitionEvent newRecognitionEvent(int identifier, Instant when, int activityIdentifier, ChangedItem... changedItems) {
     RecognitionEvent result = new RecognitionEvent();
     JavaUtils.ifPresentOrElse(root.resolveActivity(activityIdentifier), result::setActivity, () -> { throw new RuntimeException("No activity found for identifier " + activityIdentifier); });
-    initChangeEvent(result, identifier, timestamp, changedItems);
+    initChangeEvent(result, identifier, when, changedItems);
     return result;
   }
 
   @SuppressWarnings("SameParameterValue")
-  private ManualChangeEvent newManualChangeEvent(int identifier, long timestamp, ChangedItem... changedItems) {
+  private ManualChangeEvent newManualChangeEvent(int identifier, Instant when, ChangedItem... changedItems) {
     ManualChangeEvent result = new ManualChangeEvent();
-    initChangeEvent(result, identifier, timestamp, changedItems);
+    initChangeEvent(result, identifier, when, changedItems);
     return result;
   }
 
-  private void initChangeEvent(ChangeEvent result, int identifier, long timestamp, ChangedItem... changedItems) {
+  private void initChangeEvent(ChangeEvent result, int identifier, Instant when, ChangedItem... changedItems) {
     result.setIdentifier(identifier);
-    result.setTimestamp(timestamp);
+    result.setCreated(when);
     for (ChangedItem changedItem : changedItems) {
       result.addChangedItem(changedItem);
     }
diff --git a/eraser.spark/src/main/java/de/tudresden/inf/st/eraser/spark/SimpleChangeEvent.java b/eraser.spark/src/main/java/de/tudresden/inf/st/eraser/spark/SimpleChangeEvent.java
index 07894ede8b266b46bf4aa364bb4495d07abc8740..6a1c1a91bc3d8cdc28d44b07b766168e645786bf 100644
--- a/eraser.spark/src/main/java/de/tudresden/inf/st/eraser/spark/SimpleChangeEvent.java
+++ b/eraser.spark/src/main/java/de/tudresden/inf/st/eraser/spark/SimpleChangeEvent.java
@@ -3,6 +3,7 @@ package de.tudresden.inf.st.eraser.spark;
 import lombok.AllArgsConstructor;
 import lombok.Data;
 
+import java.time.Instant;
 import java.util.List;
 
 /**
@@ -13,7 +14,7 @@ import java.util.List;
 @Data
 @AllArgsConstructor
 public abstract class SimpleChangeEvent {
-  public final long timestamp;
+  public final Instant created;
   public final int identifier;
   public final List<SimpleChangedItem> changed_items;
 }
diff --git a/eraser.spark/src/main/java/de/tudresden/inf/st/eraser/spark/SimpleManualChangeEvent.java b/eraser.spark/src/main/java/de/tudresden/inf/st/eraser/spark/SimpleManualChangeEvent.java
index 71e43cdbbcce6eb65704d280540220db880ed3b6..685436cd376b993403db98d4a6192b4de94975d5 100644
--- a/eraser.spark/src/main/java/de/tudresden/inf/st/eraser/spark/SimpleManualChangeEvent.java
+++ b/eraser.spark/src/main/java/de/tudresden/inf/st/eraser/spark/SimpleManualChangeEvent.java
@@ -5,6 +5,7 @@ import de.tudresden.inf.st.eraser.util.JavaUtils;
 import lombok.Data;
 import lombok.EqualsAndHashCode;
 
+import java.time.Instant;
 import java.util.List;
 import java.util.stream.Collectors;
 
@@ -18,12 +19,12 @@ import java.util.stream.Collectors;
 public class SimpleManualChangeEvent extends SimpleChangeEvent {
   public final String type = "manual";
 
-  public SimpleManualChangeEvent(long timestamp, int identifier, List<SimpleChangedItem> changedItems) {
-    super(timestamp, identifier, changedItems);
+  public SimpleManualChangeEvent(Instant created, int identifier, List<SimpleChangedItem> changedItems) {
+    super(created, identifier, changedItems);
   }
 
   static SimpleManualChangeEvent createFrom(ManualChangeEvent event) {
-    return new SimpleManualChangeEvent(event.getTimestamp(), event.getIdentifier(),
+    return new SimpleManualChangeEvent(event.getCreated(), event.getIdentifier(),
         JavaUtils.toStream(event.getChangedItems()).map(SimpleChangedItem::createFrom).collect(Collectors.toList()));
   }
 }
diff --git a/eraser.spark/src/main/java/de/tudresden/inf/st/eraser/spark/SimpleRecognitionEvent.java b/eraser.spark/src/main/java/de/tudresden/inf/st/eraser/spark/SimpleRecognitionEvent.java
index 587c3ae127da7cf3be1064a4351e36f6bbf81e7d..0a3821e4fc49d9fa2b2d0e75717da5477c0a3fa7 100644
--- a/eraser.spark/src/main/java/de/tudresden/inf/st/eraser/spark/SimpleRecognitionEvent.java
+++ b/eraser.spark/src/main/java/de/tudresden/inf/st/eraser/spark/SimpleRecognitionEvent.java
@@ -5,6 +5,7 @@ import de.tudresden.inf.st.eraser.util.JavaUtils;
 import lombok.Data;
 import lombok.EqualsAndHashCode;
 
+import java.time.Instant;
 import java.util.List;
 import java.util.stream.Collectors;
 
@@ -20,14 +21,14 @@ public class SimpleRecognitionEvent extends SimpleChangeEvent {
   public final String description;
   public final String type = "recognition";
 
-  public SimpleRecognitionEvent(long timestamp, int identifier, List<SimpleChangedItem> changedItems, int activity, String description) {
-    super(timestamp, identifier, changedItems);
+  public SimpleRecognitionEvent(Instant created, int identifier, List<SimpleChangedItem> changedItems, int activity, String description) {
+    super(created, identifier, changedItems);
     this.activity = activity;
     this.description = description;
   }
 
   static SimpleRecognitionEvent createFrom(RecognitionEvent event) {
-    return new SimpleRecognitionEvent(event.getTimestamp(), event.getIdentifier(),
+    return new SimpleRecognitionEvent(event.getCreated(), event.getIdentifier(),
         JavaUtils.toStream(event.getChangedItems()).map(SimpleChangedItem::createFrom).collect(Collectors.toList()),
         event.getActivity().getIdentifier(), event.getActivity().getLabel());
   }
diff --git a/eraser.starter/build.gradle b/eraser.starter/build.gradle
index ddb56ddf0b9a90f815f09b20d117485c48300c70..186e75a1e448ab9f0e61c5f8df2d3ac94da2f1f9 100644
--- a/eraser.starter/build.gradle
+++ b/eraser.starter/build.gradle
@@ -18,10 +18,13 @@ dependencies {
     compile project(':feedbackloop.analyze')
     compile project(':feedbackloop.plan')
     compile project(':feedbackloop.execute')
-    compile project(':feedbackloop.learner')
+    compile project(':feedbackloop.learner_backup')
+    compile project(':datasets')
     compile group: 'com.fasterxml.jackson.dataformat', name: 'jackson-dataformat-yaml', version: '2.9.8'
     compile group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.9.8'
     compile group: 'net.sourceforge.argparse4j', name: 'argparse4j', version: '0.8.1'
+    //    compile project(':feedbackloop.learner')
+
 }
 
 run {
diff --git a/eraser.starter/src/main/java/de/tudresden/inf/st/eraser/starter/EraserStarter.java b/eraser.starter/src/main/java/de/tudresden/inf/st/eraser/starter/EraserStarter.java
index b263fd586f95781c26345076e7a3132472f20eab..acc4b93a471d0b3a02676d37cb0314c85756ed1c 100644
--- a/eraser.starter/src/main/java/de/tudresden/inf/st/eraser/starter/EraserStarter.java
+++ b/eraser.starter/src/main/java/de/tudresden/inf/st/eraser/starter/EraserStarter.java
@@ -6,18 +6,15 @@ import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
 import de.tudresden.inf.st.eraser.feedbackloop.analyze.AnalyzeImpl;
 import de.tudresden.inf.st.eraser.feedbackloop.api.Analyze;
 import de.tudresden.inf.st.eraser.feedbackloop.api.Execute;
-import de.tudresden.inf.st.eraser.feedbackloop.api.Learner;
 import de.tudresden.inf.st.eraser.feedbackloop.api.Plan;
-import de.tudresden.inf.st.eraser.feedbackloop.api.EncogModel;
 import de.tudresden.inf.st.eraser.feedbackloop.execute.ExecuteImpl;
-import de.tudresden.inf.st.eraser.feedbackloop.learner.LearnerHelper;
-import de.tudresden.inf.st.eraser.feedbackloop.learner.LearnerImpl;
+import de.tudresden.inf.st.eraser.feedbackloop.learner_backup.Learner;
+import de.tudresden.inf.st.eraser.feedbackloop.learner_backup.MachineLearningImpl;
 import de.tudresden.inf.st.eraser.feedbackloop.plan.PlanImpl;
 import de.tudresden.inf.st.eraser.jastadd.model.*;
 import de.tudresden.inf.st.eraser.openhab2.OpenHab2Importer;
 import de.tudresden.inf.st.eraser.openhab2.mqtt.MQTTUpdater;
 import de.tudresden.inf.st.eraser.spark.Application;
-import de.tudresden.inf.st.eraser.util.JavaUtils;
 import de.tudresden.inf.st.eraser.util.ParserUtils;
 import net.sourceforge.argparse4j.ArgumentParsers;
 import net.sourceforge.argparse4j.annotation.Arg;
@@ -28,10 +25,10 @@ import org.apache.logging.log4j.Logger;
 
 import java.io.File;
 import java.io.IOException;
-import java.io.InputStream;
 import java.net.MalformedURLException;
 import java.net.URL;
-import java.util.Collections;
+import java.util.ArrayList;
+import java.util.List;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.locks.Condition;
 import java.util.concurrent.locks.Lock;
@@ -113,53 +110,100 @@ public class EraserStarter {
         }
     }
 
+    // initialize backup learner
+    Learner learner = new Learner();
+
     // initialize activity recognition
     MachineLearningRoot machineLearningRoot = root.getMachineLearningRoot();
     if (settings.activity.dummy) {
-      logger.info("Using dummy activity recognition");
+      logger.info("Using dummy activity recognition, ignoring other settings for this");
       machineLearningRoot.setActivityRecognition(DummyMachineLearningModel.createDefault());
     } else {
-      logger.error("Reading activity recognition from file is not supported yet!");
-      // TODO
+      MachineLearningImpl handler = new MachineLearningImpl(learner, MachineLearningImpl.GOAL_ACTIVITY_PHONE_AND_WATCH);
+      handler.setKnowledgeBaseRoot(root);
+      logger.info("Reading activity recognition from csv file {}", settings.activity.file);
+      handler.initActivities(settings.activity.realURL().getFile());
+      ExternalMachineLearningModel machineLearningModel = new ExternalMachineLearningModel();
+      machineLearningModel.setEncoder(handler);
+      machineLearningModel.setDecoder(handler);
+      root.getMachineLearningRoot().setActivityRecognition(machineLearningModel);
+
+      //Begin the Integration
+      Item item1=model.resolveItem("m_accel_x").get();
+      Item item2=model.resolveItem("m_accel_y").get();
+      Item item3=model.resolveItem("m_accel_z").get();
+      Item item4=model.resolveItem("m_rotation_x").get();
+      Item item5=model.resolveItem("m_rotation_y").get();
+      Item item6=model.resolveItem("m_rotation_z").get();
+      Item item7=model.resolveItem("w_accel_x").get();
+      Item item8=model.resolveItem("w_accel_y").get();
+      Item item9=model.resolveItem("w_accel_z").get();
+      Item item10=model.resolveItem("w_rotation_x").get();
+      Item item11=model.resolveItem("w_rotation_y").get();
+      Item item12=model.resolveItem("w_rotation_z").get();
+      //0.2717419,8.698134,4.471172,0.043741,0.515962,0.854318,1.8818425,4.9320555,8.145074,0.2374878,-0.032836914,0.3381958,working
+      item1.setStateFromString("0.2717419");
+      item2.setStateFromString("8.698134");
+      item3.setStateFromString("4.471172");
+      item4.setStateFromString("0.043741");
+      item5.setStateFromString("0.515962");
+      item6.setStateFromString("0.854318");
+      item7.setStateFromString("1.8818425");
+      item8.setStateFromString("4.9320555");
+      item9.setStateFromString("8.145074");
+      item10.setStateFromString("0.2374878");
+      item11.setStateFromString("-0.032836914");
+      item12.setStateFromString("0.3381958");
+
+      ArrayList<Item> newData=new ArrayList<>();
+      newData.add(item1);
+      newData.add(item2);
+      newData.add(item3);
+      newData.add(item4);
+      newData.add(item5);
+      newData.add(item6);
+      newData.add(item7);
+      newData.add(item8);
+      newData.add(item9);
+      newData.add(item10);
+      newData.add(item11);
+      newData.add(item12);
+      handler.newData(newData);
+      List<ItemPreference> preference=handler.classify().getPreferences();
+      for(ItemPreference preference1 : preference){
+        preference1.apply();
+      }
     }
 
     // initialize preference learning
     if (settings.preference.dummy) {
-      logger.info("Using dummy preference learning");
+      logger.info("Using dummy preference learning, ignoring other settings for this");
       machineLearningRoot.setPreferenceLearning(DummyMachineLearningModel.createDefault());
     } else {
-      logger.info("Reading preference learning from file {}", settings.preference.file);
-      Learner learner = new LearnerImpl();
-      // there should be a method to load a model using an URL
-      boolean loadingSuccessful = false;
-      try (InputStream input = settings.preference.realURL().openStream()) {
-        loadingSuccessful = learner.loadModelFromFile(input, settings.preference.id,
-            Collections.emptyList(), Collections.emptyList(), Collections.emptyList(), Collections.emptyList());
-      } catch (IOException e) {
-        logger.catching(e);
-        loadingSuccessful = false;
-      }
-//      Model preference = learner.getTrainedModel(settings.preference.realURL(), settings.preference.id);
-      logger.debug("Loading of {} was {}", settings.preference.realURL(), loadingSuccessful ? "successful" : "failed");
-      if (loadingSuccessful) {
-        EncogModel preference = learner.getTrainedModel(settings.preference.id);
-        NeuralNetworkRoot neuralNetwork = LearnerHelper.transform(preference);
-        if (neuralNetwork == null) {
-          logger.error("Could not create preference model, see possible previous errors.");
-        } else {
-          machineLearningRoot.setPreferenceLearning(neuralNetwork);
-          neuralNetwork.setOutputApplication(zeroToThree -> 33 * zeroToThree);
-          JavaUtils.ifPresentOrElse(
-              model.resolveItem(settings.preference.affectedItem),
-              item -> neuralNetwork.getOutputLayer().setAffectedItem(item),
-              () -> logger.error("Output item not set from value '{}'", settings.preference.affectedItem));
-        }
-      } else {
-        // loading was not successful
-        logger.warn("Falling back to dummy preference learning");
-        machineLearningRoot.setPreferenceLearning(DummyMachineLearningModel.createDefault());
+      logger.info("Reading preference learning from csv file {}", settings.preference.file);
+      MachineLearningImpl handler = new MachineLearningImpl(learner, MachineLearningImpl.GOAL_PREFERENCE_BRIGHTNESS_IRIS);
+      handler.setKnowledgeBaseRoot(root);
+      handler.initPreferences(settings.preference.realURL().getFile());
+      ExternalMachineLearningModel machineLearningModel = new ExternalMachineLearningModel();
+      machineLearningModel.setEncoder(handler);
+      machineLearningModel.setDecoder(handler);
+      root.getMachineLearningRoot().setPreferenceLearning(machineLearningModel);
+      //working,medium,240,70
+      Item activity_item = model.resolveItem("activity").get();
+      String activity=activity_item.getStateAsString();
+      activity_item.setStateFromString(activity);
+      Item brightness_item = model.resolveItem("w_brightness").get();
+      brightness_item.setStateFromString("medium");
+      ArrayList<Item> newData1 = new ArrayList<>();
+      newData1.add(activity_item);
+      newData1.add(brightness_item);
+      handler.newData(newData1);
+      List<ItemPreference> preference=handler.classify().getPreferences();
+      for(ItemPreference preference1 : preference){
+        preference1.apply();
       }
     }
+
     machineLearningRoot.getPreferenceLearning().connectItems(settings.preference.items);
     if (!machineLearningRoot.getActivityRecognition().check()) {
       logger.fatal("Invalid activity recognition!");
diff --git a/eraser.starter/src/main/java/de/tudresden/inf/st/eraser/starter/Setting.java b/eraser.starter/src/main/java/de/tudresden/inf/st/eraser/starter/Setting.java
index dacbb4287bb16d2f4fcdb5ba2e2cb4b67cf6406e..09af126b0a66f54aa2b6c88fb04bda9cb7218cb3 100644
--- a/eraser.starter/src/main/java/de/tudresden/inf/st/eraser/starter/Setting.java
+++ b/eraser.starter/src/main/java/de/tudresden/inf/st/eraser/starter/Setting.java
@@ -32,7 +32,7 @@ class Setting {
     URL realURL() {
       if (external) {
         try {
-          return Paths.get(file).toUri().toURL();
+          return Paths.get(file).toUri().normalize().toURL();
         } catch (MalformedURLException e) {
           logger.catching(e);
           return null;
diff --git a/eraser.starter/src/main/resources/starter.eraser b/eraser.starter/src/main/resources/starter.eraser
index 25505fe24d64d3ed08ecdc0a3d741625b25e46ad..a8dc0c5731c9f5ce106c55aa4d2a87fc8f85df4f 100644
--- a/eraser.starter/src/main/resources/starter.eraser
+++ b/eraser.starter/src/main/resources/starter.eraser
@@ -3,26 +3,38 @@ Number Item: id="datetime_month" label="Month" state="1" topic="datetime_month";
 Number Item: id="datetime_day" label="Day" state="31" topic="datetime_day";
 Number Item: id="datetime_hour" label="Hour" state="13" topic="datetime_hour";
 Number Item: id="datetime_minute" label="Minute" state="37" topic="datetime_minute";
-Number Item: id="bias" label="bias item" state="1" ;
-Activity Item: id="activity" ;
+Number Item: id="bias" label="bias item" state="1";
+
+
+String Item: id="m_accel_x" label="" state="0.2717419" topic="m_accel_x";
+String Item: id="m_accel_y" label="" state="8.698134" topic="m_accel_y";
+String Item: id="m_accel_z" label="" state="4.471172" topic="m_accel_z";
+String Item: id="m_rotation_x" label="" state="0.043741" topic="m_rotation_x";
+String Item: id="m_rotation_y" label="" state="0.515962" topic="m_rotation_y";
+String Item: id="m_rotation_z" label="" state="0.854318" topic="m_rotation_z";
+String Item: id="w_accel_x" label="" state="1.8818425" topic="w_accel_x";
+String Item: id="w_accel_y" label="" state="4.9320555" topic="w_accel_y";
+String Item: id="w_accel_z" label="" state="8.145074" topic="w_accel_z";
+String Item: id="w_rotation_x" label="" state="0.2374878" topic="w_rotation_x";
+String Item: id="w_rotation_y" label="" state="-0.032836914" topic="w_rotation_y";
+String Item: id="w_rotation_z" label="" state="0.3381958" topic="w_rotation_y";
+String Item: id="w_brightness" label="" state="bright" topic="w_brightness";
+//String Item: id="activity" label="" state="lying" topic="activity";
+Activity Item: id="activity" topic="activity";
 
 Group: id="Lights" items=["iris1_item"];
 Group: id="Datetime" items=["datetime_month", "datetime_day", "datetime_hour", "datetime_minute"];
 
-Mqtt: incoming="oh2/out/" outgoing="oh2/in/" host="localhost:2883" ;
+Mqtt: incoming="oh2/out/" outgoing="oh2/in/" host="localhost:1883" ;
 //Mqtt: incoming="oh2/out/" outgoing="oh2/in/" host="192.168.1.250" ;
 
 Influx: host="172.22.1.152" ;
-
+//"working", "walking", "dancing", "lying", "getting up", "reading"
 ML: activities={
-  0: "Open door in empty room",
-  1: "Door closed in empty room",
-  2: "Open door with person in room",
-  3: "Door closed with person in room",
-  4: "Working",
-  5: "Watch TV",
-  6: "Reading",
-  7: "Listening to music",
-  8: "Going to sleep",
-  9: "Wake up"
+  0: "working",
+  1: "walking",
+  2: "dancing",
+  3: "lying",
+  4: "getting up",
+  5: "reading"
 } ;
diff --git a/eraser.starter/starter-setting.yaml b/eraser.starter/starter-setting.yaml
index f29763c43dfa4b789f872efc9eec88439930eff9..e8f438cf3eeb22d71d44c675e7328e61ba612562 100644
--- a/eraser.starter/starter-setting.yaml
+++ b/eraser.starter/starter-setting.yaml
@@ -24,28 +24,29 @@ load:
 
 # Model for activity recognition. If dummy is true, then the file parameter is ignored.
 activity:
-  # File to read in. Expected format = eg
-  file: activity.eg
+  # File to read in. Expected format = csv   /Users/boqi/eraser/datasets
+  file: ../datasets/backup/activity_data.csv
+  external: true
   # Use dummy model in which the current activity is directly editable. Default: false.
-  dummy: true
+  dummy: false
   # Model id. Default: 1.
   id: 1
+  # Item to change with classification result
+  affectedItem: activity
 
 # Model for preference learning. If dummy is true, then the file parameter is ignored.
 preference:
-  # File to read in. Expected format = eg
-  file: preference.eg
+  # File to read in. Expected format = csv
+  file: ../datasets/backup/preference_data.csv
+  external: true
   # Use dummy model in which the current activity is directly editable. Default: false.
   dummy: false
   # Model id. Default: 1.
   id: 1
   # Items to connect to inputs
   items:
-    - datetime_month
-    - datetime_day
-    - datetime_hour
-    - datetime_minute
-#    - activity
+    - activity
+    - w_brightness
   # Item to change with classification result
   affectedItem: iris1_item
 
diff --git a/feedbackloop.learner/.settings/org.eclipse.buildship.core.prefs b/feedbackloop.learner/.settings/org.eclipse.buildship.core.prefs
deleted file mode 100644
index b1886adb46c085de842f1283c1a3c25151bfc988..0000000000000000000000000000000000000000
--- a/feedbackloop.learner/.settings/org.eclipse.buildship.core.prefs
+++ /dev/null
@@ -1,2 +0,0 @@
-connection.project.dir=..
-eclipse.preferences.version=1
diff --git a/feedbackloop.learner_backup/build.gradle b/feedbackloop.learner_backup/build.gradle
index d0cf7913f010772f11df428d587fc351d8df634a..6199fa8da5b905d3d5d4cb02d6c6858218f3ffdd 100644
--- a/feedbackloop.learner_backup/build.gradle
+++ b/feedbackloop.learner_backup/build.gradle
@@ -8,6 +8,13 @@ dependencies {
     testCompile group: 'junit', name: 'junit', version: '4.12'
     testCompile group: 'org.hamcrest', name: 'hamcrest-junit', version: '2.0.0.0'
     compile group: 'org.encog', name: 'encog-core', version: '3.4'
+    implementation group: 'com.opencsv', name: 'opencsv', version: '4.1'
+    implementation group: 'commons-io', name: 'commons-io', version: '2.5'
+    implementation group: 'org.apache.httpcomponents', name: 'httpclient', version: '4.5.8'
+    implementation group: 'org.apache.httpcomponents', name: 'fluent-hc', version: '4.5.8'
+    // https://mvnrepository.com/artifact/org.apache.spark/spark-mllib
+    //runtime group: 'org.apache.spark', name: 'spark-mllib_2.10', version: '1.3.0'
+    compile group: 'com.sparkjava', name: 'spark-core', version: '2.9.0'
 }
 
 run {
diff --git a/feedbackloop.learner_backup/src/main/java/de/tudresden/inf/st/eraser/feedbackloop.learner_backup/CsvTransfer.java b/feedbackloop.learner_backup/src/main/java/de/tudresden/inf/st/eraser/feedbackloop.learner_backup/CsvTransfer.java
new file mode 100644
index 0000000000000000000000000000000000000000..1c08268d59dd4003149e551d2e3e60895d30e3f6
--- /dev/null
+++ b/feedbackloop.learner_backup/src/main/java/de/tudresden/inf/st/eraser/feedbackloop.learner_backup/CsvTransfer.java
@@ -0,0 +1,60 @@
+package de.tudresden.inf.st.eraser.feedbackloop.learner_backup;
+
+import java.io.*;
+import java.util.*;
+
+import com.opencsv.CSVReader;
+import com.opencsv.CSVWriter;
+
+
+public class CsvTransfer {
+    public static void main(String[] args){
+        Learner learner=new Learner();
+        learner.train("datasets/backup/activity_data.csv","datasets/backup/preference_data.csv");
+    }
+
+    //learner.train("datasets/backup/activity_data.csv","datasets/backup/preference_data.csv");
+    /**private static final String CSV_FILE_PATH
+            = "datasets/backup/activity_data_example.csv";
+    private static final String OUTPUT_FILE_PATH
+            = "datasets/backup/activity_data.csv";
+    public static void main(String[] args)
+    {
+        addDataToCSV(CSV_FILE_PATH, OUTPUT_FILE_PATH);
+    }
+    public static void addDataToCSV(String input, String output)
+    {
+        File input_file = new File(input);
+        File output_file = new File(output);
+        try {
+            // create FileWriter object with file as parameter
+            FileReader reader = new FileReader(input_file);
+            CSVReader csv_reader = new CSVReader(reader);
+            String[] nextRecord;
+            FileWriter writer = new FileWriter(output_file);
+            CSVWriter csv_writer = new CSVWriter(writer, ',',
+                    CSVWriter.NO_QUOTE_CHARACTER,
+                    CSVWriter.DEFAULT_ESCAPE_CHARACTER,
+                    CSVWriter.DEFAULT_LINE_END);
+            List<String[]> data = new ArrayList<String[]>();
+
+            while ((nextRecord = csv_reader.readNext()) != null) {
+                data.add(nextRecord);
+
+                for (String cell : nextRecord) {
+                    System.out.print(cell + "\t");
+                }
+                System.out.println();
+            }
+            csv_writer.writeAll(data);
+            writer.close();
+            csv_reader.close();
+        }
+        catch (Exception e) {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+        }
+    }*/
+}
+
+
diff --git a/feedbackloop.learner_backup/src/main/java/de/tudresden/inf/st/eraser/feedbackloop.learner_backup/DummyPreference.java b/feedbackloop.learner_backup/src/main/java/de/tudresden/inf/st/eraser/feedbackloop.learner_backup/DummyPreference.java
new file mode 100644
index 0000000000000000000000000000000000000000..59f3ad9f43fd11eab315e145b1780d4152b82181
--- /dev/null
+++ b/feedbackloop.learner_backup/src/main/java/de/tudresden/inf/st/eraser/feedbackloop.learner_backup/DummyPreference.java
@@ -0,0 +1,75 @@
+package de.tudresden.inf.st.eraser.feedbackloop.learner_backup;
+import com.opencsv.CSVWriter;
+
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Random;
+
+public class DummyPreference {
+    private static String activity;  //Activity: walking, reading, working, dancing, lying, getting up
+    private static String watch_brightness; //dark: <45; dimmer 45-70; bright >70;
+    private static String light_color_openhab_H; //red 7; green 120; blue 240; yellow 60; sky blue 180; purple 300;
+    private static String brightness_output; //1-100**/
+    private static Random random = new Random();
+
+    public static void main(String[] args) {
+        creator();
+    }
+    static void creator(){
+
+
+        try{
+            FileWriter writer = new FileWriter("datasets/backup/preference_data.csv",true);
+            CSVWriter csv_writer = new CSVWriter(writer, ',',
+                    CSVWriter.NO_QUOTE_CHARACTER,
+                    CSVWriter.DEFAULT_ESCAPE_CHARACTER,
+                    CSVWriter.DEFAULT_LINE_END);
+
+
+            //activity="walking" green
+            activity ="walking";
+
+           // activity ="reading";
+            csv_writer.writeAll(generator("walking","green"));
+            csv_writer.writeAll(generator("reading","sky blue"));
+            csv_writer.writeAll(generator("working","blue"));
+            csv_writer.writeAll(generator("dancing","purple"));
+            csv_writer.writeAll(generator("lying","red"));
+            csv_writer.writeAll(generator("getting up","yellow"));
+            csv_writer.close();
+            writer.close();
+        }catch (IOException e){e.printStackTrace();}
+    }
+    static List<String[]> generator(String activity_input, String color){
+        List<String[]> data = new ArrayList<String[]>();
+        activity = activity_input;
+        light_color_openhab_H =color;
+        //100 walking with different lighting intensity
+        for (int i=0; i<100; i++){
+            String[] add_data = new String[4];
+            int brightness = random.nextInt(3000);
+            System.out.println(brightness);
+            if (brightness<45){
+                watch_brightness = "dark";
+                brightness_output ="100";
+            }else if(45<=brightness && brightness<200){
+                watch_brightness = "dimmer";
+                brightness_output ="40";
+            }else if( 200<=brightness && brightness<1000){
+                watch_brightness = "medium";
+                brightness_output ="70";
+            }else{
+                watch_brightness = "bright";
+                brightness_output ="0";
+            }
+            add_data[0] = activity;
+            add_data[1] = watch_brightness;
+            add_data[2] = light_color_openhab_H;
+            add_data[3] = brightness_output;
+            data.add(add_data);
+        }
+        return data;
+    }
+}
diff --git a/feedbackloop.learner_backup/src/main/java/de/tudresden/inf/st/eraser/feedbackloop.learner_backup/Learner.java b/feedbackloop.learner_backup/src/main/java/de/tudresden/inf/st/eraser/feedbackloop.learner_backup/Learner.java
index c728eed8e76b70b64c74455633edec388e16ce3e..5d8021d8faf7519d9ec15305f0752cfbcd742a0c 100644
--- a/feedbackloop.learner_backup/src/main/java/de/tudresden/inf/st/eraser/feedbackloop.learner_backup/Learner.java
+++ b/feedbackloop.learner_backup/src/main/java/de/tudresden/inf/st/eraser/feedbackloop.learner_backup/Learner.java
@@ -1,16 +1,15 @@
 package de.tudresden.inf.st.eraser.feedbackloop.learner_backup;
 
 import java.io.File;
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.util.Arrays;
-
-import com.sun.javafx.tools.packager.Log;
-import org.encog.ConsoleStatusReportable;
+import java.io.IOException;
+//import java.util.ArrayList;
+//import com.sun.javafx.tools.packager.Log;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+//import org.encog.ConsoleStatusReportable;
 import org.encog.Encog;
-import org.encog.bot.BotUtil;
-import org.encog.ml.MLInput;
-import org.encog.ml.MLRegression;
+import org.encog.ml.MLClassification;
+//import org.encog.ml.MLRegression;
 import org.encog.ml.data.MLData;
 import org.encog.ml.data.versatile.NormalizationHelper;
 import org.encog.ml.data.versatile.VersatileMLDataSet;
@@ -22,8 +21,6 @@ import org.encog.ml.factory.MLMethodFactory;
 import org.encog.ml.model.EncogModel;
 import org.encog.neural.networks.BasicNetwork;
 import org.encog.util.csv.CSVFormat;
-import org.encog.util.csv.ReadCSV;
-import org.encog.util.simple.EncogUtility;
 import static org.encog.persist.EncogDirectoryPersistence.*;
 
 public class Learner {
@@ -31,129 +28,163 @@ public class Learner {
     /**
      * intial train
      * */
-    private String csv_url_activity;
-    private String csv_url_perference;
-    private String save_activity_model_file = "datasets/backup/activity_model.eg";
-    private String save_perference_model_file = "datasets/backup/preference_model.eg";
+    private File save_activity_model_file;
+    private File save_preference_model_file;
     private File csv_file;
-    private VersatileDataSource souce;
-    private VersatileMLDataSet data;
-    private EncogModel model;
+    private VersatileMLDataSet a_data;
+    private VersatileMLDataSet p_data;
+    private EncogModel a_model;
+    private EncogModel p_model;
     private NormalizationHelper activity_helper;
     private NormalizationHelper preference_helper;
-    private MLRegression best_method;
-    private String[] new_data;
-    private String activity_result;
-    private String preference_result;
+    private MLClassification a_best_method;
+    private MLClassification p_best_method;
+    private final Logger logger = LogManager.getLogger(Learner.class);
+
+    public Learner() {
+        try {
+            save_activity_model_file = File.createTempFile("activity_model", "eg");
+        } catch (IOException e) {
+            // use local alternative
+            save_activity_model_file = new File("activity_model.eq");
+        }
+        try {
+            save_preference_model_file = File.createTempFile("preference_model", "eg");
+        } catch (IOException e) {
+            // use local alternative
+            save_preference_model_file = new File("preference_model.eg");
+        }
+        save_activity_model_file.deleteOnExit();
+        save_preference_model_file.deleteOnExit();
+    }
 
     private void activityDataAnalyser(String activity_csv_url){
-        this.csv_url_activity = activity_csv_url;
+        VersatileDataSource a_souce;
+        String csv_url_activity;
+        csv_url_activity = activity_csv_url;
         this.csv_file = new File(csv_url_activity);
-        souce = new CSVDataSource(csv_file,false,CSVFormat.DECIMAL_POINT);
-        data = new VersatileMLDataSet(souce);
-        data.defineSourceColumn("monat", 0, ColumnType.continuous);
-        data.defineSourceColumn("day", 1, ColumnType.continuous);
-        data.defineSourceColumn("hour", 2, ColumnType.continuous);
-        data.defineSourceColumn("minute", 3, ColumnType.continuous);
-        ColumnDefinition outputColumn = data.defineSourceColumn("labels", 4, ColumnType.continuous);
-        data.defineSingleOutputOthersInput(outputColumn);
-        data.analyze();
-        System.out.println("get data ");
-        model = new EncogModel(data);
-        model.selectMethod(data, MLMethodFactory.TYPE_FEEDFORWARD);
-        data.normalize();
-        activity_helper = data.getNormHelper();
-        System.out.println(activity_helper.toString());
+        a_souce = new CSVDataSource(csv_file,false,CSVFormat.DECIMAL_POINT);
+        a_data = new VersatileMLDataSet(a_souce);
+        String[] activity_inputs={"m_accel_x","m_accel_y", "m_accel_z",
+                "m_rotation_x","m_rotation_y", "m_rotation_z",
+                "w_accel_x","w_accel_y", "w_accel_z",
+                "w_rotation_x","w_rotation_y","w_rotation_z"
+        };
+        for(int i=0; i < activity_inputs.length; i++){
+            a_data.defineSourceColumn(activity_inputs[i], i, ColumnType.continuous);
+        }
+        ColumnDefinition outputColumn = a_data.defineSourceColumn("labels", 12, ColumnType.nominal);
+        a_data.defineSingleOutputOthersInput(outputColumn);
+        a_data.analyze();
+        a_model = new EncogModel(a_data);
+        a_model.selectMethod(a_data, MLMethodFactory.TYPE_FEEDFORWARD);
+        a_data.normalize();
+        activity_helper = a_data.getNormHelper();
     }
 
-    private void perferenceDataAnalyser(String perference_csv_url){
-        this.csv_url_perference = perference_csv_url;
-        this.csv_file = new File(this.csv_url_perference);
-        souce = new CSVDataSource(csv_file,false,CSVFormat.DECIMAL_POINT);
-        data = new VersatileMLDataSet(souce);
-        data.defineSourceColumn("activity", 0, ColumnType.continuous);
-        data.defineSourceColumn("brightness", 1, ColumnType.continuous);
-        data.defineSourceColumn("time", 2, ColumnType.continuous);
-        data.defineSourceColumn("minute", 3, ColumnType.continuous);
-        ColumnDefinition outputColumn = data.defineSourceColumn("labels", 4, ColumnType.continuous);
-        data.defineSingleOutputOthersInput(outputColumn);
-        data.analyze();
-        model = new EncogModel(data);
-        model.selectMethod(data, MLMethodFactory.TYPE_FEEDFORWARD);
-        //model.setReport(new ConsoleStatusReportable());
-        data.normalize();
-        preference_helper = data.getNormHelper();
-        System.out.println(activity_helper.toString());
+    private void preferenceDataAnalyser(String preference_csv_url){
+        VersatileDataSource p_source;
+        String csv_url_preference;
+        csv_url_preference = preference_csv_url;
+        this.csv_file = new File(csv_url_preference);
+        p_source = new CSVDataSource(csv_file,false,CSVFormat.DECIMAL_POINT);
+        p_data = new VersatileMLDataSet(p_source);
+        p_data.defineSourceColumn("activity", 0, ColumnType.nominal);
+        p_data.defineSourceColumn("w_brightness", 1, ColumnType.nominal);
+        ColumnDefinition outputColumn1 = p_data.defineSourceColumn("label1", 2, ColumnType.continuous);
+        ColumnDefinition outputColumn2 = p_data.defineSourceColumn("label2", 3, ColumnType.continuous);
+        ColumnDefinition[] outputs = new ColumnDefinition[2];
+        outputs[0] = outputColumn1;
+        outputs[1] = outputColumn2;
+        p_data.defineMultipleOutputsOthersInput(outputs);
+        p_data.analyze();
+        p_model = new EncogModel(p_data);
+        p_model.selectMethod(p_data, MLMethodFactory.TYPE_FEEDFORWARD);
+        p_data.normalize();
+        preference_helper = p_data.getNormHelper();
     }
 
-    void train(String activity_url,String perference_url){
+    void train(String activity_url,String preference_url){
         activity_train(activity_url);
-        Log.info("activity training finished");
-        preference_train(perference_url);
-        Log.info("preference training finished");
+        preference_train(preference_url);
+        Encog.getInstance().shutdown();
 
     }
-    private void activity_train(String activity_csv_url){
+
+    void activity_train(String activity_csv_url){
+        logger.info("Activity training is beginning ... ...");
         activityDataAnalyser(activity_csv_url);
-        model.holdBackValidation(0.3, true, 1001);
-        model.selectTrainingType(data);
-        best_method = (MLRegression)model.crossvalidate(5, true);
-        System.out.println(best_method);
+        a_model.holdBackValidation(0.3, true, 1001);
+        a_model.selectTrainingType(a_data);
+        a_best_method = (MLClassification)a_model.crossvalidate(5, true);
         saveEncogModel(save_activity_model_file);
+        logger.info("Activity training is finished ... ...");
+        Encog.getInstance().shutdown();
     }
-    private void preference_train(String perfence_csv_url){
-        perferenceDataAnalyser(perfence_csv_url);
-        model.holdBackValidation(0.3, true, 1001);
-        model.selectTrainingType(data);
-        best_method = (MLRegression)model.crossvalidate(5, true);
-        System.out.println(best_method);
-        saveEncogModel(save_perference_model_file);
+    void preference_train(String prefence_csv_url){
+        logger.info("Preference training is beginning ... ...");
+        preferenceDataAnalyser(prefence_csv_url);
+        p_model.holdBackValidation(0.3, true, 1001);
+        p_model.selectTrainingType(p_data);
+        p_best_method = (MLClassification)p_model.crossvalidate(5, true);
+        saveEncogModel(save_preference_model_file);
+        logger.info("Preference training is finished ... ...");
+        Encog.getInstance().shutdown();
     }
 
     String[] predictor(String[] new_data){
-        this.new_data = new_data;
-        activityDataAnalyser("datasets/backup/activity_data.csv");
-        perferenceDataAnalyser("datasets/backup/preference_data.csv");
-        String[] result = new String[2];
-        result[0] = activity_predictor();
-        result[1] = perference_predictor();
+        String[] preference_data = new String[2];
+        String[] result = new String[3];
+        String[] activity_data= new String[12];
+        for(int i=0; i<new_data.length;i++){
+            activity_data[i]=new_data[i];
+        }
+        result[0] = activity_predictor(activity_data);
+        preference_data[0]=result[0];
+        preference_data[1]=new_data[12];
+        result[1] = preference_predictor(preference_data)[0];
+        result[2] = preference_predictor(preference_data)[1];
         Encog.getInstance().shutdown();
         return result;
     }
 
-    private String activity_predictor(){
-        BasicNetwork activity_method = (BasicNetwork) loadObject(new File(save_activity_model_file));
+    String activity_predictor(String[] new_data){
+        logger.info("Activity predicting ... ...");
+        String activity_result;
+        activityDataAnalyser("../datasets/backup/activity_data.csv");
+        BasicNetwork activity_method = (BasicNetwork) loadObject(save_activity_model_file);
         MLData input = activity_helper.allocateInputVector();
-        String[] activity_new_data = new String[4];
-        activity_new_data[0] = new_data[0];
-        activity_new_data[1] = new_data[1];
-        activity_new_data[2] = new_data[2];
-        activity_new_data[3] = new_data[3];
-        activity_helper.normalizeInputVector(activity_new_data,input.getData(),false);
+        activity_helper.normalizeInputVector(new_data,input.getData(),false);
         MLData output = activity_method.compute(input);
-        System.out.println("input:"+input);
-        System.out.println("output"+output);
         activity_result = activity_helper.denormalizeOutputVectorToString(output)[0];
-        System.out.println("output activity"+ activity_result);
+        Encog.getInstance().shutdown();
+        logger.debug("Activity Predictor result is: {}",activity_result);
         return activity_result;
     }
 
-    private String perference_predictor(){
-        BasicNetwork preference_method = (BasicNetwork)loadObject(new File(save_perference_model_file));
+    String[] preference_predictor(String[] new_data){
+        logger.info("Activity predicting ... ...");
+        String[] preference_result;
+        preference_result = new String[2];
+        preferenceDataAnalyser("../datasets/backup/preference_data.csv");
+        BasicNetwork preference_method = (BasicNetwork)loadObject(save_preference_model_file);
         MLData input = preference_helper.allocateInputVector();
-        String[] perference_new_data = new String[4];
-        perference_new_data[0] = activity_result;
-        perference_new_data[1] = new_data[4];
-        perference_new_data[2] = new_data[5];
-        perference_new_data[3] = new_data[6];
-        preference_helper.normalizeInputVector(perference_new_data, input.getData(),false);
+        preference_helper.normalizeInputVector(new_data, input.getData(),false);
         MLData output = preference_method.compute(input);
-        preference_result = preference_helper.denormalizeOutputVectorToString(output)[0];
+        preference_result[0] = preference_helper.denormalizeOutputVectorToString(output)[0];
+        preference_result[1] = preference_helper.denormalizeOutputVectorToString(output)[1];
+        Encog.getInstance().shutdown();
+        logger.debug("Preference Predictor result is, Color:  {}",Math.round(Float.valueOf(preference_result[0])));
+        logger.debug("Preference Predictor result is, Brightness: {} ",Math.round(Float.valueOf(preference_result[1])));
         return preference_result;
     }
+    private void saveEncogModel(File modelFile){
+        if (modelFile.equals(save_activity_model_file)) {
+          saveObject(modelFile, this.a_best_method);
+        } else {
+            saveObject(modelFile, this.p_best_method);
+        }
 
-    private void saveEncogModel(String model_file_url){
-        saveObject(new File(model_file_url), this.best_method);
     }
 }
 
diff --git a/feedbackloop.learner_backup/src/main/java/de/tudresden/inf/st/eraser/feedbackloop.learner_backup/MachineLearningImpl.java b/feedbackloop.learner_backup/src/main/java/de/tudresden/inf/st/eraser/feedbackloop.learner_backup/MachineLearningImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..dc16aa2353ea216a49d2d1e75d8cfcff4d36abbc
--- /dev/null
+++ b/feedbackloop.learner_backup/src/main/java/de/tudresden/inf/st/eraser/feedbackloop.learner_backup/MachineLearningImpl.java
@@ -0,0 +1,211 @@
+package de.tudresden.inf.st.eraser.feedbackloop.learner_backup;
+
+
+
+//import com.sun.javafx.tools.packager.Log;
+import de.tudresden.inf.st.eraser.jastadd.model.*;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
+import java.time.Instant;
+import java.util.*;
+import java.util.stream.Collectors;
+
+
+public class MachineLearningImpl implements MachineLearningDecoder, MachineLearningEncoder {
+
+  private List<Item> target_item_list;
+  private List<Item> relevant_item_list;
+  private String[] preference_result;
+
+  private Root root;
+  private final Logger logger = LogManager.getLogger(MachineLearningImpl.class);
+  private final Learner learner;
+  private final int goal;
+
+  public static final int GOAL_ACTIVITY_PHONE_AND_WATCH = 1;
+  public static final int GOAL_PREFERENCE_BRIGHTNESS_IRIS = 2;
+  public String activity_result;
+  private String[] activites= new String[]{"working", "walking", "dancing", "lying", "getting up", "reading"};
+  public MachineLearningImpl(Learner learner, int goal) {
+    this.learner = learner;
+    this.goal = goal;
+  }
+
+  @Override
+  public void setKnowledgeBaseRoot(Root root) {
+    this.root = root;
+    updateItems();
+  }
+
+  private void updateItems() {
+    OpenHAB2Model model = root.getOpenHAB2Model();
+    List<String> targetItemNames, relevantItemNames;
+    switch (this.goal) {
+      case GOAL_ACTIVITY_PHONE_AND_WATCH:
+        targetItemNames = Collections.singletonList("activity");
+        relevantItemNames = Arrays.asList(
+            "m_accel_x",
+            "m_accel_y",
+            "m_accel_z",
+            "m_rotation_x",
+            "m_rotation_y",
+            "m_rotation_z",
+            "w_accel_x",
+            "w_accel_y",
+            "w_accel_z",
+            "w_rotation_x",
+            "w_rotation_y",
+            "w_rotation_z"
+        );
+        break;
+      case GOAL_PREFERENCE_BRIGHTNESS_IRIS:
+        targetItemNames = Collections.singletonList("iris1_item");
+        relevantItemNames = Arrays.asList(
+            "activity",
+            "w_brightness"
+        );
+        break;
+      default:
+        logger.error("Unknown goal value ({}) set", this.goal);
+        targetItemNames = Collections.emptyList();
+        relevantItemNames = Collections.emptyList();
+    }
+    target_item_list = targetItemNames.stream()
+        .map(name -> resolve(model, name))
+        .filter(Objects::nonNull)
+        .collect(Collectors.toList());
+    relevant_item_list = relevantItemNames.stream()
+        .map(name -> resolve(model, name))
+        .filter(Objects::nonNull)
+        .collect(Collectors.toList());
+  }
+
+  private Item resolve(OpenHAB2Model model, String id) {
+    Optional<Item> maybeItem = model.resolveItem(id);
+    if (maybeItem.isPresent()) {
+      return maybeItem.get();
+    } else {
+      logger.warn("Could not find item with id {}", id);
+      return null;
+    }
+  }
+
+  @Override
+  public void newData(List<Item> changedItems) {
+    /* String topic = changedItems.get(0).getTopic().toString();
+     if(topic.equals("oh2/samsung/items1")){
+     new_data[0]=changedItems.get(0).influxMeasurementName();
+     }
+     model.getOpenHAB2Model().items();
+     Item iris_item=model.getOpenHAB2Model().resolveItem("iris_item").get();
+     iris_item.getStateAsString();*/
+    /* FIXME either save state of unchanged items here (if only changed items are reported) <- pull model
+             or let knowledge base pass all relevant items <- push model
+    */
+    if(this.goal==GOAL_ACTIVITY_PHONE_AND_WATCH){
+      String[] new_data = new String[12];
+      for (int i =0; i< new_data.length; i++){
+        new_data[i] ="0";
+      }
+      for(Item item: changedItems){
+        int i = 0;
+        for(Item item1: relevant_item_list){
+          if(item.getTopic().toString().equals(item1.getTopic().toString())){
+            new_data[i]=item.getStateAsString();
+          }
+          i++;
+        }
+      }
+      this.activity_result = learner.activity_predictor(new_data);
+
+    }else if(this.goal==GOAL_PREFERENCE_BRIGHTNESS_IRIS){
+      String[] new_data = new String[2];
+      for(Item item: changedItems){
+        if(root.getOpenHAB2Model().getActivityItem().equals(item))
+        {
+          String test=item.getStateAsString();
+          int index = Math.round(Float.valueOf(test));
+          new_data[0]=activites[index];
+        }
+        if(item.getID().equals("w_brightness")){
+          new_data[1]=item.getStateAsString();
+        }
+      }
+      this.preference_result=learner.preference_predictor(new_data);
+    }
+  }
+
+  @Override
+  public List<Item> getTargets() {
+    return target_item_list;
+  }
+
+  @Override
+  public List<Item> getRelevantItems() {
+    return relevant_item_list;
+  }
+
+  @Override
+  public void triggerTraining() {
+    logger.debug("Ignore trigger training call");
+  }
+
+  @Override
+  public Instant lastModelUpdate() {
+    return null;
+  }
+
+  @Override
+  public MachineLearningResult classify() {
+    switch (this.goal) {
+      case GOAL_ACTIVITY_PHONE_AND_WATCH:
+        String activityStringValue = activity_result;
+        Item activityItem = resolve(this.root.getOpenHAB2Model(), "activity");
+        //activityItem.setStateFromString(activityStringValue);
+        // FIXME how to translate activityStringValue to a number? or should activity item state better be a String?
+        for (int i=0; i< activites.length;i++){
+          if(activites[i].equals(activityStringValue)){
+            activityItem.setStateFromString(String.valueOf(i));
+          }
+        }
+        logger.debug("Classify would return activity: {}", activityStringValue);
+        ItemPreference classifiedActivity = new ItemPreferenceDouble(activityItem, 0);
+        return new MachineLearningResultImpl(classifiedActivity);
+      case GOAL_PREFERENCE_BRIGHTNESS_IRIS:
+//        String[] preference = {result[1], result[2]};
+        // FIXME what is the meaning of result[1] and result[2]
+        Item iris1 = resolve(this.root.getOpenHAB2Model(), "iris1_item");
+        int color = 0;
+        int brightness = 0;
+        if (preference_result != null){
+          color = Math.round(Float.valueOf(preference_result[0]));
+          brightness = Math.round(Float.valueOf(preference_result[1]));
+        }
+
+        ItemPreference classifiedPreference = new ItemPreferenceColor(iris1, TupleHSB.of(color, 100, brightness));
+        return new MachineLearningResultImpl(classifiedPreference);
+      default:
+        logger.error("Unknown goal value ({}) set in classify", this.goal);
+        return new EmptyMachineLearningResult();
+    }
+  }
+
+  public void initActivities(String filenameOfCsv) {
+    logger.debug(filenameOfCsv);
+    learner.activity_train(filenameOfCsv);
+  }
+
+  public void initPreferences(String filenameOfCsv) {
+    learner.preference_train(filenameOfCsv);
+  }
+
+  class EmptyMachineLearningResult implements MachineLearningResult {
+
+    @Override
+    public List<ItemPreference> getPreferences() {
+      return Collections.emptyList();
+    }
+  }
+
+}
diff --git a/feedbackloop.learner_backup/src/main/java/de/tudresden/inf/st/eraser/feedbackloop.learner_backup/MachineLearningResultImpl.java b/feedbackloop.learner_backup/src/main/java/de/tudresden/inf/st/eraser/feedbackloop.learner_backup/MachineLearningResultImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..61d483a566255d51ce424d23adb014df1eec8109
--- /dev/null
+++ b/feedbackloop.learner_backup/src/main/java/de/tudresden/inf/st/eraser/feedbackloop.learner_backup/MachineLearningResultImpl.java
@@ -0,0 +1,26 @@
+package de.tudresden.inf.st.eraser.feedbackloop.learner_backup;
+
+import de.tudresden.inf.st.eraser.jastadd.model.ItemPreference;
+import de.tudresden.inf.st.eraser.jastadd.model.MachineLearningResult;
+
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * TODO: Add description.
+ *
+ * @author rschoene - Initial contribution
+ */
+public class MachineLearningResultImpl implements MachineLearningResult {
+
+  private final ItemPreference preference;
+
+  MachineLearningResultImpl(ItemPreference preference) {
+    this.preference = preference;
+  }
+
+  @Override
+  public List<ItemPreference> getPreferences() {
+    return Collections.singletonList(preference);
+  }
+}
diff --git a/feedbackloop.learner_backup/src/main/java/de/tudresden/inf/st/eraser/feedbackloop.learner_backup/Main.java b/feedbackloop.learner_backup/src/main/java/de/tudresden/inf/st/eraser/feedbackloop.learner_backup/Main.java
index 8ef9e85f7e0bcb95e5f430e87fe48ac81fad2733..2580847d5ace8e832bde76159dad2e85974115a2 100644
--- a/feedbackloop.learner_backup/src/main/java/de/tudresden/inf/st/eraser/feedbackloop.learner_backup/Main.java
+++ b/feedbackloop.learner_backup/src/main/java/de/tudresden/inf/st/eraser/feedbackloop.learner_backup/Main.java
@@ -1,6 +1,9 @@
 package de.tudresden.inf.st.eraser.feedbackloop.learner_backup;
 
-import de.tudresden.inf.st.eraser.jastadd.model.*;
+import org.encog.util.csv.CSVFormat;
+import org.encog.util.csv.ReadCSV;
+
+import java.util.Arrays;
 
 public class Main {
 
@@ -8,22 +11,154 @@ public class Main {
     /**
      * new data from KB
      * */
-    String[] new_data = new String[7];
-    new_data[0]="7";
-    new_data[1]="20";
-    new_data[2]="12";
-    new_data[3]="13";
-    new_data[4]="7";
-    new_data[5]="25";
-    new_data[6]="12";
+    //ReaderCSV reader = new ReaderCSV("datasets/backup/activity_data.csv","preference");
+    //reader.updater();
+    Learner learner=new Learner();
+    //learner.preference_train("../datasets/backup/preference_data.csv");
+    //learner.train("datasets/backup/activity_data.csv","datasets/backup/preference_data.csv");
+    //0.5793968,1.2126632,-4.6244006,-0.030779,0.801127,0.590978,-3.1411927,-0.93373865,-0.31124622,-0.35992432,0.33746338,-0.79608154,dancing
+    /**String[] new_data = new String[12];
+    new_data[0]="0.5793968";
+    new_data[1]="1.2126632";
+    new_data[2]="-4.6244006";
+    new_data[3]="-0.030779";
+    new_data[4]="0.801127";
+    new_data[5]="0.590978";
+    new_data[6]="-3.1411927";
+    new_data[7]="-0.93373865";
+    new_data[8]="-0.31124622";
+    new_data[9]="-0.35992432";
+    new_data[10]="0.33746338";
+    new_data[11]="-0.79608154";
+
+    String result =learner.activity_predictor(new_data);
+    System.out.println(result);
+
+    List k=new ArrayList();
+
+    k.add(new_data);*/
+
+    //learner.preference_train("datasets/backup/preference_data.csv");
+    //learner.train("datasets/backup/activity_data.csv","datasets/backup/preference_data.csv");
+    //walking,medium,120,70
+    //reading,bright,180,0
+
+    //activity_validation_learner();
+    //0.10654198,8.6574335,4.414908,0.040269,0.516884,0.853285,1.2066777,-1.1444284,9.648633,1.2207031E-4,-0.055358887,0.5834961 working
+    String[] new_data = new String[12];
+    new_data[0]="0.010773907";
+    new_data[1]="8.610746";
+    new_data[2]="4.4963107";
+    new_data[3]="0.047136";
+    new_data[4]="0.515427";
+    new_data[5]="0.852877";
+    new_data[6]="0.9720459";
+    new_data[7]="-1.3694834";
+    new_data[8]="9.696517";
+    new_data[9]="-0.0056152344";
+    new_data[10]="-0.049438477";
+    new_data[11]="0.5576782";
+    //0.010773907,8.610746,4.4963107,0.047136,0.515427,0.852877,0.9720459,-1.3694834,9.696517,-0.0056152344,-0.049438477,0.5576782 working
+    //0.9999999988939648,-0.9995820798966354,-0.9999999999999997,-0.9999988062118802,-0.9974031940544938,-1.0
+
+    //String result =learner.activity_predictor(new_data);
+    //System.out.println(result);
+
+    /**String[] new_data_1 =new String[12];
+    //-2.6252422,8.619126,-2.7030537,0.552147,0.5078,0.450302,-8.1881695,-1.2641385,0.038307227,-0.34222412,0.49102783,-0.016540527,walking
+    new_data_1[0]="-2.6252422";
+    new_data_1[1]="8.619126";
+    new_data_1[2]="-2.7030537";
+    new_data_1[3]="0.552147";
+    new_data_1[4]="0.5078";
+    new_data_1[5]="0.450302";
+    new_data_1[6]="-8.1881695";
+    new_data_1[7]="-1.2641385";
+    new_data_1[8]="0.038307227";
+    new_data_1[9]="-0.34222412";
+    new_data_1[10]="0.49102783";
+    new_data_1[11]="-0.016540527";
+    String result1 =learner.activity_predictor(new_data_1);
+    System.out.println(result1);
     /**
      * learner.train(activity_csv_url, preference_data_url)
      * learner.predictor get the result from predictor for new data
      * */
+    /**String[] new_data_2 = new String[12];
+    //-6.5565214,5.717354,5.6658783,0.185591,0.464146,0.413321,-20.580557,3.8498764,-0.4261679,0.7647095,-0.4713745,0.23999023,dancing
+    new_data_2[0]="-6.5565214";
+    new_data_2[1]="5.717354";
+    new_data_2[2]="5.6658783";
+    new_data_2[3]="0.185591";
+    new_data_2[4]="0.464146";
+    new_data_2[5]="0.413321";
+    new_data_2[6]="-20.580557";
+    new_data_2[7]="3.8498764";
+    new_data_2[8]="-0.4261679";
+    new_data_2[9]="0.7647095";
+    new_data_2[10]="-0.4713745";
+    new_data_2[11]="0.23999023";
+
+    String[] new_data_3 = new String[12];
+    new_data_3[0]="-5.3881507";
+    new_data_3[1]="0.25378537";
+    new_data_3[2]="7.69257";
+    new_data_3[3]="-0.122974";
+    new_data_3[4]="0.247411";
+    new_data_3[5]="0.439031";
+    new_data_3[6]="4.9224787";
+    new_data_3[7]="-10.601525";
+    new_data_3[8]="-4.927267";
+    new_data_3[9]="0.7946167";
+    new_data_3[10]="0.35272217";
+    new_data_3[11]="0.16192627";
+    //"-5.3881507","0.25378537","7.69257","-0.122974","0.247411","0.439031","4.9224787","-10.601525","-4.927267","0.7946167","0.35272217","0.16192627","lying"
     Learner learner=new Learner();
-    //learner.train("datasets/activity_data.csv", "datasets/preference_data.csv");
-    String[] result = learner.predictor(new_data);
+    //learner.train("datasets/backup/activity_data.csv", "datasets/preference_data.csv");
+    String[] result = learner.predictor(new_data_3);
     System.out.println("activity is:" + result[0]);
-    System.out.println("perference is: "+ result[1]);
+    //System.out.println("perference is: "+ result[1]);**/
+  }
+  public static void activity_validation_learner(){
+    ReadCSV csv = new ReadCSV("datasets/backup/activity_data.csv", false, CSVFormat.DECIMAL_POINT);
+    String[] line = new String[12];
+    Learner learner=new Learner();
+    int wrong=0;
+    int right=0;
+    while(csv.next()) {
+      StringBuilder result = new StringBuilder();
+      line[0] = csv.get(0);
+      line[1] = csv.get(1);
+      line[2] = csv.get(2);
+      line[3] = csv.get(3);
+      line[4] = csv.get(4);
+      line[5] = csv.get(5);
+      line[6] = csv.get(6);
+      line[7] = csv.get(7);
+      line[8] = csv.get(8);
+      line[9] = csv.get(9);
+      line[10] = csv.get(10);
+      line[11] = csv.get(11);
+      String correct = csv.get(12);
+      String irisChosen = learner.predictor(line)[0];
+      result.append(Arrays.toString(line));
+      result.append(" -> predicted: ");
+      result.append(irisChosen);
+      result.append("(correct: ");
+      result.append(correct);
+      result.append(")");
+      if (irisChosen.equals(correct)!=true){
+        System.out.println(correct);
+        System.out.println(irisChosen);
+        ++wrong;
+      }else{
+        ++right;
+      }
+      System.out.println(result.toString());
+    }
+    System.out.println("wrong number"+wrong);
+    System.out.println("right number"+right);
+    //double validation = (double(right))/(double(wrong+right));
+    //System.out.println("%.2f"+validation);
   }
 }
diff --git a/feedbackloop.learner_backup/src/main/java/de/tudresden/inf/st/eraser/feedbackloop.learner_backup/ReaderCSV.java b/feedbackloop.learner_backup/src/main/java/de/tudresden/inf/st/eraser/feedbackloop.learner_backup/ReaderCSV.java
new file mode 100644
index 0000000000000000000000000000000000000000..76c1ce791b00843befc9ed8b9d0f1941532ac386
--- /dev/null
+++ b/feedbackloop.learner_backup/src/main/java/de/tudresden/inf/st/eraser/feedbackloop.learner_backup/ReaderCSV.java
@@ -0,0 +1,116 @@
+package de.tudresden.inf.st.eraser.feedbackloop.learner_backup;
+
+import java.awt.*;
+import java.io.FileReader;
+import java.io.*;
+import java.util.Arrays;
+
+import com.opencsv.CSVReader;
+import org.apache.http.client.fluent.Request;
+import org.apache.http.HttpResponse;
+import org.apache.http.entity.ContentType;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.ReentrantLock;
+
+public class ReaderCSV{
+
+    //read every 5 s from csv
+    //activity CSV
+    /**
+     * Col 1: smartphone acceleration x
+     * Col 2: smartphone acceleration y
+     * Col 3: smartphone acceleration z
+     * Col 4: smartphone rotation x
+     * Col 5: smartphone rotation y
+     * Col 6: smartphone rotation z
+     * Col 7: watch acceleration x
+     * Col 8: watch acceleration y
+     * Col 9: watch acceleration z
+     * Col 10: watch rotation x
+     * Col 11: watch rotation y
+     * Col 12: watch rotation z/*/
+    //preference CSV
+    /**
+     * Col 1: Activity
+     * Col 2: watch brightness range "bright, medium, dimmer, dark"*/
+
+    private static int TIME_PERIOD = 5000; //5 second update new value
+    private String csv_file_path;
+    private String csv_typ;
+    private File file;
+    private FileReader file_reader;
+    private CSVReader csv_reader;
+    private String[] next_record;
+    private static final Logger logger = LogManager.getLogger(ReaderCSV.class);
+    private static final String ERASER_ITEM_URI = "http://localhost:4567/model/items/";
+    //TODO ITEM_NAME HAS TO BE DISCUSSED
+    private static final String[] ACTIVITY_ITEM_NAME = {
+            "m_accel_x", "m_accel_y", "m_accel_z", "m_rotation_x",
+            "m_rotation_y", "m_rotation_z", "w_accel_x", "w_accel_y",
+            "w_accel_z", "w_rotation_x", "w_rotation_y", "w_rotation_z"};
+    private static final String[] PREFERENCE_ITEM_NAME = {
+           "w_brightness"
+    };
+
+    //csv_type is activity or preference
+    public ReaderCSV(String csv_file_path, String csv_type) {
+        this.csv_file_path = csv_file_path;
+        this.csv_typ = csv_type;
+    }
+
+    public void updater(){
+        file=new File(csv_file_path);
+        try {
+            file_reader =new FileReader(file);
+            csv_reader = new CSVReader(file_reader);
+            while ((next_record = csv_reader.readNext()) != null) {
+                Thread.sleep(TIME_PERIOD);
+                if (csv_typ =="activity"){
+                    String[] values = Arrays.copyOf(next_record,12);
+                    setNewValue(values, ACTIVITY_ITEM_NAME);
+
+               } else {
+                    String[] values = Arrays.copyOf(next_record,2);
+                    setNewValue(values, PREFERENCE_ITEM_NAME);
+                    }
+                }
+            }
+        catch (Exception e){
+            e.printStackTrace();
+        }
+    }
+    private void setNewValue(String[] values, String[] name){
+        if(this.csv_typ.equals("activity"))
+        {
+            int i = 0;
+            for(String value : values){
+                String uri = ERASER_ITEM_URI + name[i] + "/state";
+                logger.info("reader:",value);
+                try {
+                    HttpResponse httpResponse = Request.Put(uri)
+                            .bodyString(value, ContentType.TEXT_PLAIN)
+                            .execute().returnResponse();
+                }catch (Exception e){
+                    e.printStackTrace();
+                }
+                i+=1;
+            }
+
+        }else{
+            String uri= ERASER_ITEM_URI + "w_brightness" +"/state";
+            logger.info("reader:",values[1]);
+            try {
+                HttpResponse httpResponse = Request.Put(uri)
+                        .bodyString(values[1], ContentType.TEXT_PLAIN)
+                        .execute().returnResponse();
+            }catch (Exception e){
+                e.printStackTrace();
+            }
+
+        }
+
+    }
+}
\ No newline at end of file
diff --git a/feedbackloop.learner_backup/src/test/java/de/tudresden/inf/st/eraser/feedbackloop.learner_backup/ATest.java b/feedbackloop.learner_backup/src/test/java/de/tudresden/inf/st/eraser/feedbackloop.learner_backup/ATest.java
deleted file mode 100644
index 45adf05d4acbbe801d7f9ced98e2173fdf1d259d..0000000000000000000000000000000000000000
--- a/feedbackloop.learner_backup/src/test/java/de/tudresden/inf/st/eraser/feedbackloop.learner_backup/ATest.java
+++ /dev/null
@@ -1,22 +0,0 @@
-package de.tudresden.inf.st.eraser.feedbackloop.learner_backup;
-
-import de.tudresden.inf.st.eraser.jastadd.model.*;
-import org.junit.Test;
-
-import java.util.Set;
-
-import static org.hamcrest.Matchers.*;
-import static org.junit.Assert.fail;
-
-/**
- * TODO: Add description.
- *
- * @author rschoene - Initial contribution
- */
-public class ATest {
-
-  @Test
-  public void test1() {
-    fail();
-  }
-}
diff --git a/feedbackloop.plan/src/main/java/de/tudresden/inf/st/eraser/feedbackloop/plan/PlanImpl.java b/feedbackloop.plan/src/main/java/de/tudresden/inf/st/eraser/feedbackloop/plan/PlanImpl.java
index 7175767134e29d3ab39e2c27cb0858d6cb4cb119..e7f256b2928dfbbdd35e48b2dbf5b1797eee727d 100644
--- a/feedbackloop.plan/src/main/java/de/tudresden/inf/st/eraser/feedbackloop/plan/PlanImpl.java
+++ b/feedbackloop.plan/src/main/java/de/tudresden/inf/st/eraser/feedbackloop/plan/PlanImpl.java
@@ -2,9 +2,7 @@ package de.tudresden.inf.st.eraser.feedbackloop.plan;
 
 import de.tudresden.inf.st.eraser.feedbackloop.api.Execute;
 import de.tudresden.inf.st.eraser.feedbackloop.api.Plan;
-import de.tudresden.inf.st.eraser.jastadd.model.Activity;
-import de.tudresden.inf.st.eraser.jastadd.model.ItemPreference;
-import de.tudresden.inf.st.eraser.jastadd.model.Root;
+import de.tudresden.inf.st.eraser.jastadd.model.*;
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
 
@@ -38,9 +36,15 @@ public class PlanImpl implements Plan {
 
   @Override
   public void planToMatchPreferences(Activity activity) {
-    // TODO actually use activity
     logger.info("Plan got new activity [{}]: {}", activity.getIdentifier(), activity.getLabel());
     List<ItemPreference> preferences = knowledgeBase.currentPreferences();
+    knowledgeBase.getMachineLearningRoot().addChangeEvent(createRecognitionEvent(activity));
     informExecute(preferences);
   }
+
+  private ChangeEvent createRecognitionEvent(Activity activity) {
+    RecognitionEvent result = RecognitionEvent.createRecognitionEvent(knowledgeBase.getMachineLearningRoot().getActivityRecognition());
+    result.setActivity(activity);
+    return result;
+  }
 }
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index fb7ef980f26942c36accd5674b80128f6cf43abe..030ec1f8a437a05e86702c10632c66340d98ba0f 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,5 +1,6 @@
+#Tue May 07 14:40:56 CEST 2019
 distributionBase=GRADLE_USER_HOME
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.2-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.2-all.zip
diff --git a/learner_test/.gitignore b/learner_test/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..84c048a73cc2e5dd24f807669eb99b0ce3123195
--- /dev/null
+++ b/learner_test/.gitignore
@@ -0,0 +1 @@
+/build/
diff --git a/learner_test/build.gradle b/learner_test/build.gradle
new file mode 100644
index 0000000000000000000000000000000000000000..64ba25868ab02f58ed90c006f52cfb3e9563c411
--- /dev/null
+++ b/learner_test/build.gradle
@@ -0,0 +1,35 @@
+repositories {
+    mavenCentral()
+}
+
+sourceCompatibility = 1.8
+
+apply plugin: 'java'
+apply plugin: 'application'
+
+dependencies {
+    compile project(':eraser-base')
+    compile group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.8.8.1'
+    compile group: 'org.apache.logging.log4j', name: 'log4j-api', version: '2.10.0'
+    compile group: 'org.apache.logging.log4j', name: 'log4j-core', version: '2.10.0'
+    testCompile group: 'junit', name: 'junit', version: '4.12'
+    testCompile group: 'org.hamcrest', name: 'hamcrest-junit', version: '1.0.0.0'
+
+    compile 'org.encog:encog-core:3.4'
+}
+
+run {
+    mainClassName = 'de.tudresden.inf.st.eraser.learner_test.Main'
+    standardInput = System.in
+    if (project.hasProperty("appArgs")) {
+        args Eval.me(appArgs)
+    }
+}
+
+sourceSets {
+    main {
+        java {
+            srcDir 'src/main/java'
+        }
+    }
+}
diff --git a/learner_test/src/main/java/de/tudresden/inf/st/eraser/learner_test/Main.java b/learner_test/src/main/java/de/tudresden/inf/st/eraser/learner_test/Main.java
new file mode 100644
index 0000000000000000000000000000000000000000..62f00cb624f4dbae09c84bca772d09318f5c9964
--- /dev/null
+++ b/learner_test/src/main/java/de/tudresden/inf/st/eraser/learner_test/Main.java
@@ -0,0 +1,112 @@
+package de.tudresden.inf.st.eraser.learner_test;
+import org.encog.Encog;
+import org.encog.ml.MLClassification;
+import org.encog.ml.data.MLData;
+import org.encog.persist.EncogDirectoryPersistence;
+import org.encog.util.csv.CSVFormat;
+import org.encog.util.csv.ReadCSV;
+import org.encog.util.simple.EncogUtility;
+
+import org.encog.ml.data.versatile.NormalizationHelper;
+import org.encog.ml.data.versatile.VersatileMLDataSet;
+import org.encog.ml.data.versatile.columns.ColumnDefinition;
+import org.encog.ml.data.versatile.columns.ColumnType;
+import org.encog.ml.data.versatile.sources.VersatileDataSource;
+import org.encog.ml.data.versatile.sources.CSVDataSource;
+import org.encog.ml.factory.MLMethodFactory;
+import org.encog.ml.model.EncogModel;
+import org.encog.ConsoleStatusReportable;
+import org.encog.ml.MLRegression;
+import java.io.File;
+import java.util.Arrays;
+import static org.encog.persist.EncogDirectoryPersistence.*;
+
+public class Main {
+
+  public static void main(String[] args) {
+    //mapping the data into model
+    String savefile = "src/main/java/de/tudresden/inf/st/eraser/learner_test/save_model.eg";
+    String File = "src/main/java/de/tudresden/inf/st/eraser/learner_test/preference_data.csv";
+    File file = new File(File);
+    VersatileDataSource source = new CSVDataSource(file, false, CSVFormat.DECIMAL_POINT);
+    VersatileMLDataSet data = new VersatileMLDataSet(source);
+    data.defineSourceColumn("monat", 0, ColumnType.continuous);
+    data.defineSourceColumn("day", 1, ColumnType.continuous);
+    data.defineSourceColumn("hour", 2, ColumnType.continuous);
+    data.defineSourceColumn("minute", 3, ColumnType.continuous);
+    ColumnDefinition outputColumn = data.defineSourceColumn("labels", 4, ColumnType.continuous);
+    data.defineSingleOutputOthersInput(outputColumn);
+    data.analyze();
+    System.out.println("get data ");
+    EncogModel model = new EncogModel(data);
+    model.selectMethod(data, MLMethodFactory.TYPE_FEEDFORWARD);
+    //model.setReport(new ConsoleStatusReportable());
+    data.normalize();
+    NormalizationHelper helper = data.getNormHelper();
+    System.out.println(helper.toString());
+    model.holdBackValidation(0.3, true, 1001);
+    model.selectTrainingType(data);
+    MLRegression bestMethod = (MLRegression)model.crossvalidate(5, true);
+    MLClassification bestMethodtest=(MLClassification)model.crossvalidate(5,true);
+    /**System.out.println( "Training error: " + EncogUtility.calculateRegressionError(bestMethod, model.getTrainingDataset()));
+    System.out.println( "testTraining error: " + EncogUtility.calculateClassificationError(bestMethodtest, model.getTrainingDataset()));
+    System.out.println( "Validation error: " + EncogUtility.calculateRegressionError(bestMethod, model.getValidationDataset()));
+    System.out.println( "testValidation error: " + EncogUtility.calculateClassificationError(bestMethodtest, model.getValidationDataset()));
+
+    System.out.println(helper.getClass());
+    System.out.println(helper.toString());
+    System.out.println("Final model: " + bestMethod);
+    System.out.println("Final testmodel: " + bestMethodtest);**/
+    //NormalizationHelper helper = data.getNormHelper();
+
+    //test
+    String helperstr=helper.toString();
+    String [] split=helperstr.split(";");
+    String [] finalStr = split[split.length-1].replace("]","").replace("[","").
+            split(",");
+    System.out.println(helper);
+
+    // save network...
+    //to delete
+    saveObject(new File(savefile), bestMethodtest);
+    ReadCSV csv = new ReadCSV(File, false, CSVFormat.DECIMAL_POINT);
+    String[] line = new String[4];
+    MLData input = helper.allocateInputVector();
+    System.out.println("input test---------------");
+    System.out.println(input);
+    while(csv.next()) {
+      StringBuilder result = new StringBuilder();
+      line[0] = csv.get(0);
+      line[1] = csv.get(1);
+      line[2] = csv.get(2);
+      line[3] = csv.get(3);
+      String correct = csv.get(4);
+      helper.normalizeInputVector(line,input.getData(),false);
+
+      MLData output = bestMethod.compute(input);
+      System.out.println("inputs:");
+      System.out.println(input);
+      System.out.println("outputs:");
+      System.out.println(output);
+      String brightnessChosen = helper.denormalizeOutputVectorToString(output)[0];
+
+      result.append(Arrays.toString(line));
+      result.append(" -> predicted: ");
+      result.append(brightnessChosen);
+      result.append("(correct: ");
+      result.append(correct);
+      result.append(")");
+      System.out.println(result.toString());
+      break;
+
+    }
+    // Delete data file and shut down.
+    //File.delete();
+    Encog.getInstance().shutdown();
+    /**Training error: 0.299928703107046
+    testTraining error: 0.9931740614334471
+    Validation error: 0.41277024952020763
+    testValidation error: 0.992*/
+
+  }
+}
diff --git a/learner_test/src/main/java/de/tudresden/inf/st/eraser/learner_test/final_data.csv b/learner_test/src/main/java/de/tudresden/inf/st/eraser/learner_test/final_data.csv
new file mode 100644
index 0000000000000000000000000000000000000000..a1e263194d3ee4f95c64c3eff3b5123fb2246cf5
--- /dev/null
+++ b/learner_test/src/main/java/de/tudresden/inf/st/eraser/learner_test/final_data.csv
@@ -0,0 +1,418 @@
+7,20,12,13,2
+7,20,14,40,1
+7,20,14,40,2
+7,21,13,2,2
+7,21,13,2,2
+7,21,14,23,2
+7,21,14,23,2
+7,21,15,41,2
+7,21,16,54,2
+7,21,16,54,2
+7,21,17,45,3
+7,22,12,28,3
+7,22,15,35,2
+7,22,15,35,2
+7,22,18,59,3
+7,22,18,59,3
+7,23,12,32,2
+7,23,12,32,2
+7,23,16,7,2
+7,23,16,7,2
+7,23,16,7,2
+7,23,16,7,2
+7,23,16,7,2
+7,24,12,4,0
+7,24,12,4,0
+7,24,12,4,1
+7,24,14,38,2
+7,24,14,38,2
+7,24,18,54,3
+7,25,12,31,0
+7,25,12,32,1
+7,25,12,32,1
+7,25,15,6,3
+7,25,18,56,3
+7,26,13,41,2
+7,26,19,14,3
+7,27,11,39,2
+7,27,11,39,3
+7,27,11,46,3
+7,27,11,46,2
+7,27,13,8,2
+7,27,13,8,2
+7,27,13,9,2
+7,27,13,45,2
+7,27,13,45,2
+7,27,15,38,3
+7,28,12,12,2
+7,28,12,13,2
+7,28,12,41,2
+7,28,12,41,2
+7,28,12,41,2
+7,28,14,0,1
+7,28,14,0,2
+7,28,15,21,3
+7,28,18,56,3
+7,29,10,9,1
+7,29,10,9,1
+7,29,10,9,1
+7,29,11,54,0
+7,29,11,54,0
+7,29,11,54,0
+7,29,11,54,1
+7,29,14,10,2
+7,29,16,44,2
+7,29,16,44,2
+7,30,16,7,3
+7,30,18,45,3
+7,31,13,2,0
+7,31,13,2,1
+7,31,13,3,1
+7,31,13,3,1
+7,31,13,3,1
+7,31,18,39,3
+8,1,12,22,0
+8,1,12,22,1
+8,1,14,20,2
+8,1,14,20,2
+8,1,14,20,2
+8,1,15,55,3
+8,1,18,31,3
+8,1,18,37,3
+8,1,18,37,3
+8,1,19,2,3
+8,1,19,2,3
+8,1,20,5,3
+8,2,10,9,2
+8,2,10,9,1
+8,2,10,9,2
+8,2,10,9,2
+8,2,13,58,2
+8,2,13,58,2
+8,2,15,44,3
+8,2,15,44,3
+8,2,15,44,3
+8,2,17,21,3
+8,2,17,21,3
+8,2,17,21,3
+8,3,13,31,1
+8,3,13,31,2
+8,3,13,32,2
+8,3,16,43,3
+8,4,13,20,1
+8,4,13,20,2
+8,4,18,27,3
+8,5,13,37,2
+8,5,13,37,2
+8,5,18,33,3
+8,6,11,24,3
+8,6,11,24,3
+8,6,11,24,3
+8,6,13,50,3
+8,7,13,4,2
+8,7,13,4,2
+8,7,14,56,3
+8,8,12,13,2
+8,8,12,13,2
+8,8,15,51,2
+8,8,15,51,2
+8,8,15,51,3
+8,9,13,32,2
+8,9,13,32,2
+8,9,13,32,2
+8,9,15,8,2
+8,9,15,8,2
+8,9,15,8,2
+8,9,16,19,2
+8,10,11,32,0
+8,10,11,32,1
+8,10,11,32,1
+8,10,13,13,1
+8,10,13,13,1
+8,10,13,13,2
+8,10,16,42,3
+8,10,16,42,3
+8,11,14,6,2
+8,11,14,7,2
+8,11,18,54,3
+8,11,18,54,3
+8,11,18,54,3
+8,12,12,27,1
+8,12,12,27,1
+8,12,12,28,1
+8,12,13,53,2
+8,12,13,53,2
+8,12,13,53,2
+8,12,15,21,3
+8,13,13,16,1
+8,13,13,16,1
+8,13,13,16,1
+8,13,14,14,2
+8,13,14,14,2
+8,13,16,11,3
+8,13,17,18,3
+8,14,13,7,1
+8,14,13,7,1
+8,14,13,7,1
+8,14,13,7,1
+8,14,13,7,2
+8,14,13,7,2
+8,14,15,6,3
+8,15,14,5,2
+8,15,14,5,2
+8,15,14,6,2
+8,15,14,6,2
+8,15,16,41,3
+8,15,16,41,3
+8,15,17,30,3
+8,16,13,40,2
+8,16,13,40,2
+8,16,17,52,3
+8,16,17,53,3
+8,17,13,34,1
+8,17,13,35,2
+8,17,14,7,2
+8,17,19,2,3
+8,18,10,21,3
+8,18,11,14,2
+8,18,11,14,2
+8,18,11,14,2
+8,18,11,14,2
+8,18,14,25,2
+8,18,14,25,3
+8,18,14,25,2
+8,18,18,18,3
+8,18,18,19,3
+8,19,18,33,3
+8,19,18,33,3
+8,19,18,33,3
+8,19,18,33,3
+8,20,14,28,2
+8,20,14,28,2
+8,20,14,28,2
+8,20,14,28,2
+8,20,17,8,3
+8,20,18,22,3
+8,21,11,24,1
+8,21,11,24,1
+8,21,11,24,1
+8,21,15,34,3
+8,21,18,55,3
+8,22,12,3,1
+8,22,12,4,2
+8,22,12,4,2
+8,22,13,51,2
+8,22,13,51,2
+8,22,13,51,2
+8,22,18,12,3
+8,22,18,12,3
+8,22,18,12,3
+8,22,18,12,3
+8,22,18,40,3
+8,22,18,40,3
+8,23,13,42,1
+8,23,13,42,1
+8,23,17,32,3
+8,23,19,28,3
+8,23,20,27,3
+8,23,20,27,3
+8,23,21,49,3
+8,24,14,0,2
+8,24,14,0,2
+8,24,14,0,2
+8,24,14,0,2
+8,24,15,4,3
+8,24,15,4,3
+8,24,16,2,3
+8,24,16,3,3
+8,24,16,37,3
+8,24,17,9,3
+8,24,17,14,3
+8,25,13,34,1
+8,25,13,34,1
+8,25,13,34,1
+8,25,13,34,1
+8,25,13,34,1
+8,25,15,1,3
+8,25,17,58,3
+8,26,10,29,0
+8,26,10,29,0
+8,26,10,29,0
+8,26,10,29,0
+8,26,10,29,0
+8,26,16,42,3
+8,26,16,42,3
+8,26,18,41,3
+8,26,18,41,3
+8,27,13,41,2
+8,27,13,41,2
+8,27,13,41,2
+8,27,13,41,2
+8,27,17,42,3
+8,28,11,9,1
+8,28,11,9,1
+8,28,12,14,0
+8,28,12,14,1
+8,28,12,14,0
+8,28,15,3,2
+8,28,15,3,2
+8,28,16,31,3
+8,28,17,40,3
+8,29,14,44,3
+8,29,17,25,3
+8,30,12,5,0
+8,30,12,5,0
+8,30,12,5,0
+8,30,13,32,1
+8,30,13,32,1
+8,30,13,56,2
+8,30,14,23,2
+8,30,14,23,2
+8,30,14,23,2
+8,30,14,23,2
+8,30,14,41,2
+8,30,14,41,2
+8,30,14,41,2
+8,30,15,50,3
+8,30,17,0,3
+8,30,18,59,3
+8,30,18,59,3
+8,31,14,31,2
+8,31,14,31,2
+8,31,14,31,2
+8,31,17,59,3
+8,31,18,0,3
+9,1,16,13,3
+9,1,16,13,3
+9,1,16,13,3
+9,1,17,41,3
+9,2,13,44,1
+9,2,13,44,1
+9,2,13,44,1
+9,2,14,49,2
+9,2,14,49,2
+9,2,14,49,2
+9,2,16,6,3
+9,2,16,6,3
+9,2,17,2,3
+9,3,16,9,3
+9,3,17,35,3
+9,3,17,36,3
+9,4,12,57,1
+9,4,12,57,1
+9,4,15,8,3
+9,4,15,34,3
+9,4,16,26,3
+9,4,16,26,3
+9,4,18,37,3
+9,4,18,37,3
+9,4,18,37,3
+9,6,11,18,0
+9,6,11,18,0
+9,6,12,54,1
+9,6,12,54,1
+9,6,14,21,2
+9,6,14,21,2
+9,6,19,20,3
+9,7,11,50,0
+9,7,14,17,2
+9,7,14,57,3
+9,7,14,57,3
+9,7,16,56,3
+9,7,16,56,3
+9,7,16,56,3
+9,7,16,56,3
+9,7,18,38,3
+9,7,18,38,3
+9,8,11,4,2
+9,8,11,4,2
+9,8,11,13,0
+9,8,11,13,0
+9,8,11,13,0
+9,8,11,13,0
+9,8,11,13,0
+9,8,11,14,0
+9,8,11,14,1
+9,8,11,14,1
+9,8,12,1,0
+9,8,12,1,0
+9,8,12,1,0
+9,8,12,1,0
+9,8,12,1,0
+9,8,12,1,1
+9,8,12,36,0
+9,8,12,36,0
+9,8,12,36,0
+9,8,12,36,0
+9,8,12,36,0
+9,8,13,37,1
+9,8,13,37,1
+9,8,13,37,1
+9,8,14,20,2
+9,8,14,20,2
+9,8,18,20,3
+9,9,12,47,1
+9,9,12,47,2
+9,9,12,47,2
+9,9,19,5,3
+9,10,13,15,1
+9,10,13,15,1
+9,10,13,15,0
+9,10,16,49,3
+9,10,19,6,3
+9,10,21,5,3
+9,11,14,16,2
+9,11,14,16,2
+9,11,14,16,2
+9,11,18,41,3
+9,12,14,43,2
+9,12,14,43,2
+9,12,14,43,2
+9,12,16,14,3
+9,12,17,12,3
+9,12,17,12,2
+9,12,17,12,3
+9,12,17,12,2
+9,12,20,44,3
+9,13,19,52,3
+9,14,14,39,2
+9,14,14,39,2
+9,14,15,14,3
+9,14,17,29,3
+9,14,17,29,3
+9,14,17,29,3
+9,15,11,41,1
+9,15,11,41,1
+9,15,13,4,1
+9,15,14,3,1
+9,15,14,3,2
+9,16,12,36,1
+9,16,12,36,1
+9,16,12,36,1
+9,16,12,36,1
+9,16,12,48,1
+9,16,12,48,1
+9,16,13,51,1
+9,16,13,51,2
+9,16,13,51,1
+9,16,15,13,3
+9,16,15,14,3
+9,16,15,14,3
+9,17,10,27,0
+9,17,10,27,0
+9,17,11,10,0
+9,17,11,10,0
+9,17,11,10,0
+9,17,12,43,1
+9,17,12,43,1
+9,17,12,43,1
+9,17,13,32,1
+9,17,13,32,1
+9,17,14,5,1
+9,17,14,5,2
+9,17,14,6,2
+9,17,15,7,3
+9,17,15,49,3
+9,17,15,49,3
+9,17,18,12,3
+9,17,18,13,3
diff --git a/learner_test/src/main/java/de/tudresden/inf/st/eraser/learner_test/save_model.eg b/learner_test/src/main/java/de/tudresden/inf/st/eraser/learner_test/save_model.eg
new file mode 100644
index 0000000000000000000000000000000000000000..47c37ff28ef95b7b22a2df05ec050c3ffeb53a30
--- /dev/null
+++ b/learner_test/src/main/java/de/tudresden/inf/st/eraser/learner_test/save_model.eg
@@ -0,0 +1,24 @@
+encog,BasicNetwork,java,3.4.0,1,1554196571101
+[BASIC]
+[BASIC:PARAMS]
+[BASIC:NETWORK]
+beginTraining=0
+connectionLimit=0
+contextTargetOffset=0,0,0
+contextTargetSize=0,0,0
+endTraining=2
+hasContext=f
+inputCount=4
+layerCounts=1,8,5
+layerFeedCounts=1,7,4
+layerContextCount=0,0,0
+layerIndex=0,1,9
+output=0.2537517424,0.3154675575,-0.8739039638,-0.4408848221,-0.8484433638,-0.999915299,-0.6964984771,-0.208278439,1,0,0,-0.4545454545,0.3559322034,1
+outputCount=1
+weightIndex=0,8,43
+weights=0.5976774048,-0.7925906525,0.7127327881,-0.9611660362,0.8031350986,-0.7286657218,1.0990482817,-0.5985785536,-0.0783115433,0.575612931,1.1267500918,1.7184744034,0.2271044512,-1.0525796764,0.0900869671,1.1492323512,0.6141715555,-1.0455927965,-0.0925453451,0.2471651431,2.3634316872,0.3939369257,0.4607437082,-0.1435186798,0.8428535365,-0.0848896791,-0.070602589,-1.2640263565,2.4899996734,-0.2185394776,10.3421332361,-0.1650898311,-0.2750133571,-0.79680959,-0.8051139953,0.8219933747,-0.0727160299,-0.4609522002,-1.0410685492,-0.5354063412,0.3028724456,-0.6835374219,0.169591233
+biasActivation=0,1,1
+[BASIC:ACTIVATION]
+"org.encog.engine.network.activation.ActivationTANH"
+"org.encog.engine.network.activation.ActivationTANH"
+"org.encog.engine.network.activation.ActivationLinear"
diff --git a/learner_test/src/main/java/de/tudresden/inf/st/eraser/learner_test/save_model_test.eg b/learner_test/src/main/java/de/tudresden/inf/st/eraser/learner_test/save_model_test.eg
new file mode 100644
index 0000000000000000000000000000000000000000..62fe6421d95e164aa14e123b950e831e37a5f23c
--- /dev/null
+++ b/learner_test/src/main/java/de/tudresden/inf/st/eraser/learner_test/save_model_test.eg
@@ -0,0 +1,24 @@
+encog,BasicNetwork,java,3.4.0,1,1548158734516
+[BASIC]
+[BASIC:PARAMS]
+[BASIC:NETWORK]
+beginTraining=0
+connectionLimit=0
+contextTargetOffset=0,0,0
+contextTargetSize=0,0,0
+endTraining=2
+hasContext=f
+inputCount=4
+layerCounts=4,8,5
+layerFeedCounts=4,7,4
+layerContextCount=0,0,0
+layerIndex=0,4,12
+output=0.6991387348,-0.8711034513,-0.996886038,-0.832747291,-0.0935682806,-0.9996163977,0.5399150265,0.9411173394,-0.5084989975,0.4850010791,0.9999999957,1,0,-0.6666666667,-0.4545454545,0.6949152542,1
+outputCount=4
+weightIndex=0,32,67
+weights=-2.6901880743,0.6512821123,-1.2270002115,1.63124668,0.1982387305,-0.2994789552,1.5833040739,-0.9450411677,2.0541422847,-0.718279397,-1.1761952241,0.5028631512,0.0690323612,-1.496141565,-0.1955149568,-0.7453976822,-0.3691141073,0.9854755554,2.2113850088,-1.5216550292,0.9652087936,-1.3028209693,-1.3346156171,0.4142247818,1.0821207364,0.1987534858,0.6202881884,-0.2940331887,-1.4643282498,2.6960334656,-0.0167663298,-2.9907087565,0.3469960227,-0.0441249736,-2.5998575813,-0.7106361301,-0.8111809962,2.2216158678,-0.5482762437,-1.7996398291,-3.6734127565,-2.9102547958,0.4845401914,0.3760471288,-0.0124987546,0.3784047483,0.5860932613,-0.2682876707,0.7429004186,-7.559247176,-3.4421363532,1.1989747484,-2.3340717496,-1.4740773042,-0.7795788072,-1.8241693655,-0.630132295,-0.8191869009,-0.4060569987,-1.0997423162,-0.5495165849,0.1407829068,-2.2964930412,0.0798893221,-19.5271913755,2.0474187009,-0.2622671892
+biasActivation=0,1,1
+[BASIC:ACTIVATION]
+"org.encog.engine.network.activation.ActivationTANH"
+"org.encog.engine.network.activation.ActivationTANH"
+"org.encog.engine.network.activation.ActivationLinear"
diff --git a/learner_test/src/main/resources/log4j2.xml b/learner_test/src/main/resources/log4j2.xml
new file mode 100644
index 0000000000000000000000000000000000000000..0594576fac98ba859e411597c90c8e3d989378bd
--- /dev/null
+++ b/learner_test/src/main/resources/log4j2.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Configuration>
+    <Appenders>
+        <Console name="Console">
+            <PatternLayout pattern="%highlight{%d{HH:mm:ss.SSS} %-5level} %c{1.} - %msg%n"/>
+        </Console>
+        <RollingFile name="RollingFile" fileName="logs/jastadd-mquat.log"
+                    filePattern="logs/jastadd-mquat-%i.log">
+            <PatternLayout pattern="%d{HH:mm:ss.SSS} %-5level %logger{36} - %msg%n"/>
+            <Policies>
+                <OnStartupTriggeringPolicy/>
+            </Policies>
+            <DefaultRolloverStrategy max="20"/>
+        </RollingFile>
+    </Appenders>
+    <Loggers>
+        <Root level="debug">
+            <AppenderRef ref="Console"/>
+            <AppenderRef ref="RollingFile"/>
+        </Root>
+    </Loggers>
+</Configuration>
diff --git a/make-new-project.py b/make-new-project.py
index afd3a51931e3a7dc6823d47e1b9c97a65a2a2e76..635755567333e0d326ff346d5852d7d62437bbcb 100755
--- a/make-new-project.py
+++ b/make-new-project.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python3
+#!/usr/bin/env python2.7
 import argparse
 import os
 import shutil
diff --git a/ml_test_boqi/.gitignore b/ml_test_boqi/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..70b583e34c3316bcd77c807e2d6b85db5e7d49f6
--- /dev/null
+++ b/ml_test_boqi/.gitignore
@@ -0,0 +1,3 @@
+/build/
+/bin/
+logs/
diff --git a/ml_test_boqi/build.gradle b/ml_test_boqi/build.gradle
new file mode 100644
index 0000000000000000000000000000000000000000..d07b5930b7d3c75216b36bb9f5d9fa08b5d9d2c0
--- /dev/null
+++ b/ml_test_boqi/build.gradle
@@ -0,0 +1,33 @@
+repositories {
+    mavenCentral()
+}
+
+sourceCompatibility = 1.8
+
+apply plugin: 'java'
+apply plugin: 'application'
+
+dependencies {
+    compile project(':eraser-base')
+    compile group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.9.8'
+    compile group: 'org.apache.logging.log4j', name: 'log4j-api', version: '2.11.1'
+    compile group: 'org.apache.logging.log4j', name: 'log4j-core', version: '2.11.1'
+    testCompile group: 'junit', name: 'junit', version: '4.12'
+    testCompile group: 'org.hamcrest', name: 'hamcrest-junit', version: '2.0.0.0'
+}
+
+run {
+    mainClassName = 'de.tudresden.inf.st.eraser.ml_test_boqi.Main'
+    standardInput = System.in
+    if (project.hasProperty("appArgs")) {
+        args Eval.me(appArgs)
+    }
+}
+
+sourceSets {
+    main {
+        java {
+            srcDir 'src/main/java'
+        }
+    }
+}
diff --git a/ml_test_boqi/src/main/java/de/tudresden/inf/st/eraser/ml_test_boqi/Main.java b/ml_test_boqi/src/main/java/de/tudresden/inf/st/eraser/ml_test_boqi/Main.java
new file mode 100644
index 0000000000000000000000000000000000000000..f42663472e3a986c82df86e4bf89d0f9ff706441
--- /dev/null
+++ b/ml_test_boqi/src/main/java/de/tudresden/inf/st/eraser/ml_test_boqi/Main.java
@@ -0,0 +1,219 @@
+package de.tudresden.inf.st.eraser.ml_test_boqi;
+
+import de.tudresden.inf.st.eraser.jastadd.model.*;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+import org.apache.commons.math3.stat.StatUtils;
+import de.tudresden.inf.st.eraser.jastadd.model.Item;
+
+
+public class Main {
+
+  private static final Logger logger = LogManager.getLogger(Main.class);
+
+  public static void main(String[] args) {
+
+    logger.info("Hello World!");
+    createAndTestBrightnessNetwork();
+  }
+  private static Root createModel() {
+    Root model = Root.createEmptyRoot();
+    Group group = new Group();
+    group.setID("Group1");
+    model.addGroup(group);
+
+    // inputs items muss normalize 1.0, 0.06666666666666665, 0.4545454545454546, -0.5593220338983051, 1(bias)
+
+    NumberItem monthItem = new NumberItem();
+    monthItem.setState(-1.0);
+    monthItem.setID("month");
+    monthItem.setLabel("datetime-month");
+
+    NumberItem dayItem = new NumberItem();
+    dayItem.setState(0.2666666666666666);
+    dayItem.setID("day");
+    dayItem.setLabel("datetime-day");
+
+    NumberItem hourItem = new NumberItem();
+    hourItem.setState(-0.6363636363636364);
+    hourItem.setID("hour");
+    hourItem.setLabel("datetime-hour");
+
+    NumberItem minuteItem = new NumberItem();
+    minuteItem.setState(-0.5593220338983051);
+    minuteItem.setID("minute");
+    minuteItem.setLabel("datetime-minute");
+
+    NumberItem biasItem = new NumberItem();
+    biasItem.setState(1);
+    biasItem.setID("bias");
+    biasItem.setLabel("bias");
+
+    group.addItem(monthItem);
+    group.addItem(dayItem);
+    group.addItem(hourItem);
+    group.addItem(minuteItem);
+    group.addItem(biasItem);
+    return model;
+  }
+  private static final int REPETITIONS = 1;
+  private static void classifyTimed(
+          NeuralNetworkRoot nn,
+          Function<NeuralNetworkRoot, DoubleNumber> classify,
+          Function<DoubleNumber, String> leafToString) {
+    List<String> results = new ArrayList<>();
+    List<Long> times = new ArrayList<>();
+    long before = System.nanoTime();
+    DoubleNumber classification = classify.apply(nn);
+    long diff = System.nanoTime() - before;
+    results.add(leafToString.apply(classification));
+    times.add(TimeUnit.NANOSECONDS.toMillis(diff));
+    logger.info("Classification results: {}", results);
+    logger.info("Took {}ms", String.join("ms, ", times.stream().map(l -> Long.toString(l)).collect(Collectors.toList())));
+    logger.info("Took on average: {}ms",
+            Arrays.stream(times.toArray(new Long[0])).mapToLong(l -> l).average().orElse(-1));
+    logger.info("Took on median: {}ms",
+            Arrays.stream(times.toArray(new Long[0])).mapToLong(l -> l).sorted()
+                    .skip((REPETITIONS - 1) / 2).limit(2 - REPETITIONS % 2).average().orElse(Double.NaN));
+  }
+
+  /**
+   * Purpose: Create a neural network with 3 layers (5 + 8 + 4 neurons)
+   */
+  private static void createAndTestBrightnessNetwork() {
+    Root model = createModel();
+    Item monthItem = model.resolveItem("month").orElseThrow(
+            () -> new RuntimeException("Month not found"));
+    Item dayItem = model.resolveItem("day").orElseThrow(
+            () -> new RuntimeException("Day not found"));
+    Item hourItem = model.resolveItem("hour").orElseThrow(
+            () -> new RuntimeException("Hour not found"));
+    Item minuteItem = model.resolveItem("minute").orElseThrow(
+            () -> new RuntimeException("Minute not found"));
+    Item biasItem = model.resolveItem("bias").orElseThrow(
+            () -> new RuntimeException("Bias not found"));
+
+    NeuralNetworkRoot nn = new NeuralNetworkRoot();
+
+    DoubleArrayDoubleFunction sigmoid = inputs -> Math.signum(Arrays.stream(inputs).sum());
+    DoubleArrayDoubleFunction tanh= inputs ->Math.tanh(Arrays.stream(inputs).sum());
+    DoubleArrayDoubleFunction function_one= inputs->function_one();
+
+    //Weights outputs from learner Module
+    ArrayList<Double> weights= new ArrayList<Double>(Arrays.asList(
+            -4.8288886204,0.6723236931,2.1451097188,-0.8551053267,-0.7858304445,4.1369566727,-3.3096691918,
+            -0.2190980261,2.6871317298,1.2272772167,-2.5292510941,-1.2860407542,-4.2280191541,1.004752063,
+            0.8345207039,0.0123185817,-0.5921808915,0.0967336988,-0.305892589,0.5572392781,-0.7190098073,
+            -1.6247354373,0.4589248822,-0.0269816271,2.2208040852,-3.6281085698,0.2204999381,4.7263701556,
+            -4.8348948698,0.231141867,8.7120706018,-1.4912707741,0.9482851705,0.1377551973,-6.6525856465,
+            -1.321197315,-2.7369948929,17.664289214,-3.1279212743,-0.8245974167,-1.4251924355,0.8370511414,
+            2.0841638143,-0.210152817,-1.9414132298,-1.7973688846,-2.1977997794,-3.6046836685,-3.3403186721,
+            -6.1556924635,-2.8952903587,-1.0773989561,0.2300429028,-0.2184650371,0.0297181797,0.5709092417,
+            1.3960358442,-3.1577981239,0.0423944625,-17.8143314027,-1.4439317172,-0.5137688896,1.0166045804,
+            0.3059149818,1.0938282764,0.6203368549,0.702449827));
+    // input layer
+    InputNeuron month = new InputNeuron();
+    month.setItem(monthItem);
+    InputNeuron day = new InputNeuron();
+    day.setItem(dayItem);
+    InputNeuron hour = new InputNeuron();
+    hour.setItem(hourItem);
+    InputNeuron minute = new InputNeuron();
+    minute.setItem(minuteItem);
+    InputNeuron bias = new InputNeuron();
+    bias.setItem(biasItem);
+
+    nn.addInputNeuron(month);
+    nn.addInputNeuron(day);
+    nn.addInputNeuron(hour);
+    nn.addInputNeuron(minute);
+    nn.addInputNeuron(bias);
+
+    // output layer
+    OutputLayer outputLayer = new OutputLayer();
+    OutputNeuron output0 = new OutputNeuron();
+    output0.setActivationFormula(tanh);
+    OutputNeuron output1 = new OutputNeuron();
+    output1.setActivationFormula(tanh);
+    OutputNeuron output2 = new OutputNeuron();
+    output2.setActivationFormula(tanh);
+    OutputNeuron output3 = new OutputNeuron();
+    output3.setActivationFormula(tanh);
+
+    outputLayer.addOutputNeuron(output0);
+    outputLayer.addOutputNeuron(output1);
+    outputLayer.addOutputNeuron(output2);
+    outputLayer.addOutputNeuron(output3);
+
+    outputLayer.setCombinator(inputs->predictor(inputs));
+    nn.setOutputLayer(outputLayer);
+
+    // hidden layer
+    HiddenNeuron[] hiddenNeurons = new HiddenNeuron[8];
+    for (int i = 0; i < (hiddenNeurons.length); i++) {
+
+      if (i==7){
+        HiddenNeuron hiddenNeuron = new HiddenNeuron();
+        hiddenNeuron.setActivationFormula(function_one);
+        hiddenNeurons[i] = hiddenNeuron;
+        nn.addHiddenNeuron(hiddenNeuron);
+        bias.connectTo(hiddenNeuron,1.0);
+        hiddenNeuron.connectTo(output0, weights.get(i));
+        hiddenNeuron.connectTo(output1, weights.get(i+8));
+        hiddenNeuron.connectTo(output2, weights.get(i+8*2));
+        hiddenNeuron.connectTo(output3, weights.get(i+8*3));
+      }
+     else{
+        HiddenNeuron hiddenNeuron = new HiddenNeuron();
+        hiddenNeuron.setActivationFormula(tanh);
+        hiddenNeurons[i] = hiddenNeuron;
+        nn.addHiddenNeuron(hiddenNeuron);
+
+        month.connectTo(hiddenNeuron, weights.get((hiddenNeurons.length*4)+i*5));
+        day.connectTo(hiddenNeuron, weights.get((hiddenNeurons.length*4+1)+i*5));
+        hour.connectTo(hiddenNeuron, weights.get((hiddenNeurons.length*4+2)+i*5));
+        minute.connectTo(hiddenNeuron, weights.get((hiddenNeurons.length*4+3)+i*5));
+        bias.connectTo(hiddenNeuron,weights.get((hiddenNeurons.length*4+4)+i*5));
+        hiddenNeuron.connectTo(output0, weights.get(i));
+        hiddenNeuron.connectTo(output1, weights.get(i+8));
+        hiddenNeuron.connectTo(output2, weights.get(i+8*2));
+        hiddenNeuron.connectTo(output3, weights.get(i+8*3));}
+    }
+
+    model.getMachineLearningRoot().setPreferenceLearning(nn);
+    System.out.println(model.prettyPrint());
+
+    classifyTimed(nn, NeuralNetworkRoot::classify,
+            classification -> Double.toString(classification.number));
+  }
+  private static double function_one() {
+    return 1.0;
+  }
+  private static double predictor(double[] inputs) {
+    int index=0;
+    double maxinput=StatUtils.max(inputs);
+    System.out.println(inputs);
+    for (int i = 0; i < inputs.length; i++)
+    {
+      if (inputs[i] == maxinput){
+        index=i;
+      }
+    }
+    //outputs from learner
+    ArrayList<Double> outputs= new ArrayList<Double>(Arrays.asList(2.0,1.0,3.0,0.0));
+    double output=outputs.get(index);
+    return output;
+  }
+}
+
+//inputs:
+//[BasicMLData:-1.0,0.2666666666666666,-0.6363636363636364,-0.5593220338983051]
+//outputs:
+//[BasicMLData:-0.9151867668336432,-0.1568555041251098,-0.9786996639280675,-0.9436628188408074]
+//[7, 20, 12, 13] -> predicted: 1(correct: 2)
\ No newline at end of file
diff --git a/ml_test_boqi/src/main/resources/log4j2.xml b/ml_test_boqi/src/main/resources/log4j2.xml
new file mode 100644
index 0000000000000000000000000000000000000000..0594576fac98ba859e411597c90c8e3d989378bd
--- /dev/null
+++ b/ml_test_boqi/src/main/resources/log4j2.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Configuration>
+    <Appenders>
+        <Console name="Console">
+            <PatternLayout pattern="%highlight{%d{HH:mm:ss.SSS} %-5level} %c{1.} - %msg%n"/>
+        </Console>
+        <RollingFile name="RollingFile" fileName="logs/jastadd-mquat.log"
+                    filePattern="logs/jastadd-mquat-%i.log">
+            <PatternLayout pattern="%d{HH:mm:ss.SSS} %-5level %logger{36} - %msg%n"/>
+            <Policies>
+                <OnStartupTriggeringPolicy/>
+            </Policies>
+            <DefaultRolloverStrategy max="20"/>
+        </RollingFile>
+    </Appenders>
+    <Loggers>
+        <Root level="debug">
+            <AppenderRef ref="Console"/>
+            <AppenderRef ref="RollingFile"/>
+        </Root>
+    </Loggers>
+</Configuration>
diff --git a/settings.gradle b/settings.gradle
index 4492d856ad2d58bf8a3fe0eedca93b30b9c05bb2..0a118ec458b406dfae388bf1218c2abd4bfd356b 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -3,6 +3,7 @@ rootProject.name = 'eraser'
 include ':eraser-base'
 include 'openhab-mock'
 include 'integration'
+include ':benchmark'
 include ':commons.color'
 include ':skywriter-hue-integration'
 include ':org.openhab.action.machinelearn'
@@ -19,4 +20,5 @@ include ':feedbackloop.learner'
 include ':influx_test'
 include ':eraser.spark'
 include ':eraser.starter'
-include ':integration_test'
+include ':feedbackloop.learner_backup'
+include ':datasets'
diff --git a/skywriter-hue-integration/src/main/resources/smart_arrive.eraser b/skywriter-hue-integration/src/main/resources/smart_arrive.eraser
new file mode 100644
index 0000000000000000000000000000000000000000..44b67cf94d3bb8da666cc38743f008552041a152
--- /dev/null
+++ b/skywriter-hue-integration/src/main/resources/smart_arrive.eraser
@@ -0,0 +1,44 @@
+ThingType: id="hue:bridge" label="Hue Bridge" description="The hue bridge represents the Philips hue bridge." parameters=[] channelTypes=[] ;
+ThingType: id="hue:0200" label="Color Light" description="A dimmable light with changeable colors." ;
+ThingType: id="hue:0210" label="Extended Color Light" description="A dimmable light with changeable colors and tunable color temperature." parameters=[] channelTypes=[];
+ThingType: id="skywriter-hat" label="SkyWriterHAT" description="SkyWriterHAT Gesture Recognition" parameters=["brokername"] channelTypes=["flick-type", "skywriter-x", "skywriter-y"] ;
+
+Thing: id="hue:bridge:0017880adcf4" label="Philips hue (10.8.0.160)" type="hue:bridge" channels=[] ;
+Thing: id="hue:0210:0017880adcf4:1" label="Wohnzimmer" type="hue:0210" channels=["hue:0210:0017880adcf4:1:color_temperature", "hue:0210:0017880adcf4:1:effect"] ;
+Thing: id="hue:0200:0017880adcf4:5" label="Hue iris 1" type="hue:0200" channels=["hue:0210:0017880adcf4:4:color", "hue:0210:0017880adcf4:4:color_temperature", "hue:0210:0017880adcf4:4:alert", "hue:0210:0017880adcf4:4:effect"] ;
+Thing: id="hue:0210:0017880adcf4:4" label="Hue go 1" type="hue:0210" channels=["hue:0200:0017880adcf4:5:color", "hue:0200:0017880adcf4:5:alert", "hue:0200:0017880adcf4:5:effect"] ;
+Thing: id="skywriter1" label="Our skywriter" type="skywriter-hat" channels=["skywriter1-flick", "skywriter1-x", "skywriter1-y"] ;
+
+ChannelType: id="hue:color" label="Color" description="The color channel allows to control the color of a light. It is also possible to dim values and switch the light on and off." itemType="Color" category="ColorLight" ;
+ChannelType: id="hue:alert" label="Alert" description="The alert channel allows a temporary change to the bulb’s state." itemType="String" category="Unknown" ;
+ChannelType: id="hue:effect" label="Color Loop" description="The effect channel allows putting the bulb in a color looping mode." itemType="Switch" category="ColorLight" ;
+ChannelType: id="hue:color_temperature" label="Color Temperature" description="The color temperature channel allows to set the color temperature of a light from 0 (cold) to 100 (warm)." itemType="Dimmer" category="ColorLight" ;
+ChannelType: id="flick-type" itemType="String" label="Last Flick" description="Last Flick detected (and its direction)" category="Motion" readOnly ;
+ChannelType: id="skywriter-x" itemType="String" label="Current X coordinate" description="Current X coordinate" category="Motion" readOnly ;
+ChannelType: id="skywriter-y" itemType="String" label="Current Y coordinate" description="Current Y coordinate" category="Motion" readOnly ;
+
+Channel: id="hue:0210:0017880adcf4:1:color_temperature" type="hue:color_temperature" links=[] ;
+Channel: id="hue:0210:0017880adcf4:1:effect" type="hue:effect" links=[] ;
+Channel: id="hue:0210:0017880adcf4:4:color" type="hue:color" links=[] ;
+Channel: id="hue:0210:0017880adcf4:4:color_temperature" type="hue:color_temperature" links=[] ;
+Channel: id="hue:0210:0017880adcf4:4:alert" type="hue:alert" links=[] ;
+Channel: id="hue:0210:0017880adcf4:4:effect" type="hue:effect" links=[] ;
+Channel: id="hue:0200:0017880adcf4:5:color" type="hue:color" links=["iris1_item"] ;
+Channel: id="hue:0200:0017880adcf4:5:alert" type="hue:alert" links=[] ;
+Channel: id="hue:0200:0017880adcf4:5:effect" type="hue:color" links=[] ;
+Channel: id="skywriter1-flick" type="flick-type" links=[];
+Channel: id="skywriter1-x" type="skywriter-x" links=["skywriter1_x"];
+Channel: id="skywriter1-y" type="skywriter-y" links=["skywriter1_y"];
+
+Item: id="iris1_item" label="Iris 1" state="121,88,68" topic="iris1_item/state";
+Item: id="skywriter1_x" label="X" state="0" topic="skywriter/x";
+Item: id="skywriter1_y" label="Y" state="0" topic="skywriter/y";
+//Item: id="skywriter1_xyz" label="Y" state="0" topic="skywriter/xyz";
+
+Group: id="Lights" items=["iris1_item"];
+Group: id="Skywriter" items=["skywriter1_x", "skywriter1_y"];
+
+Parameter: id="brokername" label="Broker Name" description="Name of the broker as defined in the &lt;broker&gt;.url in services/mqtt.cfg. See the MQTT Binding for more information on how to configure MQTT broker connections." type="Text" context="service" default="mosquitto" required ;
+
+// MqttHost is set programmatically
+Mqtt: incoming="oh2/out/" outgoing="oh2/in/" ;