Index: java/main/src/main/java/com/framsticks/communication/ClientSideManagedConnection.java
===================================================================
--- java/main/src/main/java/com/framsticks/communication/ClientSideManagedConnection.java	(revision 102)
+++ java/main/src/main/java/com/framsticks/communication/ClientSideManagedConnection.java	(revision 103)
@@ -80,4 +80,7 @@
 		setDescription("client connection");
 		protocolVersion = -1;
+		requestedFeatures.add("request_id");
+		requestedFeatures.add("call_empty_result");
+		requestedFeatures.add("needfile_id");
 	}
 
@@ -192,4 +195,23 @@
 	}
 
+	private void sendNextUseRequest(final Iterator<String> featuresIterator, final Future<Void> future) {
+		if (!featuresIterator.hasNext()) {
+			future.pass(null);
+			return;
+		}
+		final String feature = featuresIterator.next();
+
+		send(new UseRequest().feature(feature), new ClientSideResponseFuture(future) {
+
+			@Override
+			protected void processOk(Response response) {
+				if (feature.equals("request_id")) {
+					requestIdEnabled = true;
+				}
+				sendNextUseRequest(featuresIterator, future);
+			}
+		});
+	}
+
 	private void sendQueryVersion(final int version, final Future<Void> future) {
 		send(new VersionRequest().version(version), new ClientSideResponseFuture(future) {
@@ -202,12 +224,5 @@
 					return;
 				}
-				send(new UseRequest().feature("request_id"), new ClientSideResponseFuture(future) {
-
-					@Override
-					protected void processOk(Response response) {
-						requestIdEnabled = true;
-						future.pass(null);
-					}
-				});
+				sendNextUseRequest(requestedFeatures.iterator(), future);
 
 			}
@@ -323,8 +338,7 @@
 
 			protected void send(final File result) {
-				log.info("sending file: " + result);
+				log.debug("sending file: " + result);
 				needFiles.clear(id);
 				sendFile(null, result, id, ClientSideManagedConnection.this);
-
 			}
 
Index: java/main/src/main/java/com/framsticks/communication/ManagedConnection.java
===================================================================
--- java/main/src/main/java/com/framsticks/communication/ManagedConnection.java	(revision 102)
+++ java/main/src/main/java/com/framsticks/communication/ManagedConnection.java	(revision 103)
@@ -1,3 +1,6 @@
 package com.framsticks.communication;
+
+import java.util.HashSet;
+import java.util.Set;
 
 import com.framsticks.util.lang.Pair;
@@ -8,4 +11,6 @@
 
 	protected int protocolVersion = -1;
+
+	protected Set<String> requestedFeatures = new HashSet<String>();
 
 	public ManagedConnection() {
Index: java/main/src/main/java/com/framsticks/communication/ServerSideManagedConnection.java
===================================================================
--- java/main/src/main/java/com/framsticks/communication/ServerSideManagedConnection.java	(revision 102)
+++ java/main/src/main/java/com/framsticks/communication/ServerSideManagedConnection.java	(revision 103)
@@ -53,4 +53,12 @@
 				if (feature.equals("request_id")) {
 					requestIdEnabled = true;
+					responseCallback.pass(new Response(true, null, null));
+					return;
+				}
+				if (feature.equals("call_empty_result")) {
+					responseCallback.pass(new Response(true, null, null));
+					return;
+				}
+				if (feature.equals("needfile_id")) {
 					responseCallback.pass(new Response(true, null, null));
 					return;
Index: java/main/src/main/java/com/framsticks/core/AbstractTree.java
===================================================================
--- java/main/src/main/java/com/framsticks/core/AbstractTree.java	(revision 102)
+++ java/main/src/main/java/com/framsticks/core/AbstractTree.java	(revision 103)
@@ -102,4 +102,9 @@
 	public AbstractTree() {
 		setName("tree");
+
+		registry.registerAndBuild(Result.class);
+		registry.registerAndBuild(ValueChange.class);
+		registry.registerAndBuild(ListChange.class);
+		registry.registerAndBuild(Message.class);
 	}
 
Index: java/main/src/main/java/com/framsticks/core/LocalTree.java
===================================================================
--- java/main/src/main/java/com/framsticks/core/LocalTree.java	(revision 102)
+++ java/main/src/main/java/com/framsticks/core/LocalTree.java	(revision 103)
@@ -21,4 +21,5 @@
 import com.framsticks.util.dispatching.Joinable;
 import com.framsticks.util.dispatching.JoinableState;
+import com.framsticks.util.lang.Casting;
 
 import static com.framsticks.core.TreeOperations.*;
@@ -90,8 +91,9 @@
 
 	@Override
-	public void call(Path path, ProcedureParam param, Object[] arguments, Future<Object> future) {
+	public <R> void call(Path path, ProcedureParam param, Object[] arguments, Class<R> resultType, Future<R> future) {
 		assert isActive();
 		try {
-			future.pass(bindAccess(path).call(param, arguments));
+			Object result = bindAccess(path).call(param, arguments);
+			future.pass(Casting.nullOrThrowCast(resultType, result));
 		} catch (FramsticksException e) {
 			future.handle(e);
Index: java/main/src/main/java/com/framsticks/core/Message.java
===================================================================
--- java/main/src/main/java/com/framsticks/core/Message.java	(revision 103)
+++ java/main/src/main/java/com/framsticks/core/Message.java	(revision 103)
@@ -0,0 +1,48 @@
+package com.framsticks.core;
+
+import com.framsticks.params.annotations.FramsClassAnnotation;
+import com.framsticks.params.annotations.ParamAnnotation;
+
+@FramsClassAnnotation(id = "Msg", name = "Msg")
+public class Message {
+
+	@ParamAnnotation(id = "class", name = "class")
+	public String className;
+
+	@ParamAnnotation
+	public String function;
+
+	@ParamAnnotation
+	public String message;
+
+	@ParamAnnotation
+	public int level;
+
+	/**
+	 *
+	 */
+	public Message() {
+	}
+
+
+	/**
+	 * @param function
+	 * @param message
+	 * @param level
+	 */
+	public Message(String className, String function, String message, int level) {
+		this.className = className;
+		this.function = function;
+		this.message = message;
+		this.level = level;
+	}
+
+	@Override
+	public String toString() {
+		StringBuilder b = new StringBuilder();
+		b.append("[").append(level).append("] ");
+		b.append(className).append(".").append(function);
+		b.append(": ").append(message);
+		return b.toString();
+	}
+}
Index: java/main/src/main/java/com/framsticks/core/Result.java
===================================================================
--- java/main/src/main/java/com/framsticks/core/Result.java	(revision 103)
+++ java/main/src/main/java/com/framsticks/core/Result.java	(revision 103)
@@ -0,0 +1,32 @@
+package com.framsticks.core;
+
+import com.framsticks.params.annotations.FramsClassAnnotation;
+import com.framsticks.params.annotations.ParamAnnotation;
+import com.framsticks.util.lang.Strings;
+
+@FramsClassAnnotation
+public class Result {
+
+	@ParamAnnotation
+	public Object value;
+
+
+	/**
+	 * @param value
+	 */
+	public Result(Object value) {
+		this.value = value;
+	}
+
+	/**
+	 *
+	 */
+	public Result() {
+	}
+
+	@Override
+	public String toString() {
+		return Strings.toStringNullProof(value, "<null>");
+	}
+
+}
Index: java/main/src/main/java/com/framsticks/core/Tree.java
===================================================================
--- java/main/src/main/java/com/framsticks/core/Tree.java	(revision 102)
+++ java/main/src/main/java/com/framsticks/core/Tree.java	(revision 103)
@@ -40,5 +40,5 @@
 	public void get(Path path, Future<Path> future);
 
-	public void call(Path path, ProcedureParam param, Object[] arguments, Future<Object> future);
+	public <R> void call(Path path, ProcedureParam param, Object[] arguments, Class<R> resultType, Future<R> future);
 
 	/**
Index: java/main/src/main/java/com/framsticks/core/TreeOperations.java
===================================================================
--- java/main/src/main/java/com/framsticks/core/TreeOperations.java	(revision 102)
+++ java/main/src/main/java/com/framsticks/core/TreeOperations.java	(revision 103)
@@ -236,5 +236,5 @@
 	}
 
-	public static void call(final Path path, final String procedureName, final Object[] arguments, final Future<Object> future) {
+	public static <R> void call(final Path path, final String procedureName, final Object[] arguments, final Class<R> resultType, final Future<R> future) {
 		final Tree tree = path.getTree();
 
@@ -243,16 +243,16 @@
 			protected void runAt() {
 				path.assureResolved();
-				tree.call(path, tree.getRegistry().getFramsClass(path.getTop().getParam()).getParamEntry(procedureName, ProcedureParam.class), arguments, future);
-			}
-		});
-	}
-
-	public static void call(final Path path, final ProcedureParam param, final Object[] arguments, final Future<Object> future) {
-		final Tree tree = path.getTree();
-
-		dispatchIfNotActive(tree, new RunAt<Tree>(future) {
-			@Override
-			protected void runAt() {
-				tree.call(path, param, arguments, future);
+				tree.call(path, tree.getRegistry().getFramsClass(path.getTop().getParam()).getParamEntry(procedureName, ProcedureParam.class), arguments, resultType, future);
+			}
+		});
+	}
+
+	public static <R> void call(final Path path, final ProcedureParam param, final Object[] arguments, final Class<R> resultType, final Future<R> future) {
+		final Tree tree = path.getTree();
+
+		dispatchIfNotActive(tree, new RunAt<Tree>(future) {
+			@Override
+			protected void runAt() {
+				tree.call(path, param, arguments, resultType, future);
 			}
 		});
Index: java/main/src/main/java/com/framsticks/experiment/Experiment.java
===================================================================
--- java/main/src/main/java/com/framsticks/experiment/Experiment.java	(revision 102)
+++ java/main/src/main/java/com/framsticks/experiment/Experiment.java	(revision 103)
@@ -45,4 +45,5 @@
 	protected String expdef;
 
+
 	/**
 	 *
@@ -53,15 +54,4 @@
 
 		Dispatching.dispatchLog(this, log, Level.DEBUG, "first task");
-
-
-		simulators.addListener(new EventListener<ListChange>() {
-			@Override
-			public void action(ListChange argument) {
-				if (argument.getAction() == ListChange.Action.Add) {
-					simulators.fireChildrenChange(argument, ListChange.Action.Modify, "ready");
-				}
-			}
-		});
-
 	}
 
@@ -114,4 +104,5 @@
 		this.expdef = expdef;
 	}
+
 
 	@ParamAnnotation(id = "simulators_changed")
@@ -129,8 +120,5 @@
 		simulators.add(simulator);
 		simulatorAsJoinables.add(simulator);
-
-
-
-
+		simulators.fireChildrenChange(simulator, ListChange.Action.Modify, "ready");
 
 	}
Index: java/main/src/main/java/com/framsticks/experiment/InvalidWorkPackage.java
===================================================================
--- java/main/src/main/java/com/framsticks/experiment/InvalidWorkPackage.java	(revision 103)
+++ java/main/src/main/java/com/framsticks/experiment/InvalidWorkPackage.java	(revision 103)
@@ -0,0 +1,8 @@
+package com.framsticks.experiment;
+
+import com.framsticks.util.FramsticksException;
+
+@SuppressWarnings("serial")
+public class InvalidWorkPackage extends FramsticksException {
+
+}
Index: java/main/src/main/java/com/framsticks/experiment/NetFile.java
===================================================================
--- java/main/src/main/java/com/framsticks/experiment/NetFile.java	(revision 103)
+++ java/main/src/main/java/com/framsticks/experiment/NetFile.java	(revision 103)
@@ -0,0 +1,7 @@
+package com.framsticks.experiment;
+
+public interface NetFile {
+
+	public String getShortDescription();
+
+}
Index: java/main/src/main/java/com/framsticks/experiment/NetLoadSaveLogic.java
===================================================================
--- java/main/src/main/java/com/framsticks/experiment/NetLoadSaveLogic.java	(revision 102)
+++ java/main/src/main/java/com/framsticks/experiment/NetLoadSaveLogic.java	(revision 103)
@@ -5,7 +5,8 @@
 import org.apache.logging.log4j.LogManager;
 
-import com.framsticks.communication.File;
 import com.framsticks.core.ListChange;
+import com.framsticks.core.Message;
 import com.framsticks.params.EventListener;
+import com.framsticks.params.MessageLogger;
 import com.framsticks.params.annotations.FramsClassAnnotation;
 import com.framsticks.params.annotations.ParamAnnotation;
@@ -14,47 +15,82 @@
 
 @FramsClassAnnotation
-public abstract class NetLoadSaveLogic extends AbstractExperimentLogic {
+public abstract class NetLoadSaveLogic<NF extends NetFile> extends AbstractExperimentLogic {
 	private static final Logger log = LogManager.getLogger(NetLoadSaveLogic.class);
 
+	protected String option = "an option";
 
-	protected String option = "an option";
+	protected final Class<NF> netJavaClass;
+
+	protected final MessageLogger messages = new MessageLogger(NetLoadSaveLogic.class);
 
 	/**
 	 * @param experiment
 	 */
-	public NetLoadSaveLogic(Experiment parentExperiment) {
+	public NetLoadSaveLogic(Experiment parentExperiment, Class<NF> netJavaClassArg) {
 		super(parentExperiment);
+		this.netJavaClass = netJavaClassArg;
 
 		experiment.addSimulatorsListener(new EventListener<ListChange>() {
 
 			@Override
-			public void action(ListChange argument) {
+			public void action(final ListChange change) {
 				assert experiment.isActive();
+				final Simulator simulator = experiment.getSimulators().get(change.getIdentifier());
+				log.debug("processing list change: {}", change);
 
-				if (argument.hasHint("ready")) {
-					final Simulator simulator = experiment.getSimulators().get(argument.getIdentifier());
-					log.debug("simulator is ready: {}", simulator);
+				if (change.getAction() == ListChange.Action.Add) {
+					log.debug("registering in {}", simulator);
+					simulator.getRemoteTree().getRegistry().registerAndBuild(netJavaClass);
+				}
 
-					netload(simulator, new FutureHandler<File>(simulator) {
+				if (!change.hasHint("stoped")) {
+					issueNetloadIfReady(change, simulator);
+					return;
+				}
 
-						@Override
-						protected void result(final File file) {
-							simulator.uploadNet(file, new FutureHandler<Object>(this) {
+				log.debug("issuing netsave to: {}", simulator);
+				simulator.netsave(netJavaClass, new FutureHandler<NF>(simulator) {
 
-								@Override
-								protected void result(Object result) {
-									log.debug("netload of {} done", file);
-								}
-							});
-						}
-					});
-				}
+					@Override
+					protected void result(NF net) {
+						log.debug("netsave of {} done: {}", simulator, net.getShortDescription());
+						netsave(simulator, net);
+						issueNetloadIfReady(change, simulator);
+					}
+				});
 			}
 		});
 	}
 
-	public abstract void netload(Simulator simulator, Future<File> net);
+	protected void issueNetloadIfReady(ListChange change, final Simulator simulator) {
+		if (!change.hasHint("ready")) {
+			return;
+		}
+		log.debug("issuing netload to: {}", simulator);
+		netload(simulator, new FutureHandler<NF>(simulator) {
 
-	public abstract void netsave(Simulator simulator, File net);
+			@Override
+			protected void result(final NF net) {
+				if (net == null) {
+					log.debug("no file for upload provided - leaving simulator idle");
+					return;
+				}
+
+				simulator.netload(net, new FutureHandler<Object>(this) {
+
+					@Override
+					protected void result(Object result) {
+						NetLoadSaveLogic.this.messages.info("netload", "done " + net.getShortDescription());
+						log.debug("netload of {} done", net.getShortDescription());
+						simulator.start();
+					}
+				});
+			}
+		});
+	}
+
+	public abstract void netload(Simulator simulator, Future<NF> net);
+
+	public abstract void netsave(Simulator simulator, NF net);
 
 	/**
@@ -74,3 +110,21 @@
 	}
 
+	/**
+	 * @return the netJavaClass
+	 */
+	@ParamAnnotation(name = "Java class representing netfile")
+	public String getNetJavaClassName() {
+		return netJavaClass.getCanonicalName();
+	}
+
+	@ParamAnnotation(id = "messages")
+	public void addMessageListener(EventListener<Message> listener) {
+		messages.add(listener);
+	}
+
+	@ParamAnnotation(id = "messages")
+	public void removeMessageListener(EventListener<Message> listener) {
+		messages.remove(listener);
+	}
+
 }
Index: java/main/src/main/java/com/framsticks/experiment/Simulator.java
===================================================================
--- java/main/src/main/java/com/framsticks/experiment/Simulator.java	(revision 102)
+++ java/main/src/main/java/com/framsticks/experiment/Simulator.java	(revision 103)
@@ -4,7 +4,10 @@
 import com.framsticks.communication.queries.NeedFile;
 import com.framsticks.communication.queries.NeedFileAcceptor;
+import com.framsticks.core.ListChange;
 import com.framsticks.core.Path;
 import com.framsticks.core.Tree;
 import com.framsticks.core.ValueChange;
+import com.framsticks.params.AccessOperations;
+import com.framsticks.params.CastFailure;
 import com.framsticks.params.EventListener;
 import com.framsticks.params.FramsClass;
@@ -12,4 +15,5 @@
 import com.framsticks.params.annotations.FramsClassAnnotation;
 import com.framsticks.params.annotations.ParamAnnotation;
+import com.framsticks.params.types.BooleanParam;
 import com.framsticks.params.types.EventParam;
 import com.framsticks.params.types.ProcedureParam;
@@ -59,10 +63,18 @@
 		assert experiment.isActive();
 
-		log.debug("simulator ready {}", this);
+		log.info("simulator ready {}", this);
 
 		runningListener = new EventListener<ValueChange>() {
 			@Override
 			public void action(ValueChange argument) {
-				log.debug("running state of {} changed: {}", this, argument);
+				try {
+					boolean running = simulatorClass.getParamEntry("running", BooleanParam.class).reassign(argument.value, null).getValue();
+					log.debug("running state of {} changed: {}", Simulator.this, running);
+					if (!running) {
+						Simulator.this.experiment.simulators.fireChildrenChange(Simulator.this, ListChange.Action.Modify, "ready", "stoped");
+					}
+				} catch (CastFailure e) {
+					log.error("failure: ", e);
+				}
 			}
 		};
@@ -147,8 +159,11 @@
 	@ParamAnnotation(paramType = ProcedureParam.class)
 	public void start() {
+		log.debug("starting simulator {}", this);
+		call(simulatorPath, "start", new Object[] {}, Object.class, FutureHandler.doNothing(Object.class, this));
 	}
 
 	@ParamAnnotation(paramType = ProcedureParam.class)
 	public void stop() {
+		log.debug("stoping simulator {}", this);
 	}
 
@@ -156,5 +171,5 @@
 	public void abort() {
 		assert isActive();
-		log.debug("explicitly aborting {}", this);
+		log.info("explicitly aborting {}", this);
 		experiment.removeSimulator(this);
 		interruptJoinable();
@@ -184,7 +199,8 @@
 	protected final AtomicInteger netloadIdCounter = new AtomicInteger();
 
-	public void uploadNet(final File file, final Future<Object> future) {
+	public <N> void netload(final N net, final Future<Object> future) {
 		final String netloadId = "NetLoadSaveLogic" + netloadIdCounter.getAndIncrement();
 
+		final File file = AccessOperations.convert(File.class, net, getRemoteTree().getRegistry());
 		log.debug("uploading file {} to {} identified by {}", file, simulatorPath, netloadId);
 
@@ -215,5 +231,5 @@
 		simulatorPath.getTree().addNeedFileAcceptor(Integer.MIN_VALUE, acceptor.get());
 
-		call(simulatorPath, getFramsClass(simulatorPath).getParamEntry("netload_id", ProcedureParam.class), new Object[] { netloadId }, new FutureHandler<Object>(future) {
+		call(simulatorPath, getFramsClass(simulatorPath).getParamEntry("netload_id", ProcedureParam.class), new Object[] { netloadId }, Object.class, new FutureHandler<Object>(future) {
 
 			@Override
@@ -225,3 +241,15 @@
 
 	}
+
+	public <N> void netsave(Class<N> netJavaClass, final Future<N> futureNet) {
+		call(simulatorPath, getFramsClass(simulatorPath).getParamEntry("netsave", ProcedureParam.class), new Object[] { }, netJavaClass, new FutureHandler<N>(futureNet) {
+
+			@Override
+			protected void result(N net) {
+				log.debug("download of {} done", net);
+				futureNet.pass(net);
+			}
+		});
+
+	}
 }
Index: java/main/src/main/java/com/framsticks/experiment/WorkPackage.java
===================================================================
--- java/main/src/main/java/com/framsticks/experiment/WorkPackage.java	(revision 102)
+++ java/main/src/main/java/com/framsticks/experiment/WorkPackage.java	(revision 103)
@@ -1,5 +1,10 @@
 package com.framsticks.experiment;
 
-public interface WorkPackage {
+public interface WorkPackage<S extends WorkPackage<S>> extends NetFile {
+
+	public String sumUpTask();
+	public String sumUpResult();
+
+	S getRemainder(S result);
 
 }
Index: java/main/src/main/java/com/framsticks/experiment/WorkPackageLogic.java
===================================================================
--- java/main/src/main/java/com/framsticks/experiment/WorkPackageLogic.java	(revision 102)
+++ java/main/src/main/java/com/framsticks/experiment/WorkPackageLogic.java	(revision 103)
@@ -1,9 +1,16 @@
 package com.framsticks.experiment;
+
+import java.util.IdentityHashMap;
+import java.util.LinkedList;
+import java.util.Map;
 
 import org.apache.logging.log4j.Logger;
 import org.apache.logging.log4j.LogManager;
 
-import com.framsticks.communication.File;
-import com.framsticks.params.ListSource;
+import com.framsticks.core.Message;
+import com.framsticks.core.ValueChange;
+import com.framsticks.params.EventListener;
+import com.framsticks.params.MessageLogger;
+import com.framsticks.params.SimplePrimitive;
 import com.framsticks.params.annotations.FramsClassAnnotation;
 import com.framsticks.params.annotations.ParamAnnotation;
@@ -11,33 +18,53 @@
 import com.framsticks.util.dispatching.FutureHandler;
 
-@FramsClassAnnotation
-public abstract class WorkPackageLogic<WP extends WorkPackage> extends AbstractExperimentLogic {
+@FramsClassAnnotation(order = {"netLoadSaveLogic", "newestTaskScheduled", "newestResultReceived"})
+public abstract class WorkPackageLogic<WP extends WorkPackage<WP>> extends AbstractExperimentLogic {
 
 	private static final Logger log = LogManager.getLogger(WorkPackageLogic.class);
 
 	@ParamAnnotation
-	public final NetLoadSaveLogic netLoadSaveLogic;
+	public final NetLoadSaveLogic<WP> netLoadSaveLogic;
+
+	protected final Class<WP> packageJavaClass;
+
+	protected final MessageLogger messages = new MessageLogger(WorkPackageLogic.class);
+
+	protected final Map<Simulator, WP> sentPackages = new IdentityHashMap<>();
+	protected final LinkedList<WP> queuedPackages = new LinkedList<>();
+
+	protected final SimplePrimitive<String> newestTaskSent = new SimplePrimitive<>();
+	protected final SimplePrimitive<String> newestResultReceived = new SimplePrimitive<>();
+
 
 	/**
 	 * @param experiment
 	 */
-	public WorkPackageLogic(Experiment experiment) {
+	public WorkPackageLogic(Experiment experiment, Class<WP> packageJavaClass) {
 		super(experiment);
+		this.packageJavaClass = packageJavaClass;
 
-		netLoadSaveLogic = new NetLoadSaveLogic(experiment) {
+		netLoadSaveLogic = new NetLoadSaveLogic<WP>(experiment, packageJavaClass) {
 
 			@Override
-			public void netload(Simulator simulator, final Future<File> net) {
+			public void netload(final Simulator simulator, final Future<WP> netFuture) {
 				assert experiment.isActive();
 				log.debug("providing netload file for {}", simulator);
 
-				generateNextPackage(new FutureHandler<WP> (net) {
+				findNextPackage(new FutureHandler<WP> (netFuture) {
 
 					@Override
-					protected void result(WP result) {
-						log.debug("sending package: {}", result);
-						File file = new File("test-file", ListSource.createFrom("# a test"));
+					protected void result(WP net) {
+						assert experiment.isActive();
 
-						net.pass(file);
+						if (net == null) {
+							log.debug("no more packages left");
+							return;
+						}
+						WorkPackageLogic.this.messages.info("netload", net.sumUpTask());
+						log.debug("sending package: {}", net);
+						newestTaskSent.set(net.sumUpTask());
+						sentPackages.put(simulator, net);
+
+						netFuture.pass(net);
 					}
 				});
@@ -46,5 +73,30 @@
 
 			@Override
-			public void netsave(Simulator simulator, File net) {
+			public void netsave(Simulator simulator, WP netResult) {
+				assert experiment.isActive();
+
+				log.debug("received package from {}: {}", simulator, netResult);
+				WorkPackageLogic.this.messages.info("netsave", netResult.toString());
+
+				WP netSent = sentPackages.get(simulator);
+				if (netSent == null) {
+					log.error("no task found in {} for received result {}", simulator, netResult);
+					return;
+				}
+				sentPackages.remove(simulator);
+
+				try {
+					WP netRemainder = netSent.getRemainder(netResult);
+					if (netRemainder != null) {
+						log.warn("queueing remainder: {}", netRemainder);
+						queuedPackages.add(netRemainder);
+					}
+				} catch (InvalidWorkPackage e) {
+					log.error("in simulator {}, result {} is in no relation to task {} ({}), rescheduling", simulator, netResult, netSent, e.getShortMessage(new StringBuilder()));
+					queuedPackages.add(netSent);
+					return;
+				}
+
+				returnPackage(netResult);
 				// processFile();
 			}
@@ -53,5 +105,76 @@
 
 
+
+	protected void findNextPackage(final Future<WP> future) {
+		if (!queuedPackages.isEmpty()) {
+			WP workPackage = queuedPackages.pollFirst();
+			future.pass(workPackage);
+			return;
+		}
+
+		generateNextPackage(new FutureHandler<WP>(experiment) {
+
+			@Override
+			protected void result(WP result) {
+				if (result == null) {
+					log.info("no more packages left");
+					future.pass(null);
+					return;
+				}
+				future.pass(result);
+			}
+		});
+	}
+
 	protected abstract void generateNextPackage(Future<WP> future);
+	protected abstract void returnPackage(WP workPackage);
+
+	/**
+	 * @return the newestTaskScheduled
+	 */
+	@ParamAnnotation(id = "newest_task_sent")
+	public String getNewestTaskSent() {
+		return newestTaskSent.get();
+	}
+
+	/**
+	 * @return the newestResultReceived
+	 */
+	@ParamAnnotation(id = "newest_result_received")
+	public String getNewestResultReceived() {
+		return newestResultReceived.get();
+	}
+
+	@ParamAnnotation(id = "newest_task_sent_changed")
+	public void addNewestTaskSentListener(EventListener<ValueChange> listener) {
+		newestTaskSent.addListener(listener);
+	}
+
+	@ParamAnnotation(id = "newest_task_sent_changed")
+	public void removeNewestTaskSentListener(EventListener<ValueChange> listener) {
+		newestTaskSent.removeListener(listener);
+	}
+
+	@ParamAnnotation(id = "newest_result_received_changed")
+	public void addNewestResultReceivedListener(EventListener<ValueChange> listener) {
+		newestResultReceived.addListener(listener);
+	}
+
+	@ParamAnnotation(id = "newest_result_received_changed")
+	public void removeNewestResultReceivedListener(EventListener<ValueChange> listener) {
+		newestResultReceived.removeListener(listener);
+	}
+
+	@ParamAnnotation(id = "messages")
+	public void addMessageListener(EventListener<Message> listener) {
+		messages.add(listener);
+	}
+
+	@ParamAnnotation(id = "messages")
+	public void removeMessageListener(EventListener<Message> listener) {
+		messages.remove(listener);
+	}
+
+
 
 }
Index: java/main/src/main/java/com/framsticks/gui/controls/ProcedureControl.java
===================================================================
--- java/main/src/main/java/com/framsticks/gui/controls/ProcedureControl.java	(revision 102)
+++ java/main/src/main/java/com/framsticks/gui/controls/ProcedureControl.java	(revision 103)
@@ -73,5 +73,5 @@
 		assert path.getTree().isActive();
 
-		path.getTree().call(path, param, arguments, new FutureHandler<Object>(frame) {
+		path.getTree().call(path, param, arguments, Object.class, new FutureHandler<Object>(frame) {
 
 			@Override
Index: java/main/src/main/java/com/framsticks/gui/tree/TreeModel.java
===================================================================
--- java/main/src/main/java/com/framsticks/gui/tree/TreeModel.java	(revision 102)
+++ java/main/src/main/java/com/framsticks/gui/tree/TreeModel.java	(revision 103)
@@ -19,4 +19,5 @@
 import com.framsticks.core.SideNoteKey;
 import com.framsticks.core.TreeOperations;
+import com.framsticks.core.ValueChange;
 import com.framsticks.gui.Frame;
 import com.framsticks.params.Access;
@@ -321,5 +322,5 @@
 
 
-	protected void registerForEventParam(final TreeNode treeNode, Path path, final EventParam eventParam, ValueParam valueParam) {
+	protected void registerForEventParam(final TreeNode treeNode, Path path, final EventParam eventParam, final ValueParam valueParam) {
 		/** TODO make this listener not bind hold the reference to this TreeNode, maybe hold WeakReference internally */
 		if (valueParam instanceof PrimitiveParam) {
@@ -328,5 +329,13 @@
 				@Override
 				public void action(Object argument) {
-					loadPath(treeNode.assurePath(), true);
+					assert treeNode.getTree().isActive();
+					if (argument instanceof ValueChange) {
+						ValueChange valueChange = (ValueChange) argument;
+						Path path = treeNode.assurePath();
+						bindAccess(path).set(valueParam, valueChange.value);
+						frame.updatePanelIfIsLeadSelection(path);
+					} else {
+						loadPath(treeNode.assurePath(), true);
+					}
 				}
 			});
Index: java/main/src/main/java/com/framsticks/hosting/Cli.java
===================================================================
--- java/main/src/main/java/com/framsticks/hosting/Cli.java	(revision 102)
+++ java/main/src/main/java/com/framsticks/hosting/Cli.java	(revision 103)
@@ -28,4 +28,6 @@
 	protected final ClientAtServer client;
 
+	protected final String address;
+
 	@ParamAnnotation
 	public final Map<String, CliEvent> events = new TreeMap<>();
@@ -37,4 +39,5 @@
 		this.client = client;
 		this.tree = client.getTree();
+		this.address = client.connection.getAddress();
 	}
 
@@ -78,3 +81,11 @@
 	}
 
+	/**
+	 * @return the address
+	 */
+	@ParamAnnotation
+	public String getAddress() {
+		return address;
+	}
+
 }
Index: java/main/src/main/java/com/framsticks/hosting/CliEvent.java
===================================================================
--- java/main/src/main/java/com/framsticks/hosting/CliEvent.java	(revision 102)
+++ java/main/src/main/java/com/framsticks/hosting/CliEvent.java	(revision 103)
@@ -23,16 +23,5 @@
 
 	protected EventListener<Object> listener;
-	// protected String name;
 
-
-
-	/**
-	 * @param id
-	 * @param listener
-	 * @param tree
-	 * @param name
-	 * @param path
-	 * @param param
-	 */
 	public CliEvent() {
 	}
@@ -62,5 +51,5 @@
 	@ParamAnnotation
 	public String getName() {
-		return id;
+		return name;
 	}
 
Index: java/main/src/main/java/com/framsticks/hosting/ClientAtServer.java
===================================================================
--- java/main/src/main/java/com/framsticks/hosting/ClientAtServer.java	(revision 102)
+++ java/main/src/main/java/com/framsticks/hosting/ClientAtServer.java	(revision 103)
@@ -76,4 +76,6 @@
 			.param(Param.build().id(id).name(framsClass.getName()).type("o " + framsClass.getId()))
 			.param(Param.build().id("cli").name("CLI").type("o Cli"))
+			.param(Param.build().id("system").name("Operating system").type("s").flags(ParamFlags.READONLY))
+			.param(Param.build().id("user").name("User name").type("s").flags(ParamFlags.READONLY))
 			.finish();
 
@@ -89,4 +91,6 @@
 		access.set(id, treeRootObject);
 		access.set("cli", cliObject);
+		access.set("system", System.getProperties().getProperty("os.name") + " " + System.getProperties().getProperty("os.version") + " " + System.getProperties().getProperty("os.arch"));
+		access.set("user", System.getProperties().getProperty("user.name"));
 
 		rootTree.assignRootParam(access.buildParam(new ParamBuilder()).name(rootFramsClassId).finish(CompositeParam.class));
@@ -157,10 +161,11 @@
 				if (request instanceof CallRequest) {
 					final CallRequest callRequest = (CallRequest) request;
-					tree.call(path, access.getFramsClass().getParamEntry(callRequest.getProcedure(), ProcedureParam.class), callRequest.getArguments().toArray(), new FutureHandler<Object>(responseCallback) {
+					tree.call(path, access.getFramsClass().getParamEntry(callRequest.getProcedure(), ProcedureParam.class), callRequest.getArguments().toArray(), Object.class, new FutureHandler<Object>(responseCallback) {
 						@Override
 						protected void result(Object result) {
 							ListSink sink = new ListSink();
 							sink.print("Result:").breakLine();
-							sink.print("value:").print("[");
+							sink.print("value:");
+							sink.print("[");
 							if (result != null) {
 								sink.print(result);
Index: java/main/src/main/java/com/framsticks/params/AccessOperations.java
===================================================================
--- java/main/src/main/java/com/framsticks/params/AccessOperations.java	(revision 102)
+++ java/main/src/main/java/com/framsticks/params/AccessOperations.java	(revision 103)
@@ -1,10 +1,23 @@
 package com.framsticks.params;
+
+import java.util.LinkedList;
+import java.util.ListIterator;
+
+import javax.annotation.Nullable;
 
 import org.apache.logging.log4j.Logger;
 import org.apache.logging.log4j.LogManager;
 
+import com.framsticks.communication.File;
+import com.framsticks.params.types.ListParam;
+import com.framsticks.parsers.MultiParamLoader;
 import com.framsticks.util.FramsticksException;
+import com.framsticks.util.FramsticksUnsupportedOperationException;
+import com.framsticks.util.Misc;
+import com.framsticks.util.UnimplementedException;
+import com.framsticks.util.lang.Casting;
 import com.framsticks.util.lang.Containers;
 import com.framsticks.util.lang.Holder;
+import com.framsticks.util.lang.Pair;
 // import com.framsticks.util.lang.Containers;
 
@@ -14,5 +27,5 @@
 public final class AccessOperations {
 
-	private final static Logger log = LogManager.getLogger(SimpleAbstractAccess.class.getName());
+	private final static Logger log = LogManager.getLogger(AccessOperations.class);
 
 	/**
@@ -75,22 +88,172 @@
 	}
 
-	public static void save(Access access, Sink sink) {
+	public static <A extends Access> A assureSelected(A access) {
+		if (access.getSelected() == null) {
+			access.select(access.createAccessee());
+		}
+		return access;
+	}
+
+	public static Access loadAll(@Nullable final Access rootAccess, Source source, final Registry registry) {
+		final MultiParamLoader loader = new MultiParamLoader();
+		loader.setNewSource(source);
+		final LinkedList<Access> accessesStack = new LinkedList<>();
+		if (rootAccess != null) {
+			assureSelected(rootAccess);
+			accessesStack.add(rootAccess);
+		}
+		final Holder<Boolean> first = new Holder<>(true);
+		final Holder<Boolean> needAdd = new Holder<>();
+		final Holder<Access> currentAccess = new Holder<>();
+		final Holder<Pair<Access, CompositeParam>> parent = new Holder<>();
+
+		loader.setAccessProvider(new AccessProvider() {
+			@Override
+			public Access getAccess(String name) {
+				if (first.get()) {
+					first.set(false);
+					if (rootAccess != null) {
+						if (name.equals(rootAccess.getId())) {
+							needAdd.set(false);
+							currentAccess.set(rootAccess);
+							return rootAccess;
+						}
+					} else {
+						Access access = registry.createAccess(name);
+						needAdd.set(false);
+						currentAccess.set(access);
+						return access;
+
+					}
+				}
+
+				ListIterator<Access> accessIterator = accessesStack.listIterator(accessesStack.size());
+				parent.set(null);
+				// log.debug("accesses stack: {}", accessesStack);
+
+				while (accessIterator.hasPrevious()) {
+					Access a = accessIterator.previous();
+					assert a != null;
+
+					for (CompositeParam p : Containers.filterInstanceof(a.getParams(), CompositeParam.class)) {
+						if (p.getContainedTypeName().equals(name)) {
+
+							if (parent.get() != null) {
+								throw new FramsticksException().msg("ambiguity encountered during loading").arg("name", name);
+							}
+
+							if (p instanceof ListParam) {
+								ListAccess listAccess = Casting.assertCast(ListAccess.class, registry.prepareAccess(p));
+								listAccess.select(a.get(p, Object.class));
+								parent.set(new Pair<Access, CompositeParam>(listAccess, listAccess.prepareParamFor(Integer.toString(listAccess.getParamCount()))));
+
+							} else {
+								parent.set(Pair.make(a, p));
+							}
+						}
+					}
+
+					if (parent.get() == null) {
+						accessIterator.remove();
+					}
+				}
+
+				if (parent.get() == null) {
+					throw new FramsticksException().msg("failed to find place for loaded object").arg("name", name);
+				}
+
+				currentAccess.set(registry.prepareAccess(parent.get().second));
+				Object object = parent.get().first.get(parent.get().second, Object.class);
+				if (object != null) {
+					currentAccess.get().select(object);
+					needAdd.set(false);
+				} else {
+					object = currentAccess.get().createAccessee();
+					currentAccess.get().select(object);
+					needAdd.set(true);
+				}
+
+				return currentAccess.get();
+			}
+		});
+
+		loader.addListener(MultiParamLoader.Status.AfterObject, new MultiParamLoader.StatusListener() {
+			@Override
+			public void onStatusChange() {
+				if (needAdd.get()) {
+					parent.get().first.set(parent.get().second, currentAccess.get().getSelected());
+				}
+				if (currentAccess.get() != rootAccess)	{
+					accessesStack.add(currentAccess.get());
+				}
+				currentAccess.set(null);
+			}
+		});
+
+		loader.go();
+		if (accessesStack.isEmpty()) {
+			throw new FramsticksException().msg("failed to load from source").arg("source", source);
+		}
+		return accessesStack.get(0);
+	}
+
+	public static void saveAll(Access access, Sink sink, Registry registry) {
+		if (access instanceof ObjectAccess) {
+			savePrimitives(access, sink);
+		}
+		for (CompositeParam p : filterInstanceof(access.getParams(), CompositeParam.class)) {
+			Object child = access.get(p, Object.class);
+			if (child == null) {
+				continue;
+			}
+			saveAll(registry.prepareAccess(p).select(child), sink, registry);
+		}
+	}
+
+	public static void saveComposites(Access access, Sink sink, Registry registry) {
+		for (CompositeParam p : filterInstanceof(access.getParams(), CompositeParam.class)) {
+			Object child = access.get(p, Object.class);
+			if (child == null) {
+				continue;
+			}
+			savePrimitives(registry.prepareAccess(p).select(child), sink);
+		}
+	}
+
+	public static void savePrimitives(Access access, Sink sink) {
 		if (access instanceof ObjectAccess) {
 			ObjectAccess objectAccess = (ObjectAccess) access;
 			FramsClass framsClass = access.getFramsClass();
 			assert framsClass != null;
-			sink.print(framsClass.getId()).print(":").breakLine();
+			boolean headerNeeded = true;
+			// sink.print(framsClass.getId()).print(":").breakLine();
 			for (PrimitiveParam<?> p : filterInstanceof(framsClass.getParamEntries(), PrimitiveParam.class)) {
+
 				Object value = objectAccess.get(p, Object.class);
 				if ((value == null) || value.equals(p.getDef(Object.class))) {
 					continue;
 				}
+
+				if (headerNeeded) {
+					sink.print(framsClass.getId()).print(":").breakLine();
+					headerNeeded = false;
+				}
+
 				sink.print(p.getId()).print(":");
 				p.save(sink, value);
 				sink.breakLine();
 			}
-			sink.breakLine();
+			if (!headerNeeded) {
+				sink.breakLine();
+			}
 			return;
-
+		}
+		throw new FramsticksException().msg("invalid type of access for primitive save").arg("access", access);
+	}
+
+	public static void save(Access access, Sink sink) {
+		if (access instanceof ObjectAccess) {
+			savePrimitives(access, sink);
+			return;
 		}
 		if (access instanceof ListAccess) {
@@ -107,4 +270,41 @@
 	}
 
+	public static void loadComposites(Access access, Source source, final Registry registry) {
+		if (access instanceof ObjectAccess) {
+			final ObjectAccess objectAccess = (ObjectAccess) access;
+
+			MultiParamLoader loader = new MultiParamLoader();
+
+			loader.setNewSource(source);
+
+			loader.setAccessProvider(new AccessProvider() {
+				@Override
+				public Access getAccess(String name) {
+					CompositeParam result = null;
+					for (CompositeParam p : filterInstanceof(objectAccess.getParams(), CompositeParam.class)) {
+						if (p.getContainedTypeName().equals(name)) {
+							if (result != null) {
+								throw new FramsticksException().msg("class name is ambiguous in access").arg("name", name).arg("first candidate", result).arg("second candidate", p);
+							}
+							result = p;
+
+						}
+					}
+					if (result == null) {
+						throw new FramsticksException().msg("class name is unknown").arg("name", name).arg("in", objectAccess);
+					}
+
+					return registry.prepareAccess(result).select(objectAccess.get(result, Object.class));
+				}
+			});
+
+
+			loader.go();
+
+			return;
+		}
+		throw new UnimplementedException().msg("unknown access category").arg("access", access);
+	}
+
 	public static void load(Access access, Source source) {
 		if (!(access instanceof ObjectAccess)) {
@@ -128,5 +328,4 @@
 			}
 		}
-
 	}
 
@@ -215,3 +414,74 @@
 	}
 
+
+	/**
+	 *
+	 * If both arguments are File, than do nothing; otherwise:
+	 *
+	 * If from argument is a File:
+	 * - if toJavaClass is Object.class, than try read using registry
+	 * - otherwise: try use loadComposites
+	 *
+	 * If to argument is a File:
+	 * - use Registry to saveAll
+	 *
+	 */
+	public static <T, F> T convert(Class<T> toJavaClass, F from, Registry registry) {
+		if (toJavaClass.equals(from.getClass())) {
+			return toJavaClass.cast(from);
+		}
+		if (from instanceof File) {
+			File file = (File) from;
+			return Casting.throwCast(toJavaClass, loadAll((toJavaClass.equals(Object.class) ? null : registry.createAccess(toJavaClass)), file.getContent(), registry).getSelected());
+		}
+		if (toJavaClass.equals(File.class)) {
+			ListSink sink = new ListSink();
+			saveAll(registry.createAccess(from.getClass()).select(from), sink, registry);
+			return Casting.throwCast(toJavaClass, new File("", new ListSource(sink.getOut())));
+		}
+
+		throw new FramsticksUnsupportedOperationException().msg("conversion").arg("from", from.getClass()).arg("to", toJavaClass);
+	}
+
+	@SuppressWarnings("serial")
+	public static class EqualityException extends FramsticksException {
+	}
+
+
+	public static void assureEquality(Access a, Access b, Registry registry) {
+		try {
+			if (a.getParamCount() != b.getParamCount()) {
+				throw new EqualityException().msg("param count not equal").arg("left", a.getParamCount()).arg("right", b.getParamCount());
+			}
+			for (ValueParam avp : Containers.filterInstanceof(a.getParams(), ValueParam.class)) {
+				Param bp = b.getParam(avp.getId());
+				if (bp == null) {
+					throw new EqualityException().msg("param from left not present in right").arg("param", avp);
+				}
+				Misc.checkEquals(avp.getClass(), bp.getClass(), "params type not equals", null);
+				ValueParam bvp = (ValueParam) bp;
+
+				Object oa = a.get(avp, Object.class);
+				Object ob = b.get(avp, Object.class);
+
+				if (avp instanceof CompositeParam) {
+					assureEquality(registry.prepareAccess((CompositeParam) avp).select(oa), registry.prepareAccess((CompositeParam) bvp).select(ob), registry);
+					continue;
+				}
+				Misc.checkEquals(oa, ob, "values not equal", null);
+			}
+		} catch (EqualityException e) {
+			throw e.arg("left", a).arg("right", b);
+		}
+	}
+
+	public static boolean areEqual(Access a, Access b, Registry registry) {
+		try {
+			assureEquality(a, b, registry);
+			return true;
+		} catch (EqualityException e) {
+		}
+		return false;
+	}
+
 }
Index: java/main/src/main/java/com/framsticks/params/AccessProvider.java
===================================================================
--- java/main/src/main/java/com/framsticks/params/AccessProvider.java	(revision 102)
+++ java/main/src/main/java/com/framsticks/params/AccessProvider.java	(revision 103)
@@ -4,5 +4,4 @@
 
 	public Access getAccess(String name);
-	public void addAccess(Access access);
 
 }
Index: java/main/src/main/java/com/framsticks/params/ListSource.java
===================================================================
--- java/main/src/main/java/com/framsticks/params/ListSource.java	(revision 102)
+++ java/main/src/main/java/com/framsticks/params/ListSource.java	(revision 103)
@@ -73,4 +73,7 @@
 			b.append(list.get(i));
 		}
+		if (list.size() > print) {
+			b.append(" ...");
+		}
 		return b.toString();
 	}
Index: java/main/src/main/java/com/framsticks/params/MessageLogger.java
===================================================================
--- java/main/src/main/java/com/framsticks/params/MessageLogger.java	(revision 103)
+++ java/main/src/main/java/com/framsticks/params/MessageLogger.java	(revision 103)
@@ -0,0 +1,23 @@
+package com.framsticks.params;
+
+import com.framsticks.core.Message;
+
+public class MessageLogger extends EventListeners<Message> {
+
+	protected String className;
+
+	public MessageLogger() {
+		this(MessageLogger.class);
+	}
+
+	public MessageLogger(Class<?> ownerClass) {
+		className = ownerClass.getSimpleName();
+	}
+
+	public void info(String function, String message) {
+		if (!listeners.isEmpty()) {
+			actionForAll(new Message(className, function, message, 0));
+		}
+	}
+
+}
Index: java/main/src/main/java/com/framsticks/params/Registry.java
===================================================================
--- java/main/src/main/java/com/framsticks/params/Registry.java	(revision 102)
+++ java/main/src/main/java/com/framsticks/params/Registry.java	(revision 103)
@@ -8,5 +8,4 @@
 import com.framsticks.util.DoubleMap;
 import com.framsticks.util.FramsticksException;
-import com.framsticks.util.FramsticksUnsupportedOperationException;
 import com.framsticks.util.lang.Strings;
 
@@ -166,8 +165,8 @@
 	}
 
-	@Override
-	public void addAccess(Access access) {
-		throw new FramsticksUnsupportedOperationException().msg("adding accesses to Registry");
+	public Access bindAccessFor(Object object) {
+		return createAccess(object.getClass()).select(object);
 	}
 
+
 }
Index: java/main/src/main/java/com/framsticks/params/SimplePrimitive.java
===================================================================
--- java/main/src/main/java/com/framsticks/params/SimplePrimitive.java	(revision 103)
+++ java/main/src/main/java/com/framsticks/params/SimplePrimitive.java	(revision 103)
@@ -0,0 +1,53 @@
+package com.framsticks.params;
+
+import com.framsticks.core.ValueChange;
+import com.framsticks.util.lang.Strings;
+
+public class SimplePrimitive<T> {
+
+	protected T value;
+	protected final EventListeners<ValueChange> listeners = new EventListeners<>();
+
+	/**
+	 * @param value
+	 */
+	public SimplePrimitive(T value) {
+		this.value = value;
+	}
+
+	/**
+	 * @param value
+	 */
+	public SimplePrimitive() {
+		this(null);
+	}
+
+	/**
+	 * @return the value
+	 */
+	public T get() {
+		return value;
+	}
+
+	/**
+	 * @param value the value to set
+	 */
+	public void set(T value) {
+		this.value = value;
+		listeners.actionForAll(new ValueChange(value != null ? value.toString() : null));
+	}
+
+	public void addListener(EventListener<ValueChange> listener) {
+		listeners.add(listener);
+	}
+
+	public void removeListener(EventListener<ValueChange> listener) {
+		listeners.remove(listener);
+	}
+
+	@Override
+	public String toString() {
+		return Strings.toStringNullProof(value);
+	}
+
+}
Index: java/main/src/main/java/com/framsticks/params/SimpleUniqueList.java
===================================================================
--- java/main/src/main/java/com/framsticks/params/SimpleUniqueList.java	(revision 102)
+++ java/main/src/main/java/com/framsticks/params/SimpleUniqueList.java	(revision 103)
@@ -74,3 +74,7 @@
 		return Collections.unmodifiableMap(children);
 	}
+
+	public Map<String, T> getMap() {
+		return children;
+	}
 }
Index: java/main/src/main/java/com/framsticks/params/UniqueListAccess.java
===================================================================
--- java/main/src/main/java/com/framsticks/params/UniqueListAccess.java	(revision 102)
+++ java/main/src/main/java/com/framsticks/params/UniqueListAccess.java	(revision 103)
@@ -205,5 +205,9 @@
 	@Override
 	public <T> int set(int i, T value) {
-		throw new FramsticksUnsupportedOperationException().msg("accesing unique list through index");
+		if (i != map.size()) {
+			throw new FramsticksUnsupportedOperationException().msg("setting element in unique list through index is available only for addition");
+		}
+		set(getUidOf(value), value);
+		return 0;
 	}
 
Index: java/main/src/main/java/com/framsticks/parsers/AccessStash.java
===================================================================
--- java/main/src/main/java/com/framsticks/parsers/AccessStash.java	(revision 102)
+++ java/main/src/main/java/com/framsticks/parsers/AccessStash.java	(revision 103)
@@ -16,9 +16,10 @@
 	}
 
-	@Override
-	public void addAccess(Access access) {
+	public AccessStash add(Access access) {
 		/**TODO: by id or by name? rather by id, because from file is always lowercase*/
 		accesses.put(access.getId(), access);
+		return this;
 	}
 
+
 }
Index: java/main/src/main/java/com/framsticks/parsers/GenotypeLoader.java
===================================================================
--- java/main/src/main/java/com/framsticks/parsers/GenotypeLoader.java	(revision 102)
+++ java/main/src/main/java/com/framsticks/parsers/GenotypeLoader.java	(revision 103)
@@ -56,5 +56,5 @@
 
 		Access reflectionParam = new PropertiesAccess(entries);
-		addAccess(reflectionParam);
+		setAccessProvider(new AccessStash().add(reflectionParam));
 		addBreakCondition(Status.AfterObject);
 	}
Index: java/main/src/main/java/com/framsticks/parsers/Loaders.java
===================================================================
--- java/main/src/main/java/com/framsticks/parsers/Loaders.java	(revision 102)
+++ java/main/src/main/java/com/framsticks/parsers/Loaders.java	(revision 103)
@@ -22,6 +22,5 @@
 		Access paramBuilderAccess = new ReflectionAccess(ParamBuilder.class, FramsClass.build().forClass(ParamBuilder.class));
 		framsClassAccess.select(builder);
-		loader.addAccess(framsClassAccess);
-		loader.addAccess(paramBuilderAccess);
+		loader.setAccessProvider(new AccessStash().add(framsClassAccess).add(paramBuilderAccess));
 
 		loader.addListener(MultiParamLoader.Status.AfterObject, new MultiParamLoader.StatusListener() {
Index: java/main/src/main/java/com/framsticks/parsers/MultiParamLoader.java
===================================================================
--- java/main/src/main/java/com/framsticks/parsers/MultiParamLoader.java	(revision 102)
+++ java/main/src/main/java/com/framsticks/parsers/MultiParamLoader.java	(revision 103)
@@ -2,4 +2,6 @@
 
 import com.framsticks.params.*;
+import com.framsticks.util.Misc;
+
 import org.apache.logging.log4j.Logger;
 import org.apache.logging.log4j.LogManager;
@@ -87,5 +89,5 @@
 	 * List of known classes.
 	 */
-	protected AccessProvider accessProvider = new AccessStash();
+	protected AccessProvider accessProvider = null;
 
 	/**
@@ -123,4 +125,5 @@
 	 */
 	public Status go() {
+		Misc.throwIfNull(accessProvider);
 		log.trace("go");
 
@@ -310,11 +313,4 @@
 
 	/**
-	 * Adds another class.
-	 */
-	public void addAccess(Access access) {
-		accessProvider.addAccess(access);
-	}
-
-	/**
 	 * Checks whether execution is finished.
 	 */
@@ -443,5 +439,5 @@
 		final MultiParamLoader loader = new MultiParamLoader();
 		loader.setNewSource(source);
-		loader.addAccess(access);
+		loader.setAccessProvider(new AccessStash().add(access));
 		loader.addListener(MultiParamLoader.Status.AfterObject, new StatusListener() {
 			@Override
Index: java/main/src/main/java/com/framsticks/remote/RemoteTree.java
===================================================================
--- java/main/src/main/java/com/framsticks/remote/RemoteTree.java	(revision 102)
+++ java/main/src/main/java/com/framsticks/remote/RemoteTree.java	(revision 103)
@@ -17,5 +17,4 @@
 import com.framsticks.params.types.ProcedureParam;
 import com.framsticks.parsers.Loaders;
-import com.framsticks.parsers.MultiParamLoader;
 import com.framsticks.util.*;
 import com.framsticks.util.dispatching.AtOnceDispatcher;
@@ -29,5 +28,4 @@
 import com.framsticks.util.dispatching.JoinableState;
 import com.framsticks.util.dispatching.ThrowExceptionHandler;
-import com.framsticks.util.lang.Casting;
 import com.framsticks.util.dispatching.RunAt;
 import static com.framsticks.core.TreeOperations.*;
@@ -269,5 +267,5 @@
 
 	@Override
-	public void call(@Nonnull final Path path, @Nonnull final ProcedureParam procedure, @Nonnull Object[] arguments, final Future<Object> future) {
+	public <R> void call(@Nonnull final Path path, @Nonnull final ProcedureParam procedure, @Nonnull Object[] arguments, final Class<R> resultType, final Future<R> future) {
 		assert isActive();
 		assert path.isResolved();
@@ -278,6 +276,15 @@
 			protected void processOk(Response response) {
 				assert isActive();
-				// InstanceUtils.processFetchedValues(path, response.getFiles());
-				future.pass(null);
+
+				if (response.getFiles().size() == 0) {
+					future.pass(null);
+					return;
+				}
+				if (response.getFiles().size() == 1) {
+					future.pass(AccessOperations.convert(resultType, response.getFiles().get(0), registry));
+					return;
+				}
+				throw new FramsticksUnsupportedOperationException().msg("call result with multiple files");
+
 			}
 		});
@@ -303,26 +310,6 @@
 					protected void runAt() {
 						assert isActive();
-						if (argumentType.equals(File.class)) {
-							listener.action(Casting.tryCast(argumentType, file));
-							return;
-						}
-						// Access access = registry.createAccess(argumentType);
-
-						// log.info("executing event with argument {}", argumentType);
-						MultiParamLoader loader = new MultiParamLoader();
-						loader.setNewSource(file.getContent());
-						loader.addBreakCondition(MultiParamLoader.Status.AfterObject);
-						loader.setAccessProvider(registry);
-						// loader.addAccess(access);
-						loader.go();
-						Object argument = loader.getLastAccess().getSelected();
-						// Object argument = access.getSelected();
-						if (argument == null) {
-							listener.action(null);
-						}
-						if (!argumentType.isInstance(argument)) {
-							throw new FramsticksException().msg("created argument is of wrong type").arg("expected", argumentType).arg("created", argument.getClass());
-						}
-						listener.action(argumentType.cast(argument));
+
+						listener.action(AccessOperations.convert(argumentType, file, registry));
 					}
 				});
Index: java/main/src/main/java/com/framsticks/running/ExternalProcess.java
===================================================================
--- java/main/src/main/java/com/framsticks/running/ExternalProcess.java	(revision 102)
+++ java/main/src/main/java/com/framsticks/running/ExternalProcess.java	(revision 103)
@@ -130,5 +130,5 @@
 	@Override
 	protected void joinableStart() {
-		log.debug("running process {}", this);
+		log.info("running process {}", this);
 		builder.command(arguments);
 		try {
Index: java/main/src/main/java/com/framsticks/test/PrimeExperiment.java
===================================================================
--- java/main/src/main/java/com/framsticks/test/PrimeExperiment.java	(revision 102)
+++ java/main/src/main/java/com/framsticks/test/PrimeExperiment.java	(revision 103)
@@ -1,12 +1,21 @@
 package com.framsticks.test;
+
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
 
 import org.apache.logging.log4j.Logger;
 import org.apache.logging.log4j.LogManager;
 
+import com.framsticks.core.ValueChange;
 import com.framsticks.experiment.Experiment;
 import com.framsticks.experiment.WorkPackageLogic;
+import com.framsticks.params.EventListener;
+import com.framsticks.params.EventListeners;
 import com.framsticks.params.annotations.FramsClassAnnotation;
 import com.framsticks.params.annotations.ParamAnnotation;
+import com.framsticks.test.prime.ExpParams;
 import com.framsticks.test.prime.PrimePackage;
+import com.framsticks.util.FramsticksException;
 import com.framsticks.util.dispatching.Future;
 
@@ -18,7 +27,13 @@
 	public final WorkPackageLogic<PrimePackage> workPackageLogic;
 
-	protected int maxNumber = 3000;
+	final PrimePackage task = new PrimePackage();
+
 	protected int step = 100;
-	protected int numberCounter = 1;
+
+	protected int nextWaitNumber = 1;
+	protected List<PrimePackage> waitingPackages = new LinkedList<>();
+	protected List<Integer> primes = new LinkedList<>();
+
+	protected final EventListeners<ValueChange> primesListeners = new EventListeners<>();
 
 	/**
@@ -28,24 +43,113 @@
 		setExpdef("prime");
 
-		workPackageLogic = new WorkPackageLogic<PrimePackage>(this) {
+		task.params.from_number = 1;
+		task.params.to_number = 1000;
+		task.state.current_number = 1;
+
+		workPackageLogic = new WorkPackageLogic<PrimePackage>(this, PrimePackage.class) {
 
 			@Override
 			protected void generateNextPackage(Future<PrimePackage> future) {
 				assert isActive();
-				PrimePackage wp = new PrimePackage();
+				if (task.state.current_number > task.params.to_number) {
+					log.debug("no more packages in range left");
+					future.pass(null);
+					return;
+				}
 
-				log.debug("generated package: {}", wp);
-				wp.params.from_number = numberCounter;
-				numberCounter += step;
-				wp.params.to_number = numberCounter - 1;
-				wp.state.current_number = wp.params.from_number;
-				wp.state.getResultList().clear();
+				PrimePackage wp = PrimePackage.compose(task.state.current_number, Math.min(task.params.to_number, task.state.current_number + step - 1));
+
+				task.state.current_number += step;
+
+				log.debug("generated package: {}", wp.getShortDescription());
 
 				future.pass(wp);
+			}
+
+			@Override
+			protected void returnPackage(PrimePackage result) {
+				log.debug("returned package: {}", result);
+
+				if (tryAddResult(result)) {
+					while (tryMergeWaitingPackages()) {
+					}
+				} else if (result.params.from_number > nextWaitNumber) {
+					waitingPackages.add(result);
+				}
+
+				try {
+					isComplete();
+				} catch (FramsticksException e) {
+					log.debug("experiment is not done yet: {}", e.getShortMessage(new StringBuilder()));
+					return;
+				}
+				log.info("experiment is done, {} primes found", primes.size());
+				log.debug("primes: {}", primes);
 			}
 		};
 	}
 
-	protected void processFile() {
+	protected boolean tryAddResult(PrimePackage result) {
+		if (result.params.from_number > nextWaitNumber) {
+			return false;
+		}
+		if (result.params.from_number < nextWaitNumber) {
+			throw new FramsticksException().msg("duplicate result").arg("result", result);
+		}
+
+		primes.addAll(result.state.getResultList());
+		nextWaitNumber = result.params.to_number + 1;
+
+		primesListeners.actionForAll(new ValueChange(getDescription()));
+
+		return true;
+	}
+
+	protected boolean tryMergeWaitingPackages() {
+		Iterator<PrimePackage> i = waitingPackages.iterator();
+		while (i.hasNext()) {
+			if (tryAddResult(i.next())) {
+				i.remove();
+				return true;
+			}
+		}
+		return false;
+	}
+
+	protected void isComplete() {
+		if (nextWaitNumber - 1 != task.params.to_number) {
+			throw new FramsticksException().msg("not ready yet").arg("done to", nextWaitNumber - 1);
+		}
+	}
+
+	/**
+	 * @return the maxNumber
+	 */
+	@ParamAnnotation
+	public int getMaxNumber() {
+		return task.params.to_number;
+	}
+
+	/**
+	 * @param maxNumber the maxNumber to set
+	 */
+	@ParamAnnotation
+	public void setMaxNumber(int maxNumber) {
+		task.params.to_number = maxNumber;
+	}
+
+	@ParamAnnotation
+	public String getDescription() {
+		return primes.size() + " found in range " + new ExpParams(task.params.from_number, nextWaitNumber - 1);
+	}
+
+	@ParamAnnotation(id = "description_changed")
+	public void addPrimesListener(EventListener<ValueChange> listener) {
+		primesListeners.add(listener);
+	}
+
+	@ParamAnnotation(id = "description_changed")
+	public void removePrimesListener(EventListener<ValueChange> listener) {
+		primesListeners.remove(listener);
 	}
 
Index: java/main/src/main/java/com/framsticks/test/TestChangeEvent.java
===================================================================
--- java/main/src/main/java/com/framsticks/test/TestChangeEvent.java	(revision 102)
+++ 	(revision )
@@ -1,17 +1,0 @@
-package com.framsticks.test;
-
-import com.framsticks.params.annotations.FramsClassAnnotation;
-import com.framsticks.params.annotations.ParamAnnotation;
-
-@FramsClassAnnotation
-public class TestChangeEvent {
-
-	@ParamAnnotation
-	public String history;
-
-	@Override
-	public String toString() {
-		return "[test change event: " + history + "]";
-	}
-
-}
Index: java/main/src/main/java/com/framsticks/test/TestChild.java
===================================================================
--- java/main/src/main/java/com/framsticks/test/TestChild.java	(revision 102)
+++ java/main/src/main/java/com/framsticks/test/TestChild.java	(revision 103)
@@ -10,10 +10,10 @@
 	protected String name = "child";
 
-	protected final TestClass parent;
+	protected TestClass parent;
+
 	/**
 	 *
 	 */
-	public TestChild(TestClass parent) {
-		this.parent = parent;
+	public TestChild() {
 	}
 
@@ -32,5 +32,12 @@
 	public void setName(String name) {
 		this.name = name;
-		parent.children.modify(this);
+		if (parent != null) {
+			parent.children.modify(this);
+		}
+	}
+
+	@Override
+	public String toString() {
+		return "test child " + name;
 	}
 
Index: java/main/src/main/java/com/framsticks/test/TestClass.java
===================================================================
--- java/main/src/main/java/com/framsticks/test/TestClass.java	(revision 102)
+++ java/main/src/main/java/com/framsticks/test/TestClass.java	(revision 103)
@@ -7,7 +7,9 @@
 
 import com.framsticks.core.ListChange;
+import com.framsticks.core.ValueChange;
 import com.framsticks.params.EventListener;
-import com.framsticks.params.EventListeners;
+import com.framsticks.params.SimplePrimitive;
 import com.framsticks.params.SimpleUniqueList;
+import com.framsticks.params.annotations.AutoAppendAnnotation;
 import com.framsticks.params.annotations.FramsClassAnnotation;
 import com.framsticks.params.annotations.ParamAnnotation;
@@ -27,11 +29,9 @@
 )
 public class TestClass {
-	private static final Logger log =
-		LogManager.getLogger(TestClass.class);
+	private static final Logger log = LogManager.getLogger(TestClass.class);
 
 
 	protected String name = "test";
-	protected String history = "initial|";
-	protected final EventListeners<TestChangeEvent> historyListeners = new EventListeners<>();
+	protected final SimplePrimitive<String> history = new SimplePrimitive<>("initial|");
 
 	protected final SimpleUniqueList<TestChild> children = new SimpleUniqueList<>(TestChild.class, 'c');
@@ -64,5 +64,5 @@
 	@ParamAnnotation
 	public String getHistory() {
-		return history;
+		return history.get();
 	}
 
@@ -72,5 +72,5 @@
 	@ParamAnnotation
 	public void setHistory(String history) {
-		this.history = history;
+		this.history.set(history);
 	}
 
@@ -80,5 +80,5 @@
 	@ParamAnnotation
 	public Map<String, TestChild> getChildren() {
-		return children.getView();
+		return children.getMap();
 	}
 
@@ -86,7 +86,7 @@
 	public int appendHistory(String line) {
 		log.debug("appending '{}'", line);
-		history = history + line + "|";
-		fireHistoryChange();
-		return history.length();
+		history.set(history.get() + line + "|");
+		// fireHistoryChange();
+		return history.get().length();
 	}
 
@@ -94,30 +94,28 @@
 	public void resetHistory() {
 		log.debug("reseting");
-		history = "";
-		fireHistoryChange();
+		history.set("");
 	}
 
 	@ParamAnnotation(paramType = ProcedureParam.class)
 	public void createChild(String name) {
-		TestChild child = new TestChild(this);
+		TestChild child = new TestChild();
 		child.name = name;
+		addChild(child);
+	}
+
+	@AutoAppendAnnotation
+	public void addChild(TestChild child) {
+		child.parent = this;
 		children.add(child);
 	}
 
-	protected void fireHistoryChange() {
-		TestChangeEvent event = new TestChangeEvent();
-		event.history = history;
-		historyListeners.actionForAll(event);
-	}
-
-
 	@ParamAnnotation(id = "history_changed")
-	public void addHistoryListener(EventListener<TestChangeEvent> listener) {
-		historyListeners.add(listener);
+	public void addHistoryListener(EventListener<ValueChange> listener) {
+		history.addListener(listener);
 	}
 
 	@ParamAnnotation(id = "history_changed")
-	public void removeHistoryListener(EventListener<TestChangeEvent> listener) {
-		historyListeners.remove(listener);
+	public void removeHistoryListener(EventListener<ValueChange> listener) {
+		history.removeListener(listener);
 	}
 
Index: java/main/src/main/java/com/framsticks/test/prime/ExpParams.java
===================================================================
--- java/main/src/main/java/com/framsticks/test/prime/ExpParams.java	(revision 102)
+++ java/main/src/main/java/com/framsticks/test/prime/ExpParams.java	(revision 103)
@@ -13,7 +13,26 @@
 	public int to_number;
 
+	/**
+	 *
+	 */
+	public ExpParams() {
+	}
+
+	/**
+	 * @param from_number
+	 * @param to_number
+	 */
+	public ExpParams(int from_number, int to_number) {
+		this.from_number = from_number;
+		this.to_number = to_number;
+	}
+
 	@Override
 	public String toString() {
 		return "[" + from_number + ":" + to_number + "]";
 	}
+
+	public boolean isInsideOf(ExpParams outer) {
+		return from_number >= outer.from_number && to_number <= outer.to_number;
+	}
 }
Index: java/main/src/main/java/com/framsticks/test/prime/PrimePackage.java
===================================================================
--- java/main/src/main/java/com/framsticks/test/prime/PrimePackage.java	(revision 102)
+++ java/main/src/main/java/com/framsticks/test/prime/PrimePackage.java	(revision 103)
@@ -1,12 +1,16 @@
 package com.framsticks.test.prime;
 
+import com.framsticks.experiment.InvalidWorkPackage;
 import com.framsticks.experiment.WorkPackage;
 import com.framsticks.params.annotations.FramsClassAnnotation;
+import com.framsticks.params.annotations.ParamAnnotation;
 
-@FramsClassAnnotation
-public class PrimePackage implements WorkPackage {
+@FramsClassAnnotation(order = {"params", "state"})
+public class PrimePackage implements WorkPackage<PrimePackage> {
 
+	@ParamAnnotation
 	public final ExpParams params = new ExpParams();
 
+	@ParamAnnotation
 	public final ExpState state = new ExpState();
 
@@ -16,3 +20,39 @@
 	}
 
+	@Override
+	public String sumUpTask() {
+		return params.toString();
+	}
+
+	@Override
+	public String sumUpResult() {
+		return state.toString();
+	}
+
+	@Override
+	public String getShortDescription() {
+		return params.toString();
+	}
+
+	public static PrimePackage compose(int from, int to) {
+		PrimePackage wp = new PrimePackage();
+		wp.params.from_number = from;
+		wp.params.to_number = to;
+		wp.state.current_number = from;
+		return wp;
+	}
+
+	@Override
+	public PrimePackage getRemainder(PrimePackage result) {
+		if (!result.params.isInsideOf(params)) {
+			throw new InvalidWorkPackage().msg("result is not inside of task");
+		}
+		if (result.params.from_number != params.from_number) {
+			throw new InvalidWorkPackage().msg("result is not subpackage");
+		}
+		if (result.state.current_number == params.to_number + 1) {
+			return null;
+		}
+		return compose(result.state.current_number, params.to_number);
+	}
 }
Index: java/main/src/main/java/com/framsticks/util/Misc.java
===================================================================
--- java/main/src/main/java/com/framsticks/util/Misc.java	(revision 102)
+++ java/main/src/main/java/com/framsticks/util/Misc.java	(revision 103)
@@ -59,5 +59,9 @@
 			return;
 		}
-		throw new FramsticksException().msg(message).arg("expected", expected).arg("found", found).arg("in", context);
+		FramsticksException e = new FramsticksException().msg(message).arg("expected", expected).arg("found", found);
+		if (context != null) {
+			e.arg("in", context);
+		}
+		throw e;
 	}
 }
Index: java/main/src/main/resources/log4j2.xml
===================================================================
--- java/main/src/main/resources/log4j2.xml	(revision 102)
+++ java/main/src/main/resources/log4j2.xml	(revision 103)
@@ -17,10 +17,10 @@
 		<!-- <logger name="com.framsticks.util.dispatching.AbstractJoinable.Report" level="info" /> -->
 		<!-- <logger name="com.framsticks.util.dispatching.Monitor" level="debug" /> -->
-		<logger name="com.framsticks.util.dispatching.BufferedDispatcher" level="debug" />
+		<!-- <logger name="com.framsticks.util.dispatching.BufferedDispatcher" level="debug" /> -->
 		<!-- <logger name="com.framsticks.util.dispatching.Dispatching" level="debug" /> -->
-		<logger name="com.framsticks.running" level="debug" />
+		<!-- <logger name="com.framsticks.running" level="debug" /> -->
 		<!-- <logger name="com.framsticks.communication" level="debug" /> -->
-		<logger name="com.framsticks.experiment" level="debug" />
-		<logger name="com.framsticks.experiment.Simulator" level="debug" />
+		<!-- <logger name="com.framsticks.experiment" level="debug" /> -->
+		<!-- <logger name="com.framsticks.experiment.Simulator" level="debug" /> -->
 		<root level="info">
 			<appender-ref ref="Console"/>
Index: java/main/src/main/resources/prime.xml
===================================================================
--- java/main/src/main/resources/prime.xml	(revision 102)
+++ java/main/src/main/resources/prime.xml	(revision 103)
@@ -8,5 +8,5 @@
 	<Server port="9007">
 		<LocalTree name="prime-local-tree">
-			<PrimeExperiment>
+			<PrimeExperiment maxNumber="30000">
 				<SimulatorConnector address="localhost:9100" />
 				<SimulatorConnector address="localhost:9101" />
Index: java/main/src/test/java/com/framsticks/gui/ProcedureBrowserTest.java
===================================================================
--- java/main/src/test/java/com/framsticks/gui/ProcedureBrowserTest.java	(revision 102)
+++ java/main/src/test/java/com/framsticks/gui/ProcedureBrowserTest.java	(revision 103)
@@ -10,4 +10,5 @@
 import com.framsticks.core.Tree;
 import com.framsticks.core.LocalTree;
+import com.framsticks.core.ValueChange;
 import com.framsticks.params.Access;
 import com.framsticks.params.EventListener;
@@ -17,5 +18,4 @@
 import com.framsticks.params.types.StringParam;
 import com.framsticks.parsers.XmlLoader;
-import com.framsticks.test.TestChangeEvent;
 import com.framsticks.test.TestClass;
 import com.framsticks.util.dispatching.FutureHandler;
@@ -82,9 +82,9 @@
 		waitForIdle();
 
-		final EventListener<TestChangeEvent> listener = new EventListener<TestChangeEvent>() {
+		final EventListener<ValueChange> listener = new EventListener<ValueChange>() {
 
 			@Override
-			public void action(TestChangeEvent argument) {
-				assertThat(argument.history).isEqualTo("");
+			public void action(ValueChange argument) {
+				assertThat(argument.value).isEqualTo("");
 			}
 		};
@@ -96,5 +96,5 @@
 				assertThat(access.get("history", String.class)).isEqualTo("initial|Żółw|");
 
-				tree.addListener(Path.to(tree, "/"), access.getFramsClass().getParamEntry("history_changed", EventParam.class), listener, TestChangeEvent.class, FutureHandler.doNothing(Void.class, failOnException));
+				tree.addListener(Path.to(tree, "/"), access.getFramsClass().getParamEntry("history_changed", EventParam.class), listener, ValueChange.class, FutureHandler.doNothing(Void.class, failOnException));
 			}
 		});
Index: java/main/src/test/java/com/framsticks/hosting/ServerTest.java
===================================================================
--- java/main/src/test/java/com/framsticks/hosting/ServerTest.java	(revision 102)
+++ java/main/src/test/java/com/framsticks/hosting/ServerTest.java	(revision 103)
@@ -11,9 +11,10 @@
 import com.framsticks.core.LocalTree;
 import com.framsticks.core.Path;
+import com.framsticks.core.Result;
 import com.framsticks.core.TreeOperations;
+import com.framsticks.core.ValueChange;
 import com.framsticks.core.XmlBasedTest;
 import com.framsticks.remote.RemoteTree;
 
-import com.framsticks.test.TestChangeEvent;
 import com.framsticks.test.TestClass;
 import com.framsticks.core.Tree;
@@ -45,5 +46,5 @@
 	protected LocalTree hosted;
 	protected TestClass hostedObject;
-	protected EventListener<TestChangeEvent> listener;
+	protected EventListener<ValueChange> listener;
 	protected EventListener<ListChange> childListener;
 
@@ -123,9 +124,9 @@
 	public void registerListener() {
 		final Waiter waiter = produceWaiter(1.0);
-		listener = new EventListener<TestChangeEvent>() {
-
-			@Override
-			public void action(TestChangeEvent argument) {
-				listenerArguments.add(argument.history);
+		listener = new EventListener<ValueChange>() {
+
+			@Override
+			public void action(ValueChange argument) {
+				listenerArguments.add(argument.value.toString());
 			}
 		};
@@ -138,5 +139,5 @@
 		});
 
-		addListener(remotePath, remoteTestFramsClass.getParamEntry("history_changed", EventParam.class), listener, TestChangeEvent.class, produceWaiter(1.0).passInFuture(Void.class));
+		addListener(remotePath, remoteTestFramsClass.getParamEntry("history_changed", EventParam.class), listener, ValueChange.class, produceWaiter(1.0).passInFuture(Void.class));
 	}
 
@@ -145,12 +146,14 @@
 		final Waiter waiter = produceWaiter(2.0);
 
-		call(remotePath, remoteTestFramsClass.getParamEntry("resetHistory", ProcedureParam.class), new Object[] {}, produceWaiter(2.0).passInFuture(Object.class));
-
-		call(remotePath, remoteTestFramsClass.getParamEntry("appendHistory", ProcedureParam.class), new Object[] {"next word"}, new FutureHandler<Object>(failOnException) {
-			@Override
-			protected void result(Object result) {
+		call(remotePath, remoteTestFramsClass.getParamEntry("resetHistory", ProcedureParam.class), new Object[] {}, Object.class, produceWaiter(2.0).passInFuture(Object.class));
+
+		call(remotePath, remoteTestFramsClass.getParamEntry("appendHistory", ProcedureParam.class), new Object[] {"next word"}, Result.class, new FutureHandler<Result>(failOnException) {
+			@Override
+			protected void result(final Result result) {
 				hosted.dispatch(new RunAt<Tree>(failOnException) {
 					@Override
 					protected void runAt() {
+						// assert
+
 						assertThat(hostedObject.getHistory()).isEqualTo("next word|");
 						waiter.pass();
@@ -186,6 +189,6 @@
 	public void createChild() {
 		final Waiter waiter = produceWaiter(2.0);
-		call(remotePath, "createChild", new Object[] { "a child" }, produceWaiter(2.0).passInFuture(Object.class));
-		call(remotePath, "createChild", new Object[] { "another child" }, produceWaiter(2.0).passInFuture(Object.class));
+		call(remotePath, "createChild", new Object[] { "a child" }, Object.class, produceWaiter(2.0).passInFuture(Object.class));
+		call(remotePath, "createChild", new Object[] { "another child" }, Object.class, produceWaiter(2.0).passInFuture(Object.class));
 
 		tryGet(remote, "/testClass/children/c0", new FutureHandler<Path>(failOnException) {
Index: java/main/src/test/java/com/framsticks/params/AccessOperationsTest.java
===================================================================
--- java/main/src/test/java/com/framsticks/params/AccessOperationsTest.java	(revision 103)
+++ java/main/src/test/java/com/framsticks/params/AccessOperationsTest.java	(revision 103)
@@ -0,0 +1,79 @@
+package com.framsticks.params;
+
+import static org.fest.assertions.Assertions.*;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+import com.framsticks.test.TestClass;
+import com.framsticks.test.TestConfiguration;
+import static com.framsticks.params.AccessOperations.*;
+
+@Test
+public class AccessOperationsTest extends TestConfiguration {
+
+	Registry registry;
+
+	TestClass testObject;
+
+	List<String> printResult;
+
+	List<String> printed = Arrays.asList(
+		"TestClass:",
+		"name:just a test",
+		"history:a very, very long history...",
+		"",
+		"TestChild:",
+		"name:first child",
+		"uid:c0",
+		"",
+		"TestChild:",
+		"name:second child",
+		"uid:c1",
+		""
+	);
+
+	@BeforeClass
+	public void setUp() {
+		registry = new Registry();
+		registry.registerAndBuild(TestClass.class);
+
+		testObject = new TestClass();
+		testObject.setName("just a test");
+		testObject.setHistory("a very, very long history...");
+
+		testObject.createChild("first child");
+		testObject.createChild("second child");
+	}
+
+	@Test
+	public void testEquals() {
+		assertThat(areEqual(registry.bindAccessFor(testObject), registry.bindAccessFor(testObject), registry)).isTrue();
+	}
+
+	@Test
+	public void testSaveAll() {
+
+		ListSink sink = new ListSink();
+		saveAll(registry.bindAccessFor(testObject), sink, registry);
+		printResult = sink.getOut();
+
+		assertThat(printResult).isEqualTo(printed);
+	}
+
+	@Test
+	public void testLoadAll() {
+		TestClass testLoad = new TestClass();
+		loadAll(registry.bindAccessFor(testLoad), new ListSource(printed), registry);
+		assertThat(areEqual(registry.bindAccessFor(testLoad), registry.bindAccessFor(testObject), registry)).isTrue();
+
+		ListSink sink = new ListSink();
+		saveAll(registry.bindAccessFor(testLoad), sink, registry);
+
+		assertThat(sink.getOut()).isEqualTo(printed);
+	}
+
+}
Index: java/main/src/test/java/com/framsticks/params/FramsClassBuilderTest.java
===================================================================
--- java/main/src/test/java/com/framsticks/params/FramsClassBuilderTest.java	(revision 102)
+++ java/main/src/test/java/com/framsticks/params/FramsClassBuilderTest.java	(revision 103)
@@ -6,9 +6,9 @@
 import org.testng.annotations.Test;
 
+import com.framsticks.core.ValueChange;
 import com.framsticks.params.types.EventParam;
 import com.framsticks.params.types.ProcedureParam;
 import com.framsticks.params.types.StringParam;
 import com.framsticks.parsers.Savers;
-import com.framsticks.test.TestChangeEvent;
 import com.framsticks.test.TestClass;
 import com.framsticks.test.TestConfiguration;
@@ -69,5 +69,5 @@
 					"id:history_changed",
 					"name:HistoryListener",
-					"type:e TestChangeEvent",
+					"type:e ValueChange",
 					"",
 					"prop:",
@@ -128,9 +128,9 @@
 		final Holder<String> called = new Holder<>();
 
-		final EventListener<TestChangeEvent> listener = new EventListener<TestChangeEvent>() {
+		final EventListener<ValueChange> listener = new EventListener<ValueChange>() {
 
 			@Override
-			public void action(TestChangeEvent argument) {
-				called.set(argument.history);
+			public void action(ValueChange argument) {
+				called.set(argument.value.toString());
 			}
 		};
Index: java/main/src/test/java/com/framsticks/params/ParamBuilderTest.java
===================================================================
--- java/main/src/test/java/com/framsticks/params/ParamBuilderTest.java	(revision 102)
+++ java/main/src/test/java/com/framsticks/params/ParamBuilderTest.java	(revision 103)
@@ -5,4 +5,5 @@
 import com.framsticks.params.types.FloatParam;
 import com.framsticks.params.types.StringParam;
+import com.framsticks.parsers.AccessStash;
 import com.framsticks.parsers.MultiParamLoader;
 import com.framsticks.test.TestConfiguration;
@@ -34,5 +35,5 @@
 		MultiParamLoader loader = new MultiParamLoader();
 		loader.setNewSource(source);
-		loader.addAccess(access);
+		loader.setAccessProvider(new AccessStash().add(access));
 		loader.addBreakCondition(MultiParamLoader.Status.AfterObject);
 
Index: java/main/src/test/java/com/framsticks/test/prime/PrimePackageTest.java
===================================================================
--- java/main/src/test/java/com/framsticks/test/prime/PrimePackageTest.java	(revision 102)
+++ java/main/src/test/java/com/framsticks/test/prime/PrimePackageTest.java	(revision 103)
@@ -1,8 +1,19 @@
 package com.framsticks.test.prime;
 
-// import static org.fest.assertions.Assertions.*;
+import static org.fest.assertions.Assertions.*;
 
+import java.util.Arrays;
+import java.util.List;
+
+import org.testng.annotations.BeforeClass;
 import org.testng.annotations.Test;
 
+import com.framsticks.params.AccessOperations;
+import com.framsticks.params.FramsClass;
+import com.framsticks.params.ListSink;
+import com.framsticks.params.ListSource;
+// import com.framsticks.params.ListSource;
+import com.framsticks.params.Registry;
+import com.framsticks.params.types.ObjectParam;
 import com.framsticks.test.TestConfiguration;
 
@@ -10,16 +21,67 @@
 public class PrimePackageTest extends TestConfiguration {
 
+	Registry registry;
 
+	protected final List<String> printedPrimePackage = Arrays.asList(
+		"ExpParams:",
+		"from_number:100",
+		"to_number:200",
+		"",
+		"ExpState:",
+		"current_number:201",
+		"result:151,157,163,167,173,179,181,191,193,197,199",
+		""
+	);
 
+	@BeforeClass
+	public void setupRegistry() {
+		registry = new Registry();
+		registry.registerAndBuild(PrimePackage.class);
+	}
 
 	@Test
+	public void primePackageFramsClass() {
+		FramsClass framsClass = registry.getFramsClassForJavaClass(PrimePackage.class);
+		assertThat(framsClass).isNotNull();
+		assertThat(framsClass.getParamCount()).isEqualTo(2);
+		assertThat(framsClass.getParam(0)).isInstanceOf(ObjectParam.class);
+		assertThat(framsClass.getParam(1)).isInstanceOf(ObjectParam.class);
+	}
+
+	@Test(dependsOnMethods = "primePackageFramsClass")
 	public void printPrimePackage() {
+		PrimePackage primePackage = new PrimePackage();
+		primePackage.params.from_number = 100;
+		primePackage.params.to_number = 200;
+
+		primePackage.state.current_number = 201;
+		primePackage.state.getResultList().addAll(Arrays.asList(151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199));
+
+		assertThat(primePackage.state.getResult()).isEqualTo("151,157,163,167,173,179,181,191,193,197,199");
+
+		ListSink sink = new ListSink();
+
+		AccessOperations.saveAll(registry.createAccess(PrimePackage.class).select(primePackage), sink, registry);
+
+		assertThat(sink.getOut()).isEqualTo(printedPrimePackage);
 	}
-	// ExpParams:
-	// from_number:100
-	// to_number:200
 
-	// ExpState:
-	// current_number:201
-	// result:151,157,163,167,173,179,181,191,193,197,199
+	@Test(dependsOnMethods = "printPrimePackage")
+	public void loadPrimePackage() {
+
+		// PrimePackage primePackage = new PrimePackage();
+
+		ListSource source = new ListSource(printedPrimePackage);
+
+		Object result = AccessOperations.loadAll(registry.createAccess(PrimePackage.class), source, registry).getSelected();
+		assertThat(result).isInstanceOf(PrimePackage.class);
+		PrimePackage primePackage = (PrimePackage) result;
+
+		assertThat(primePackage.params.from_number).isEqualTo(100);
+		assertThat(primePackage.params.to_number).isEqualTo(200);
+
+		assertThat(primePackage.state.current_number).isEqualTo(201);
+		assertThat(primePackage.state.getResultList()).isEqualTo(Arrays.asList(151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199));
+
+	}
 }
Index: java/main/src/test/resources/log4j2.xml
===================================================================
--- java/main/src/test/resources/log4j2.xml	(revision 102)
+++ java/main/src/test/resources/log4j2.xml	(revision 103)
@@ -8,8 +8,12 @@
 	<loggers>
 		<logger name="com.framsticks" level="info" />
-		<logger name="com.framsticks.running.ExternalProcess" level="debug" />
 		<logger name="com.framsticks.test.TestConfiguration" level="info" />
-		<logger name="com.framsticks.experiment" level="debug" />
-		<logger name="com.framsticks.test.PrimeExperiment" level="debug" />
+
+		<!-- <logger name="com.framsticks.running.ExternalProcess" level="debug" /> -->
+		<!-- <logger name="com.framsticks.experiment" level="debug" /> -->
+		<!-- <logger name="com.framsticks.test.PrimeExperiment" level="debug" /> -->
+		<!-- <logger name="com.framsticks.experiment.NetLoadSaveLogic" level="debug" /> -->
+		<!-- <logger name="com.framsticks.experiment.WorkPackageLogic" level="debug" /> -->
+		<!-- <logger name="com.framsticks.params.AccessOperations" level="debug" /> -->
 		<!-- <logger name="com.framsticks.util.dispatching.AbstractJoinable" level="debug" /> -->
 		<!-- <logger name="com.framsticks.util.dispatching.AbstractJoinable.Report" level="info" /> -->
