diff --git a/libs/ragconnect-0.2.2.jar b/libs/ragconnect-0.2.2.jar
new file mode 100644
index 0000000000000000000000000000000000000000..c2a95e44dc2a392419f58a5a31731d0e7e61849f
Binary files /dev/null and b/libs/ragconnect-0.2.2.jar differ
diff --git a/ros3rag.common/src/main/java/de/tudresden/inf/st/ros3rag/common/Util.java b/ros3rag.common/src/main/java/de/tudresden/inf/st/ros3rag/common/Util.java
index 65f58a1e667398f4b4b8fe59880e5fae9e02def9..af978eb6022b4e2d6a1f7b68a1c5903655fe0cae 100644
--- a/ros3rag.common/src/main/java/de/tudresden/inf/st/ros3rag/common/Util.java
+++ b/ros3rag.common/src/main/java/de/tudresden/inf/st/ros3rag/common/Util.java
@@ -81,6 +81,8 @@ public class Util {
   private final static Set<String> modules = new HashSet<>() {{
     add("ros3rag.placeA");
     add("ros3rag.placeB");
+    add("ros3rag.old.a");
+    add("ros3rag.old.b");
     add("ros3rag.common");
     add("ros3rag.coordinator");
   }};
diff --git a/ros3rag.common/src/main/resources/old-jastadd/types.connect b/ros3rag.common/src/main/resources/old-jastadd/types.connect
new file mode 100644
index 0000000000000000000000000000000000000000..1d21d81d358d380c0f0f928654a0075d5cfdc513
--- /dev/null
+++ b/ros3rag.common/src/main/resources/old-jastadd/types.connect
@@ -0,0 +1,64 @@
+ParseScene maps byte[] bytes to de.tudresden.inf.st.ceti.Scene {:
+  return de.tudresden.inf.st.ceti.Scene.parseFrom(bytes);
+:}
+
+ConvertScene maps de.tudresden.inf.st.ceti.Scene pbScene to Scene {:
+  var result = new Scene();
+  for (var pbObject : pbScene.getObjectsList()) {
+    ObjectOfInterest obj;
+    switch (pbObject.getType()) {
+      case BOX:
+        // BOX == MovableObject
+        MovableObject movableObject = new MovableObject();
+        result.addMovableObject(movableObject);
+        obj = movableObject;
+        break;
+      case DROP_OFF_LOCATION:
+        // DROP_OFF_LOCATION == DropOffLocation
+        DropOffLocation dropOffLocation = new DropOffLocation();
+        result.addDropOffLocation(dropOffLocation);
+        obj = dropOffLocation;
+        break;
+      case COLLABORATION_ZONE:
+        // COLLABORATION_ZONE == CollaborationZone
+        CollaborationZone cz = new CollaborationZone();
+        result.addDropOffLocation(cz);
+        obj = cz;
+        break;
+      case ARM:
+        // ARM == RobotObject
+        RobotObject ro = new RobotObject();
+        ro.setState(pbObject.getState());
+        result.addRobotObject(ro);
+        obj = ro;
+        break;
+      default:
+        // ignore object, continue for loop
+        continue;
+    }
+    obj.setName(pbObject.getId());
+
+    // position
+    var pos = new Position();
+    pos.setX(pbObject.getPos().getX());
+    pos.setY(pbObject.getPos().getY());
+    pos.setZ(pbObject.getPos().getZ());
+    obj.setPosition(pos);
+
+    // orientation
+    var orient = new Orientation();
+    orient.setX(pbObject.getOrientation().getX());
+    orient.setY(pbObject.getOrientation().getY());
+    orient.setZ(pbObject.getOrientation().getZ());
+    orient.setW(pbObject.getOrientation().getW());
+    obj.setOrientation(orient);
+
+    // size
+    var size = new Size();
+    size.setLength(pbObject.getSize().getLength());
+    size.setWidth(pbObject.getSize().getWidth());
+    size.setHeight(pbObject.getSize().getHeight());
+    obj.setSize(size);
+  }
+  return result;
+:}
diff --git a/ros3rag.common/src/main/resources/old-jastadd/types.jadd b/ros3rag.common/src/main/resources/old-jastadd/types.jadd
new file mode 100644
index 0000000000000000000000000000000000000000..8ee7d98d85588cca63675ff54ac47761ac74dbce
--- /dev/null
+++ b/ros3rag.common/src/main/resources/old-jastadd/types.jadd
@@ -0,0 +1,337 @@
+import org.apache.commons.math3.geometry.euclidean.threed.Rotation;
+import org.apache.commons.math3.geometry.euclidean.threed.Vector3D;
+import java.util.*;
+
+aspect Resolving {
+  //--- resolveObjectOfInterest ---
+  syn ObjectOfInterest Scene.resolveObjectOfInterest(String name) {
+    for (DropOffLocation location : getDropOffLocationList()) {
+      if (location.getName().equals(name)) {
+        return location;
+      }
+    }
+    for (MovableObject movableObject : getMovableObjectList()) {
+      if (movableObject.getName().equals(name)) {
+        return movableObject;
+      }
+    }
+    for (RobotObject robotObject : getRobotObjectList()) {
+      if (robotObject.getName().equals(name)) {
+        return robotObject;
+      }
+    }
+    return null;
+  }
+
+  //--- resolveLogicalObjectOfInterest ---
+  syn LogicalObjectOfInterest LogicalScene.resolveLogicalObjectOfInterest(String name) {
+    for (LogicalRegion region : getLogicalRegionList()) {
+      if (region.getName().equals(name)) {
+        return region;
+      }
+    }
+    for (LogicalMovableObject movableObject : getLogicalMovableObjectList()) {
+      if (movableObject.getName().equals(name)) {
+        return movableObject;
+      }
+    }
+    return null;
+  }
+
+  syn DropOffLocation LogicalMovableObject.myLocation() {
+    // classical reference attribute (was relation, but not allowed with RagConnect)
+    ObjectOfInterest obj = containingScene().resolveObjectOfInterest(getNameOfMyLocation());
+    return obj == null ? null : obj.asDropOffLocation();
+  }
+}
+
+aspect Computation {
+  //--- isLocatedAt ---
+  syn boolean MovableObject.isLocatedAt(DropOffLocation location) {
+    Orientation orient = location.getOrientation();
+    Position locationPosition = location.getPosition();
+    // true to do normalization, first parameter is scalar value
+    Rotation locationRotation = new Rotation(orient.getW(), orient.getX(), orient.getY(), orient.getZ(), true);
+
+    Position pos = this.getPosition();
+    // first do translation of objectVector to coordinate system of location
+    Vector3D objectVector = new Vector3D(pos.getX() - locationPosition.getX(),
+                                         pos.getY() - locationPosition.getY(),
+                                         pos.getZ() - locationPosition.getZ());
+
+    // apply rotation on this point
+    Vector3D rotatedObjectVector = locationRotation.applyInverseTo(objectVector);
+
+    // check whether coordinates are within the bounds of the given location
+    Size locationSize = location.getSize();
+    // we use half of the size of to the position as it is in the center of the location
+    double halfLocationLength = 0.5 * locationSize.getLength();
+    double halfLocationWidth = 0.5 * locationSize.getWidth();
+//    double halfLocationHeight = 0.5 * locationSize.getHeight();
+
+    double rotatedX = rotatedObjectVector.getX();
+    double rotatedY = rotatedObjectVector.getY();
+    double rotatedZ = rotatedObjectVector.getZ();
+
+//    System.out.printf("min: (%f , %f , %f). rotated: (%f , %f , %f), max: (%f , %f , %f)%n",
+//      -halfLocationLength, -halfLocationWidth, -halfLocationHeight,
+//      rotatedX, rotatedY, rotatedZ,
+//      halfLocationLength,
+//      halfLocationWidth,
+//      halfLocationHeight);
+
+    return  LT(-halfLocationLength, rotatedX) && LT(rotatedX, halfLocationLength) &&
+       LT(-halfLocationWidth, rotatedY) && LT(rotatedY, halfLocationWidth); // &&
+       //LT(-halfLocationHeight, rotatedZ) && LT(rotatedZ, halfLocationHeight);
+  }
+
+  syn MovableObject DropOffLocation.getObjectLocatedHere() {
+    for (MovableObject obj : containingScene().getMovableObjects()) {
+      if (obj.isLocatedAt(this)) {
+        return obj;
+      }
+    }
+    return null;
+  }
+
+  //--- getLogicalScene ---
+  syn LogicalScene Scene.getLogicalScene() {
+    var result = new LogicalScene();
+    Map<MovableObject, LogicalMovableObject> objects = new HashMap<>();
+    for (MovableObject movableObject : getMovableObjectList()) {
+      LogicalMovableObject newLogicalMovableObject = new LogicalMovableObject();
+      newLogicalMovableObject.setName(movableObject.getName());
+      result.addLogicalMovableObject(newLogicalMovableObject);
+      objects.put(movableObject, newLogicalMovableObject);
+    }
+    for (Region region : regionList()) {
+      LogicalRegion logicalRegion = new LogicalRegion();
+      logicalRegion.setName(region.getName());
+      result.addLogicalRegion(logicalRegion);
+      for (MovableObject movableObject : getMovableObjectList()) {
+        for (DropOffLocation location : region.locationList()) {
+          if (movableObject.isLocatedAt(location)) {
+            LogicalMovableObject logicalObject = objects.get(movableObject);
+            logicalRegion.addContainedObject(logicalObject);
+            logicalObject.setNameOfMyLocation(location.getName());
+          }
+        }
+      }
+    }
+    return result;
+  }
+
+  private static final double MovableObject.DELTA = 0.0001;
+
+  //--- LT ---
+  /**
+   * @return d1 <= d2 (within a DELTA)
+   */
+  private boolean MovableObject.LT(double d1, double d2) {
+    return org.apache.commons.math3.util.Precision.compareTo(d1, d2, DELTA) <= 0;
+  }
+}
+
+aspect Navigation {
+  // --- isDropOffLocation ---
+  syn boolean ObjectOfInterest.isDropOffLocation() = false;
+  eq DropOffLocation.isDropOffLocation() = true;
+
+  // --- asDropOffLocation ---
+  syn DropOffLocation ObjectOfInterest.asDropOffLocation() = null;
+  eq DropOffLocation.asDropOffLocation() = this;
+
+  // --- isRobotObject ---
+  syn boolean ObjectOfInterest.isRobotObject() = false;
+  eq RobotObject.isRobotObject() = true;
+
+  // --- asRobotObject ---
+  syn RobotObject ObjectOfInterest.asRobotObject() = null;
+  eq RobotObject.asRobotObject() = this;
+
+  // --- isLogicalRegion ---
+  syn boolean LogicalObjectOfInterest.isLogicalRegion() = false;
+  eq LogicalRegion.isLogicalRegion() = true;
+
+  // --- asLogicalRegion ---
+  syn LogicalRegion LogicalObjectOfInterest.asLogicalRegion() = null;
+  eq LogicalRegion.asLogicalRegion() = this;
+
+  // --- isLogicalMovableObject ---
+  syn boolean LogicalObjectOfInterest.isLogicalMovableObject() = false;
+  eq LogicalMovableObject.isLogicalMovableObject() = true;
+
+  // --- asLogicalMovableObject ---
+  syn LogicalMovableObject LogicalObjectOfInterest.asLogicalMovableObject() = null;
+  eq LogicalMovableObject.asLogicalMovableObject() = this;
+
+  inh Scene DropOffLocation.containingScene();
+  inh Scene MovableObject.containingScene();
+  inh Scene LogicalMovableObject.containingScene();
+  eq Scene.getChild().containingScene() = this;
+
+  syn boolean LogicalMovableObject.hasLocatedAt() = !getLocatedAtList().isEmpty();
+
+  // must be "implemented" in concrete world models, i.e., an equation must be defined
+  inh JastAddList<Region> Scene.regionList();
+
+  syn List<Region> DropOffLocation.containedInRegion() {
+    List<Region> result = new ArrayList<>();
+    for (Region region : containingScene().regionList()) {
+      List<String> locationNames = Arrays.asList(region.getLocationNames().split(","));
+      if (locationNames.contains(getName())) {
+        result.add(region);
+      }
+    }
+    return result;
+  }
+
+  protected static List<String> ASTNode.arrayAsList(String array) {
+    if (array == null || array.length() == 0) {
+      return new ArrayList<>();
+    }
+    return new ArrayList<>(Arrays.asList(array.split(",")));
+  }
+  syn List<String> Region.locationNamesAsList() = arrayAsList(getLocationNames()) ;
+  syn List<DropOffLocation> Region.locationList();
+
+  syn Set<String> LogicalMovableObject.regionNameSet() {
+    return getLocatedAtList().stream().map(LogicalRegion::getName).collect(java.util.stream.Collectors.toSet());
+  }
+}
+
+aspect Printing {
+  //--- prettyPrint ---
+  syn String JastAddList.prettyPrint() {
+    return prettyPrint(Object::toString);
+  }
+  syn String JastAddList.prettyPrint(java.util.function.Function<T, String> toString) {
+    return java.util.stream.StreamSupport.stream(Spliterators.spliteratorUnknownSize(this.iterator(), 16), false).map(toString::apply).collect(java.util.stream.Collectors.joining(", ", "[", "]"));
+  }
+
+  syn String Scene.prettyPrint() {
+    StringBuilder sb = new StringBuilder();
+    if (getNumDropOffLocation() == 0) {
+      sb.append(" no locations\n");
+    } else {
+      for (var location : getDropOffLocationList()) {
+        sb.append(" location ").append(location.prettyPrint()).append("\n");
+      }
+    }
+    if (getNumMovableObject() == 0) {
+      sb.append(" no objects\n");
+    } else {
+      for (var obj : getMovableObjectList()) {
+        sb.append(" obj ").append(obj.prettyPrint()).append("\n");
+      }
+    }
+    return sb.toString();
+  }
+
+  syn String MovableObject.prettyPrint() {
+    return "<obj " + nameAndHash() + getPosition().prettyPrint() + getOrientation().prettyPrint() + getSize().prettyPrint() + ">";
+  }
+
+  syn String DropOffLocation.prettyPrint() {
+    return "{" + printPrefix() + " " + getName() + getPosition().prettyPrint() + getOrientation().prettyPrint() + getSize().prettyPrint() + "}";
+  }
+
+  syn String DropOffLocation.printPrefix() = "loc";
+  eq CollaborationZone.printPrefix() = "CZ";
+
+  syn String Region.prettyPrint() {
+    return "{reg " + nameAndHash() + "}";
+  }
+
+  syn String Position.prettyPrint() {
+    return " pos=(" + getX() + "," + getY() + "," + getZ() + ")";
+  }
+
+  syn String Orientation.prettyPrint() {
+    return " orient=(" + getX() + "," + getY() + "," + getZ() + "," + getW() + ")";
+  }
+
+  syn String Size.prettyPrint() {
+    return " size=(" + getLength() + "," + getWidth() + "," + getHeight() + ")";
+  }
+
+  syn String LogicalScene.prettyPrint() {
+    StringBuilder sb = new StringBuilder();
+    if (getNumLogicalRegion() == 0) {
+      sb.append(" no region\n");
+    } else {
+      // TODO
+      for (LogicalRegion region : getLogicalRegionList()) {
+        sb.append(" region ").append(region.prettyPrint());
+        if (!region.getContainedObjectList().isEmpty()) {
+          sb.append(" (objects: ").append(region.getContainedObjectList().stream().map(LogicalMovableObject::getName).collect(java.util.stream.Collectors.joining(","))).append(")");
+        }
+        sb.append("\n");
+      }
+    }
+    if (getNumLogicalMovableObject() == 0) {
+      sb.append(" no objects\n");
+    } else {
+      for (LogicalMovableObject obj : getLogicalMovableObjectList()) {
+        sb.append(" obj ").append(obj.prettyPrint());
+        if (obj.hasLocatedAt()) {
+          sb.append(" (locatedAt: ").append(obj.getLocatedAtList().stream().map(LogicalRegion::nameAndHash).collect(java.util.stream.Collectors.joining(","))).append(")");
+        }
+        sb.append("\n");
+      }
+    }
+    return sb.toString();
+  }
+
+  syn String LogicalMovableObject.prettyPrint() {
+    return  "<lObj " + nameAndHash() + ">";
+  }
+  syn String LogicalRegion.prettyPrint() {
+    return "{lReg " + nameAndHash() + "}";
+  }
+
+  syn String LogicalObjectOfInterest.nameAndHash() = getName() + "@" + Integer.toHexString(hashCode());
+  syn String ObjectOfInterest.nameAndHash() = getName() + "@" + Integer.toHexString(hashCode());
+  syn String Region.nameAndHash() = getName() + "@" + Integer.toHexString(hashCode());
+}
+
+aspect ConvenienceMethods {
+  // --- of ---
+  public static DropOffLocation DropOffLocation.of(String name,
+        Position position, Orientation orientation, Size size) {
+    var location = new DropOffLocation();
+    initObjectOfInterest(location, name, position, orientation, size);
+    return location;
+  }
+
+  public static MovableObject MovableObject.of(String name, Position position) {
+    var location = new MovableObject();
+    initObjectOfInterest(location, name, position,
+        Orientation.of(0, 0, 0, 0), Size.of(0, 0, 0));
+    return location;
+  }
+
+  protected static void ObjectOfInterest.initObjectOfInterest(ObjectOfInterest object, String name,
+        Position position, Orientation orientation, Size size) {
+    object.setName(name);
+    object.setPosition(position);
+    object.setOrientation(orientation);
+    object.setSize(size);
+  }
+
+  public static Position Position.of(double x, double y, double z) {
+    return new Position(x, y, z);
+  }
+
+  public static Orientation Orientation.of(double x, double y, double z, double w) {
+    return new Orientation(x, y, z, w);
+  }
+
+  public static Size Size.of(double length, double width, double height) {
+    return new Size(length, width, height);
+  }
+}
+
+aspect Glue {
+  class MqttHandler implements de.tudresden.inf.st.ros3rag.common.SharedMainParts.MqttHandlerWrapper<MqttHandler> {}
+}
diff --git a/ros3rag.common/src/main/resources/old-jastadd/types.relast b/ros3rag.common/src/main/resources/old-jastadd/types.relast
new file mode 100644
index 0000000000000000000000000000000000000000..c5585b92ce2e51aa1930e25d63cbe1bc114764e7
--- /dev/null
+++ b/ros3rag.common/src/main/resources/old-jastadd/types.relast
@@ -0,0 +1,27 @@
+Position ::= <X:double> <Y:double> <Z:double> ;
+Size ::= <Length:double> <Width:double> <Height:double> ;
+Orientation ::= <X:double> <Y:double> <Z:double> <W:double> ;
+
+// Regions cannot be contained in scene, but must be retrieved via attribute
+Scene ::= DropOffLocation* MovableObject* RobotObject* /LogicalScene/ ;
+
+ObjectOfInterest ::= <Name:String> Position Size Orientation ;
+
+DropOffLocation : ObjectOfInterest ;
+MovableObject : ObjectOfInterest ;
+RobotObject : ObjectOfInterest ::= <State:de.tudresden.inf.st.ceti.Object.State> ;
+
+LogicalScene ::= LogicalRegion* LogicalMovableObject* ;
+LogicalObjectOfInterest ::= <Name:String> ;
+LogicalRegion : LogicalObjectOfInterest ;
+LogicalMovableObject : LogicalObjectOfInterest ::= <NameOfMyLocation> ;
+rel LogicalRegion.ContainedObject* <-> LogicalMovableObject.LocatedAt* ;
+
+// could lead to problems when including this information and sending it
+//rel LogicalMovableObject.MyLocation? -> DropOffLocation ;
+
+Region ::= <Name:String> <LocationNames> ;
+//rel Region.Location* <-> DropOffLocation.ContainedInRegion* ;
+
+// only used in site-B, but needed here for parsing the scene
+CollaborationZone : DropOffLocation ;
diff --git a/ros3rag.common/src/main/resources/tasks.gradle b/ros3rag.common/src/main/resources/tasks.gradle
index 938cb0b6d844fb138245b1cec1b83bc92251af32..b0c1d7800c824f2fa15ba10e06c65c3a7726cc32 100644
--- a/ros3rag.common/src/main/resources/tasks.gradle
+++ b/ros3rag.common/src/main/resources/tasks.gradle
@@ -1,9 +1,14 @@
-// setting default value
+// setting default values
 try {
     project.ext.ragConnectProtocols
 } catch(ignored) {
     project.ext.ragConnectProtocols = 'mqtt'
 }
+try {
+    project.ext.useOldRagConnect
+} catch(ignored) {
+    project.ext.useOldRagConnect = false
+}
 
 dependencies {
     jastadd2 "org.jastadd:jastadd2:2.3.5-dresden-6"
@@ -42,6 +47,28 @@ task ragConnect(type: JavaExec) {
 
 }
 
+task mergeFilesForOldRagConnect {
+    mkdir 'src/gen/workaround/'
+    (file('src/gen/workaround/merged.relast')).text = file(project.ext.ragConnectInputGrammar).getText() + new File(file(project.ext.sharedJastAddDir), 'types.relast').getText()
+    (file('src/gen/workaround/merged.connect')).text = file(project.ext.ragConnectInputConnect).getText() + new File(file(project.ext.sharedJastAddDir), 'types.connect').getText()
+}
+
+task oldRagConnect(type: JavaExec) {
+    group = 'Build'
+    main = '-jar'
+
+    args([
+            '../libs/ragconnect-0.2.2.jar',
+//            '--verbose',
+            '--o=src/gen/jastadd',
+            file('src/gen/workaround/merged.relast'),
+            file('src/gen/workaround/merged.connect'),
+            '--rootNode=' + project.ext.ragConnectRootNode,
+            '--protocols=' + project.ext.ragConnectProtocols,
+            '--List=JastAddList'
+    ])
+}
+
 // Input files for relast
 //def relastFiles = ["src/gen/jastadd/MinimalModel.relast", "src/gen/jastadd/RagConnect.relast"]
 
@@ -50,8 +77,7 @@ task grammar2uml(type: JavaExec) {
     classpath = configurations.grammar2uml
 
     args([
-            '--verbose',
-            'src/gen/jastadd/types.relast'
+            '--verbose'
     ] + project.ext.relastFiles)
 }
 
@@ -73,11 +99,10 @@ task relastToJastAdd(type: JavaExec) {
           "--jastAddList=JastAddList",
           "--serializer=jackson",
           "--resolverHelper",
-          "--file",
-          "src/gen/jastadd/types.relast"
+          "--file"
     ] + project.ext.relastFiles
 
-    inputs.files project.ext.relastFiles + ['src/gen/jastadd/types.relast']
+    inputs.files project.ext.relastFiles
     outputs.files file("./src/gen/jastadd/model.ast"), file("./src/gen/jastadd/model.jadd")
 }
 
@@ -127,7 +152,11 @@ jastadd {
 
     // jastaddOptions = ["--lineColumnNumbers", "--visitCheck=true", "--rewrite=cnta", "--cache=all"]
     // default options are: '--rewrite=cnta', '--safeLazy', '--visitCheck=false', '--cacheCycle=false'
-    extraJastAddOptions = [
+    extraJastAddOptions = project.ext.useOldRagConnect ? [
+            '--lineColumnNumbers',
+            '--List=JastAddList',
+    ] :
+    [
             '--lineColumnNumbers',
             '--List=JastAddList',
             '--cache=all',
@@ -143,4 +172,9 @@ cleanGen.doFirst {
 
 // Workflow configuration for phases
 generateAst.dependsOn relastToJastAdd
-relastToJastAdd.dependsOn ragConnect
+if (project.ext.useOldRagConnect) {
+    oldRagConnect.dependsOn mergeFilesForOldRagConnect
+    relastToJastAdd.dependsOn oldRagConnect
+} else {
+    relastToJastAdd.dependsOn ragConnect
+}
diff --git a/ros3rag.old.a/.gitignore b/ros3rag.old.a/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..87b4cdd3d7c6a41502ca98703abeeb69a1d536fb
--- /dev/null
+++ b/ros3rag.old.a/.gitignore
@@ -0,0 +1,5 @@
+build
+src/gen-res/
+src/gen/
+out/
+*.class
diff --git a/ros3rag.old.a/build.gradle b/ros3rag.old.a/build.gradle
new file mode 100644
index 0000000000000000000000000000000000000000..7a6e03b0b05047705403a48078b29135cc2519d8
--- /dev/null
+++ b/ros3rag.old.a/build.gradle
@@ -0,0 +1,34 @@
+buildscript {
+    repositories.mavenCentral()
+    dependencies {
+        classpath group: 'org.jastadd', name: 'jastaddgradle', version: "${jastadd_gradle_version}"
+    }
+}
+
+plugins {
+    id 'ros3rag.java-application-conventions'
+    id 'ros3rag.java-old-ragconnect-conventions'
+}
+
+mainClassName = 'de.tudresden.inf.st.old.a.OldMainA'
+
+task simpleRun(type: JavaExec) {
+    group 'application'
+    classpath sourceSets.main.runtimeClasspath
+    main = "de.tudresden.inf.st.old.a.OldSimpleMainA"
+
+}
+
+dependencies {
+    implementation project(':ros3rag.common')
+}
+
+ext.sharedJastAddDir = 'src/main/jastadd/old-shared'
+ext.ragConnectInputGrammar = 'src/main/jastadd/OldWorldModelA.relast'
+ext.ragConnectInputConnect = 'src/main/jastadd/OldWorldModelA.connect'
+ext.ragConnectRootNode = 'ArtificialRoot'
+ext.relastFiles = ["src/gen/jastadd/merged.relast", "src/gen/jastadd/RagConnect.relast"]
+ext.jastaddAstPackage = 'de.tudresden.inf.st.old.a.ast'
+ext.useOldRagConnect = true
+
+apply from: '../ros3rag.common/src/main/resources/tasks.gradle'
diff --git a/ros3rag.old.a/src/main/jastadd/Additional.jadd b/ros3rag.old.a/src/main/jastadd/Additional.jadd
new file mode 100644
index 0000000000000000000000000000000000000000..d3d5e23b7fa4a1dbb5eb9fd63727a44742e3a2d3
--- /dev/null
+++ b/ros3rag.old.a/src/main/jastadd/Additional.jadd
@@ -0,0 +1,16 @@
+aspect NewComputationNeededForOldRagConnect {
+  syn String WorldModelA.getLogicalSceneAsNtaToken() {
+    // copied from placeA/src/gen/jastadd/RagConnect.jadd -> ASTNode._ragconnect__apply__TreeDefaultLogicalSceneToBytesMapping(LogicalScene input)
+    java.io.ByteArrayOutputStream outputStream = new java.io.ByteArrayOutputStream();
+  com.fasterxml.jackson.core.JsonFactory factory = new com.fasterxml.jackson.core.JsonFactory();
+  try {
+    com.fasterxml.jackson.core.JsonGenerator generator = factory.createGenerator(outputStream, com.fasterxml.jackson.core.JsonEncoding.UTF8);
+    getLogicalScene().serialize(generator);
+    generator.flush();
+  } catch (IOException | SerializationException e) {
+    e.printStackTrace();
+    return null;
+  }
+  return outputStream.toString();
+  }
+}
diff --git a/ros3rag.old.a/src/main/jastadd/OldWorldModelA.connect b/ros3rag.old.a/src/main/jastadd/OldWorldModelA.connect
new file mode 100644
index 0000000000000000000000000000000000000000..65d03e47f6dc7802b95fe44e84f2a018c1ddbfc5
--- /dev/null
+++ b/ros3rag.old.a/src/main/jastadd/OldWorldModelA.connect
@@ -0,0 +1,7 @@
+// --- receiving ---
+//receive WorldModelA.Scene using ParseScene, ConvertScene ;
+
+// --- sending ---
+send WorldModelA.LogicalSceneAsNtaToken ;
+
+// probably need dependency definitions?
diff --git a/ros3rag.old.a/src/main/jastadd/OldWorldModelA.jadd b/ros3rag.old.a/src/main/jastadd/OldWorldModelA.jadd
new file mode 100644
index 0000000000000000000000000000000000000000..85580b4d450c90ff9b836b9ccfb20799a4459459
--- /dev/null
+++ b/ros3rag.old.a/src/main/jastadd/OldWorldModelA.jadd
@@ -0,0 +1,22 @@
+aspect Navigation {
+  //--- worldModelA ---
+  inh WorldModelA ASTNode.worldModelA();
+  eq WorldModelA.getChild().worldModelA() = this;
+}
+
+aspect Glue {
+  class ArtificialRoot implements de.tudresden.inf.st.ros3rag.common.SharedMainParts.WorldModelWrapper {}
+
+  //--- getLogicalScene ---
+  syn LogicalScene WorldModelA.getLogicalScene() = hasScene() ? getScene().getLogicalScene() : new LogicalScene();
+
+  eq WorldModelA.getScene().regionList() = getRegionList();
+  eq Region.locationList() {
+    List<DropOffLocation> result = new ArrayList<>();
+    if (!worldModelA().hasScene()) { return result; }
+    for (String locationName : locationNamesAsList()) {
+      result.add(worldModelA().getScene().resolveObjectOfInterest(locationName).asDropOffLocation());
+    }
+    return result;
+  }
+}
diff --git a/ros3rag.old.a/src/main/jastadd/OldWorldModelA.relast b/ros3rag.old.a/src/main/jastadd/OldWorldModelA.relast
new file mode 100644
index 0000000000000000000000000000000000000000..90bea5f02498d78f36bf90d76eeb17488a0560dc
--- /dev/null
+++ b/ros3rag.old.a/src/main/jastadd/OldWorldModelA.relast
@@ -0,0 +1,3 @@
+ArtificialRoot ::= WorldModelA ;
+
+WorldModelA ::= Region* [Scene] /LogicalScene/ /<LogicalSceneAsNtaToken>/ ;
diff --git a/ros3rag.old.a/src/main/jastadd/forwardsComp.jadd b/ros3rag.old.a/src/main/jastadd/forwardsComp.jadd
new file mode 100644
index 0000000000000000000000000000000000000000..00ab287ea1c39896c0a5f42b53d7a6972e9cad19
--- /dev/null
+++ b/ros3rag.old.a/src/main/jastadd/forwardsComp.jadd
@@ -0,0 +1,5 @@
+aspect BackwardsCompatibility {
+  public void ArtificialRoot.ragconnectCheckIncremental() {
+    // empty by definition (no incremental evaluation)
+  }
+}
diff --git a/ros3rag.old.a/src/main/jastadd/old-shared b/ros3rag.old.a/src/main/jastadd/old-shared
new file mode 120000
index 0000000000000000000000000000000000000000..1a2dff41ee8ae3f38e6ee93f962b4a983b0cbc3a
--- /dev/null
+++ b/ros3rag.old.a/src/main/jastadd/old-shared
@@ -0,0 +1 @@
+../../../../ros3rag.common/src/main/resources/old-jastadd
\ No newline at end of file
diff --git a/ros3rag.old.a/src/main/java/de/tudresden/inf/st/old/a/OldMainA.java b/ros3rag.old.a/src/main/java/de/tudresden/inf/st/old/a/OldMainA.java
new file mode 100644
index 0000000000000000000000000000000000000000..e7645576b8d4d7722c64aac41b7d218cdcac2028
--- /dev/null
+++ b/ros3rag.old.a/src/main/java/de/tudresden/inf/st/old/a/OldMainA.java
@@ -0,0 +1,94 @@
+package de.tudresden.inf.st.old.a;
+
+import de.tudresden.inf.st.old.a.ast.ArtificialRoot;
+import de.tudresden.inf.st.old.a.ast.MqttHandler;
+import de.tudresden.inf.st.old.a.ast.Scene;
+import de.tudresden.inf.st.old.a.ast.WorldModelA;
+import de.tudresden.inf.st.ros3rag.common.SharedMainParts;
+import de.tudresden.inf.st.ros3rag.common.Util;
+
+import java.io.File;
+import java.io.IOException;
+
+import static de.tudresden.inf.st.ros3rag.common.Util.mqttUri;
+import static de.tudresden.inf.st.ros3rag.common.Util.readScene;
+
+/**
+ * Entry point for RAG model in place A.
+ *
+ * @author rschoene - Initial contribution
+ */
+public class OldMainA extends SharedMainParts<MqttHandler, ArtificialRoot> {
+  private final String TOPIC_SCENE_UPDATE_FROM_ROS;
+  private final String TOPIC_SCENE_UPDATE_TO_PLACE_B;
+
+  private final String TOPIC_DEMO_MOVE_objectRed1_BLUE;
+  private final String TOPIC_DEMO_MOVE_objectRed1_RED;
+  private final String TOPIC_EVAL_MOVE;
+
+  OldMainA(String configFile) {
+    super("place-a", OldUtilA.pathToDirectoryOfPlaceA().resolve(configFile));
+    this.TOPIC_SCENE_UPDATE_FROM_ROS = cellName + "/scene/update";
+    this.TOPIC_SCENE_UPDATE_TO_PLACE_B = cellName + "/logical/update";
+
+    this.TOPIC_DEMO_MOVE_objectRed1_BLUE = cellName + "/demo/move/objectRed1/blue";
+    this.TOPIC_DEMO_MOVE_objectRed1_RED = cellName + "/demo/move/objectRed1/red";
+    this.TOPIC_EVAL_MOVE = cellName + "/eval/move";
+  }
+
+  public static void main(String[] args) throws Exception {
+    String configFile = args.length == 0 ? "src/main/resources/config-a.yaml" : args[0];
+    new OldMainA(configFile).run();
+  }
+
+  @Override
+  protected MqttHandler createMqttHandler() {
+    return new MqttHandler("mainHandlerA");
+  }
+
+  @Override
+  protected void createSpecificMainHandlerConnections() {
+    mainHandler.newConnection(TOPIC_DEMO_MOVE_objectRed1_BLUE, bytes ->
+        OldUtilA.updatePositionOfObjectToLocation(model.getWorldModelA().getScene(), "objectRed1", "binBlue")
+    );
+    mainHandler.newConnection(TOPIC_DEMO_MOVE_objectRed1_RED, bytes ->
+        OldUtilA.updatePositionOfObjectToLocation(model.getWorldModelA().getScene(), "objectRed1", "binRed")
+    );
+    mainHandler.newConnection(TOPIC_EVAL_MOVE, bytes -> {
+        String[] tokens = new String(bytes).split(" to ");
+        String objectName = tokens[0];
+        String locationName = tokens[1];
+        OldUtilA.updatePositionOfObjectToLocation(model.getWorldModelA().getScene(), objectName, locationName);
+    });
+  }
+
+  @Override
+  protected ArtificialRoot createWorldModel() throws Exception {
+    de.tudresden.inf.st.ceti.Scene scene = readScene(
+        OldUtilA.pathToDirectoryOfPlaceA().resolve(config.forA.filenameInitialScene)
+    );
+    Scene myScene = OldUtilA.convert(scene);
+    WorldModelA worldModel = new WorldModelA().setScene(myScene);
+    return new ArtificialRoot().setWorldModelA(worldModel);
+  }
+
+  @Override
+  protected void readInitialConfigs() throws IOException {
+    // read and set regions
+    File regionFile = OldUtilA.pathToDirectoryOfPlaceA().resolve(config.filenameRegions).toFile();
+    OldUtilA.setRegions(model.getWorldModelA(), Util.parseRegionConfig(regionFile));
+
+    // no robots to be set
+  }
+
+  @Override
+  protected void connectEndpoints() throws IOException {
+//    model.connectScene(mqttUri(TOPIC_SCENE_UPDATE_FROM_ROS, config));
+    model.getWorldModelA().connectLogicalSceneAsNtaToken(mqttUri(TOPIC_SCENE_UPDATE_TO_PLACE_B, config), true);
+  }
+
+  @Override
+  protected String getModelInfos(ArtificialRoot artificialRoot, boolean detailed) {
+    return OldUtilA.getModelInfos(artificialRoot.getWorldModelA(), detailed);
+  }
+}
diff --git a/ros3rag.old.a/src/main/java/de/tudresden/inf/st/old/a/OldSimpleMainA.java b/ros3rag.old.a/src/main/java/de/tudresden/inf/st/old/a/OldSimpleMainA.java
new file mode 100644
index 0000000000000000000000000000000000000000..1641138d82b0d0c3ecfef967877eea3887b928d7
--- /dev/null
+++ b/ros3rag.old.a/src/main/java/de/tudresden/inf/st/old/a/OldSimpleMainA.java
@@ -0,0 +1,138 @@
+package de.tudresden.inf.st.old.a;
+
+import de.tudresden.inf.st.old.a.ast.*;
+import org.apache.commons.math3.geometry.euclidean.threed.Rotation;
+import org.apache.commons.math3.geometry.euclidean.threed.Vector3D;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
+import java.util.Scanner;
+import java.util.concurrent.TimeUnit;
+
+import static de.tudresden.inf.st.ros3rag.common.Util.readScene;
+
+/**
+ * Testing features for placeA.
+ *
+ * @author rschoene - Initial contribution
+ */
+public class OldSimpleMainA {
+  private static final Logger logger = LogManager.getLogger(OldSimpleMainA.class);
+
+  @SuppressWarnings("CommentedOutCode")
+  public static void main(String[] args) throws Exception {
+//    testLocatedAt();
+//    testBuildModelA();
+    testReadSceneConfig();
+  }
+
+  @SuppressWarnings("CommentedOutCode")
+  private static void testReadSceneConfig() throws Exception {
+    final var path = OldUtilA.pathToDirectoryOfPlaceA().resolve("src/main/resources/config-scene-a.json");
+    de.tudresden.inf.st.ceti.Scene scene = readScene(path);
+    Scene myScene = OldUtilA.convert(scene);
+
+    ArtificialRoot root = new ArtificialRoot();
+
+    WorldModelA model = new WorldModelA();
+    model.setScene(myScene);
+    root.setWorldModelA(model);
+
+    // send initial scene once
+//    MqttHandler publisher = new MqttHandler().dontSendWelcomeMessage().setHost("localhost");
+//    publisher.publish("scene/init", scene.toByteArray());
+    logger.fatal("Skipping publishing to scene/init for now");
+
+    root.ragconnectCheckIncremental();
+    root.ragconnectSetupMqttWaitUntilReady(2, TimeUnit.SECONDS);
+
+//    model.connectScene("mqtt://localhost/scene/update");
+    model.connectLogicalSceneAsNtaToken("mqtt://localhost/logical/scene/update", true);
+  }
+
+  @SuppressWarnings("unused")
+  private static void testBuildModelA() {
+    WorldModelA model = new WorldModelA();
+
+    // scene
+    var scene = new Scene();
+    model.setScene(scene);
+    scene.addMovableObject(MovableObject.of("obj1", Position.of(1, 2, 3)));
+    scene.addDropOffLocation(DropOffLocation.of("placeAlfa",
+        Position.of(0, 0, 0),
+        Orientation.of(0, 0, 0, 1),
+        Size.of(1, 1, 1)));
+    scene.addDropOffLocation(DropOffLocation.of("placeBeta",
+        Position.of(1, 1, 1),
+        Orientation.of(0, 0, 0, 1),
+        Size.of(1, 1, 1)));
+    scene.addDropOffLocation(DropOffLocation.of("placeGamma",
+        Position.of(2, 2, 2),
+        Orientation.of(0, 0, 0, 1),
+        Size.of(2, 2, 2)));
+    logger.info("obj1 at gamma: {}",
+        scene.getMovableObject(0).isLocatedAt(scene.getDropOffLocation(2)));
+
+    // check logical scene
+    var logicalScene = scene.getLogicalScene();
+    logger.info("logicalScene:\n{}", logicalScene.prettyPrint());
+  }
+
+  @SuppressWarnings("unused")
+  private static void testLocatedAt() {
+    Rotation r = new Rotation(0, 0, 1, 0, false);
+    Vector3D v = new Vector3D(1, 2, 3);
+    r.applyTo(v);
+
+    var modelA = new WorldModelA();
+    var sceneA = new Scene();
+    modelA.setScene(sceneA);
+
+    // rotate bin2 by 90°, so width and height should effectively be swapped afterwards
+    Vector3D start = new Vector3D(1, 0, 0);
+    Vector3D end = new Vector3D(0, 0, 1);
+    Rotation rot = new Rotation(start, end);
+
+    DropOffLocation bin1 = DropOffLocation.of("Bin1",
+        Position.of(1, 1, 1),
+        Orientation.of(0, 0, 0, 1),
+        Size.of(2, 3, 4));
+    DropOffLocation bin2 = DropOffLocation.of("Bin2",
+        Position.of(1, 1, 1),
+        Orientation.of((float) rot.getQ1(), (float) rot.getQ2(), (float) rot.getQ3(), (float) rot.getQ0()),
+        Size.of(2, 3, 4));
+    MovableObject objectA = MovableObject.of("ObjectA",
+        Position.of(0, 0, 0));
+    MovableObject objectB = MovableObject.of("ObjectB",
+        Position.of(1, 1, 1));
+    sceneA.addDropOffLocation(bin1)
+        .addMovableObject(objectA)
+        .addMovableObject(objectB);
+
+    /*
+     0.0 <= x <= 2.0
+    -0.5 <= y <= 2.5
+    -1.0 <= z <= 3.0
+     */
+
+    logger.info("ObjectA locatedAt Bin1: {}", objectA.isLocatedAt(bin1));
+    logger.info("ObjectB locatedAt Bin1: {}", objectB.isLocatedAt(bin1));
+    logger.info("ObjectA locatedAt Bin2: {}", objectA.isLocatedAt(bin2));
+    logger.info("ObjectB locatedAt Bin2: {}", objectB.isLocatedAt(bin2));
+    Scanner scanner = new Scanner(System.in);
+    while (true) {
+      try {
+        System.out.print("x: ");
+        float x = scanner.nextFloat();
+        System.out.print("y: ");
+        float y = scanner.nextFloat();
+        System.out.print("z: ");
+        float z = scanner.nextFloat();
+        MovableObject object = MovableObject.of("temp", Position.of(x, y, z));
+        System.out.println("located at Bin2? : " + object.isLocatedAt(bin2));
+      } catch (Exception e) {
+        break;
+      }
+    }
+  }
+}
diff --git a/ros3rag.old.a/src/main/java/de/tudresden/inf/st/old/a/OldUtilA.java b/ros3rag.old.a/src/main/java/de/tudresden/inf/st/old/a/OldUtilA.java
new file mode 100644
index 0000000000000000000000000000000000000000..1da9db4beb5104e3f9178a72e61349f293dedb5b
--- /dev/null
+++ b/ros3rag.old.a/src/main/java/de/tudresden/inf/st/old/a/OldUtilA.java
@@ -0,0 +1,84 @@
+package de.tudresden.inf.st.old.a;
+
+import de.tudresden.inf.st.old.a.ast.*;
+import de.tudresden.inf.st.ros3rag.common.RegionConfiguration;
+import de.tudresden.inf.st.ros3rag.common.RegionConfiguration.RegionDefinition;
+import de.tudresden.inf.st.ros3rag.common.Util;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
+import java.nio.file.Path;
+
+/**
+ * Static utility methods used only for place A.
+ *
+ * @author rschoene - Initial contribution
+ */
+public class OldUtilA {
+  private static final Logger logger = LogManager.getLogger(OldUtilA.class);
+
+  static Path pathToDirectoryOfPlaceA() {
+    return Util.pathToModuleDirectory("ros3rag.old.a");
+  }
+
+  static Scene convert(de.tudresden.inf.st.ceti.Scene scene) throws Exception {
+    return new ExposingASTNode().exposed_apply_ConvertScene(scene);
+  }
+
+  static void setRegions(WorldModelA model, RegionConfiguration config) {
+    JastAddList<Region> result = new JastAddList<>();
+    for (RegionDefinition def : config.regions) {
+      Region region = new Region();
+      region.setName(def.name);
+      region.setLocationNames(String.join(",", def.positions));
+      result.add(region);
+    }
+    model.setRegionList(result);
+  }
+
+  static void updatePositionOfObjectToLocation(Scene scene, String objName, String locationName) {
+    ObjectOfInterest obj = scene.resolveObjectOfInterest(objName);
+    ObjectOfInterest location = scene.resolveObjectOfInterest(locationName);
+    if (obj != null && location != null) {
+      // move objectRed1 to binBlue
+      logger.info("Got " + obj + " and location " + location);
+      logger.debug("before to {} at {}\n{}", locationName, location.getPosition(),
+          scene.prettyPrint());
+
+      obj.setPosition(Position.of(location.getPosition().getX(),
+          location.getPosition().getY(),
+          location.getPosition().getZ()));
+
+      logger.debug("after\n{}", scene.prettyPrint());
+    } else {
+      logger.error("Obj (" + obj + ") or location (" + location + ") are null");
+    }
+  }
+
+  public static String getModelInfos(WorldModelA model, boolean detailed) {
+    StringBuilder sb = new StringBuilder();
+    if (detailed) {
+      // also include "normal" scene
+      sb.append("myScene:");
+      if (model.hasScene()) {
+        sb.append("\n").append(model.getScene().prettyPrint());
+      } else {
+        sb.append(" (unset)\n");
+      }
+    }
+    sb.append("myLogicalScene:");
+    if (model.hasScene()) {
+      sb.append("\n").append(model.getScene().getLogicalScene().prettyPrint());
+    } else {
+      sb.append(" (unset)\n");
+    }
+    return sb.toString();
+  }
+
+  @SuppressWarnings("rawtypes")
+  static class ExposingASTNode extends ASTNode {
+    public Scene exposed_apply_ConvertScene(de.tudresden.inf.st.ceti.Scene pbScene) throws Exception {
+      return _apply_ConvertScene(pbScene);
+    }
+  }
+}
diff --git a/ros3rag.old.a/src/main/resources b/ros3rag.old.a/src/main/resources
new file mode 120000
index 0000000000000000000000000000000000000000..8fd64e88271c6953242ad5f5ff2666ff332882ce
--- /dev/null
+++ b/ros3rag.old.a/src/main/resources
@@ -0,0 +1 @@
+../../../ros3rag.placeA/src/main/resources
\ No newline at end of file
diff --git a/ros3rag.old.b/.gitignore b/ros3rag.old.b/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..3447a4e17f56acc57a97d96cfec3bd43d90a05d9
--- /dev/null
+++ b/ros3rag.old.b/.gitignore
@@ -0,0 +1,6 @@
+build
+src/gen-res/
+src/gen/
+out/
+*.class
+images/
diff --git a/ros3rag.old.b/build.gradle b/ros3rag.old.b/build.gradle
new file mode 100644
index 0000000000000000000000000000000000000000..516dbc7c7a4883a17d7a2bd3ca62afa4f97e1e59
--- /dev/null
+++ b/ros3rag.old.b/build.gradle
@@ -0,0 +1,36 @@
+buildscript {
+    repositories.mavenLocal()
+    repositories.mavenCentral()
+    dependencies {
+        classpath group: 'org.jastadd', name: 'jastaddgradle', version: "${jastadd_gradle_version}"
+    }
+}
+
+plugins {
+    id 'ros3rag.java-application-conventions'
+    id 'ros3rag.java-old-ragconnect-conventions'
+}
+
+mainClassName = 'de.tudresden.inf.st.old.b.OldMainB'
+
+task simpleRun(type: JavaExec) {
+    group 'application'
+    classpath sourceSets.main.runtimeClasspath
+    main = "de.tudresden.inf.st.old.b.OldSimpleMainB"
+    standardInput = System.in
+}
+
+dependencies {
+    implementation project(':ros3rag.common')
+    testImplementation group: 'org.junit.jupiter', name: 'junit-jupiter-params', version: "${jupiter_version}"
+}
+
+ext.sharedJastAddDir = 'src/main/jastadd/old-shared'
+ext.ragConnectInputGrammar = 'src/main/jastadd/OldWorldModelB.relast'
+ext.ragConnectInputConnect = 'src/main/jastadd/OldWorldModelB.connect'
+ext.ragConnectRootNode = 'ArtificialRoot'
+ext.relastFiles = ["src/gen/jastadd/merged.relast", "src/main/jastadd/BFS/BFS.relast", "src/main/jastadd/OldRobotReachabilityToBFS.relast", "src/gen/jastadd/RagConnect.relast"]
+ext.jastaddAstPackage = 'de.tudresden.inf.st.old.b.ast'
+ext.useOldRagConnect = true
+
+apply from: '../ros3rag.common/src/main/resources/tasks.gradle'
diff --git a/ros3rag.old.b/src/main/jastadd/Additional.jadd b/ros3rag.old.b/src/main/jastadd/Additional.jadd
new file mode 100644
index 0000000000000000000000000000000000000000..a8d2e113e9c1632a841cbc836520336a99bd6312
--- /dev/null
+++ b/ros3rag.old.b/src/main/jastadd/Additional.jadd
@@ -0,0 +1,44 @@
+aspect NewComputationNeededForOldRagConnect {
+  syn nta Opt<Scene> WorldModelB.getMySceneOpt() {
+    if (getMySceneAsProtobuf() == null) {
+      return new Opt<Scene>();
+    } else {
+        try {
+          return new Opt<Scene>(ASTNode._apply_ConvertScene(getMySceneAsProtobuf()));
+        } catch (Exception e) {
+          e.printStackTrace();
+          return new Opt<Scene>();
+        }
+    }
+  }
+
+  syn nta JastAddList<LogicalScene> WorldModelB.getOtherSceneList() {
+    if (getOtherSceneAsJson().equals("")) {
+      return new JastAddList<LogicalScene>();
+    } else {
+      try {
+        com.fasterxml.jackson.databind.ObjectMapper mapper = new com.fasterxml.jackson.databind.ObjectMapper();
+        com.fasterxml.jackson.core.JsonFactory factory = new com.fasterxml.jackson.core.JsonFactory();
+        com.fasterxml.jackson.core.JsonParser parser = factory.createParser(getOtherSceneAsJson());
+        LogicalScene logicalScene = LogicalScene.deserialize((com.fasterxml.jackson.databind.JsonNode)mapper.readTree(parser));
+        parser.close();
+        return new JastAddList<LogicalScene>().addChild(logicalScene);
+      } catch (IOException | DeserializationException e) {
+        e.printStackTrace();
+        return new JastAddList<LogicalScene>();
+      }
+    }
+  }
+
+  syn de.tudresden.inf.st.ceti.Command WorldModelB.getNextOperationAsNtaToken() {
+    return getNextOperation().toCommand();
+  }
+
+  refine JsonToModel public static WorldModelB WorldModelB.deserialize(com.fasterxml.jackson.databind.JsonNode node) throws DeserializationException {
+    throw new DeserializationException("Unable to deserialize child node of type \"WorldModelB\"");
+  }
+
+  refine ModelToJson public void WorldModelB.serialize(com.fasterxml.jackson.core.JsonGenerator g, String fieldName) throws SerializationException {
+    throw new SerializationException("unable to serialize WorldModelB");
+  }
+}
diff --git a/ros3rag.old.b/src/main/jastadd/BFS/BFS.jrag b/ros3rag.old.b/src/main/jastadd/BFS/BFS.jrag
new file mode 100644
index 0000000000000000000000000000000000000000..9112eee1dbe640ba6773d56627a8b1d63842dcf0
--- /dev/null
+++ b/ros3rag.old.b/src/main/jastadd/BFS/BFS.jrag
@@ -0,0 +1,68 @@
+import java.util.*;
+
+aspect BFS {
+  //--- BFS ---
+  syn List<Edge> Vertex.BFS(Vertex goal) {
+    Map<Vertex, Edge> pred = new HashMap<>();
+    Queue<Vertex> Q = new LinkedList<>();
+    Set<Vertex> seen = new HashSet<>();
+    seen.add(this);
+    Q.add(this);
+    while (!Q.isEmpty()) {
+      Vertex v = Q.remove();
+      if (v.equals(goal)) {
+        return reconstructFrom(goal, pred);
+      }
+      for (Edge e : v.getOutgoingList()) {
+        Vertex w = e.getTo();
+        if (seen.contains(w)) {
+          continue;
+        }
+        seen.add(w);
+        pred.put(w, e);
+        Q.add(w);
+      }
+      for (Edge e : v.getIncomingList()) {
+        if (!e.getBidirectional()) { continue; }
+        Vertex w = e.getFrom();
+        if (seen.contains(w)) {
+          continue;
+        }
+        seen.add(w);
+        pred.put(w, e);
+        Q.add(w);
+      }
+    }
+    // failure
+    return null;
+  }
+
+  //--- reconstructFrom ---
+  private List<Edge> Vertex.reconstructFrom(Vertex goal, Map<Vertex, Edge> pred) {
+    // used at the end of BFS to back-track path from goal to start
+    List<Edge> result = new ArrayList<>();
+    Vertex current = goal;
+    while (!current.equals(this)) {
+      Edge e = pred.get(current);
+      result.add(e);
+      current = e.getFrom().equals(current) ? e.getTo() : e.getFrom();
+    }
+//    result.add(this);
+    Collections.reverse(result);
+    return result;
+  }
+
+  //--- prettyPrint ---
+  public String Graph.prettyPrint() {
+    StringJoiner sj = new StringJoiner(", ", "Graph {\n", "\n}");
+    if (!hasVertex()) { sj.add("<no vertices>"); }
+    for (Vertex v : getVertexList()) { sj.add(v.toString()); }
+    sj.add("\n");
+    if (!hasEdge()) { sj.add("<no edges>"); }
+    for (Edge e : getEdgeList()) { sj.add(e.prettyPrint()); }
+    return sj.toString();
+  }
+  public String Edge.prettyPrint() {
+    return this.toString() + " : " + getFrom() + (getBidirectional() ? " <-> " : " -> ") + getTo();
+  }
+}
diff --git a/ros3rag.old.b/src/main/jastadd/BFS/BFS.relast b/ros3rag.old.b/src/main/jastadd/BFS/BFS.relast
new file mode 100644
index 0000000000000000000000000000000000000000..c3931ad536b40be9d04dfe733a542e8f56360c37
--- /dev/null
+++ b/ros3rag.old.b/src/main/jastadd/BFS/BFS.relast
@@ -0,0 +1,5 @@
+Graph ::= Vertex* Edge* ;
+Vertex ;
+Edge ::= <Bidirectional:boolean> ;
+rel Edge.From <-> Vertex.Outgoing* ;
+rel Edge.To <-> Vertex.Incoming* ;
diff --git a/ros3rag.old.b/src/main/jastadd/OldRobotReachabilityToBFS.jrag b/ros3rag.old.b/src/main/jastadd/OldRobotReachabilityToBFS.jrag
new file mode 100644
index 0000000000000000000000000000000000000000..5ec92e5420a08745c4b8807fdab063cc073fea7c
--- /dev/null
+++ b/ros3rag.old.b/src/main/jastadd/OldRobotReachabilityToBFS.jrag
@@ -0,0 +1,91 @@
+aspect RobotReachabilityToBFS {
+  //--- toReachabilityGraph ---
+  syn nta Graph WorldModelB.toReachabilityGraph() {
+    Graph result = new Graph();
+    if (!hasMyScene()) {
+      return result;
+    }
+    Map<ObjectOfInterest, Vertex> mapping = new HashMap<>();
+    // TODO insert vertices for objects, if they are contained in a location. or remove objects altogether?
+    for (DropOffLocation loc : getMyScene().getDropOffLocationList()) {
+      VertexWithObjectOfInterest vertex = new VertexWithObjectOfInterest();
+      vertex.setNameOfObjectOfInterest(loc.getName());
+      result.addVertex(vertex);
+      mapping.put(loc, vertex);
+    }
+//    for (LogicalMovableObject obj : getMyScene().getLogicalScene().getLogicalMovableObjectList()) {
+//      Vertex vertex = new Vertex();
+//      vertex.setObjectOfInterest(obj);
+//      result.addVertex(vertex);
+//      mapping.put(obj, vertex);
+//    }
+    for (Robot robot : getRobotList()) {
+      if (robot.isBusy()) {
+        continue;
+      }
+      List<DropOffLocation> reachableLocations = robot.reachableObjects().stream()
+          .filter(Objects::nonNull)
+          .filter(ObjectOfInterest::isDropOffLocation)
+          .map(ObjectOfInterest::asDropOffLocation)
+          .collect(java.util.stream.Collectors.toList());
+      // bidirectional edges between locations by default
+      // unidirectional edges from all occupied locations to free locations
+      // no edge if both locations are occupied
+      for (DropOffLocation loc : reachableLocations) {
+        for (DropOffLocation other : reachableLocations) {
+          if (loc == other) { continue; }
+          if (loc.getObjectLocatedHere() != null && other.getObjectLocatedHere() != null) { continue; }
+          EdgeWithRobot edge = new EdgeWithRobot();
+          edge.setNameOfRobot(robot.getName());
+          edge.setBidirectional(loc.getObjectLocatedHere() == null);
+          edge.setFrom(mapping.get(loc));
+          edge.setTo(mapping.get(other));
+          result.addEdge(edge);
+        }
+      }
+    }
+    return result;
+  }
+
+  //--- correspondingVertex ---
+  syn Optional<Vertex> LogicalObjectOfInterest.correspondingVertex() = worldModelB().correspondingVertex(this.getName());
+  syn Optional<Vertex> ObjectOfInterest.correspondingVertex() = worldModelB().correspondingVertex(this.getName());
+  syn Optional<Vertex> WorldModelB.correspondingVertex(String name) {
+    if (!hasMyScene()) {
+      return Optional.empty();
+    }
+    for (Vertex v : toReachabilityGraph().getVertexList()) {
+      if (v.isVertexWithObjectOfInterest() && v.asVertexWithObjectOfInterest().getNameOfObjectOfInterest().equals(name)) {
+        return Optional.of(v);
+      }
+    }
+    return Optional.empty();
+  }
+}
+
+aspect Printing {
+  public String VertexWithObjectOfInterest.toString() {
+    return "V(" + getNameOfObjectOfInterest() + ")";
+  }
+  public String EdgeWithRobot.toString() {
+    return "E[" + getNameOfRobot() + "]";
+  }
+}
+
+aspect Navigation {
+  // --- isVertexWithObjectOfInterest ---
+  syn boolean Vertex.isVertexWithObjectOfInterest() = false;
+  eq VertexWithObjectOfInterest.isVertexWithObjectOfInterest() = true;
+
+  // --- asVertexWithObjectOfInterest ---
+  syn VertexWithObjectOfInterest Vertex.asVertexWithObjectOfInterest() = null;
+  eq VertexWithObjectOfInterest.asVertexWithObjectOfInterest() = this;
+
+  // --- isEdgeWithRobot ---
+  syn boolean Edge.isEdgeWithRobot() = false;
+  eq EdgeWithRobot.isEdgeWithRobot() = true;
+
+  // --- asEdgeWithRobot ---
+  syn EdgeWithRobot Edge.asEdgeWithRobot() = null;
+  eq EdgeWithRobot.asEdgeWithRobot() = this;
+}
diff --git a/ros3rag.old.b/src/main/jastadd/OldRobotReachabilityToBFS.relast b/ros3rag.old.b/src/main/jastadd/OldRobotReachabilityToBFS.relast
new file mode 100644
index 0000000000000000000000000000000000000000..96a4b0cdda9cfda9d2e79037853f6e537a510126
--- /dev/null
+++ b/ros3rag.old.b/src/main/jastadd/OldRobotReachabilityToBFS.relast
@@ -0,0 +1,4 @@
+//rel Vertex.ObjectOfInterest -> ObjectOfInterest ;
+VertexWithObjectOfInterest : Vertex ::= <NameOfObjectOfInterest> ;
+//rel Edge.Robot -> Robot ;
+EdgeWithRobot : Edge ::= <NameOfRobot> ;
diff --git a/ros3rag.old.b/src/main/jastadd/OldWorldModelB.connect b/ros3rag.old.b/src/main/jastadd/OldWorldModelB.connect
new file mode 100644
index 0000000000000000000000000000000000000000..165fa1a5d2a1ec717882bf8d3d0c7977a5d58f56
--- /dev/null
+++ b/ros3rag.old.b/src/main/jastadd/OldWorldModelB.connect
@@ -0,0 +1,189 @@
+// --- receiving ---
+receive WorldModelB.MySceneAsProtobuf using ParseScene ;
+receive WorldModelB.OtherSceneAsJson ;
+//ONLY-IN-NEW receive Robot.CanReachObjectOfInterest using ParseReachability, ConvertReachability ;
+receive Robot.OwnedCollaborationZoneNames using ConfigChangeCommandCheckForOwnedCollaborationZone ;
+receive Robot.OccupiedCollaborationZoneNames using CommandCheckForOccupiedCollaborationZone ;
+receive Robot.CurrentPosition ;
+//ONLY-IN-NEW receive indexed with add WorldModelB.ExecutedOperation using ParseCommand, ConvertCommand ;
+
+ParseReachability maps byte[] bytes to de.tudresden.inf.st.ceti.Reachability {:
+  return de.tudresden.inf.st.ceti.Reachability.parseFrom(bytes);
+:}
+
+ConvertReachability maps de.tudresden.inf.st.ceti.Reachability r to JastAddList<CanReachObjectOfInterest> {:
+  var result = new JastAddList<CanReachObjectOfInterest>();
+  for (var objReach : r.getObjectsList()) {
+    if (objReach.getReachable()) {
+      result.addChild(new CanReachObjectOfInterest().setObjectName(objReach.getIdObject()));
+    }
+  }
+  return result;
+:}
+
+ParseCommand maps byte[] bytes to de.tudresden.inf.st.ceti.Command {:
+  return de.tudresden.inf.st.ceti.Command.parseFrom(bytes);
+:}
+
+ConvertCommand maps de.tudresden.inf.st.ceti.Command command to Operation {:
+  WorldModelB model = singletonWorldModelB;
+  if (command.hasPickAndPlace()) {
+    return new PickAndPlace()
+      .setObjectToPick(model.getMyScene().getLogicalScene().resolveLogicalObjectOfInterest(command.getPickAndPlace().getIdPick()).asLogicalMovableObject())
+      .setTargetLocation(model.getMyScene().resolveObjectOfInterest(command.getPickAndPlace().getIdPlace()).asDropOffLocation())
+    .setRobotToExecute(model.findRobot(command.getPickAndPlace().getIdRobot()).get());
+  } else if (command.hasConfigChange()) {
+    return new ConfigChange()
+      .setCollaborationZone(model.getMyScene().resolveObjectOfInterest(command.getConfigChange().getIdCollaborationZone()).asDropOffLocation().asCollaborationZone())
+      .setRobotToExecute(model.findRobot(command.getConfigChange().getIdRobotNewOwner()).get());
+  } else if (command.hasEvacuate()) {
+    return new Evacuate()
+      .setCollaborationZone(model.getMyScene().resolveObjectOfInterest(command.getEvacuate().getIdCollaborationZone()).asDropOffLocation().asCollaborationZone())
+      .setRobotToExecute(model.findRobot(command.getEvacuate().getIdRobot()).get());
+  }
+  return new ErrorOperation().setErrorMessage("Could not parse operation " + command);
+:}
+
+// --- sending ---
+send WorldModelB.NextOperationAsNtaToken using PrintCommand ;
+// (direct manipulation is dangerous) send WorldModelB.NextOperation using PrintAndRememberOperation ;
+send Robot.MyPosition ;
+// (direct manipulation is dangerous) send Robot.myPosition(String) using ImmediateUpdate ;
+
+PrintCommand maps de.tudresden.inf.st.ceti.Command cmd to byte[] {:
+  if (cmd == null) {
+    // here we accept, that cmd can be null (it will print an exception in the log, but no message will be sent)
+    reject();
+  }
+  return cmd.toByteArray();
+:}
+
+// (direct manipulation is dangerous)
+//PrintAndRememberOperation maps Operation op to byte[] {:
+//  byte[] result = op.toProtobufByteArray();
+//  if (result == null) {
+//    reject();
+//  }
+//  ((WorldModelB) this).addExecutedOperation(op);
+//  return result;
+//:}
+//
+// (direct manipulation is dangerous)
+//ImmediateUpdate maps String pos to String {:
+//  Robot robot = (Robot) this;
+//  robot.setCurrentPosition(pos);
+//  return pos;
+//:}
+
+ConfigChangeCommandCheckForOwnedCollaborationZone maps byte[] bytes to String {:
+  de.tudresden.inf.st.ceti.Command command = null;
+  try {
+    command = de.tudresden.inf.st.ceti.Command.parseFrom(bytes);
+  } catch (com.google.protobuf.InvalidProtocolBufferException e) {
+    reject();
+  }
+  // if the command is not a ConfigChange command, do not change anything
+  if (!command.hasConfigChange()) {
+    reject();
+  }
+//  System.out.println(command);
+  de.tudresden.inf.st.ceti.ConfigChange cc = command.getConfigChange();
+  Scene scene = singletonWorldModelB.getMyScene();
+  ObjectOfInterest obj = scene.resolveObjectOfInterest(cc.getIdCollaborationZone());
+  DropOffLocation loc = obj.asDropOffLocation();
+  CollaborationZone cz = loc.asCollaborationZone();
+  Robot thisRobot = hackTemporaryRobot;
+  List<String> collaborationZoneNames = thisRobot.ownedCollaborationZonesAsList();
+  boolean robotIsNewOwner = thisRobot.getName().equals(cc.getIdRobotNewOwner());
+  boolean collaborationZoneAlreadyOwned = collaborationZoneNames.contains(cc.getIdCollaborationZone());
+  if (robotIsNewOwner && !collaborationZoneAlreadyOwned) {
+    // config change is for this robot, add collaboration zone
+    collaborationZoneNames.add(cc.getIdCollaborationZone());
+  } else if (!robotIsNewOwner && collaborationZoneAlreadyOwned) {
+    // config change is for another robot, remove collaboration zone
+    collaborationZoneNames.remove(cc.getIdCollaborationZone());
+  } else {
+    // otherwise don't change
+    reject();
+  }
+  return String.join(",", collaborationZoneNames);
+:}
+
+CommandCheckForOccupiedCollaborationZone maps byte[] bytes to String {:
+  de.tudresden.inf.st.ceti.Command command = null;
+  try {
+    command = de.tudresden.inf.st.ceti.Command.parseFrom(bytes);
+  } catch (com.google.protobuf.InvalidProtocolBufferException e) {
+    reject();
+  }
+  // if the command is not the correct command type, do not change anything
+  if (!command.hasPickAndPlace() && !command.hasEvacuate()) {
+    reject();
+  }
+//  System.out.println(command);
+
+  Scene scene = singletonWorldModelB.getMyScene();
+  Robot thisRobot = hackTemporaryRobot;
+
+//  // get current value, but remove every "moving out" zone
+//  List<String> occupiedZoneNames = thisRobot.occupiedCollaborationZonesAsList().stream()
+//    .filter(!zone -> zone.startsWith("(^)"))
+//    .collect(java.util.stream.Collectors.toList());
+
+  // with a new command, begin with a clean occ list
+  List<String> occupiedZoneNames = new java.util.ArrayList<>();
+
+  // (>) == moving in, (^) == evacuate/moving out
+  boolean updated = false;
+  if (command.hasPickAndPlace()) {
+    de.tudresden.inf.st.ceti.PickAndPlace pp = command.getPickAndPlace();
+
+    // if the command is not executed by this robot, do not change anything
+    if (!thisRobot.getName().equals(pp.getIdRobot())) {
+      reject();
+    }
+
+    // if target is collaboration zone
+    ObjectOfInterest obj = scene.resolveObjectOfInterest(pp.getIdPlace());
+    DropOffLocation loc = obj.asDropOffLocation();
+    if (loc.isCollaborationZone()) {
+      String specialIncomingName = "(>)" + loc.getName();
+      if (!occupiedZoneNames.contains(specialIncomingName)) {
+        occupiedZoneNames.add(specialIncomingName);
+        updated = true;
+      }
+    }
+    // if object is located at collaboration zone
+    LogicalObjectOfInterest logicalObj = scene.getLogicalScene().resolveLogicalObjectOfInterest(pp.getIdPick());
+    LogicalMovableObject toBePicked = logicalObj.asLogicalMovableObject();
+    DropOffLocation sourceLocation = toBePicked.myLocation();
+    if (sourceLocation != null && sourceLocation.isCollaborationZone()) {
+      String specialIncomingName = "(^)" + sourceLocation.getName();
+      if (!occupiedZoneNames.contains(specialIncomingName)) {
+        occupiedZoneNames.add(specialIncomingName);
+        updated = true;
+      }
+    }
+  } else if (command.hasEvacuate()) {
+    de.tudresden.inf.st.ceti.Evacuate ev = command.getEvacuate();
+
+    // if the command is not executed by this robot, do not change anything
+    if (!thisRobot.getName().equals(ev.getIdRobot())) {
+      reject();
+    }
+    ObjectOfInterest obj = scene.resolveObjectOfInterest(ev.getIdCollaborationZone());
+    DropOffLocation loc = obj.asDropOffLocation();
+    if (loc.isCollaborationZone()) {
+      CollaborationZone cz = loc.asCollaborationZone();
+      String specialEvacuateName = "(^)" + cz.getName();
+      if (!occupiedZoneNames.contains(specialEvacuateName)) {
+        occupiedZoneNames.add(specialEvacuateName);
+        updated = true;
+      }
+    }
+  }
+  if (!updated) {
+    reject();
+  }
+  return String.join(",", occupiedZoneNames);
+:}
diff --git a/ros3rag.old.b/src/main/jastadd/OldWorldModelB.jadd b/ros3rag.old.b/src/main/jastadd/OldWorldModelB.jadd
new file mode 100644
index 0000000000000000000000000000000000000000..fc133eb15804137beaed2b9a11749a4dc6507866
--- /dev/null
+++ b/ros3rag.old.b/src/main/jastadd/OldWorldModelB.jadd
@@ -0,0 +1,647 @@
+aspect Computation {
+  static boolean ASTNode.VERBOSE = false;
+
+  //--- unspecifiedRegion ---
+  syn nta LogicalRegion WorldModelB.unspecifiedRegion() = new LogicalRegion().setName("<unspecified>");
+
+  //--- mergedOtherScene ---
+  syn nta LogicalScene WorldModelB.mergedOtherScene() {
+    // return empty scene, if there are no other scenes (yet)
+    if (!hasOtherScene()) {
+      return new LogicalScene();
+    }
+    // return scene, if there is exactly one. (TODO: check if copy is needed here)
+    if (getNumOtherScene() == 1) {
+      return getOtherScene(0);
+    }
+    var result = new LogicalScene();
+    // use getOtherSceneList() and merge by name all regions, objects and relations into one new, unified scene
+    Map<String, LogicalRegion> mergedRegions = new HashMap<>();
+    Map<String, LogicalMovableObject> mergedObjects = new HashMap<>();
+    // first create all regions
+    for (LogicalScene scene : getOtherSceneList()) {
+      for (LogicalRegion region : scene.getLogicalRegionList()) {
+        if (!mergedRegions.containsKey(region.getName())) {
+          LogicalRegion copyOfRegion = new LogicalRegion();
+          copyOfRegion.setName(region.getName());
+          mergedRegions.put(region.getName(), copyOfRegion);
+          result.addLogicalRegion(copyOfRegion);
+        }
+      }
+    }
+    // then create all objects, and set LocatedAt relation (checking for possible conflicts)
+    for (LogicalScene scene : getOtherSceneList()) {
+      for (LogicalMovableObject obj : scene.getLogicalMovableObjectList()) {
+        if (mergedObjects.containsKey(obj.getName())) {
+          // object already known
+          LogicalMovableObject knownObj = mergedObjects.get(obj.getName());
+          for (LogicalRegion region : obj.getLocatedAtList()) {
+            LogicalRegion knownRegionOfObj = mergedRegions.get(region.getName());
+            if (!knownObj.getLocatedAtList().contains(knownRegionOfObj)) {
+              // obj has region that is not yet add to knownObj
+              knownObj.addLocatedAt(knownRegionOfObj);
+            }
+          }
+        } else {
+          // object not known, needs to be created
+          LogicalMovableObject newObj = new LogicalMovableObject();
+          newObj.setName(obj.getName());
+          for (LogicalRegion region : obj.getLocatedAtList()) {
+            newObj.addLocatedAt(mergedRegions.get(region.getName()));
+          }
+          mergedObjects.put(obj.getName(), newObj);
+          result.addLogicalMovableObject(newObj);
+        }
+      }
+    }
+    return result;
+  }
+
+  //--- diffScenes ---
+  syn nta JastAddList<Difference> WorldModelB.diffScenes() {
+    var result = new JastAddList<Difference>();
+    if (!hasMyScene() || !hasOtherScene()) {
+      // without my and at least one other scene, there are no differences
+      return result;
+    }
+    var myLogicalScene = getMyScene().getLogicalScene();
+    for (LogicalMovableObject otherObject : mergedOtherScene().getLogicalMovableObjectList()) {
+      LogicalObjectOfInterest myGenericObject = myLogicalScene.resolveLogicalObjectOfInterest(otherObject.getName());
+      if (myGenericObject == null) {
+        // new object, currently not handled
+        var diff = new DifferenceNewObject();
+        diff.setObject(otherObject);
+        result.add(diff);
+        continue;
+      }
+      if (!myGenericObject.isLogicalMovableObject()) {
+        if (VERBOSE) {
+          System.err.println("MovableObject " + otherObject.getName() + " is not a MovableObject in myScene. Skipping!");
+        }
+        continue;
+      }
+      LogicalMovableObject myObject = myGenericObject.asLogicalMovableObject();
+      if (myObject.hasLocatedAt() && !otherObject.hasLocatedAt()) {
+        if (myObject.getLocatedAtList().size() > 1) {
+          if (VERBOSE) {
+            System.err.println("More than one region found for my " + myObject.getName() + ", using only first.");
+          }
+        }
+        var diff = new DifferenceObjectMisplaced();
+        diff.setObject(myObject);
+        // use first region
+        diff.setPreviousRegion(myObject.getLocatedAtList().get(0));
+        result.add(diff);
+        continue;
+      }
+      if (myObject.getLocatedAtList().size() > 1) {
+        if (VERBOSE) {
+          System.err.println("More than one region found for my " + myObject.getName() + ", using only first.");
+        }
+      }
+      if (otherObject.getLocatedAtList().size() > 1) {
+        if (VERBOSE) {
+          System.err.println("More than one region found for other " + otherObject.getName() + ", using only first.");
+        }
+      }
+      Set<String> myRegions = myObject.regionNameSet();
+      Set<String> otherRegions = otherObject.regionNameSet();
+      if (!myObject.hasLocatedAt() && !otherObject.hasLocatedAt() ||
+          (myObject.hasLocatedAt() && otherObject.hasLocatedAt() &&
+              myRegions.equals(otherRegions))) {
+        // no diff if: otherObject has no region information, or if both objects are located at same region(s)
+        // otherObject is always non-null, so this case does not need to be treated
+        continue;
+      }
+      var difference = new DifferenceObjectAtWrongPlace();
+      difference.setObject(myObject);
+      if (myObject.hasLocatedAt()) {
+        difference.setPreviousRegion(myObject.getLocatedAtList().get(0));
+      }
+      difference.setNewRegion(otherObject.getLocatedAtList().get(0));
+      result.add(difference);
+    }
+    return result;
+  }
+
+  //--- diffToOperations ---
+  syn nta JastAddList<Operation> WorldModelB.diffToOperations() {
+    var result = new JastAddList<Operation>();
+    for (Difference difference : diffScenes()) {
+      for (Operation operation : difference.computeOperations()) {
+        result.add(operation);
+      }
+    }
+    return result;
+  }
+
+  //--- computeOperations ---
+  syn List<Operation> Difference.computeOperations();
+  eq DifferenceObjectAtWrongPlace.computeOperations() {
+    // need to use position of object and pick one from new region
+
+    DropOffLocation previousLocation = getObject().myLocation();
+    if (previousLocation == null) {
+      return error("No previous location");
+    }
+    // (workaround) check if WorldModelB is not null ... could happen if scene has no parent
+    try {
+      previousLocation.correspondingVertex();
+    } catch (NullPointerException e) {
+      return error("Could not resolve WorldModelB linked to previousLocation " + previousLocation.nameAndHash());
+    }
+    return previousLocation.correspondingVertex().map(previousVertex -> {
+      Region region = getNewRegion().realRegion();
+      if (region == null) {
+        return error("No region found for " + getNewRegion().nameAndHash());
+      }
+      // pick location from newRegion, that is free
+      return region.locationList().stream()
+          .filter(location -> location.getObjectLocatedHere() == null)
+          .findFirst()
+          .map(newLocation -> {
+            // (workaround) check if WorldModelB is not null ... could happen if scene has no parent
+            try {
+              newLocation.correspondingVertex();
+            } catch (NullPointerException e) {
+              return error("Could not resolve WorldModelB linked to newLocation " + newLocation.nameAndHash());
+            }
+            return newLocation.correspondingVertex().map(newVertex -> {
+              List<Edge> shortestPath = previousVertex.BFS(newVertex);
+              if (shortestPath == null || shortestPath.isEmpty()) {
+                return error("No sequence of operations to move " + getObject().getName() + (hasPreviousRegion() ? " from " + getPreviousRegion().getName() : "") + " to " + getNewRegion().getName());
+              }
+              List<Operation> result = new ArrayList<>();
+              Vertex transit = previousVertex;
+              for (Edge edge : shortestPath) {
+                Vertex target = edge.getFrom().equals(transit) ? edge.getTo() : edge.getFrom();
+                DropOffLocation sourceLocation = worldModelB().getMyScene().resolveObjectOfInterest(previousVertex.asVertexWithObjectOfInterest().getNameOfObjectOfInterest()).asDropOffLocation();
+                DropOffLocation targetLocation = worldModelB().getMyScene().resolveObjectOfInterest(target.asVertexWithObjectOfInterest().getNameOfObjectOfInterest()).asDropOffLocation();
+//                Robot executingRobot = worldModelB().findRobot(edge.asEdgeWithRobot().getNameOfRobot());
+                worldModelB().findRobot(edge.asEdgeWithRobot().getNameOfRobot()).ifPresentOrElse(executingRobot -> {
+                  /* for both locations, in case it is a collaboration zone, we need to ensure the following:
+                     (a) claimed by the executing robot, and
+                     (b) not occupied by another robot, and
+                     (c) free (as no movable object is contained) -- this should be reflected in the graph!
+                  */
+                  if (sourceLocation.isCollaborationZone()) {
+                    CollaborationZone cz = sourceLocation.asCollaborationZone();
+                    if (VERBOSE) {
+                      System.out.println("source is cz, occ:" + (cz.hasOccupient() ? cz.occupient().nameAndHash() : "none") + ", owner: " + (cz.hasOwner() ? cz.owner().nameAndHash() : "none"));
+                    }
+                    // order is important here, first add Evacuate, then ConfigChange
+                    if (cz.hasOccupient() && !cz.occupient().equals(executingRobot)) {
+                      if (cz.occupient().isBusy()) {
+                        result.add(Wait.of());
+                      } else {
+                        result.add(Evacuate.of(cz.occupient(), cz));
+                      }
+                    }
+                    if (!cz.hasOwner() || (cz.hasOwner() && !cz.owner().equals(executingRobot))) {
+                      if (cz.hasOccupient() && (!cz.occupient().equals(executingRobot) || cz.occupient().isBusy())) {
+                        result.add(Wait.of());
+                      } else {
+                        result.add(ConfigChange.of(executingRobot, cz));
+                      }
+                    }
+                  }
+                  if (targetLocation.isCollaborationZone()) {
+                    CollaborationZone cz = targetLocation.asCollaborationZone();
+                    if (VERBOSE) {
+                      System.out.println("target is cz, occ:" + (cz.hasOccupient() ? cz.occupient().nameAndHash() : "none") + ", owner: " + (cz.hasOwner() ? cz.owner().nameAndHash() : "none"));
+                    }
+                    // order is important here, first add Evacuate, then ConfigChange
+                    if (cz.hasOccupient() && !cz.occupient().equals(executingRobot)) {
+                      if (cz.occupient().isBusy()) {
+                        result.add(Wait.of());
+                      } else {
+                        result.add(Evacuate.of(cz.occupient(), cz));
+                      }
+                    }
+                    if (!cz.hasOwner() || (cz.hasOwner() && !cz.owner().equals(executingRobot))) {
+                      if (cz.hasOccupient() && (!cz.occupient().equals(executingRobot) || cz.occupient().isBusy())) {
+                        result.add(Wait.of());
+                      } else {
+                        result.add(ConfigChange.of(executingRobot, cz));
+                      }
+                    }
+                  }
+                  result.add(PickAndPlace.of(executingRobot, getObject(), targetLocation));
+                }, () -> result.add(new ErrorOperation().setErrorMessage("Could not find robot with name " + edge.asEdgeWithRobot().getNameOfRobot())));
+                transit = target;
+              }
+              return result;
+            }).orElseGet(() -> error("Could not resolve graph vertex of new region " + getNewRegion().nameAndHash()));
+          }).orElseGet(() -> error("Could not find a free location in " + getNewRegion().nameAndHash() + " for " + getObject().nameAndHash()));
+    }).orElseGet(() -> error("Could not resolve graph vertex of previous location " + previousLocation.nameAndHash()));
+  }
+  eq DifferenceNewObject.computeOperations() {
+    // FIXME. stub, may be implemented later
+    return Collections.emptyList();
+  }
+  eq DifferenceObjectMisplaced.computeOperations() {
+    // FIXME. stub, may be implemented later
+    return Collections.emptyList();
+  }
+
+  //--- error ---
+  protected static List<Operation> Difference.error(String message) {
+    return Collections.singletonList(new ErrorOperation().setErrorMessage(message));
+  }
+
+  //--- Operation.of ---
+  public static PickAndPlace PickAndPlace.of(Robot robot, LogicalMovableObject obj, DropOffLocation target) {
+    PickAndPlace result = new PickAndPlace();
+    result.setRobotToExecute(robot);
+    result.setObjectToPick(obj);
+    result.setTargetLocation(target);
+    return result;
+  }
+
+  public static ConfigChange ConfigChange.of(Robot robot, CollaborationZone cz) {
+    ConfigChange result = new ConfigChange();
+    result.setRobotToExecute(robot);
+    result.setCollaborationZone(cz);
+    return result;
+  }
+
+  public static Evacuate Evacuate.of(Robot robot, CollaborationZone cz) {
+    Evacuate result = new Evacuate();
+    result.setRobotToExecute(robot);
+    result.setCollaborationZone(cz);
+    return result;
+  }
+
+  public static Wait Wait.of() {
+    return new Wait();
+  }
+
+  syn Operation WorldModelB.lastOperationFor(Robot robot) {
+    if (robot == null) {
+      return null;
+    }
+    for (int index = getNumExecutedOperation() - 1; index >= 0; index--) {
+      Operation op = getExecutedOperation(index);
+      if (robot.equals(op.getRobotToExecute())) {
+        return op;
+      }
+    }
+    return null;
+  }
+
+  syn nta ErrorOperation WorldModelB.errorNoOperationComputed() = new ErrorOperation().setErrorMessage("No operation computed!");
+  syn nta ErrorOperation WorldModelB.errorDuplicateOperation() = new ErrorOperation().setErrorMessage("Do not send duplicate operation twice!");
+  syn nta ErrorOperation WorldModelB.errorNoExecutableOperation() = new ErrorOperation().setErrorMessage("No executable operation found!");
+  //--- getNextOperation ---
+  syn Operation WorldModelB.getNextOperation() {
+    if (diffToOperations().getNumChild() == 0) {
+      return errorNoOperationComputed();
+    }
+    for (Operation op : diffToOperations()) {
+      Robot executingRobot = op.getRobotToExecute();
+      if (!op.isErrorOperation()) {
+        if (op.equals(lastOperationFor(executingRobot))) {
+          return errorDuplicateOperation();
+        }
+        return op;
+      }
+    }
+    return errorNoExecutableOperation();
+  }
+
+//  //--- canReach --- | TODO not used
+//  syn boolean Robot.canReach(String objectName) {
+//    for (CanReachObjectOfInterest canReachObj : getCanReachObjectOfInterestList()) {
+//      if (canReachObj.getObjectName().equals(objectName)) {
+//        return true;
+//      }
+//    }
+//    return false;
+//  }
+
+  //--- reachableObjects ---
+  syn List<ObjectOfInterest> Robot.reachableObjects() {
+    if (!worldModelB().hasMyScene()) {
+      return Collections.emptyList();
+    }
+    List<ObjectOfInterest> result = new ArrayList<>();
+    for (CanReachObjectOfInterest canReachObj : getCanReachObjectOfInterestList()) {
+      result.add(worldModelB().getMyScene().resolveObjectOfInterest(canReachObj.getObjectName()));
+    }
+    return result;
+  }
+
+  syn DropOffLocation Region.firstFreeDropOffLocation() {
+    for (DropOffLocation location : locationList()) {
+      if (location.getObjectLocatedHere() == null) {
+        return location;
+      }
+    }
+    return null;
+  }
+
+  syn String Robot.getMyPosition() {
+    //TODO "(^)" "(>)"
+    RobotObject myRobotObject = myRobotObject();
+    de.tudresden.inf.st.ceti.Object.State myState = myRobotObject != null ? myRobotObject.getState() : de.tudresden.inf.st.ceti.Object.State.STATE_UNKNOWN;
+    String pre = "eval of my pos for " + getName() + " .. current-pos: " + getCurrentPosition() + ", occ: '" + getOccupiedCollaborationZoneNames() + "', state: " + (myRobotObject != null ? myRobotObject.getState() : "null") + " -> ";
+    for (String zoneName : arrayAsList(getOccupiedCollaborationZoneNames())) {
+      if (zoneName.startsWith("(>)")) {
+        String targetZone = zoneName.substring(3);
+        // (1)
+        String currentTarget = getCurrentPosition().startsWith("(") ? getCurrentPosition().substring(3) : getCurrentPosition();
+        if (!targetZone.equals(currentTarget) && myState == de.tudresden.inf.st.ceti.Object.State.STATE_IDLE) {
+          return logAndReturn(pre, "(+)" + targetZone);
+        }
+      }
+      // (2) // getCurrentPosition().startsWith("(+)") &&
+      if (isStateMoving(myState)) {
+        return logAndReturn(pre, zoneName);
+      }
+      // (3)
+      if (getCurrentPosition().startsWith("(>)") && myState == de.tudresden.inf.st.ceti.Object.State.STATE_IDLE) {
+        return logAndReturn(pre, getCurrentPosition().substring(3));
+      }
+      if (zoneName.startsWith("(^)")) {
+        String sourceZone = zoneName.substring(3);
+        // (4)
+        if (!getCurrentPosition().startsWith("(^)") && !getCurrentPosition().equals("safe") && myState == de.tudresden.inf.st.ceti.Object.State.STATE_IDLE) {
+          return logAndReturn(pre, "(-)" + sourceZone);
+        }
+        // (6)
+        if (getCurrentPosition().startsWith("(^)") && myState == de.tudresden.inf.st.ceti.Object.State.STATE_IDLE) {
+          return logAndReturn(pre, "safe");
+        }
+      }
+      // (5)
+      if (getCurrentPosition().startsWith("(-)") && isStateMoving(myState)) {
+        return logAndReturn(pre, "(^)" + getCurrentPosition().substring(3));
+      }
+    }
+    // no-op
+    return logAndReturn(pre, getCurrentPosition());
+  }
+
+  private String Robot.logAndReturn(String pre, String returnValue) {
+    if (VERBOSE) {
+      System.out.println(pre + returnValue);
+    }
+    return returnValue;
+  }
+
+  private boolean Robot.isStateMoving(de.tudresden.inf.st.ceti.Object.State state) {
+    return state == de.tudresden.inf.st.ceti.Object.State.STATE_MOVING || state == de.tudresden.inf.st.ceti.Object.State.STATE_PICKING || state == de.tudresden.inf.st.ceti.Object.State.STATE_PLACING;
+  }
+}
+
+aspect AttributeMappings {
+  //--- toCommand ---
+  syn de.tudresden.inf.st.ceti.Command Operation.toCommand() = null;
+  eq ErrorOperation.toCommand() {
+    if (VERBOSE) {
+      System.err.println(getErrorMessage());
+    }
+    return null;
+  }
+  eq PickAndPlace.toCommand() = de.tudresden.inf.st.ceti.Command.newBuilder()
+      .setPickAndPlace(de.tudresden.inf.st.ceti.PickAndPlace.newBuilder()
+          .setIdRobot(getRobotToExecute().getName())
+          .setIdPick(getObjectToPick().getName())
+          .setIdPlace(getTargetLocation().getName())
+          .build())
+      .build();
+  eq ConfigChange.toCommand() = de.tudresden.inf.st.ceti.Command.newBuilder()
+      .setConfigChange(de.tudresden.inf.st.ceti.ConfigChange.newBuilder()
+          .setIdRobotNewOwner(getRobotToExecute().getName())
+          .setIdCollaborationZone(getCollaborationZone().getName())
+          .build())
+      .build();
+  eq Evacuate.toCommand() = de.tudresden.inf.st.ceti.Command.newBuilder()
+      .setEvacuate(de.tudresden.inf.st.ceti.Evacuate.newBuilder()
+          .setIdRobot(getRobotToExecute().getName())
+          .setIdCollaborationZone(getCollaborationZone().getName())
+          .build())
+      .build();
+  eq Wait.toCommand() = null;
+}
+
+aspect Navigation {
+  // --- isCollaborationZone ---
+  syn boolean DropOffLocation.isCollaborationZone() = false;
+  eq CollaborationZone.isCollaborationZone() = true;
+
+  // --- asCollaborationZone ---
+  syn CollaborationZone DropOffLocation.asCollaborationZone() = null;
+  eq CollaborationZone.asCollaborationZone() = this;
+
+  //--- worldModelB ---
+  inh WorldModelB ASTNode.worldModelB();
+  eq WorldModelB.getChild().worldModelB() = this;
+
+  syn boolean Operation.isErrorOperation() = false;
+  eq ErrorOperation.isErrorOperation() = true;
+
+  syn boolean Operation.isPickAndPlace() = false;
+  eq PickAndPlace.isPickAndPlace() = true;
+
+  syn boolean Operation.isConfigChange() = false;
+  eq ConfigChange.isConfigChange() = true;
+
+  syn boolean Operation.isEvacuate() = false;
+  eq Evacuate.isEvacuate() = true;
+
+  syn ErrorOperation Operation.asErrorOperation() = null;
+  eq ErrorOperation.asErrorOperation() = this;
+
+  syn PickAndPlace Operation.asPickAndPlace() = null;
+  eq PickAndPlace.asPickAndPlace() = this;
+
+  syn ConfigChange Operation.asConfigChange() = null;
+  eq ConfigChange.asConfigChange() = this;
+
+  syn Evacuate Operation.asEvacuate() = null;
+  eq Evacuate.asEvacuate() = this;
+
+  syn Region LogicalRegion.realRegion() {
+    if (hasWorldModelB()) {
+      return worldModelB().findRegion(getName());
+    }
+    return new Region().setName("unknown region for " + getName());
+  }
+
+  private boolean LogicalRegion.hasWorldModelB() {
+    ASTNode parent = getParent();
+    while (parent.getParent() != null) {
+      parent = parent.getParent();
+    }
+    return parent instanceof WorldModelB;
+  }
+
+  //--- allMappings ---
+  //  inh LocationMapping LogicalDropOffLocation.allMappings();
+  //  eq WorldModelB.getChild().allMappings() = getLocationMapping();
+  syn boolean CollaborationZone.hasOccupient() = occupient() != null;
+  syn Robot CollaborationZone.occupient() {
+    // (>) == moving in, (^) == evacuate/moving out
+    for (Robot robot : worldModelB().getRobotList()) {
+      String zoneName = robot.getCurrentPosition().startsWith("(") ? robot.getCurrentPosition().substring(3) : robot.getCurrentPosition();
+      if (zoneName.equals(getName())) {
+        // robot is currently in this zone, or moving into or out of this zone. always regard it as occupied by it
+        return robot;
+      }
+    }
+    return null;
+  }
+  syn boolean CollaborationZone.hasOwner() = owner() != null;
+  syn Robot CollaborationZone.owner() {
+    for (Robot robot : worldModelB().getRobotList()) {
+      List<String> collaborationZoneNames = arrayAsList(robot.getOwnedCollaborationZoneNames());
+      if (collaborationZoneNames.contains(getName())) {
+        return robot;
+      }
+    }
+    return null;
+  }
+  syn List<String> Robot.ownedCollaborationZonesAsList() = arrayAsList(getOwnedCollaborationZoneNames());
+  syn List<String> Robot.occupiedCollaborationZonesAsList() = arrayAsList(getOccupiedCollaborationZoneNames());
+  eq Region.locationList() {
+    List<DropOffLocation> result = new ArrayList<>();
+    if (!worldModelB().hasMyScene()) {
+      return result;
+    }
+    for (String locationName : locationNamesAsList()) {
+      result.add(worldModelB().getMyScene().resolveObjectOfInterest(locationName).asDropOffLocation());
+    }
+    return result;
+  }
+
+  syn boolean Robot.isBusy() {
+    if (getCurrentPosition().startsWith("(")) {
+      return true;
+    }
+    RobotObject obj = myRobotObject();
+    return obj != null && obj.getState() != de.tudresden.inf.st.ceti.Object.State.STATE_IDLE;
+  }
+
+  syn RobotObject Robot.myRobotObject() {
+    ObjectOfInterest obj = worldModelB().getMyScene().resolveObjectOfInterest(getName());
+    return obj != null ? obj.asRobotObject() : null;
+  }
+}
+
+aspect GlueForShared {
+  //--- resolveLogicalObjectOfInterest ---
+  // uncache Difference.resolveLogicalObjectOfInterest
+  inh LogicalObjectOfInterest Difference.resolveLogicalObjectOfInterest(String name);
+  eq WorldModelB.diffScenes().resolveLogicalObjectOfInterest(String name) = getMyScene().getLogicalScene().resolveLogicalObjectOfInterest(name);
+
+  class ArtificialRoot implements de.tudresden.inf.st.ros3rag.common.SharedMainParts.WorldModelWrapper {
+  }
+
+  eq WorldModelB.getMyScene().regionList() = getRegionList();
+}
+
+aspect Printing {
+  //--- prettyPrint ---
+  syn String Robot.prettyPrint() = "~Robot " + nameAndHash() + "~";
+  syn String Robot.nameAndHash() = getName() + "@" + Integer.toHexString(hashCode());
+
+  syn String Difference.prettyPrint();
+  eq DifferenceObjectAtWrongPlace.prettyPrint() {
+    return "-DifferenceObjectAtWrongPlace of " + getObject().prettyPrint() + ": " + (hasPreviousRegion() ? getPreviousRegion().prettyPrint() : "_") + " -> " + getNewRegion().prettyPrint() + "-";
+  }
+  eq DifferenceNewObject.prettyPrint() {
+    return "-DifferenceNewObject of " + getObject().prettyPrint() + "-";
+  }
+  eq DifferenceObjectMisplaced.prettyPrint() {
+    return "-DifferenceObjectMisplaced of " + getObject().prettyPrint() + ": " + getPreviousRegion().prettyPrint() + "-";
+  }
+
+  syn String Operation.prettyPrint();
+  eq PickAndPlace.prettyPrint() {
+    return "+PickAndPlace by " + getRobotToExecute().prettyPrint() + " of " + getObjectToPick().prettyPrint() + " -> " + getTargetLocation().prettyPrint() + "+";
+  }
+  eq ErrorOperation.prettyPrint() {
+    return "+Error: " + getErrorMessage() + "+";
+  }
+  eq ConfigChange.prettyPrint() {
+    return "+ConfigChange: " + getRobotToExecute().prettyPrint() + " owns " + getCollaborationZone().prettyPrint() + "+";
+  }
+  eq Evacuate.prettyPrint() {
+    return "+Evacuate: " + getRobotToExecute().prettyPrint() + " from " + getCollaborationZone().prettyPrint() + "+";
+  }
+  eq Wait.prettyPrint() {
+    return "+Wait+";
+  }
+}
+
+aspect DumpAst {
+  public String WorldModelB.dumpAst(java.util.function.Consumer<de.tudresden.inf.st.jastadd.dumpAst.ast.DumpBuilder> options) {
+    String now = java.time.LocalDateTime.now().format(java.time.format.DateTimeFormatter.ISO_LOCAL_DATE_TIME).replaceAll("[:\\.]", "-");
+    try {
+      de.tudresden.inf.st.jastadd.dumpAst.ast.DumpBuilder builder = de.tudresden.inf.st.jastadd.dumpAst.ast.Dumper.read(this);
+      options.accept(builder);
+      //builder.dumpAsPNG(java.nio.file.Paths.get("images/" + now + ".png"));
+      java.nio.file.Path path = java.nio.file.Paths.get("images/" + now + ".svg");
+      builder.dumpAsSVG(path);
+      return path.getFileName().toString();
+    } catch (java.io.IOException e) {
+      e.printStackTrace();
+      return null;
+    }
+  }
+}
+
+aspect Comparison {
+  boolean Operation.equals(Operation other) { return false; }
+  boolean PickAndPlace.equals(Operation other) {
+    if (other == null || !other.isPickAndPlace()) {
+      return false;
+    }
+    PickAndPlace otherPickAndPlace = other.asPickAndPlace();
+    return getRobotToExecute().equals(otherPickAndPlace.getRobotToExecute()) &&
+        getObjectToPick().getName().equals(otherPickAndPlace.getObjectToPick().getName()) &&
+        getTargetLocation().getName().equals(otherPickAndPlace.getTargetLocation().getName());
+  }
+  boolean ConfigChange.equals(Operation other) {
+    if (other == null || !other.isConfigChange()) {
+      return false;
+    }
+    ConfigChange otherConfigChange = other.asConfigChange();
+    return getRobotToExecute().equals(otherConfigChange.getRobotToExecute()) &&
+        getCollaborationZone().getName().equals(otherConfigChange.getCollaborationZone().getName());
+  }
+  boolean Evacuate.equals(Operation other) {
+    if (other == null || !other.isEvacuate()) {
+      return false;
+    }
+    Evacuate otherEvacuate = other.asEvacuate();
+    return getRobotToExecute().equals(otherEvacuate.getRobotToExecute()) &&
+        getCollaborationZone().getName().equals(otherEvacuate.getCollaborationZone().getName());
+  }
+}
+
+aspect Resolving {
+  //--- findRobot ---
+  public Optional<Robot> WorldModelB.findRobot(String name) {
+    for (Robot robot : getRobotList()) {
+      if (robot.getName().equals(name)) {
+        return Optional.of(robot);
+      }
+    }
+    return Optional.empty();
+  }
+
+  // TODO use Optional here, or not?
+  public Region WorldModelB.findRegion(String name) {
+    for (Region region : getRegionList()) {
+      if (region.getName().equals(name)) {
+        return region;
+      }
+    }
+    return null;
+  }
+
+  //  // do not resolve real regions and real locations (send by site-A)
+  //  refine RefResolverStubs eq LogicalMovableObject.resolveMyLocationByToken(String name) = null;
+}
diff --git a/ros3rag.old.b/src/main/jastadd/OldWorldModelB.relast b/ros3rag.old.b/src/main/jastadd/OldWorldModelB.relast
new file mode 100644
index 0000000000000000000000000000000000000000..46e19cf4abfebfe5eacc2047668f6e44c5cf0170
--- /dev/null
+++ b/ros3rag.old.b/src/main/jastadd/OldWorldModelB.relast
@@ -0,0 +1,36 @@
+ArtificialRoot ::= WorldModelB ;
+
+// OtherScene will always be a list of one scene at most (maybe change later to reflect this. but will change quite a few place
+WorldModelB ::= Region* Robot* <MySceneAsProtobuf:de.tudresden.inf.st.ceti.Scene> /[MyScene:Scene]/ <OtherSceneAsJson> /OtherScene:LogicalScene*/ ExecutedOperation:Operation* /NextOperation:Operation/ /<NextOperationAsNtaToken:de.tudresden.inf.st.ceti.Command>/ ;
+
+Robot ::= <Name:String> CanReachObjectOfInterest* <OwnedCollaborationZoneNames> <OccupiedCollaborationZoneNames> <CurrentPosition> /<MyPosition>/ ;
+// relations into nodes received by RagConnect are not allowed
+//rel Robot.OwnedCollaborationZone* <-> CollaborationZone.Owner? ;
+//rel Robot.OccupiedCollaborationZone? <-> CollaborationZone.Occupient? ;
+
+CanReachObjectOfInterest ::= <ObjectName:String> ;
+
+abstract Difference ;
+rel Difference.Object -> LogicalMovableObject ;
+DifferenceObjectAtWrongPlace : Difference ;
+rel DifferenceObjectAtWrongPlace.PreviousRegion? -> LogicalRegion ;
+rel DifferenceObjectAtWrongPlace.NewRegion -> LogicalRegion ;
+DifferenceNewObject : Difference ;
+DifferenceObjectMisplaced : Difference ;
+rel DifferenceObjectMisplaced.PreviousRegion -> LogicalRegion ;
+
+abstract Operation ;
+rel Operation.RobotToExecute? -> Robot ;
+ErrorOperation : Operation ::= <ErrorMessage:String> ;
+
+PickAndPlace : Operation ;
+rel PickAndPlace.ObjectToPick -> LogicalMovableObject ;
+rel PickAndPlace.TargetLocation -> DropOffLocation ;
+
+ConfigChange : Operation ;
+rel ConfigChange.CollaborationZone -> CollaborationZone ;
+
+Evacuate : Operation ;
+rel Evacuate.CollaborationZone -> CollaborationZone ;
+
+Wait : Operation ;
diff --git a/ros3rag.old.b/src/main/jastadd/forwardsComp.jadd b/ros3rag.old.b/src/main/jastadd/forwardsComp.jadd
new file mode 100644
index 0000000000000000000000000000000000000000..7406eb8f53fd0e68fb7fe3b189ef9c8e889fc2e2
--- /dev/null
+++ b/ros3rag.old.b/src/main/jastadd/forwardsComp.jadd
@@ -0,0 +1,96 @@
+aspect ForwardsCompatibility {
+  public void ArtificialRoot.ragconnectCheckIncremental() {
+    // empty by definition (no incremental evaluation)
+  }
+  static WorldModelB ASTNode.singletonWorldModelB;
+  refine ASTNode public WorldModelB.WorldModelB() {
+    refined();
+    singletonWorldModelB = this;
+  }
+
+  static Robot ASTNode.hackTemporaryRobot;
+//  refine MqttHandler public boolean MqttHandler.newConnection(String topic, java.util.function.Consumer<byte[]> callback) {
+//    if (topic.equals("/ceti_cell_placeworld/command")) {
+//      // add decorator consumer to set hackTemporaryRobot
+//      java.util.function.Consumer<byte[]> decoratedConsumer = input -> {
+//
+//      };
+//    }
+//    refined();
+//  }
+    refine ROS2RAG public boolean Robot.connectOwnedCollaborationZoneNames(String uriString) throws java.io.IOException {
+  String scheme,host, path;
+java.net.URI uri;
+try {
+  uri = new java.net.URI(uriString);
+  scheme = uri.getScheme();
+  host = uri.getHost();
+  path = uri.getPath();
+} catch (java.net.URISyntaxException e) {
+  System.err.println(e.getMessage());  // Maybe re-throw error?
+  return false;
+}
+
+  java.util.function.Consumer<byte[]> consumer = message -> {
+    String result_apply_ConfigChangeCommandCheckForOwnedCollaborationZone;
+    hackTemporaryRobot = this;
+try {
+  result_apply_ConfigChangeCommandCheckForOwnedCollaborationZone = _apply_ConfigChangeCommandCheckForOwnedCollaborationZone(message);
+} catch (Exception e) {
+  e.printStackTrace();
+  return;
+}
+if (getOwnedCollaborationZoneNames() != null ? getOwnedCollaborationZoneNames().equals(result_apply_ConfigChangeCommandCheckForOwnedCollaborationZone) : result_apply_ConfigChangeCommandCheckForOwnedCollaborationZone == null) {
+  return;
+}
+
+    setOwnedCollaborationZoneNames(result_apply_ConfigChangeCommandCheckForOwnedCollaborationZone);
+  };
+  switch (scheme) {
+    case "mqtt": return _mqttHandler().newConnection(uri, consumer);
+    default:
+      System.err.println("Unknown protocol '" + scheme + "'.");
+      return false;
+  }
+}
+
+  refine ROS2RAG public boolean Robot.connectOccupiedCollaborationZoneNames(String uriString) throws java.io.IOException {
+  String scheme,host, path;
+java.net.URI uri;
+try {
+  uri = new java.net.URI(uriString);
+  scheme = uri.getScheme();
+  host = uri.getHost();
+  path = uri.getPath();
+} catch (java.net.URISyntaxException e) {
+  System.err.println(e.getMessage());  // Maybe re-throw error?
+  return false;
+}
+
+  java.util.function.Consumer<byte[]> consumer = message -> {
+    String result_apply_CommandCheckForOccupiedCollaborationZone;
+    hackTemporaryRobot = this;
+try {
+  result_apply_CommandCheckForOccupiedCollaborationZone = _apply_CommandCheckForOccupiedCollaborationZone(message);
+} catch (Exception e) {
+  e.printStackTrace();
+  return;
+}
+if (getOccupiedCollaborationZoneNames() != null ? getOccupiedCollaborationZoneNames().equals(result_apply_CommandCheckForOccupiedCollaborationZone) : result_apply_CommandCheckForOccupiedCollaborationZone == null) {
+  return;
+}
+
+    setOccupiedCollaborationZoneNames(result_apply_CommandCheckForOccupiedCollaborationZone);
+  };
+  switch (scheme) {
+    case "mqtt": return _mqttHandler().newConnection(uri, consumer);
+    default:
+      System.err.println("Unknown protocol '" + scheme + "'.");
+      return false;
+  }
+}
+
+  static void ASTNode.reject() {
+    throw new RuntimeException("poor mans reject. please ignore.");
+  }
+}
diff --git a/ros3rag.old.b/src/main/jastadd/old-shared b/ros3rag.old.b/src/main/jastadd/old-shared
new file mode 120000
index 0000000000000000000000000000000000000000..1a2dff41ee8ae3f38e6ee93f962b4a983b0cbc3a
--- /dev/null
+++ b/ros3rag.old.b/src/main/jastadd/old-shared
@@ -0,0 +1 @@
+../../../../ros3rag.common/src/main/resources/old-jastadd
\ No newline at end of file
diff --git a/ros3rag.old.b/src/main/java/de/tudresden/inf/st/old/b/OldMainB.java b/ros3rag.old.b/src/main/java/de/tudresden/inf/st/old/b/OldMainB.java
new file mode 100644
index 0000000000000000000000000000000000000000..7cf3c3e473feeb47483d56ed60b2254b41d01cb7
--- /dev/null
+++ b/ros3rag.old.b/src/main/java/de/tudresden/inf/st/old/b/OldMainB.java
@@ -0,0 +1,199 @@
+package de.tudresden.inf.st.old.b;
+
+import de.tudresden.inf.st.ceti.Object;
+import de.tudresden.inf.st.old.b.ast.*;
+import de.tudresden.inf.st.ros3rag.common.SharedMainParts;
+import de.tudresden.inf.st.ros3rag.common.Util;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.function.Function;
+
+import static de.tudresden.inf.st.ros3rag.common.Util.mqttUri;
+
+/**
+ * Entry point for RAG model in place B.
+ *
+ * @author rschoene - Initial contribution
+ */
+public class OldMainB extends SharedMainParts<MqttHandler, ArtificialRoot> {
+  private final String TOPIC_MODEL_SVG_PATH;
+
+  private de.tudresden.inf.st.ceti.Scene demo_scene;
+
+  OldMainB(String configFile) {
+    super("place-b", OldUtilB.pathToDirectoryOfPlaceB().resolve(configFile));
+
+    this.TOPIC_MODEL_SVG_PATH = cellName + "/model/svg/path";
+  }
+
+  public static void main(String[] args) throws Exception {
+    String configFile = args.length == 0 ? "src/main/resources/config-b.yaml" : args[0];
+    new OldMainB(configFile).run();
+  }
+
+  @Override
+  public void run() throws Exception {
+    // ensure that directory "images" exists
+    File imagesDirectory = Paths.get("images/").toFile();
+    if (!imagesDirectory.exists()) {
+      boolean success = imagesDirectory.mkdir();
+      if (!success) {
+        logger.debug("Failed to create directory {}", imagesDirectory.getAbsolutePath());
+      }
+    }
+
+    super.run();
+  }
+
+  @Override
+  protected MqttHandler createMqttHandler() {
+    return new MqttHandler("mainHandlerB");
+  }
+
+  @Override
+  protected void createSpecificMainHandlerConnections() {
+    mainHandler.newConnection("place-b/demo", bytes -> {
+      String command = new String(bytes);
+      int colonIndex = command.indexOf(":");
+      if (colonIndex == -1) {
+        logger.error("Unknown demo command {}", command);
+        return;
+      }
+      String key = command.substring(0, colonIndex);
+      String value = command.substring(colonIndex + 1);
+      int slashIndex;
+      switch (key) {
+        case "scene":
+          if (!value.equals("initial")) {
+            logger.warn("Can only send initial scene, but got {}. Sending initial scene.", command);
+          }
+          try {
+            demo_scene = Util.readScene(OldUtilB.pathToDirectoryOfPlaceB().resolve("src/main/resources/config-scene-b-placeworld-manual.json"));
+            mainHandler.publish(config.forB.topicsSceneUpdate.get(0), demo_scene.toByteArray());
+          } catch (IOException e) {
+            e.printStackTrace();
+          }
+          break;
+        case "robot":
+          slashIndex = value.indexOf("/");
+          String robot = value.substring(0, slashIndex);
+          String stateString = "STATE_" + value.substring(slashIndex + 1).toUpperCase();
+          Object.State state = Object.State.valueOf(stateString);
+          updateAndPublishScene(robot, r -> r.toBuilder().setState(state).build());
+          break;
+        case "object":
+          slashIndex = value.indexOf("/");
+          String obj = value.substring(0, slashIndex);
+          String location = value.substring(slashIndex + 1);
+          Position pos = model.getWorldModelB().getMyScene().resolveObjectOfInterest(location).asDropOffLocation().getPosition();
+          updateAndPublishScene(obj, o -> {
+            Object.Builder builder = o.toBuilder();
+            builder.getPosBuilder()
+                .setX(pos.getX())
+                .setY(pos.getY())
+                .setZ(pos.getZ());
+            return builder.build();
+          });
+          break;
+        default:
+          logger.error("Unknown demo command {}", command);
+      }
+    });
+  }
+
+  private void updateAndPublishScene(String objectName, Function<Object, Object> change) {
+    demo_scene = OldUtilB.updateObject(demo_scene, objectName, change);
+    mainHandler.publish(config.forB.topicsSceneUpdate.get(0), demo_scene.toByteArray());
+  }
+
+  @Override
+  protected ArtificialRoot createWorldModel() {
+    WorldModelB worldModel = new WorldModelB();
+//    worldModel.ragconnectResetEvaluationCounter();
+    worldModel.addOtherScene(new LogicalScene());
+    return new ArtificialRoot().setWorldModelB(worldModel);
+  }
+
+  @Override
+  protected void readInitialConfigs() throws Exception {
+    model.getWorldModelB().setMyScene(new Scene());
+
+    // read and set regions
+    File regionBFile = OldUtilB.pathToDirectoryOfPlaceB().resolve(config.filenameRegions).toFile();
+    OldUtilB.setRegions(model.getWorldModelB(), Util.parseRegionConfig(regionBFile));
+
+    // init robots and reachability
+    // assumption: robots do not change during runtime, so we have stable connections
+    Path path = OldUtilB.pathToDirectoryOfPlaceB().resolve(Paths.get(config.forB.filenameReachability));
+    OldReachabilityConfiguration reachability = OldUtilB.readReachability(path.toFile());
+
+    for (OldReachabilityConfiguration.RobotConfiguration robotConfiguration : reachability.robots) {
+      Robot robot = OldUtilB.createRobot(robotConfiguration.name);
+      model.getWorldModelB().addRobot(robot);
+
+      JastAddList<CanReachObjectOfInterest> reachabilityList = OldUtilB.convertToReachability(robotConfiguration.reachableLocations);
+      robot.setCanReachObjectOfInterestList(reachabilityList);
+    }
+  }
+
+  @Override
+  protected void connectEndpoints() throws IOException {
+    for (String topic : config.forB.topicsSceneUpdate) {
+      checkSuccess(model.getWorldModelB().connectMySceneAsProtobuf(mqttUri(topic, config)),
+          "MySceneAsProtobuf");
+    }
+    checkSuccess(model.getWorldModelB().connectOtherSceneAsJson(mqttUri("place-a/logical/update", config)),
+        "OtherSceneAsJson");
+    checkSuccess(model.getWorldModelB().connectNextOperationAsNtaToken(mqttUri(config.forB.topicCommand, config), false),
+        "NextOperation");
+    // indexed add not supported!!
+//    checkSuccess(model.getWorldModelB().connectExecutedOperation(mqttUri(config.forB.topicCommand, config)),
+//        "OperationHistory");
+    for (Robot robot : model.getWorldModelB().getRobotList()) {
+      // self-loop
+      checkSuccess(robot.connectOwnedCollaborationZoneNames(mqttUri(config.forB.topicCommand, config)),
+          "OwnedCollaborationZoneNames (" + robot.getName() + ")");
+      checkSuccess(robot.connectOccupiedCollaborationZoneNames(mqttUri(config.forB.topicCommand, config)),
+          "OccupiedCollaborationZoneNames (" + robot.getName() + ")");
+
+      String topicPosition = joinTopics("place-b", robot.getName(), "position");
+      checkSuccess(robot.connectCurrentPosition(mqttUri(topicPosition, config)),
+          "CurrentPosition (" + robot.getName() + ")");
+      checkSuccess(robot.connectMyPosition(mqttUri(topicPosition, config), true),
+          "MyPosition (" + robot.getName() + ")");
+    }
+  }
+
+  private void checkSuccess(boolean connectSuccess, String target) {
+    if (!connectSuccess) {
+      logger.warn("Did not connect successfully to {}", target);
+    }
+  }
+
+  @Override
+  protected String getModelInfos(ArtificialRoot artificialRoot, boolean detailed) {
+//    Thread t = new Thread(() -> {
+      try {
+        String filename = artificialRoot.getWorldModelB().dumpAst(builder -> {
+          builder.excludeChildren("Orientation", "Size");
+          builder.excludeRelations("ContainedInRegion");
+          builder.includeNonterminalAttributes("LogicalScene", "diffScenes", "diffToOperations");
+          builder.includeAttributes("realRegion", "computeOperations", "myPosition");
+          builder.includeNullNodes();
+        });
+        mainHandler.publish(TOPIC_MODEL_SVG_PATH, filename.getBytes(StandardCharsets.UTF_8));
+      } catch (Exception e) {
+        logger.catching(e);
+      }
+//    });
+//    t.setDaemon(true);
+//    t.start();
+
+    return OldUtilB.getModelInfos(artificialRoot.getWorldModelB(), detailed);
+  }
+
+}
diff --git a/ros3rag.old.b/src/main/java/de/tudresden/inf/st/old/b/OldReachabilityConfiguration.java b/ros3rag.old.b/src/main/java/de/tudresden/inf/st/old/b/OldReachabilityConfiguration.java
new file mode 100644
index 0000000000000000000000000000000000000000..87ca6434bf32c1a6f0a319e3276358b49eb7c11d
--- /dev/null
+++ b/ros3rag.old.b/src/main/java/de/tudresden/inf/st/old/b/OldReachabilityConfiguration.java
@@ -0,0 +1,17 @@
+package de.tudresden.inf.st.old.b;
+
+import java.util.List;
+
+/**
+ * Data class for reachability information.
+ *
+ * @author rschoene - Initial contribution
+ */
+public class OldReachabilityConfiguration {
+  public List<RobotConfiguration> robots;
+
+  public static class RobotConfiguration {
+    public String name;
+    public List<String> reachableLocations;
+  }
+}
diff --git a/ros3rag.old.b/src/main/java/de/tudresden/inf/st/old/b/OldSimpleMainB.java b/ros3rag.old.b/src/main/java/de/tudresden/inf/st/old/b/OldSimpleMainB.java
new file mode 100644
index 0000000000000000000000000000000000000000..89b0db03285b5c4fb0d76e52f4506dfb632af105
--- /dev/null
+++ b/ros3rag.old.b/src/main/java/de/tudresden/inf/st/old/b/OldSimpleMainB.java
@@ -0,0 +1,434 @@
+package de.tudresden.inf.st.old.b;
+
+import de.tudresden.inf.st.ceti.Object;
+import de.tudresden.inf.st.old.b.ast.*;
+import de.tudresden.inf.st.ros3rag.common.Configuration;
+import de.tudresden.inf.st.ros3rag.common.Util;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
+
+/**
+ * Testing features for placeB.
+ *
+ * @author rschoene - Initial contribution
+ */
+public class OldSimpleMainB {
+  private static final Logger logger = LogManager.getLogger(OldSimpleMainB.class);
+
+  static class Scenario {
+    final String suffix;
+    final boolean loadAndChangeScenes;
+    final boolean exitAutomatically;
+    final String mqttHost;
+    final String topicSceneUpdateB;
+    final String topicCommand;
+    Scenario(String suffix) {
+      this(suffix, true, true,
+          "localhost", "place-b/scene/update", "place-b/command");
+    }
+    Scenario(String suffix, boolean loadAndChangeScenes, boolean exitAutomatically,
+             String mqttHost, String topicSceneUpdateB, String topicCommand) {
+      this.suffix = suffix;
+      this.loadAndChangeScenes = loadAndChangeScenes;
+      this.exitAutomatically = exitAutomatically;
+      this.mqttHost = mqttHost;
+      this.topicSceneUpdateB = topicSceneUpdateB;
+      this.topicCommand = topicCommand;
+    }
+  }
+  Scenario s2022 = new Scenario("2022");
+  Scenario sMini = new Scenario("mini");
+  Scenario sPlaceworld = new Scenario("placeworld", false, false,
+      "192.168.0.122",
+      "/ceti_cell_placeworld/scene/update",
+      "/ceti_cell_placeworld/command");
+  Scenario sPlaceworldManual = new Scenario("placeworld-manual", false, false,
+      "localhost",
+      "/ceti_cell_placeworld/scene/update",
+      "/ceti_cell_placeworld/command");
+
+  @SuppressWarnings("unused" )
+  Scenario[] allScenarios = new Scenario[] { s2022, sMini, sPlaceworld, sPlaceworldManual };
+
+  final Scenario scenario = sMini;
+
+  public static void main(String[] args) throws Exception {
+    System.out.println("Running SimpleMainB");
+    new OldSimpleMainB().run(args);
+  }
+
+  @SuppressWarnings({"unused"})
+  private void run(String[] args) throws Exception {
+    readModelAndReceiveFromA();
+  }
+
+  private void readModelAndReceiveFromA() throws Exception {
+    Configuration config = new Configuration();
+    config.mqttHost = scenario.mqttHost;
+    String filenameInitialSceneB = "src/main/resources/config-scene-b-" + scenario.suffix + ".json";
+    config.filenameRegions = "src/main/resources/regions-b-" + scenario.suffix + ".json";
+    config.forB = new Configuration.ConfigurationForB();
+    config.forB.filenameReachability = "src/main/resources/reachability-b-" + scenario.suffix + ".json";
+
+    Configuration configA = new Configuration();
+    String filenameInitialSceneA = "src/main/resources/config-scene-a-" + scenario.suffix + ".json";
+    configA.filenameRegions = "src/main/resources/regions-a-" + scenario.suffix + ".json";
+
+    final String topicSceneUpdateB = scenario.topicSceneUpdateB;
+    final String topicUpdateFromPlaceA = "update/logical/fromA";
+    final String topicCommand = scenario.topicCommand;
+    final String topicExit = "place-b/exit";
+    final String topicModel = "place-b/model";
+    final String topicModelStatus = "place-b/status";
+
+    logger.info("Using scenario {}", scenario.suffix);
+
+    ArtificialRoot root = new ArtificialRoot();
+
+    WorldModelB model = new WorldModelB();
+    model.addOtherScene(new LogicalScene());
+    root.setWorldModelB(model);
+
+    MqttHandler mqttHandler = new MqttHandler().dontSendWelcomeMessage();
+    mqttHandler.setHost(config.mqttHost);
+    mqttHandler.waitUntilReady(2, TimeUnit.SECONDS);
+    root.ragconnectSetupMqttWaitUntilReady(2, TimeUnit.SECONDS);
+
+    Scene myScene = new Scene();
+    // read initial scene
+    Path initialSceneFile = OldUtilB.pathToDirectoryOfPlaceB().resolve(filenameInitialSceneB);
+    if (initialSceneFile.toFile().exists()) {
+      de.tudresden.inf.st.ceti.Scene initialScene = Util.readScene(initialSceneFile);
+      if (scenario.loadAndChangeScenes) {
+        myScene = OldUtilB.convert(initialScene);
+      } else {
+        mqttHandler.newConnection("coordinating/rag-b/command", bytes -> {
+          if (new String(bytes).equals("start")) {
+            mqttHandler.publish(scenario.topicSceneUpdateB, initialScene.toByteArray());
+          }
+        });
+      }
+    }
+    model.setMyScene(myScene);
+
+    // read and set regions
+    File regionBFile = OldUtilB.pathToDirectoryOfPlaceB().resolve(config.filenameRegions).toFile();
+    OldUtilB.setRegions(model, Util.parseRegionConfig(regionBFile));
+
+    // init robots and reachability
+    // assumption: robots do not change during runtime, so we have stable connections
+    Path path = OldUtilB.pathToDirectoryOfPlaceB().resolve(Paths.get(config.forB.filenameReachability));
+    OldReachabilityConfiguration reachability = OldUtilB.readReachability(path.toFile());
+    for (OldReachabilityConfiguration.RobotConfiguration robotConfiguration : reachability.robots) {
+
+      Robot robot = OldUtilB.createRobot(robotConfiguration.name);
+      model.addRobot(robot);
+
+      JastAddList<CanReachObjectOfInterest> reachabilityList = OldUtilB.convertToReachability(robotConfiguration.reachableLocations);
+      robot.setCanReachObjectOfInterestList(reachabilityList);
+    }
+
+    Runnable close = () -> {
+      logger.info("Exiting ...");
+      mqttHandler.close();
+      root.ragconnectCloseConnections();
+    };
+    Runtime.getRuntime().addShutdownHook(new Thread(close));
+
+    model.connectOtherSceneAsJson(Util.mqttUri(topicUpdateFromPlaceA, config));
+    model.connectMySceneAsProtobuf(Util.mqttUri(topicSceneUpdateB, config));
+    for (Robot robot : model.getRobotList()) {
+      robot.connectOwnedCollaborationZoneNames(Util.mqttUri(topicCommand, config));
+    }
+    model.connectNextOperationAsNtaToken(Util.mqttUri(topicCommand, config), true);
+
+    // prepare exit condition
+    final CountDownLatch exitCondition = new CountDownLatch(1);
+    mqttHandler.newConnection(topicExit, bytes -> exitCondition.countDown());
+    logger.info("Quit via " + topicExit);
+
+    // prepare model status
+    mqttHandler.newConnection(topicModel, bytes -> {
+      String message = new String(bytes);
+      model.dumpAst(builder -> {
+        builder.excludeChildren("Orientation", "Size");
+        builder.excludeRelations("ContainedInRegion");
+        builder.includeNonterminalAttributes("LogicalScene", "diffScenes", "diffToOperations");
+        builder.includeAttributes("realRegion", "computeOperations");
+        builder.includeNullNodes();
+      });
+      String content = OldUtilB.getModelInfos(model, message.equals("Start") || message.startsWith("detail"));
+      logger.info("WorldModel\n{}", content);
+      mqttHandler.publish(topicModelStatus, content.getBytes(StandardCharsets.UTF_8));
+    });
+
+    // read scene from A, serialize it and send it via mqtt
+    Path sceneAFile = Util.pathToModuleDirectory("ros3rag.placeA").resolve(filenameInitialSceneA);
+    File regionAFile = Util.pathToModuleDirectory("ros3rag.placeA").resolve(configA.filenameRegions).toFile();
+    de.tudresden.inf.st.ceti.Scene scenePlaceA = Util.readScene(sceneAFile);
+    Scene sceneFromPlaceA = OldUtilB.convert(scenePlaceA);
+    // need to "wrap" the scene in a world model to access regions. will use one from site-B here for convenience
+    WorldModelB tempWorldModel = new WorldModelB();
+    tempWorldModel.setMyScene(sceneFromPlaceA);
+    OldUtilB.setRegions(tempWorldModel, Util.parseRegionConfig(regionAFile));
+    LogicalScene logicalSceneFromPlaceA = sceneFromPlaceA.getLogicalScene();
+    byte[] bytesToSend = _ragconnect__apply__TreeDefaultLogicalSceneToBytesMapping(logicalSceneFromPlaceA);
+
+    if (scenario.loadAndChangeScenes && initialSceneFile.toFile().exists()) {
+      de.tudresden.inf.st.ceti.Scene initialScene = Util.readScene(initialSceneFile);
+
+      describedWait(1, "send new logical scene" );
+      mqttHandler.publish(topicUpdateFromPlaceA, bytesToSend);
+
+      describedWait(2, "print model status" );
+      mqttHandler.publish(topicModel, "detailed".getBytes(StandardCharsets.UTF_8));
+
+      // set object O1 to position of P-E in sceneB and publish it
+      describedWait(3, "send updated sceneB (P-E)");
+      de.tudresden.inf.st.ceti.Scene scene = updatePositionOfObject(initialScene, "O1", myScene.resolveObjectOfInterest("P-E").getPosition());
+      mqttHandler.publish(topicSceneUpdateB, scene.toByteArray());
+
+      describedWait(4, "set R1 to not busy");
+      scene = updateNotBusyOfRobot(scene, "R1");
+
+      describedWait(5, "print model status");
+      mqttHandler.publish(topicModel, "detailed".getBytes(StandardCharsets.UTF_8));
+
+      // set object O1 to position of P2.2 in sceneB and publish it
+      describedWait(6, "send updated sceneB (P2.2)");
+      scene = updatePositionOfObject(scene, "O1", myScene.resolveObjectOfInterest("P2.2").getPosition());
+      mqttHandler.publish(topicSceneUpdateB, scene.toByteArray());
+
+      describedWait(7, "print model status");
+      mqttHandler.publish(topicModel, "detailed".getBytes(StandardCharsets.UTF_8));
+
+      describedWait(8, "set R2 to not busy");
+      scene = updateNotBusyOfRobot(scene, "R2");
+      mqttHandler.publish(topicSceneUpdateB, scene.toByteArray());
+
+      describedWait(9, "print model status");
+      mqttHandler.publish(topicModel, "detailed".getBytes(StandardCharsets.UTF_8));
+    } else {
+      mqttHandler.newConnection("coordinating/rag-a/command", bytes -> {
+        if (new String(bytes).equals("start")) {
+          mqttHandler.publish(topicUpdateFromPlaceA, bytesToSend);
+        }
+      });
+    }
+
+    if (scenario.exitAutomatically) {
+      TimeUnit.SECONDS.sleep(5);
+      exitCondition.countDown();
+    }
+
+    exitCondition.await();
+  }
+
+  static void describedWait(int stepNr, String description) throws InterruptedException {
+    logger.info("({}) Wait 2 secs, then {}", stepNr, description);
+    TimeUnit.SECONDS.sleep(2);
+    logger.info(description);
+  }
+
+  static de.tudresden.inf.st.ceti.Scene updatePositionOfObject(
+      de.tudresden.inf.st.ceti.Scene scene,
+      @SuppressWarnings("SameParameterValue" ) String objectName,
+      Position newPosition) {
+    return OldUtilB.updateObject(scene, objectName, obj -> {
+      Object.Builder builder = obj.toBuilder();
+      builder.getPosBuilder()
+          .setX(newPosition.getX())
+          .setY(newPosition.getY())
+          .setZ(newPosition.getZ());
+      return builder.build();
+    });
+  }
+
+  static de.tudresden.inf.st.ceti.Scene updateNotBusyOfRobot(
+      de.tudresden.inf.st.ceti.Scene scene,
+      String objectName) {
+    return OldUtilB.updateObject(scene, objectName, obj -> obj.toBuilder().setState(Object.State.STATE_MOVING).build());
+  }
+
+
+  // copied from WorldModelA
+  protected static byte[] _ragconnect__apply__TreeDefaultLogicalSceneToBytesMapping(LogicalScene input) throws Exception {
+    java.io.ByteArrayOutputStream outputStream = new java.io.ByteArrayOutputStream();
+    com.fasterxml.jackson.core.JsonFactory factory = new com.fasterxml.jackson.core.JsonFactory();
+    com.fasterxml.jackson.core.JsonGenerator generator = factory.createGenerator(outputStream, com.fasterxml.jackson.core.JsonEncoding.UTF8);
+    input.serialize(generator);
+    generator.flush();
+    return outputStream.toString().getBytes();
+  }
+
+  @SuppressWarnings("unused")
+  private void printReachability(WorldModelB model) {
+    System.out.println("ModelInfos:");
+    System.out.println(OldUtilB.getModelInfos(model, true));
+
+    System.out.println("Reachability:");
+    model.getRobotList().forEach(r -> System.out.println(r.getName() + ": " + r.reachableObjects().stream().map(ObjectOfInterest::getName).collect(Collectors.joining(", "))));
+
+    System.out.println("ReachabilityGraph:");
+    System.out.println(model.toReachabilityGraph().prettyPrint());
+  }
+
+  @SuppressWarnings("unused")
+  private void printShortestPath(WorldModelB model, String source, String target) {
+    LogicalRegion sourceLocation = model.getMyScene().getLogicalScene()
+        .resolveLogicalObjectOfInterest(source).asLogicalRegion();
+    LogicalRegion targetLocation = model.getMyScene().getLogicalScene()
+        .resolveLogicalObjectOfInterest(target).asLogicalRegion();
+
+    List<Edge> bfs = sourceLocation.correspondingVertex().orElseThrow().BFS(targetLocation.correspondingVertex().orElseThrow());
+
+    System.out.println("Shortest path from " + sourceLocation.getName() + " to " + targetLocation.getName() + ": " + bfs);
+  }
+
+  @SuppressWarnings("unused")
+  private void testBFS() {
+    /*
+      A   B
+      | \ |
+      C - D
+     */
+    Graph g = new Graph();
+    Vertex a = makeVertex("a");
+    Vertex b = makeVertex("b");
+    Vertex c = makeVertex("c");
+    Vertex d = makeVertex("d");
+    Edge ac = makeEdge(a, c);
+    Edge ad = makeEdge(a, d);
+    Edge cd = makeEdge(c, d);
+    Edge db = makeEdge(d, b);
+    g.addVertex(a);
+    g.addVertex(b);
+    g.addVertex(c);
+    g.addVertex(d);
+    g.addEdge(ac);
+    g.addEdge(ad);
+    g.addEdge(cd);
+    g.addEdge(db);
+
+    System.out.println(a.BFS(b));
+  }
+
+  private Vertex makeVertex(String name) {
+    return new Vertex() {
+      @Override
+      public String toString() {
+        return name;
+      }
+    };
+  }
+
+  private Edge makeEdge(Vertex from, Vertex to) {
+    Edge result = new Edge();
+    result.setFrom(from);
+    result.setTo(to);
+    return result;
+  }
+
+  @SuppressWarnings("unused")
+  private void testDistance() throws Exception {
+    de.tudresden.inf.st.ceti.Scene scene = Util.readScene(
+        OldUtilB.pathToDirectoryOfPlaceB().resolve("src/main/resources/config-scene-b.json")
+    );
+
+    Scene myScene = OldUtilB.convert(scene);
+    float arm1X = 0f;
+    float arm1Y = 0f;
+    float arm1Z = 0.75f;
+
+    float arm2X = 1f;
+    float arm2Y = 0f;
+    float arm2Z = 0.75f;
+
+    for (var location : myScene.getDropOffLocationList()) {
+      check(arm1X, arm1Y, arm1Z, location.getPosition(), "arm1", location.getName());
+      check(arm2X, arm2Y, arm2Z, location.getPosition(), "arm2", location.getName());
+    }
+  }
+
+  private void check(double x, double y, double z, Position position, String robotName, String locationName) {
+    double dx = x - position.getX();
+    double dy = y - position.getY();
+    double dz = z - position.getZ();
+
+    if (Math.sqrt(dx*dx + dy*dy) < 0.05) {
+      System.out.println(robotName + " too close to " + locationName);
+    }
+    if (Math.sqrt(dx*dx + dy*dy + dz*dz) > 0.75) {
+      System.out.println(robotName + " too far away from " + locationName);
+    }
+  }
+
+  @SuppressWarnings("unused")
+  private void testBuildModelB() {
+    WorldModelB model = new WorldModelB();
+
+    // robots
+    model.addRobot(OldUtilB.createRobot("Alice", "placeAlfa", "placeBeta"));
+    model.addRobot(OldUtilB.createRobot("Bob", "placeBeta", "placeGamma"));
+
+    // myScene
+    var myScene = new Scene();
+    myScene.addMovableObject(MovableObject.of("obj1", Position.of(0, 0, 0)));
+    myScene.addDropOffLocation(DropOffLocation.of("placeAlfa",
+        Position.of(0, 0, 0),
+        Orientation.of(0, 0, 0, 1),
+        Size.of(1, 1, 1)));
+    myScene.addDropOffLocation(DropOffLocation.of("placeBeta",
+        Position.of(1, 1, 1),
+        Orientation.of(0, 0, 0, 1),
+        Size.of(1, 1, 1)));
+    myScene.addDropOffLocation(DropOffLocation.of("placeGamma",
+        Position.of(3, 3, 3),
+        Orientation.of(0, 0, 0, 1),
+        Size.of(2, 2, 2)));
+    logger.info("obj1 at alfa: {}",
+        myScene.getMovableObject(0).isLocatedAt(myScene.getDropOffLocation(0)));
+    model.setMyScene(myScene);
+
+    // otherScene
+    var otherScene = new LogicalScene();
+    LogicalMovableObject otherObj1 = new LogicalMovableObject().setName("obj1");
+    otherScene.addLogicalMovableObject(otherObj1);
+    otherScene.addLogicalRegion(new LogicalRegion().setName("placeAlfa"));
+    otherScene.addLogicalRegion(new LogicalRegion().setName("placeBeta"));
+    LogicalRegion otherGamma = new LogicalRegion().setName("placeGamma");
+    otherGamma.addContainedObject(otherObj1);
+    otherScene.addLogicalRegion(otherGamma);
+    model.addOtherScene(otherScene);
+
+    // printing and testing
+    printModelInfos(model);
+
+    // now simulate, that Alice has moved obj1 to placeBeta
+    myScene.getMovableObject(0).setPosition(Position.of(1, 1, 1));
+    logger.warn("Moving obj1 manually to beta");
+
+    printModelInfos(model);
+
+    // now simulate, that Bob has moved obj1 to placeGamma
+    myScene.getMovableObject(0).setPosition(Position.of(3, 3, 3));
+    logger.warn("Moving obj1 manually to gamma");
+
+    // expect error-operation
+    printModelInfos(model);
+  }
+
+  private void printModelInfos(WorldModelB model) {
+    logger.info(OldUtilB.getModelInfos(model));
+  }
+}
diff --git a/ros3rag.old.b/src/main/java/de/tudresden/inf/st/old/b/OldUtilB.java b/ros3rag.old.b/src/main/java/de/tudresden/inf/st/old/b/OldUtilB.java
new file mode 100644
index 0000000000000000000000000000000000000000..f3f33936baabbc54b06a2ed416dea1c9fcdc11f2
--- /dev/null
+++ b/ros3rag.old.b/src/main/java/de/tudresden/inf/st/old/b/OldUtilB.java
@@ -0,0 +1,180 @@
+package de.tudresden.inf.st.old.b;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import de.tudresden.inf.st.ceti.Object;
+import de.tudresden.inf.st.old.b.ast.*;
+import de.tudresden.inf.st.ros3rag.common.RegionConfiguration;
+import de.tudresden.inf.st.ros3rag.common.RegionConfiguration.RegionDefinition;
+import de.tudresden.inf.st.ros3rag.common.Util;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Path;
+import java.util.List;
+import java.util.function.Function;
+
+/**
+ * Static utility methods used only for place B.
+ *
+ * @author rschoene - Initial contribution
+ */
+public class OldUtilB {
+  private static final Logger logger = LogManager.getLogger(OldUtilB.class);
+
+  static OldReachabilityConfiguration readReachability(File reachabilityFile) throws IOException {
+    logger.info("Using reachability config file: {}", reachabilityFile.getAbsolutePath());
+    ObjectMapper mapper = new ObjectMapper();
+    return mapper.readValue(reachabilityFile, OldReachabilityConfiguration.class);
+  }
+
+  static Path pathToDirectoryOfPlaceB() {
+    return Util.pathToModuleDirectory("ros3rag.old.b");
+  }
+
+  static Robot createRobot(String name, String... canReach) {
+    Robot result = new Robot().setName(name).setCurrentPosition("unknown");
+
+    for (String canReachName : canReach) {
+      result.addCanReachObjectOfInterest(new CanReachObjectOfInterest(canReachName));
+    }
+    return result;
+  }
+
+  private static String resolveObjName(WorldModelB model, String objName) {
+    if (!model.hasMyScene()) {
+      return "\"" + objName + "\"";
+    }
+    try {
+      return model.getMyScene().resolveObjectOfInterest(objName).getName();
+    } catch (NullPointerException ignore) {
+      return "+" + objName + "(not resolved)+";
+    }
+  }
+
+  static String getModelInfos(WorldModelB model) {
+    return getModelInfos(model, false);
+  }
+
+  static String getModelInfos(WorldModelB model, boolean detailed) {
+    StringBuilder sb = new StringBuilder();
+    sb.append("myRobots: ")
+        .append(model.getRobotList().prettyPrint(
+            robot -> robot.getName()
+                + "(" + (robot.isBusy() ? "busy" : "free")
+                + ", canReach: "
+                + robot.getCanReachObjectOfInterestList().prettyPrint(
+                    canReachObj -> resolveObjName(model, canReachObj.getObjectName()))
+                + ")"))
+        .append("\n");
+    if (detailed) {
+      // also include "normal" scene
+      sb.append("myScene:");
+      if (model.hasMyScene()) {
+        sb.append("\n").append(model.getMyScene().prettyPrint());
+      } else {
+        sb.append(" (unset)\n");
+      }
+    }
+    sb.append("myLogicalScene:");
+    if (model.hasMyScene()) {
+      sb.append("\n").append(model.getMyScene().getLogicalScene().prettyPrint());
+    } else {
+      sb.append(" (unset)\n");
+    }
+    sb.append("otherScene:");
+    if (model.hasOtherScene()) {
+      sb.append("\n").append(model.mergedOtherScene().prettyPrint());
+    } else {
+      sb.append(" (unset)\n");
+    }
+    sb.append("Diff: ").append(model.diffScenes().prettyPrint(Difference::prettyPrint)).append("\n");
+    if (detailed) {
+      sb.append("Graph: ").append(model.toReachabilityGraph().prettyPrint()).append("\n");
+    }
+    sb.append("Operations: ").append(model.diffToOperations().prettyPrint(Operation::prettyPrint)).append("\n");
+    sb.append("Next operation: ").append(model.getNextOperation().prettyPrint()).append("\n");
+    sb.append("Operation History: ").append(model.getExecutedOperations().prettyPrint(Operation::prettyPrint)).append("\n");
+//    String summary = model.ragconnectEvaluationCounterSummary();
+//    sb.append("EvaluationCounter:\n").append(summary);
+//    sb.append("% skipped: ").append(percentageSkipped(summary)).append("\n");
+    return sb.toString();
+  }
+
+  static double percentageSkipped(String summary) {
+    int sumCall = 0;
+    int sumSkipped = 0;
+    try {
+      for (String line : summary.split("\n")) {
+        String[] tokens = line.split(",");
+        if (tokens.length == 0 || tokens[0].equals("parentTypeName")) {
+          continue;
+        }
+        sumCall += Integer.parseInt(tokens[4]);
+        sumSkipped += Integer.parseInt(tokens[6]);
+      }
+    } catch (NumberFormatException e) {
+      logger.catching(e);
+    }
+    if (sumCall == 0) {
+      return 0;
+    }
+    return sumSkipped * 100.0 / sumCall;
+  }
+
+  static Scene convert(de.tudresden.inf.st.ceti.Scene scene) throws Exception {
+    return new ExposingASTNode().exposed_apply_ConvertScene(scene);
+  }
+
+  static JastAddList<CanReachObjectOfInterest> convertToReachability(List<String> reachableLocations) {
+    JastAddList<CanReachObjectOfInterest> result = new JastAddList<>();
+    reachableLocations.forEach(location -> result.addChild(new CanReachObjectOfInterest(location)));
+    return result;
+  }
+
+  static void setRegions(WorldModelB model, RegionConfiguration config) {
+    JastAddList<Region> result = new JastAddList<>();
+    for (RegionDefinition def : config.regions) {
+      Region region = new Region();
+      region.setName(def.name);
+      region.setLocationNames(String.join(",", def.positions));
+      result.add(region);
+    }
+    model.setRegionList(result);
+  }
+
+  static de.tudresden.inf.st.ceti.Scene updateObject(
+      de.tudresden.inf.st.ceti.Scene scene,
+      String objectName,
+      Function<Object, Object> change) {
+    List<Object> objectsList = scene.getObjectsList();
+    Object newObj = null;
+    int index, objectsListSize;
+    for (index = 0, objectsListSize = objectsList.size(); index < objectsListSize; index++) {
+      Object obj = objectsList.get(index);
+      if (obj.getId().equals(objectName)) {
+        newObj = change.apply(obj);
+        break;
+      }
+    }
+    if (newObj == null) {
+      logger.error("Did not find object {}!", objectName);
+    } else {
+      scene = scene.toBuilder().setObjects(index, newObj).build();
+      logger.info("Update {} in scene to:\n {}", objectName, newObj);
+    }
+    return scene;
+  }
+
+  @SuppressWarnings("rawtypes")
+  static class ExposingASTNode extends ASTNode {
+    public Scene exposed_apply_ConvertScene(de.tudresden.inf.st.ceti.Scene pbScene) throws Exception {
+      return _apply_ConvertScene(pbScene);
+    }
+//    public CanReachObjectOfInterestWrapper exposed_apply_ConvertReachability(de.tudresden.inf.st.ceti.Reachability r) throws Exception {
+//      return _ragconnect__apply_ConvertReachability(r);
+//    }
+  }
+
+}
diff --git a/ros3rag.old.b/src/main/resources b/ros3rag.old.b/src/main/resources
new file mode 120000
index 0000000000000000000000000000000000000000..6c8b4ad6a116f4b2f549614fbf69beb1784c408f
--- /dev/null
+++ b/ros3rag.old.b/src/main/resources
@@ -0,0 +1 @@
+../../../ros3rag.placeB/src/main/resources
\ No newline at end of file
diff --git a/ros3rag.placeA/build.gradle b/ros3rag.placeA/build.gradle
index 5e90f00c02c0ffe44d5e15740f9d6c6702702c4e..bef7375749dbb33acd61ec3f609152950ff0d611 100644
--- a/ros3rag.placeA/build.gradle
+++ b/ros3rag.placeA/build.gradle
@@ -27,7 +27,7 @@ ext.sharedJastAddDir = 'src/main/jastadd/shared'
 ext.ragConnectInputGrammar = 'src/main/jastadd/WorldModelA.relast'
 ext.ragConnectInputConnect = 'src/main/jastadd/WorldModelA.connect'
 ext.ragConnectRootNode = 'WorldModelA'
-ext.relastFiles = ["src/gen/jastadd/WorldModelA.relast", "src/gen/jastadd/RagConnect.relast"]
+ext.relastFiles = ["src/gen/jastadd/types.relast", "src/gen/jastadd/WorldModelA.relast", "src/gen/jastadd/RagConnect.relast"]
 ext.jastaddAstPackage = 'de.tudresden.inf.st.placeA.ast'
 
 apply from: '../ros3rag.common/src/main/resources/tasks.gradle'
diff --git a/ros3rag.placeB/build.gradle b/ros3rag.placeB/build.gradle
index 5a2da9d4f49dc04cf2096201b826400e2e32dd21..2ceb2594ab0e6e3269484c2af24bcf6b62c2c2f0 100644
--- a/ros3rag.placeB/build.gradle
+++ b/ros3rag.placeB/build.gradle
@@ -29,7 +29,7 @@ ext.sharedJastAddDir = 'src/main/jastadd/shared'
 ext.ragConnectInputGrammar = 'src/main/jastadd/WorldModelB.relast'
 ext.ragConnectInputConnect = 'src/main/jastadd/WorldModelB.connect'
 ext.ragConnectRootNode = 'WorldModelB'
-ext.relastFiles = ["src/gen/jastadd/WorldModelB.relast", "src/main/jastadd/BFS/BFS.relast", "src/main/jastadd/RobotReachabilityToBFS.relast", "src/gen/jastadd/RagConnect.relast"]
+ext.relastFiles = ["src/gen/jastadd/types.relast", "src/gen/jastadd/WorldModelB.relast", "src/main/jastadd/BFS/BFS.relast", "src/main/jastadd/RobotReachabilityToBFS.relast", "src/gen/jastadd/RagConnect.relast"]
 ext.jastaddAstPackage = 'de.tudresden.inf.st.placeB.ast'
 
 apply from: '../ros3rag.common/src/main/resources/tasks.gradle'
diff --git a/ros3rag.scaling.a/build.gradle b/ros3rag.scaling.a/build.gradle
index b858870b90b5d9a12547cc2432465c7a90842645..52373c1ca92c3a58a484d552a0886bb310b0a87c 100644
--- a/ros3rag.scaling.a/build.gradle
+++ b/ros3rag.scaling.a/build.gradle
@@ -27,7 +27,7 @@ ext.sharedJastAddDir = 'src/main/jastadd/shared'
 ext.ragConnectInputGrammar = 'src/main/jastadd/ScalingModelA.relast'
 ext.ragConnectInputConnect = 'src/main/jastadd/ScalingModelA.connect'
 ext.ragConnectRootNode = 'CompleteWorld'
-ext.relastFiles = ["src/gen/jastadd/ScalingModelA.relast", "src/gen/jastadd/RagConnect.relast"]
+ext.relastFiles = ["src/gen/jastadd/types.relast", "src/gen/jastadd/ScalingModelA.relast", "src/gen/jastadd/RagConnect.relast"]
 ext.jastaddAstPackage = 'de.tudresden.inf.st.scaling.a.ast'
 
 apply from: '../ros3rag.common/src/main/resources/tasks.gradle'
diff --git a/ros3rag.scaling.b/build.gradle b/ros3rag.scaling.b/build.gradle
index 27c72a4d782507584ead0e6bd459e03337007165..e8158b2a2023c96d9211d0c731f565b135d3d983 100644
--- a/ros3rag.scaling.b/build.gradle
+++ b/ros3rag.scaling.b/build.gradle
@@ -28,7 +28,7 @@ ext.sharedJastAddDir = 'src/main/jastadd/fromPlaceB/shared'
 ext.ragConnectInputGrammar = 'src/main/jastadd/fromPlaceB/WorldModelB.relast'
 ext.ragConnectInputConnect = 'src/main/jastadd/fromPlaceB/WorldModelB.connect'
 ext.ragConnectRootNode = 'WorldModelB'
-ext.relastFiles = ["src/gen/jastadd/WorldModelB.relast", "src/main/jastadd/fromPlaceB/BFS/BFS.relast", "src/main/jastadd/fromPlaceB/RobotReachabilityToBFS.relast", "src/gen/jastadd/RagConnect.relast"]
+ext.relastFiles = ["src/gen/jastadd/types.relast", "src/gen/jastadd/WorldModelB.relast", "src/main/jastadd/fromPlaceB/BFS/BFS.relast", "src/main/jastadd/fromPlaceB/RobotReachabilityToBFS.relast", "src/gen/jastadd/RagConnect.relast"]
 ext.jastaddAstPackage = 'de.tudresden.inf.st.scaling.b.ast'
 
 apply from: '../ros3rag.common/src/main/resources/tasks.gradle'
diff --git a/settings.gradle b/settings.gradle
index bf9973ba7eefa23a0b986f3166d505ca55f85d4e..dd56cbc8dbbeb26c57f31e2a79a915a7a8409c9a 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -14,3 +14,6 @@ include 'ros3rag.common'
 
 include 'ros3rag.scaling.a'
 include 'ros3rag.scaling.b'
+
+include 'ros3rag.old.a'
+include 'ros3rag.old.b'