Index: java/main/src/main/java/com/framsticks/communication/ClientSideManagedConnection.java
===================================================================
--- java/main/src/main/java/com/framsticks/communication/ClientSideManagedConnection.java	(revision 98)
+++ java/main/src/main/java/com/framsticks/communication/ClientSideManagedConnection.java	(revision 99)
@@ -2,9 +2,10 @@
 
 import com.framsticks.communication.queries.ApplicationRequest;
+import com.framsticks.communication.queries.CallRequest;
 import com.framsticks.communication.queries.ProtocolRequest;
-import com.framsticks.communication.queries.RegistrationRequest;
+import com.framsticks.communication.queries.RegisterRequest;
 import com.framsticks.communication.queries.UseRequest;
 import com.framsticks.communication.queries.VersionRequest;
-import com.framsticks.communication.util.LoggingStateCallback;
+import com.framsticks.core.Path;
 import com.framsticks.params.ListSource;
 import com.framsticks.util.*;
@@ -18,4 +19,5 @@
 import com.framsticks.util.lang.Pair;
 import com.framsticks.util.lang.Strings;
+import com.framsticks.params.EventListener;
 
 import org.apache.log4j.Logger;
@@ -32,8 +34,7 @@
 	private final static Logger log = Logger.getLogger(ClientSideManagedConnection.class);
 
-	protected final Map<String, Subscription<?>> subscriptions = new HashMap<>();
-
 	private final List<Runnable> applicationRequestsBuffer = new LinkedList<>();
 	private boolean isHandshakeDone = false;
+
 
 	/**
@@ -93,22 +94,11 @@
 	}
 
-	private static class EventFire extends InboundMessage {
-		public final Subscription<?> subscription;
-
-		private EventFire(Subscription<?> subscription) {
-			this.subscription = subscription;
-		}
-
-		public void startFile(String path) {
-			assert path == null;
-			initCurrentFile(null);
-		}
-
-		@Override
-		public void eof() {
-			finishCurrentFile();
-
-			subscription.dispatchCall(getFiles());
-		}
+	protected List<String> readFileContent() {
+		List<String> content = new LinkedList<String>();
+		String line;
+		while (!(line = getLine()).startsWith("eof")) {
+			content.add(line);
+		}
+		return content;
 	}
 
@@ -239,22 +229,4 @@
 	}
 
-	public <C> void subscribe(final String path, final Dispatcher<C> dispatcher, final SubscriptionCallback<? extends C> callback) {
-		send(new RegistrationRequest().path(path), AtOnceDispatcher.getInstance(), new ClientSideResponseFuture(callback) {
-			@Override
-			protected void processOk(Response response) {
-				assert response.getFiles().isEmpty();
-				Subscription<C> subscription = new Subscription<C>(ClientSideManagedConnection.this, path, response.getComment(), dispatcher);
-				log.debug("registered on event: " + subscription);
-				synchronized (subscriptions) {
-					subscriptions.put(subscription.getRegisteredPath(), subscription);
-				}
-				subscription.setEventCallback(callback.subscribed(subscription));
-				if (subscription.getEventCallback() == null) {
-					log.info("subscription for " + path + " aborted");
-					subscription.unsubscribe(new LoggingStateCallback(log, "abort subscription"));
-				}
-			}
-		});
-	}
 
 	private void sendQueryVersion(final int version, final Future<Void> future) {
@@ -322,15 +294,22 @@
 		Matcher matcher = Request.EVENT_PATTERN.matcher(rest);
 		if (!matcher.matches()) {
-			log.error("invalid event line: " + rest);
-			return;
-		}
-		Subscription<?> subscription = subscriptions.get(matcher.group(1));
-		if (subscription == null) {
-			log.error("non subscribed event: " + matcher.group(1));
-			return;
-		}
-		EventFire event = new EventFire(subscription);
-		event.startFile(null);
-		processMessage(event);
+			throw new FramsticksException().msg("invalid event line").arg("rest", rest);
+		}
+		String fileLine = getLine();
+		if (!fileLine.equals("file")) {
+			throw new FramsticksException().msg("expected file line").arg("got", fileLine);
+		}
+		String eventObjectPath = Request.takeGroup(rest, matcher, 1).toString();
+		String eventCalleePath = Request.takeGroup(rest, matcher, 2).toString();
+		final File file = new File("", new ListSource(readFileContent()));
+		log.debug("firing event " + eventObjectPath);
+		EventListener<File> listener;
+		synchronized (registeredListeners) {
+			listener = registeredListeners.get(eventObjectPath);
+		}
+		if (listener  == null) {
+			throw new FramsticksException().msg("failed to find registered event").arg("event path", eventObjectPath).arg("object", eventCalleePath);
+		}
+		listener.action(file);
 	}
 
@@ -397,3 +376,45 @@
 	}
 
+	protected final Map<String, EventListener<File>> registeredListeners = new HashMap<>();
+
+	public <C> void addListener(String path, final EventListener<File> listener, final Dispatcher<C> dispatcher, final Future<Void> future) {
+		send(new RegisterRequest().path(path), dispatcher, new ClientSideResponseFuture(future) {
+			@Override
+			protected void processOk(Response response) {
+				synchronized (registeredListeners) {
+					registeredListeners.put(Path.validateString(response.getComment()), listener);
+				}
+				future.pass(null);
+			}
+		});
+	}
+
+	public <C> void removeListener(EventListener<File> listener, final Dispatcher<C> dispatcher, final Future<Void> future) {
+		String eventPath = null;
+		synchronized (registeredListeners) {
+			for (Map.Entry<String, EventListener<File>> e : registeredListeners.entrySet()) {
+				if (e.getValue() == listener) {
+					eventPath = e.getKey();
+					break;
+				}
+			}
+		}
+		if (eventPath == null) {
+			future.handle(new FramsticksException().msg("listener is not registered").arg("listener", listener));
+			return;
+		}
+
+		final String finalEventPath = eventPath;
+				//TODO add arguments to the exception
+		send(new CallRequest().procedure("remove").path(eventPath), dispatcher, new ClientSideResponseFuture(future) {
+
+			@Override
+			protected void processOk(Response response) {
+				synchronized (registeredListeners) {
+					registeredListeners.remove(finalEventPath);
+				}
+				future.pass(null);
+			}
+		});
+	}
 }
Index: java/main/src/main/java/com/framsticks/communication/Request.java
===================================================================
--- java/main/src/main/java/com/framsticks/communication/Request.java	(revision 98)
+++ java/main/src/main/java/com/framsticks/communication/Request.java	(revision 99)
@@ -37,5 +37,5 @@
 			case "info": return new InfoRequest();
 			case "call": return new CallRequest();
-			case "reg": return new RegistrationRequest();
+			case "reg": return new RegisterRequest();
 			case "use": return new UseRequest();
 			case "version": return new VersionRequest();
Index: java/main/src/main/java/com/framsticks/communication/ServerSideManagedConnection.java
===================================================================
--- java/main/src/main/java/com/framsticks/communication/ServerSideManagedConnection.java	(revision 98)
+++ java/main/src/main/java/com/framsticks/communication/ServerSideManagedConnection.java	(revision 99)
@@ -68,4 +68,25 @@
 	}
 
+	protected final void putFile(File file, String outId) {
+		putLine("file" + outId/* + " " + f.getPath()*/);
+		SourceInterface content = file.getContent();
+		String line;
+		while ((line = content.readLine()) != null) {
+			putLine(line);
+		}
+		putLine("eof");
+	}
+
+	public final void sendFile(final String header, final File file) {
+		senderThread.dispatch(new RunAt<Connection>(requestHandler) {
+			@Override
+			protected void runAt() {
+				putLine(header);
+				putFile(file, "");
+				flushOut();
+			}
+		});
+	}
+
 	protected final void respond(final Response response, final Integer id) {
 		senderThread.dispatch(new RunAt<Connection>(requestHandler) {
@@ -75,11 +96,5 @@
 				if (response.getFiles() != null) {
 					for (File f : response.getFiles()) {
-						putLine("file" + outId/* + " " + f.getPath()*/);
-						SourceInterface content = f.getContent();
-						String line;
-						while ((line = content.readLine()) != null) {
-							putLine(line);
-						}
-						putLine("eof");
+						putFile(f, outId);
 					}
 				}
@@ -87,5 +102,5 @@
 				statusLine.append(response.getOk() ? "ok" : "error").append(outId);
 				if (Strings.notEmpty(response.getComment())) {
-					statusLine.append(" \"").append(response.getComment()).append('"');
+					Request.quoteValue(statusLine.append(" "), response.getComment());
 				}
 				putLine(statusLine.toString());
Index: java/main/src/main/java/com/framsticks/communication/ServerSideResponseFuture.java
===================================================================
--- java/main/src/main/java/com/framsticks/communication/ServerSideResponseFuture.java	(revision 98)
+++ java/main/src/main/java/com/framsticks/communication/ServerSideResponseFuture.java	(revision 99)
@@ -11,5 +11,5 @@
 	@Override
 	public final void handle(FramsticksException e) {
-		result(new Response(false, e.getClass().getCanonicalName() + ": " + e.getMsg(), null));
+		result(new Response(false, e.getClass().getCanonicalName() + ": " + e.getMessage(), null));
 	}
 
Index: java/main/src/main/java/com/framsticks/communication/Subscription.java
===================================================================
--- java/main/src/main/java/com/framsticks/communication/Subscription.java	(revision 98)
+++ 	(revision )
@@ -1,82 +1,0 @@
-package com.framsticks.communication;
-
-import java.util.List;
-
-import com.framsticks.communication.queries.RegistrationRequest;
-import com.framsticks.util.dispatching.AtOnceDispatcher;
-import com.framsticks.util.dispatching.Dispatcher;
-import com.framsticks.util.dispatching.Dispatching;
-import com.framsticks.util.dispatching.RunAt;
-import com.framsticks.util.dispatching.ThrowExceptionHandler;
-
-import org.apache.log4j.Logger;
-
-
-/**
- * @author Piotr Sniegowski
- */
-public class Subscription<C> {
-
-	private final static Logger log = Logger.getLogger(Subscription.class);
-
-	private final ClientSideManagedConnection connection;
-	private final String path;
-	private final String registeredPath;
-	private final Dispatcher<C> dispatcher;
-
-	private EventCallback eventCallback;
-
-	public Subscription(ClientSideManagedConnection connection, String path, String registeredPath, Dispatcher<C> dispatcher) {
-		this.connection = connection;
-		this.path = path;
-		this.registeredPath = registeredPath;
-		this.dispatcher = dispatcher;
-	}
-
-	public String getPath () {
-		return path;
-	}
-
-	public String getRegisteredPath() {
-		return registeredPath;
-	}
-
-	@Override
-	public String toString() {
-		return path + "(" + registeredPath + ")";
-	}
-
-	public void unsubscribe(final ClientSideResponseFuture future) {
-		//@todo remove that /cli/ prefix, when registeredPath will be a fully qualified path
-		connection.send(new RegistrationRequest().register(false).path(registeredPath), AtOnceDispatcher.getInstance(), new ClientSideResponseFuture(future) {
-
-			@Override
-			protected void processOk(Response response) {
-				assert response.hasFiles();
-				log.debug("unsunscribed " + this);
-				future.pass(response);
-			}
-		});
-	}
-
-	public EventCallback getEventCallback() {
-		return eventCallback;
-	}
-
-	public Dispatcher<C> getDispatcher() {
-		return dispatcher;
-	}
-
-	public void setEventCallback(EventCallback eventCallback) {
-		this.eventCallback = eventCallback;
-	}
-
-	public void dispatchCall(final List<File> files) {
-		Dispatching.dispatchIfNotActive(dispatcher, new RunAt<C>(ThrowExceptionHandler.getInstance()) {
-			@Override
-			protected void runAt() {
-				eventCallback.call(files);
-			}
-		});
-	}
-}
Index: java/main/src/main/java/com/framsticks/communication/SubscriptionCallback.java
===================================================================
--- java/main/src/main/java/com/framsticks/communication/SubscriptionCallback.java	(revision 98)
+++ 	(revision )
@@ -1,17 +1,0 @@
-package com.framsticks.communication;
-
-import com.framsticks.util.FramsticksException;
-import com.framsticks.util.dispatching.ExceptionResultHandler;
-
-/**
- * @author Piotr Sniegowski
- */
-public abstract class SubscriptionCallback<C> implements ExceptionResultHandler {
-	public abstract EventCallback subscribed(Subscription<? super C> subscription);
-
-	@Override
-	public void handle(FramsticksException exception) {
-		throw exception;
-	}
-
-}
Index: java/main/src/main/java/com/framsticks/communication/queries/ApplicationRequest.java
===================================================================
--- java/main/src/main/java/com/framsticks/communication/queries/ApplicationRequest.java	(revision 98)
+++ java/main/src/main/java/com/framsticks/communication/queries/ApplicationRequest.java	(revision 99)
@@ -23,4 +23,8 @@
 	}
 
+	public String getActualPath() {
+		return path;
+	}
+
 
 	@Override
Index: java/main/src/main/java/com/framsticks/communication/queries/RegisterRequest.java
===================================================================
--- java/main/src/main/java/com/framsticks/communication/queries/RegisterRequest.java	(revision 99)
+++ java/main/src/main/java/com/framsticks/communication/queries/RegisterRequest.java	(revision 99)
@@ -0,0 +1,40 @@
+package com.framsticks.communication.queries;
+
+import com.framsticks.core.Path;
+import com.framsticks.util.lang.Pair;
+
+/**
+ * @author Piotr Sniegowski
+ */
+public class RegisterRequest extends ApplicationRequest {
+
+	protected String actualPath;
+	protected String eventName;
+
+	public RegisterRequest register() {
+		return this;
+	}
+
+	public String getCommand() {
+		return "reg";
+	}
+
+	@Override
+	public RegisterRequest path(String path) {
+		super.path(path);
+		Pair<String, String> p = Path.removeLastElement(path);
+		actualPath = p.first;
+		eventName = p.second;
+		return this;
+	}
+
+	@Override
+	public String getActualPath() {
+		return actualPath;
+	}
+
+	public String getEventName() {
+		return eventName;
+	}
+
+}
Index: java/main/src/main/java/com/framsticks/communication/queries/RegistrationRequest.java
===================================================================
--- java/main/src/main/java/com/framsticks/communication/queries/RegistrationRequest.java	(revision 98)
+++ 	(revision )
@@ -1,30 +1,0 @@
-package com.framsticks.communication.queries;
-
-/**
- * @author Piotr Sniegowski
- */
-public class RegistrationRequest extends ApplicationRequest {
-	boolean register = true;
-
-	public RegistrationRequest() {
-	}
-
-	public RegistrationRequest register(boolean register) {
-		this.register = register;
-		return this;
-	}
-
-	@Override
-	protected StringBuilder construct(StringBuilder buffer) {
-		super.construct(buffer);
-		if (!register) {
-			buffer.append(" remove");
-		}
-		return buffer;
-	}
-
-	public String getCommand() {
-		return register ? "reg" : "call";
-	}
-
-}
Index: java/main/src/main/java/com/framsticks/communication/util/LoggingSubscriptionCallback.java
===================================================================
--- java/main/src/main/java/com/framsticks/communication/util/LoggingSubscriptionCallback.java	(revision 98)
+++ 	(revision )
@@ -1,32 +1,0 @@
-package com.framsticks.communication.util;
-
-import com.framsticks.communication.EventCallback;
-import com.framsticks.communication.Subscription;
-import com.framsticks.communication.SubscriptionCallback;
-import org.apache.log4j.Logger;
-
-/**
- * @author Piotr Sniegowski
- */
-public class LoggingSubscriptionCallback<C> extends SubscriptionCallback<C> {
-
-	protected final Logger logger;
-	protected final String message;
-	private final EventCallback eventCallback;
-
-	public LoggingSubscriptionCallback(Logger logger, String message, EventCallback eventCallback) {
-		this.logger = logger;
-		this.message = message;
-		this.eventCallback = eventCallback;
-	}
-
-	@Override
-	public EventCallback subscribed(Subscription<? super C> subscription) {
-		if (subscription == null) {
-			logger.error("failed to subscribe for " + message);
-			return null;
-		}
-		logger.info("successfuly subscribed for " + message);
-		return eventCallback;
-	}
-}
Index: java/main/src/main/java/com/framsticks/core/AbstractTree.java
===================================================================
--- java/main/src/main/java/com/framsticks/core/AbstractTree.java	(revision 98)
+++ java/main/src/main/java/com/framsticks/core/AbstractTree.java	(revision 99)
@@ -32,5 +32,5 @@
 public abstract class AbstractTree extends AbstractJoinable implements Dispatcher<Tree>, Tree, JoinableParent {
 
-	private static final Logger log = Logger.getLogger(Tree.class);
+	private static final Logger log = Logger.getLogger(AbstractTree.class);
 
 	private Node root = null;
@@ -45,5 +45,5 @@
 		}
 		root = new Node(this, param, null);
-		log.info("assigned root type: " + root);
+		log.debug("assigned root type: " + root);
 	}
 
@@ -57,5 +57,5 @@
 		}
 		root = new Node(this, root.getParam(), object);
-		log.info("assigned root object: " + root);
+		log.debug("assigned root object: " + root);
 	}
 
@@ -177,4 +177,12 @@
 	}
 
+	/**
+	 * @return the registry
+	 */
+	@Override
+	public Registry getRegistry() {
+		return registry;
+	}
+
 	@Override
 	protected void joinableStart() {
Index: java/main/src/main/java/com/framsticks/core/Framsticks.java
===================================================================
--- java/main/src/main/java/com/framsticks/core/Framsticks.java	(revision 98)
+++ java/main/src/main/java/com/framsticks/core/Framsticks.java	(revision 99)
@@ -21,4 +21,6 @@
 	public Framsticks() {
 		PropertyConfigurator.configure(getClass().getResource("/configs/log4j.properties"));
+
+		// log.info("config is: " + System.getProperties().getProperty("framsticks.config", "/configs/framsticks.xml"));
 	}
 
Index: java/main/src/main/java/com/framsticks/core/LocalTree.java
===================================================================
--- java/main/src/main/java/com/framsticks/core/LocalTree.java	(revision 99)
+++ java/main/src/main/java/com/framsticks/core/LocalTree.java	(revision 99)
@@ -0,0 +1,139 @@
+package com.framsticks.core;
+
+import org.apache.log4j.Logger;
+
+import com.framsticks.params.AccessInterface;
+import com.framsticks.params.CompositeParam;
+import com.framsticks.params.EventListener;
+import com.framsticks.params.FramsClass;
+import com.framsticks.params.ParamBuilder;
+import com.framsticks.params.PrimitiveParam;
+import com.framsticks.params.ValueParam;
+import com.framsticks.params.annotations.AutoAppendAnnotation;
+import com.framsticks.params.annotations.FramsClassAnnotation;
+import com.framsticks.params.types.EventParam;
+import com.framsticks.params.types.ProcedureParam;
+import com.framsticks.util.FramsticksException;
+import com.framsticks.util.dispatching.Future;
+
+import static com.framsticks.core.TreeOperations.*;
+
+@FramsClassAnnotation
+public final class LocalTree extends AbstractTree {
+	private static final Logger log = Logger.getLogger(LocalTree.class);
+
+	protected Object rootObject;
+
+	/**
+	 *
+	 */
+	public LocalTree() {
+		super();
+
+	}
+
+	@AutoAppendAnnotation
+	public void setRootObject(Object object) {
+		final Class<?> javaClass = object.getClass();
+		registry.registerAndBuild(javaClass);
+
+		AccessInterface access = registry.createAccess(javaClass);
+
+		assignRootParam(access.buildParam(new ParamBuilder()).id(getName()).finish(CompositeParam.class));
+		assignRootObject(object);
+	}
+
+	public Object getRootObject() {
+		return getAssignedRoot().getObject();
+	}
+
+	public <T> T getRootObject(Class<T> type) {
+		Object result = getRootObject();
+		if (result == null) {
+			throw new FramsticksException().msg("object tree is empty").arg("tree", this);
+		}
+		if (!type.isInstance(result)) {
+			throw new FramsticksException().msg("object tree holds object of different kind").arg("object", result).arg("requested", type).arg("tree", this);
+		}
+		return type.cast(result);
+	}
+
+	@Override
+	public void get(Path path, Future<Path> future) {
+		assert isActive();
+		log.debug("requesting: " + path);
+		path = resolveTopSync(path);
+		future.pass(path);
+	}
+
+	@Override
+	public void get(Path path, ValueParam param, Future<Object> future) {
+		assert isActive();
+		path = resolveTopSync(path);
+		future.pass(bindAccess(path).get(param, Object.class));
+	}
+
+	@Override
+	public void call(Path path, ProcedureParam param, Object[] arguments, Future<Object> future) {
+		assert isActive();
+		try {
+			future.pass(bindAccess(path).call(param, arguments));
+		} catch (FramsticksException e) {
+			future.handle(e);
+		}
+	}
+
+	@Override
+	public void info(Path path, Future<FramsClass> future) {
+		assert isActive();
+		Path p = path.tryResolveIfNeeded();
+		Class<?> javaClass = p.getTopObject().getClass();
+		FramsClass framsClass = registry.registerReflectedIfNeeded(javaClass);
+		if (framsClass != null) {
+			future.pass(framsClass);
+		} else {
+			future.handle(new FramsticksException().msg("failed to find info for class").arg("java class", javaClass));
+		}
+	}
+
+	protected Path resolveTopSync(Path path) {
+		assert isActive();
+		assert path.isOwner(this);
+		if (path.getTop().getObject() != null) {
+			return path;
+		}
+		AccessInterface access = bindAccess(path.getUnder());
+		Object object = access.get(path.getTop().getParam(), Object.class);
+		if (object == null) {
+			throw new FramsticksException().msg("failed to resolve").arg("path", path);
+		}
+		return path.appendResolution(object);
+	}
+
+
+	@Override
+	public void set(Path path, PrimitiveParam<?> param, Object value, final Future<Integer> future) {
+		assert isActive();
+		future.pass(bindAccess(path).set(param, value));
+	}
+
+	public <A> void addListener(Path path, EventParam param, EventListener<A> listener, Class<A> argumentType, Future<Void> future) {
+		assert isActive();
+		try {
+			bindAccess(path).reg(param, listener);
+			future.pass(null);
+		} catch (FramsticksException e) {
+			future.handle(e);
+		}
+	}
+
+	public void removeListener(Path path, EventParam param, EventListener<?> listener, Future<Void> future) {
+		assert isActive();
+		try {
+			bindAccess(path).regRemove(param, listener);
+			future.pass(null);
+		} catch (FramsticksException e) {
+			future.handle(e);
+		}
+	}
+}
Index: java/main/src/main/java/com/framsticks/core/Mode.java
===================================================================
--- java/main/src/main/java/com/framsticks/core/Mode.java	(revision 98)
+++ 	(revision )
@@ -1,6 +1,0 @@
-package com.framsticks.core;
-
-public enum Mode {
-	CACHE,
-	FETCH
-}
Index: java/main/src/main/java/com/framsticks/core/ObjectTree.java
===================================================================
--- java/main/src/main/java/com/framsticks/core/ObjectTree.java	(revision 98)
+++ 	(revision )
@@ -1,105 +1,0 @@
-package com.framsticks.core;
-
-import org.apache.log4j.Logger;
-
-import com.framsticks.params.AccessInterface;
-import com.framsticks.params.CompositeParam;
-import com.framsticks.params.FramsClass;
-import com.framsticks.params.Param;
-import com.framsticks.params.PrimitiveParam;
-import com.framsticks.params.ValueParam;
-import com.framsticks.params.annotations.AutoAppendAnnotation;
-import com.framsticks.params.annotations.FramsClassAnnotation;
-import com.framsticks.params.types.ProcedureParam;
-import com.framsticks.util.FramsticksException;
-import com.framsticks.util.dispatching.Future;
-
-import static com.framsticks.core.TreeOperations.*;
-
-@FramsClassAnnotation
-public class ObjectTree extends AbstractTree {
-	private static final Logger log = Logger.getLogger(ObjectTree.class);
-
-	@AutoAppendAnnotation
-	public void setRootObject(Object object) {
-		registry.registerAndBuild(object.getClass());
-		AccessInterface access = registry.createAccess(object.getClass());
-		assignRootParam(Param.build().forAccess(access).id(getName()).finish(CompositeParam.class));
-		assignRootObject(object);
-	}
-
-	public Object getRootObject() {
-		return getAssignedRoot().getObject();
-	}
-
-	public <T> T getRootObject(Class<T> type) {
-		Object result = getRootObject();
-		if (result == null) {
-			throw new FramsticksException().msg("object tree is empty").arg("tree", this);
-		}
-		if (!type.isInstance(result)) {
-			throw new FramsticksException().msg("object tree holds object of different kind").arg("object", result).arg("requested", type).arg("tree", this);
-		}
-		return type.cast(result);
-	}
-
-	@Override
-	public void get(Path path, Mode mode, Future<Path> future) {
-		assert isActive();
-		log.debug("requesting: " + path);
-		path = resolveTopSync(path);
-		future.pass(path);
-	}
-
-	@Override
-	public void get(Path path, ValueParam param, Mode mode, Future<Object> future) {
-		assert isActive();
-		path = resolveTopSync(path);
-		future.pass(bindAccess(path).get(param, Object.class));
-	}
-
-	@Override
-	public void call(Path path, ProcedureParam param, Object[] arguments, Future<Object> future) {
-		assert isActive();
-		try {
-			future.pass(bindAccess(path).call(param, arguments));
-		} catch (FramsticksException e) {
-			future.handle(e);
-		}
-	}
-
-	@Override
-	public void info(Path path, Future<FramsClass> future) {
-		assert isActive();
-		Path p = path.tryResolveIfNeeded();
-		Class<?> javaClass = p.getTopObject().getClass();
-		FramsClass framsClass = registry.registerReflectedIfNeeded(javaClass);
-		if (framsClass != null) {
-			future.pass(framsClass);
-		} else {
-			future.handle(new FramsticksException().msg("failed to find info for class").arg("java class", javaClass));
-		}
-	}
-
-	protected Path resolveTopSync(Path path) {
-		assert isActive();
-		assert path.isOwner(this);
-		if (path.getTop().getObject() != null) {
-			return path;
-		}
-		AccessInterface access = bindAccess(path.getUnder());
-		Object object = access.get(path.getTop().getParam(), Object.class);
-		if (object == null) {
-			return path;
-		}
-		return path.appendResolution(object);
-	}
-
-
-	@Override
-	public void set(Path path, PrimitiveParam<?> param, Object value, final Future<Integer> future) {
-		assert isActive();
-		future.pass(bindAccess(path).set(param, value));
-	}
-
-}
Index: java/main/src/main/java/com/framsticks/core/Path.java
===================================================================
--- java/main/src/main/java/com/framsticks/core/Path.java	(revision 98)
+++ java/main/src/main/java/com/framsticks/core/Path.java	(revision 99)
@@ -6,8 +6,12 @@
 import com.framsticks.util.FramsticksException;
 import com.framsticks.util.dispatching.Dispatching;
+import com.framsticks.util.dispatching.ExceptionResultHandler;
+import com.framsticks.util.dispatching.IgnoreExceptionHandler;
+import com.framsticks.util.lang.Pair;
 
 import java.util.Iterator;
 import java.util.LinkedList;
 import java.util.List;
+import java.util.regex.Pattern;
 
 import javax.annotation.Nonnull;
@@ -27,5 +31,5 @@
 	final LinkedList<Node> nodes;
 
-	protected static Object getKnownChild(Tree tree, AccessInterface access, CompositeParam param) {
+	protected static Object getKnownChild(Tree tree, AccessInterface access, CompositeParam param, ExceptionResultHandler handler) {
 		Object child = access.get(param, Object.class);
 		if (child == null) {
@@ -36,4 +40,5 @@
 			return child;
 		} catch (FramsticksException e) {
+			handler.handle(e);
 		}
 		return null;
@@ -130,6 +135,9 @@
 		}
 
-
 		public PathBuilder resolve(@Nonnull Tree tree, String textual) {
+			return resolve(tree, textual, IgnoreExceptionHandler.getInstance());
+		}
+
+		public PathBuilder resolve(@Nonnull Tree tree, String textual, ExceptionResultHandler handler) {
 
 			assert nodes.isEmpty();
@@ -146,12 +154,14 @@
 				String e = i.next();
 				Param p = access.getParam(e);
+				if (p == null) {
+					break;
+				}
 				if (!(p instanceof CompositeParam)) {
-					//entries.add(new Entry());
-					break;
-				}
-				CompositeParam c = (CompositeParam)p;
+					throw new FramsticksException().msg("param is not a composite").arg("param", p).arg("tree", tree).arg("textual", textual).arg("access", access);
+				}
+				CompositeParam c = (CompositeParam) p;
 				b.append("/").append(e);
 				access.select(current.getObject());
-				current = new Node(current.getTree(), c, getKnownChild(tree, access, c));
+				current = new Node(current.getTree(), c, getKnownChild(tree, access, c, handler));
 				nodes.add(current);
 			}
@@ -245,5 +255,5 @@
 			return Path.build().resolve(tree, "/").finish();
 		}
-		Object child = getKnownChild(tree, TreeOperations.bindAccess(getUnder()), getTop().getParam());
+		Object child = getKnownChild(tree, TreeOperations.bindAccess(getUnder()), getTop().getParam(), IgnoreExceptionHandler.getInstance());
 		if (child == null) {
 			return this;
@@ -274,6 +284,14 @@
 	}
 
+	public static Path tryTo(@Nonnull Tree tree, String textual) {
+		return Path.build().resolve(tree, textual).finish();
+	}
+
 	public static Path to(@Nonnull Tree tree, String textual) {
-		return Path.build().resolve(tree, textual).finish();
+		Path path = tryTo(tree, textual);
+		if (path.getTextual().equals(textual)) {
+			return path;
+		}
+		throw new FramsticksException().msg("failed to create path").arg("textual", textual).arg("result", path).arg("tree", tree);
 	}
 
@@ -299,4 +317,37 @@
 	}
 
+	public static final Pattern pathPattern = Pattern.compile("(\\/)|((\\/[^/]+)+)");
+
+	public static boolean isValidString(String path) {
+		return pathPattern.matcher(path).matches();
+	}
+
+	public static String appendString(String path, String element) {
+		if (path.equals("/")) {
+			return path + element;
+		}
+		return path + "/" + element;
+	}
+
+	public static Pair<String, String> removeLastElement(String path) {
+		assert isValidString(path);
+		if (path.equals("/")) {
+			throw new FramsticksException().msg("cannot remove last element from root path");
+		}
+		int index = path.lastIndexOf('/');
+		assert index != -1;
+		if (index == 0) {
+			return new Pair<String, String>("/", path.substring(1));
+		}
+		return new Pair<String, String>(path.substring(0, index), path.substring(index + 1));
+	}
+
+	public static String validateString(String path) {
+		if (!isValidString(path)) {
+			throw new FramsticksException().msg("path string validation failured").arg("path", path);
+		}
+		return path;
+	}
+
 
 	// public boolean isEmpty() {
Index: java/main/src/main/java/com/framsticks/core/Tree.java
===================================================================
--- java/main/src/main/java/com/framsticks/core/Tree.java	(revision 98)
+++ java/main/src/main/java/com/framsticks/core/Tree.java	(revision 99)
@@ -5,8 +5,10 @@
 import com.framsticks.params.AccessInterface;
 import com.framsticks.params.CompositeParam;
+import com.framsticks.params.EventListener;
 import com.framsticks.params.FramsClass;
 import com.framsticks.params.PrimitiveParam;
 import com.framsticks.params.Registry;
 import com.framsticks.params.ValueParam;
+import com.framsticks.params.types.EventParam;
 import com.framsticks.params.types.ProcedureParam;
 import com.framsticks.util.dispatching.Dispatcher;
@@ -34,7 +36,7 @@
 	 *
 	 */
-	public void get(Path path, ValueParam param, Mode mode, Future<Object> future);
+	public void get(Path path, ValueParam param, Future<Object> future);
 
-	public void get(Path path, Mode mode, Future<Path> future);
+	public void get(Path path, Future<Path> future);
 
 	public void call(Path path, ProcedureParam param, Object[] arguments, Future<Object> future);
@@ -57,3 +59,9 @@
 	public JoinableDispatcher<Tree> getDispatcher();
 
+	public <A> void addListener(Path path, EventParam param, EventListener<A> listener, Class<A> argumentType, Future<Void> future);
+
+	public void removeListener(Path path, EventParam param, EventListener<?> listener, Future<Void> future);
+
+	public Registry getRegistry();
+
 }
Index: java/main/src/main/java/com/framsticks/core/TreeOperations.java
===================================================================
--- java/main/src/main/java/com/framsticks/core/TreeOperations.java	(revision 98)
+++ java/main/src/main/java/com/framsticks/core/TreeOperations.java	(revision 99)
@@ -2,5 +2,7 @@
 
 
+import java.util.HashSet;
 import java.util.List;
+import java.util.Set;
 
 import javax.annotation.Nonnull;
@@ -10,9 +12,12 @@
 import com.framsticks.communication.File;
 import com.framsticks.params.AccessInterface;
-import com.framsticks.params.CompositeParam;
+import com.framsticks.params.EventListener;
 import com.framsticks.params.FramsClass;
 import com.framsticks.params.ListAccess;
 import com.framsticks.params.Param;
 import com.framsticks.params.PrimitiveParam;
+import com.framsticks.params.UniqueListAccess;
+import com.framsticks.params.Util;
+import com.framsticks.params.types.EventParam;
 import com.framsticks.params.types.ObjectParam;
 import com.framsticks.params.types.ProcedureParam;
@@ -73,21 +78,57 @@
 
 			ListAccess listAccess = (ListAccess) bindAccess(node);
-			listAccess.clearValues();
+
+			Set<String> oldValuesIds = new HashSet<>();
+			for (Param p : listAccess.getParams()) {
+				oldValuesIds.add(p.getId());
+			}
+
+			// listAccess.clearValues();
 
 			AccessInterface elementAccess = listAccess.getElementAccess();
+			AccessInterface clonerInterface = elementAccess.cloneAccess();
+
 			loader.addAccessInterface(elementAccess);
 			MultiParamLoader.Status status;
+			int number = 0;
 			while ((status = loader.go()) != MultiParamLoader.Status.Finished) {
 				if (status == MultiParamLoader.Status.AfterObject) {
 					AccessInterface accessInterface = loader.getLastAccessInterface();
 
-					String id = listAccess.computeIdentifierFor(accessInterface.getSelected());
-					//TODO listAccessParam
-					CompositeParam param = Param.build().forAccess(accessInterface).id(id).finish(CompositeParam.class);
-					Object child = accessInterface.getSelected();
+					String id;
+					if (listAccess instanceof UniqueListAccess) {
+						id = ((UniqueListAccess) listAccess).computeIdentifierFor(accessInterface.getSelected());
+					} else {
+						id = Integer.toString(number);
+					}
+					++number;
+
+					Object childTo = listAccess.get(id, Object.class);
+					boolean newOne;
+					if (childTo == null) {
+						childTo = clonerInterface.createAccessee();
+						newOne = true;
+					} else {
+						assert oldValuesIds.contains(id);
+						newOne = false;
+					}
+					oldValuesIds.remove(id);
+					clonerInterface.select(childTo);
+					Util.takeAllNonNullValues(clonerInterface, accessInterface);
+					if (newOne) {
+						listAccess.set(id, childTo);
+					}
+
+					// listAccess.set(id, accessInterface.getSelected());
 					accessInterface.select(null);
-					assert child != null;
-					bindAccess(node).set(param, child);
+
 				}
+			}
+			/** It looks tricky for ArrayListAccess but should also work.
+ 			 *
+			 * They should be sorted.
+			 */
+			for (String id : oldValuesIds) {
+				listAccess.set(id, null);
 			}
 
@@ -170,6 +211,33 @@
 	}
 
-
-	/** This might not be correct. */
+	public static <A> void addListener(final Path path, final EventParam param, final EventListener<A> listener, final Class<A> argument, final Future<Void> future) {
+		final Tree tree = path.getTree();
+
+		dispatchIfNotActive(tree, new RunAt<Tree>(future) {
+			@Override
+			protected void runAt() {
+				tree.addListener(path, param, listener, argument, future);
+			}
+		});
+	}
+
+	public static void removeListener(final Path path, final EventParam param, final EventListener<?> listener, final Future<Void> future) {
+		final Tree tree = path.getTree();
+
+		dispatchIfNotActive(tree, new RunAt<Tree>(future) {
+			@Override
+			protected void runAt() {
+				tree.removeListener(path, param, listener, future);
+			}
+		});
+	}
+
+
+	/**
+	 *
+	 * If StackOverflow occurs in that loop in LocalTree it is probably caused
+	 * the by the fact, that get operation may find the object, but Path resolution
+	 * cannot.
+	 * */
 	public static void tryGet(final Tree tree, final String targetPath, final Future<Path> future) {
 		log.debug("resolve textual: " + targetPath + " for " + tree);
@@ -178,5 +246,6 @@
 			@Override
 			protected void runAt() {
-				final Path path = Path.to(tree, targetPath);
+				final Path path = Path.tryTo(tree, targetPath).tryResolveIfNeeded();
+				log.debug("found: " + path);
 				if (path.isResolved()) {
 					future.pass(path);
@@ -184,7 +253,12 @@
 				}
 
-				tree.get(path, Mode.FETCH, new FutureHandler<Path>(future) {
+				tree.get(path, new FutureHandler<Path>(future) {
 					@Override
 					protected void result(Path result) {
+						// if (result.isResolved(targetPath)) {
+						// 	future.pass(result);
+						// 	return;
+						// }
+						log.debug("retrying resolve textual: " + targetPath + " for " + tree + " with " + result);
 						tryGet(tree, targetPath, future);
 					}
@@ -198,3 +272,4 @@
 		return path.getTree().getInfoFromCache(path.getTop().getParam().getContainedTypeName());
 	}
+
 }
Index: java/main/src/main/java/com/framsticks/gui/AbstractNode.java
===================================================================
--- java/main/src/main/java/com/framsticks/gui/AbstractNode.java	(revision 98)
+++ 	(revision )
@@ -1,18 +1,0 @@
-package com.framsticks.gui;
-
-
-import com.framsticks.gui.view.TreeCellRenderer;
-
-public abstract class AbstractNode {
-
-	public AbstractNode() {
-	}
-
-	public abstract int getChildCount();
-	public abstract AbstractNode getChild(int number);
-	public abstract int getIndexOfChild(AbstractNode child);
-
-	public abstract boolean isLeaf();
-	public abstract void render(TreeCellRenderer renderer);
-
-}
Index: java/main/src/main/java/com/framsticks/gui/Browser.java
===================================================================
--- java/main/src/main/java/com/framsticks/gui/Browser.java	(revision 98)
+++ java/main/src/main/java/com/framsticks/gui/Browser.java	(revision 99)
@@ -4,4 +4,6 @@
 import com.framsticks.gui.console.Console;
 import com.framsticks.gui.console.TrackConsole;
+import com.framsticks.gui.table.ColumnsConfig;
+import com.framsticks.gui.table.ListPanelProvider;
 import com.framsticks.params.annotations.AutoAppendAnnotation;
 import com.framsticks.params.annotations.FramsClassAnnotation;
@@ -57,8 +59,12 @@
 	}
 
+	protected final StandardPanelProvider standardPanelProvider;
+	protected final ListPanelProvider listPanelProvider;
+
 	public Browser() {
 		setName("browser");
 		JPopupMenu.setDefaultLightWeightPopupEnabled(false);
-		addPanelProvider(new StandardPanelProvider());
+		addPanelProvider(standardPanelProvider = new StandardPanelProvider());
+		addPanelProvider(listPanelProvider = new ListPanelProvider());
 
 		mainFrame = new MainFrame(Browser.this);
@@ -116,4 +122,9 @@
 
 	@AutoAppendAnnotation
+	public void addColumnsConfig(ColumnsConfig columnsConfig) {
+		listPanelProvider.addColumnsConfig(columnsConfig);
+	}
+
+	@AutoAppendAnnotation
 	public void addPopupMenuEntryProvider(PopupMenuEntryProvider popupMenuEntryProvider) {
 		popupMenuEntryProviders.add(popupMenuEntryProvider);
@@ -122,5 +133,5 @@
 	@AutoAppendAnnotation
 	public void addTree(Tree tree) {
-		log.info("adding tree: " + tree);
+		log.debug("adding tree: " + tree);
 		tree.setDispatcher(new SwingDispatcher<Tree>());
 		trees.add(tree);
@@ -155,31 +166,4 @@
 	}
 
-	public void createTreeNodeForChild(final Path path) {
-		assert !isActive();
-		//assert tree.isActive();
-
-		/*
-		 final TreeNode parentTreeNode = (TreeNode) child.getParent().getUserObject();
-		 if (parentTreeNode == null) {
-		 Dispatching.invokeDispatch(this, manager, new Runnable() {
-		 @Override
-		 public void run() {
-		 createTreeNodeForChild(child);
-		 }
-		 });
-		 return;
-		 }
-		 log.debug(child.getClass().getSimpleName() + " created: " + child);
-
-
-		 invokeLater(new Runnable() {
-		 @Override
-		 public void run() {
-		 parentTreeNode.getOrCreateChildTreeNodeFor(child);
-		 }
-		 });
-		 */
-	}
-
 	@Override
 	protected void joinableStart() {
@@ -288,22 +272,3 @@
 	}
 
-	// final protected Map<EventParam, Subscription<?>> userSubscriptions = new HashMap<>();
-	// public boolean hasSubscribed(EventParam param) {
-	// 	assert frame.isActive();
-	// 	return userSubscriptions.containsKey(param);
-	// }
-
-	// public void unsubscribe(EventParam eventParam) {
-	// 	assert frame.isActive();
-	// 	if (!hasSubscribed(eventParam)) {
-	// 		log.error("could not unsubscribe from " + eventParam);
-	// 		return;
-	// 	}
-	// 	userSubscriptions.get(eventParam).unsubscribe(new LoggingStateCallback(log, "unsubscribed " + eventParam));
-	// 	userSubscriptions.remove(eventParam);
-	// }
-
-
-
-
 }
Index: java/main/src/main/java/com/framsticks/gui/EmptyNode.java
===================================================================
--- java/main/src/main/java/com/framsticks/gui/EmptyNode.java	(revision 98)
+++ 	(revision )
@@ -1,50 +1,0 @@
-package com.framsticks.gui;
-
-
-import com.framsticks.gui.view.TreeCellRenderer;
-import com.framsticks.params.CompositeParam;
-
-public class EmptyNode extends AbstractNode {
-
-	protected final CompositeParam param;
-
-	/**
-	 * @param param
-	 */
-	public EmptyNode(CompositeParam param) {
-		this.param = param;
-	}
-
-	@Override
-	public int getChildCount() {
-		return 0;
-	}
-
-	@Override
-	public AbstractNode getChild(int number) {
-		return null;
-	}
-
-	@Override
-	public int getIndexOfChild(AbstractNode child) {
-		return -1;
-	}
-
-	@Override
-	public boolean isLeaf() {
-		return true;
-	}
-
-	@Override
-	public void render(TreeCellRenderer renderer) {
-		renderer.setIcon(ImageProvider.loadImage(TreeCellRenderer.findIconName(param)));
-		renderer.setText(param.getId());
-		renderer.setToolTipText("?");
-	}
-
-	@Override
-	public String toString() {
-		return param.toString();
-	}
-
-}
Index: java/main/src/main/java/com/framsticks/gui/Frame.java
===================================================================
--- java/main/src/main/java/com/framsticks/gui/Frame.java	(revision 98)
+++ java/main/src/main/java/com/framsticks/gui/Frame.java	(revision 99)
@@ -38,10 +38,10 @@
 import org.apache.log4j.Logger;
 
-import com.framsticks.core.Mode;
 import com.framsticks.core.Path;
 import com.framsticks.core.Tree;
-import com.framsticks.core.TreeOperations;
-import com.framsticks.gui.view.TreeCellRenderer;
-import com.framsticks.params.AccessInterface;
+import com.framsticks.gui.tree.MetaNode;
+import com.framsticks.gui.tree.TreeCellRenderer;
+import com.framsticks.gui.tree.TreeModel;
+import com.framsticks.gui.tree.TreeNode;
 import com.framsticks.util.dispatching.Dispatching;
 import com.framsticks.util.dispatching.FutureHandler;
@@ -126,5 +126,5 @@
 			@Override
 			public void valueChanged(TreeSelectionEvent e) {
-				chooseTreeNode(e.getNewLeadSelectionPath());
+				treeModel.chooseTreeNode(e.getNewLeadSelectionPath());
 			}
 		});
@@ -139,5 +139,5 @@
 			@Override
 			public void treeExpanded(TreeExpansionEvent e) {
-				loadChildren(treeModel.convertToPath(e.getPath()), false);
+				// loadChildren(treeModel.convertToPath(e.getPath()), false);
 			}
 		});
@@ -243,5 +243,5 @@
 			public void actionPerformed(ActionEvent actionEvent) {
 
-				loadPath(treeModel.convertToPath(jtree.getSelectionPath()), true);
+				treeModel.loadPath(treeModel.convertToPath(jtree.getSelectionPath()), true);
 			}
 		});
@@ -258,7 +258,7 @@
 		Tree tree = path.getTree();
 
-		log.info("trying mount: " + path);
+		log.debug("trying mount: " + path);
 		if (!tree.getAssignedRoot().isResolved()) {
-			tree.get(path, Mode.FETCH, new FutureHandler<Path>(this) {
+			tree.get(path, new FutureHandler<Path>(this) {
 
 				@Override
@@ -275,5 +275,5 @@
 		treeAtFrames.put(tree, e);
 
-		rootNode.getChildren().add(new TreeNode(tree.getAssignedRoot()));
+		rootNode.getChildren().add(new TreeNode(e, Path.to(tree, "/")));
 		e.rootNode = tree.getAssignedRoot();
 		treeModel.nodeStructureChanged(new TreePath(rootNode));
@@ -311,58 +311,11 @@
 	}
 
-	public void loadChildren(Path path, boolean reload) {
-		if (path == null) {
-			return;
+	public void updatePanelIfIsLeadSelection(TreePath treePath, Path path) {
+		assert isActive();
+		if (treePath.equals(jtree.getSelectionPath())) {
+			treeAtFrames.get(path.getTree()).useOrCreatePanel(treePath);
 		}
-		AccessInterface access = TreeOperations.bindAccess(path);
-
-		int count = access.getCompositeParamCount();
-		for (int i = 0; i < count; ++i) {
-			Path childPath = path.appendParam(access.getCompositeParam(i)).tryFindResolution();
-			loadPath(childPath, reload);
-		}
-
-	}
-
-	public void loadPath(Path path, boolean reload) {
-		if (path == null) {
-			return;
-		}
-		if (path.isResolved() && !reload) {
-			return;
-		}
-		path.getTree().get(path, Mode.FETCH, new FutureHandler<Path>(this) {
-			@Override
-			protected void result(Path result) {
-				final TreePath treePath = treeModel.convertToTreePath(result);
-
-				treeModel.nodeStructureChanged(treePath);
-				if (treePath.equals(jtree.getSelectionPath())) {
-					treeAtFrames.get(result.getTree()).useOrCreatePanel(treePath);
-				}
-			}
-		});
-	}
-
-	public void chooseTreeNode(final TreePath treePath) {
-		assert isActive();
-		if (treePath == null) {
-			return;
-		}
-		if (treeModel.isChanging()) {
-			return;
-		}
-
-		Path path = treeModel.convertToPath(treePath);
-		if (path == null) {
-			return;
-		}
-		path = path.assureResolved();
-		final Tree tree = path.getTree();
-
-		treeAtFrames.get(tree).useOrCreatePanel(treePath);
-		loadChildren(path, false);
-
-	}
+	}
+
 
 
@@ -420,4 +373,11 @@
 
 	/**
+	 * @return the jtree
+	 */
+	public JTree getJtree() {
+		return jtree;
+	}
+
+	/**
 	 * @return the treeModel
 	 */
@@ -426,3 +386,17 @@
 	}
 
+	/**
+	 * @return the rootNode
+	 */
+	public MetaNode getRootNode() {
+		return rootNode;
+	}
+
+	/**
+	 * @return the treeAtFrames
+	 */
+	public Map<Tree, TreeAtFrame> getTreeAtFrames() {
+		return treeAtFrames;
+	}
+
 }
Index: java/main/src/main/java/com/framsticks/gui/Gui.java
===================================================================
--- java/main/src/main/java/com/framsticks/gui/Gui.java	(revision 98)
+++ java/main/src/main/java/com/framsticks/gui/Gui.java	(revision 99)
@@ -101,5 +101,5 @@
 
 	public static <P extends Param, C extends Control> void fillWithControls(ControlOwner owner, Collection<P> params, Map<P, C> components, Class<C> controlType) {
-		JPanel panel = owner.getPanel();
+		JPanel panel = owner.getPanelForControls();
 		for (P param : params) {
 			if (param.isUserHidden()) {
Index: java/main/src/main/java/com/framsticks/gui/ListPanel.java
===================================================================
--- java/main/src/main/java/com/framsticks/gui/ListPanel.java	(revision 98)
+++ 	(revision )
@@ -1,117 +1,0 @@
-package com.framsticks.gui;
-
-import com.framsticks.gui.view.TableModel;
-import com.framsticks.params.AccessInterface;
-import org.apache.log4j.Logger;
-
-import javax.swing.*;
-import javax.swing.table.TableColumn;
-
-/**
- * Panel contains table and allows to manages displaying columns.
- */
-@SuppressWarnings("serial")
-public class ListPanel extends ModifiablePanel {
-
-	private static final Logger log = Logger.getLogger(ListPanel.class.getName());
-
-	final protected TableModel tableModel = new TableModel();
-	final protected JTable table = new JTable(tableModel);
-
-	public ListPanel(Parameters parameters) {
-		super(parameters);
-
-		table.getTableHeader().setReorderingAllowed(false);
-		table.setColumnSelectionAllowed(false);
-		table.setCellSelectionEnabled(false);
-		table.setColumnSelectionAllowed(false);
-
-		contentPanel.add(table);
-
-		log.debug("created");
-
-		/*
-		AccessInterface elementAccess = ((ListAccess)access).getElementAccess();
-		if (elementAccess == null) {
-			log.error("no type class");
-			return;
-		}
-		List<String> list = new ArrayList<String>();
-		addColumn(elementAccess.getId(), elementAccess.getId(), 0);
-		list.add(elementAccess.getId());
-		for (int p = 0; p < elementAccess.getParamCount(); ++p) {
-			Param param = elementAccess.getParam(p);
-			if (param.isUserHidden()) {
-				continue;
-			}
-			if (param instanceof CompositeParam) {
-				continue;
-			}
-			addColumn(param.getId(), param.getId(), 0);
-			list.add(param.getId());
-		}
-		tableModel.addRow(list.toArray());
-		*/
-		/*
-		JMenuBar menuBar = new JMenuBar();
-		selectColumnMenu = new JMenu("Columns");
-		menuBar.add(selectColumnMenu);
-		createTable();
-		this.setLayout(new BorderLayout());
-		this.add(menuBar, BorderLayout.PAGE_START);
-		*/
-
-	}
-
-	/**
-	 * Adds column to table.
-	 *
-	 * @param columnName Name of column.
-	 * @param columnId   Column getId.
-	 * @param index      Column index.
-	 */
-	public void addColumn(String columnName, String columnId, int index) {
-		TableColumn tableColumn = new TableColumn();
-		tableColumn.setHeaderValue(columnName);
-		tableColumn.setIdentifier(columnId);
-		tableColumn.setModelIndex(index);
-		tableModel.addColumn(tableColumn);
-
-		//userColumnsConfig.addColumn(getPath(), columnId);
-	}
-
-	/**
-	 * Removes column from table.
-	 *
-	 * @param columnId Id of column.
-	 */
-	public void removeColumn(String columnId) {
-		tableModel.removeColumn(columnId);
-		//userColumnsConfig.removeColumn(getPath(), columnId);
-	}
-
-	/**
-	 * Clears table.
-	 */
-	public void clearTable() {
-		tableModel.setRowCount(0);
-	}
-
-	public void refreshTable() {
-		clearTable();
-	}
-
-	@Override
-	protected void applyChanges() {
-	}
-
-	@Override
-	public void pullValuesFromLocalToUser(AccessInterface access) {
-
-	}
-
-	@Override
-	public String getTitle() {
-		return "List";
-	}
-}
Index: java/main/src/main/java/com/framsticks/gui/ListPanelProvider.java
===================================================================
--- java/main/src/main/java/com/framsticks/gui/ListPanelProvider.java	(revision 98)
+++ 	(revision )
@@ -1,15 +1,0 @@
-package com.framsticks.gui;
-
-import com.framsticks.params.types.ListParam;
-
-public class ListPanelProvider implements PanelProvider {
-
-	@Override
-	public Panel providePanel(Panel.Parameters parameters) {
-		if (parameters.param instanceof ListParam) {
-			return new ListPanel(parameters);
-		}
-		return null;
-	}
-
-}
Index: java/main/src/main/java/com/framsticks/gui/MetaNode.java
===================================================================
--- java/main/src/main/java/com/framsticks/gui/MetaNode.java	(revision 98)
+++ 	(revision )
@@ -1,67 +1,0 @@
-package com.framsticks.gui;
-
-import java.util.LinkedList;
-import java.util.List;
-
-
-import com.framsticks.gui.view.TreeCellRenderer;
-
-public class MetaNode extends AbstractNode {
-
-	protected List<AbstractNode> children = new LinkedList<>();
-	protected String name = "meta node";
-
-	/**
-	 * @return the children
-	 */
-	public List<AbstractNode> getChildren() {
-		return children;
-	}
-
-	/**
-	 * @return the name
-	 */
-	public String getName() {
-		return name;
-	}
-
-	/**
-	 * @param name the name to set
-	 */
-	public void setName(String name) {
-		this.name = name;
-	}
-
-	@Override
-	public int getChildCount() {
-		return children.size();
-	}
-
-	@Override
-	public AbstractNode getChild(int number) {
-		return children.get(number);
-	}
-
-	@Override
-	public int getIndexOfChild(AbstractNode child) {
-		return children.indexOf(child);
-	}
-
-	@Override
-	public String toString() {
-		return name;
-	}
-
-	@Override
-	public boolean isLeaf() {
-		return false;
-	}
-
-	@Override
-	public void render(TreeCellRenderer renderer) {
-		renderer.setIcon(ImageProvider.loadImage(ImageProvider.SERVER));
-		renderer.setText(name);
-		renderer.setToolTipText("?");
-	}
-
-}
Index: java/main/src/main/java/com/framsticks/gui/ModifiablePanel.java
===================================================================
--- java/main/src/main/java/com/framsticks/gui/ModifiablePanel.java	(revision 98)
+++ java/main/src/main/java/com/framsticks/gui/ModifiablePanel.java	(revision 99)
@@ -20,8 +20,10 @@
 	 * Pane to which components will be added.
 	 */
-	protected JPanel contentPanel;
 
-	final protected JLabel label;
-	final protected JButton applyButton;
+	protected final JLabel label;
+	protected final JButton applyButton;
+	protected final JPanel centerPanel;
+
+	protected Component contentComponent;
 
 	public ModifiablePanel(Panel.Parameters parameters) {
@@ -30,8 +32,4 @@
 
 
-		contentPanel = new JPanel();
-		contentPanel.setLayout(new BoxLayout(contentPanel, BoxLayout.PAGE_AXIS));
-		JScrollPane scroll = new JScrollPane(contentPanel);
-		//scroll.setBorder(BorderFactory.createEtchedBorder());
 
 		JPanel pageEndPanel = new JPanel();
@@ -53,10 +51,11 @@
 
 		label = new JLabel();
-		JPanel centerPanel = new JPanel();
+		centerPanel = new JPanel();
 		centerPanel.setLayout(new BorderLayout());
 		centerPanel.add(Box.createHorizontalStrut(10), BorderLayout.LINE_START);
 		centerPanel.add(Box.createHorizontalStrut(10), BorderLayout.LINE_END);
 		centerPanel.add(label, BorderLayout.PAGE_START);
-		centerPanel.add(scroll, BorderLayout.CENTER);
+
+
 		centerPanel.add(pageEndPanel, BorderLayout.PAGE_END);
 
@@ -68,3 +67,8 @@
 	protected abstract void applyChanges();
 
+	protected void setupContentComponent(Component contentComponent) {
+		this.contentComponent = contentComponent;
+		centerPanel.add(contentComponent, BorderLayout.CENTER);
+	}
+
 }
Index: java/main/src/main/java/com/framsticks/gui/ObjectPanel.java
===================================================================
--- java/main/src/main/java/com/framsticks/gui/ObjectPanel.java	(revision 98)
+++ java/main/src/main/java/com/framsticks/gui/ObjectPanel.java	(revision 99)
@@ -29,6 +29,14 @@
 	final protected Map<ValueParam, ValueControl> valueControls = new IdentityHashMap<ValueParam, ValueControl>();
 
+	protected final JPanel contentPanel;
+	protected final JScrollPane scrollPane;
+
 	public ObjectPanel(Panel.Parameters parameters, Collection<Param> params) {
 		super(parameters);
+
+		contentPanel = new JPanel();
+		scrollPane = new JScrollPane(contentPanel);
+		contentPanel.setLayout(new BoxLayout(contentPanel, BoxLayout.PAGE_AXIS));
+		setupContentComponent(scrollPane);
 
 		Gui.fillWithControls(this, params, components, Control.class);
@@ -102,5 +110,5 @@
 
 	@Override
-	public JPanel getPanel() {
+	public JPanel getPanelForControls() {
 		return contentPanel;
 	}
Index: java/main/src/main/java/com/framsticks/gui/Panel.java
===================================================================
--- java/main/src/main/java/com/framsticks/gui/Panel.java	(revision 98)
+++ java/main/src/main/java/com/framsticks/gui/Panel.java	(revision 99)
@@ -22,4 +22,6 @@
 		public final TreeAtFrame treeAtFrame;
 		public final CompositeParam param;
+
+		/** Contained type FramsClass. */
 		public final FramsClass framsClass;
 
Index: java/main/src/main/java/com/framsticks/gui/TreeAtFrame.java
===================================================================
--- java/main/src/main/java/com/framsticks/gui/TreeAtFrame.java	(revision 98)
+++ java/main/src/main/java/com/framsticks/gui/TreeAtFrame.java	(revision 99)
@@ -8,4 +8,5 @@
 import com.framsticks.core.TreeOperations;
 import com.framsticks.gui.controls.ValueControl;
+import com.framsticks.gui.tree.TreeNode;
 import com.framsticks.params.CompositeParam;
 import com.framsticks.params.FramsClass;
Index: java/main/src/main/java/com/framsticks/gui/TreeModel.java
===================================================================
--- java/main/src/main/java/com/framsticks/gui/TreeModel.java	(revision 98)
+++ 	(revision )
@@ -1,172 +1,0 @@
-package com.framsticks.gui;
-
-// import java.util.Enumeration;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.List;
-
-import javax.swing.event.TreeModelEvent;
-import javax.swing.event.TreeModelListener;
-import javax.swing.tree.TreePath;
-
-import org.apache.log4j.Logger;
-
-
-import com.framsticks.core.Node;
-import com.framsticks.core.Path;
-import com.framsticks.util.FramsticksException;
-import com.framsticks.util.UnsupportedOperationException;
-import com.framsticks.util.lang.Casting;
-
-public class TreeModel implements javax.swing.tree.TreeModel {
-	private static final Logger log = Logger.getLogger(TreeModel.class);
-
-
-	protected List<TreeModelListener> listeners = new LinkedList<>();
-
-	protected final Frame frame;
-
-	/**
-	 * @param frame
-	 */
-	public TreeModel(Frame frame) {
-		this.frame = frame;
-	}
-
-	@Override
-	public void addTreeModelListener(TreeModelListener listener) {
-		listeners.add(listener);
-	}
-
-	@Override
-	public AbstractNode getChild(Object parent, int number) {
-		return Casting.assertCast(AbstractNode.class, parent).getChild(number);
-	}
-
-	@Override
-	public int getChildCount(Object parent) {
-		return Casting.assertCast(AbstractNode.class, parent).getChildCount();
-	}
-
-	@Override
-	public int getIndexOfChild(Object parent, Object child) {
-		if ((parent == null) || (child == null)) {
-			return -1;
-		}
-		return Casting.assertCast(AbstractNode.class, parent).getIndexOfChild(Casting.assertCast(AbstractNode.class, child));
-	}
-
-	@Override
-	public MetaNode getRoot() {
-		return frame.rootNode;
-	}
-
-	@Override
-	public boolean isLeaf(Object node) {
-		return Casting.assertCast(AbstractNode.class, node).isLeaf();
-	}
-
-	@Override
-	public void removeTreeModelListener(TreeModelListener listener) {
-		listeners.remove(listener);
-	}
-
-	@Override
-	public void valueForPathChanged(TreePath path, Object value) {
-		throw new UnsupportedOperationException().msg("changing value of tree node");
-	}
-
-
-	protected boolean changing = false;
-
-	public void nodeStructureChanged(TreePath treePath) {
-		if (treePath == null) {
-			return;
-		}
-		assert frame.isActive();
-
-		changing = true;
-		log.debug("changing: " + treePath);
-		// Enumeration<TreePath> expanded = frame.jtree.getExpandedDescendants(treePath);
-		// TreePath selection = frame.jtree.getSelectionPath();
-
-		for (TreeModelListener listener : listeners) {
-			listener.treeStructureChanged(new TreeModelEvent(this, treePath));
-		}
-		// if (expanded != null) {
-		// 	while (expanded.hasMoreElements()) {
-		// 		TreePath expansion = expanded.nextElement();
-		// 		// log.info("reexpanding: " + expansion);
-		// 		frame.jtree.expandPath(expansion);
-		// 	}
-		// }
-		// if (selection != null) {
-		// 	frame.jtree.setSelectionPath(selection);
-		// }
-		changing = false;
-	}
-
-	public Path convertToPath(TreePath treePath) {
-		final Object[] components = treePath.getPath();
-		assert components[0] == frame.rootNode;
-		if (components.length == 1) {
-			return null;
-		}
-		Path.PathBuilder builder = Path.build();
-		builder.tree(Casting.assertCast(TreeNode.class, components[1]).getTree());
-		List<Node> nodes = new LinkedList<>();
-		for (int i = 1; i < components.length; ++i) {
-			TreeNode treeNode = Casting.tryCast(TreeNode.class, components[i]);
-			if (treeNode == null) {
-				return null;
-			}
-			Node node = treeNode.tryCreateNode();
-			if (node == null) {
-				throw new FramsticksException().msg("failed to recreate path").arg("treePath", treePath);
-			}
-			nodes.add(node);
-		}
-		builder.buildUpTo(nodes, null);
-
-		return builder.finish();
-	}
-
-	public TreePath convertToTreePath(Path path) {
-		assert frame.isActive();
-
-		List<Object> accumulator = new LinkedList<Object>();
-		accumulator.add(frame.rootNode);
-
-		for (AbstractNode r : frame.rootNode.getChildren()) {
-			if (r instanceof TreeNode) {
-				TreeNode root = (TreeNode) r;
-				if (root.getTree() == path.getTree()) {
-					accumulator.add(root);
-
-					Iterator<Node> i = path.getNodes().iterator();
-					i.next();
-					TreeNode treeNode = root;
-
-					while (i.hasNext()) {
-						Node node = i.next();
-						treeNode = treeNode.getTreeNodeForChild(node.getObject());
-						if (treeNode == null) {
-							break;
-						}
-						accumulator.add(treeNode);
-					}
-
-					break;
-				}
-			}
-		}
-		return new TreePath(accumulator.toArray());
-	}
-
-	/**
-	 * @return the changing
-	 */
-	public boolean isChanging() {
-		return changing;
-	}
-}
Index: java/main/src/main/java/com/framsticks/gui/TreeNode.java
===================================================================
--- java/main/src/main/java/com/framsticks/gui/TreeNode.java	(revision 98)
+++ 	(revision )
@@ -1,219 +1,0 @@
-package com.framsticks.gui;
-
-import java.lang.ref.WeakReference;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.concurrent.atomic.AtomicInteger;
-
-import javax.swing.tree.TreePath;
-
-import org.apache.log4j.Logger;
-
-import com.framsticks.core.Node;
-import com.framsticks.core.Tree;
-import com.framsticks.gui.view.TreeCellRenderer;
-import com.framsticks.params.AccessInterface;
-import com.framsticks.params.CompositeParam;
-import com.framsticks.params.types.StringParam;
-import com.framsticks.util.FramsticksException;
-import com.framsticks.util.lang.Casting;
-import com.framsticks.util.lang.Pair;
-import com.framsticks.util.swing.TooltipConstructor;
-
-public class TreeNode extends AbstractNode {
-	private static final Logger log = Logger.getLogger(TreeNode.class);
-
-
-	protected static final AtomicInteger counter = new AtomicInteger();
-
-	protected final WeakReference<Object> reference;
-	protected final CompositeParam param;
-	protected final Tree tree;
-	protected final List<Pair<WeakReference<Object>, WeakReference<TreeNode>>> children = new LinkedList<>();
-	protected final int number;
-
-	public TreeNode(Tree tree, CompositeParam param, Object object) {
-		this.tree = tree;
-		this.param = param;
-		reference = new WeakReference<Object>(object);
-		number = counter.getAndIncrement();
-	}
-
-	public TreeNode(Node node) {
-		this(node.getTree(), node.getParam(), node.assureResolved().getObject());
-	}
-
-	public Node tryCreateNode() {
-		Object child = lock();
-		if (child == null) {
-			return null;
-		}
-		return new Node(tree, param, child);
-	}
-
-	@Override
-	public int getChildCount() {
-		Object referent = lock();
-		if (referent == null) {
-			return 0;
-		}
-		AccessInterface access = tree.prepareAccess(param).select(referent);
-		final int count = access.getCompositeParamCount();
-		return count;
-	}
-
-	public TreeNode getTreeNodeForChild(Object child) {
-		Iterator<Pair<WeakReference<Object>, WeakReference<TreeNode>>> i = children.iterator();
-		while (i.hasNext()) {
-			Pair<WeakReference<Object>, WeakReference<TreeNode>> p = i.next();
-			Object object = p.first.get();
-			if (object == null) {
-				i.remove();
-				continue;
-			}
-			TreeNode treeNode = p.second.get();
-			if (treeNode == null) {
-				i.remove();
-				continue;
-			}
-			if (object == child) {
-				return treeNode;
-			}
-		}
-		return null;
-
-		// WeakReference<GuiTreeNode> resultReference = children.get(child);
-		// if (resultReference == null) {
-		//	return null;
-		// }
-		// return resultReference.get();
-	}
-
-	@Override
-	public AbstractNode getChild(int number) {
-		Object referent = lock();
-		if (referent == null) {
-			throw new FramsticksException().msg("invalid state - missing referent");
-		}
-		AccessInterface access = tree.prepareAccess(param).select(referent);
-
-		final int count = access.getCompositeParamCount();
-		if (number >= count) {
-			throw new FramsticksException().msg("invalid state - no child");
-		}
-
-		CompositeParam childParam = access.getCompositeParam(number);
-		Object child = access.get(childParam, Object.class);
-		if (child == null) {
-			log.debug("returing dummy node for " + childParam + " in " + referent);
-			return new EmptyNode(childParam);
-		}
-
-		TreeNode result = getTreeNodeForChild(child);
-		if (result != null) {
-			return result;
-		}
-		result = new TreeNode(tree, childParam, child);
-
-		children.add(Pair.make(new WeakReference<Object>(child), new WeakReference<TreeNode>(result)));
-
-		return result;
-
-	}
-
-	public Object lock() {
-		return reference.get();
-	}
-
-	@Override
-	public int getIndexOfChild(AbstractNode child) {
-		final TreeNode treeChild = Casting.tryCast(TreeNode.class, child);
-		if (treeChild == null) {
-			return -1;
-		}
-		final Object childObject = treeChild.lock();
-		final Object parentObject = lock();
-		if (childObject == null || parentObject == null) {
-			return -1;
-		}
-		final AccessInterface access = tree.prepareAccess(param).select(parentObject);
-
-		final int count = access.getCompositeParamCount();
-		for (int i = 0; i < count; ++i) {
-			Object c = access.get(access.getCompositeParam(i), Object.class);
-			if (c == childObject) {
-				return i;
-			}
-		}
-		log.debug(child + " not found in " + this);
-		return -1;
-	}
-
-	/**
-	 * @return the param
-	 */
-	public CompositeParam getParam() {
-		return param;
-	}
-
-	/**
-	 * @return the tree
-	 */
-	public Tree getTree() {
-		return tree;
-	}
-
-
-	@Override
-	public String toString() {
-		return param.toString();
-	}
-
-	public static Node tryGetNode(TreePath treePath) {
-		return Casting.throwCast(TreeNode.class, treePath.getLastPathComponent()).tryCreateNode();
-	}
-
-	@Override
-	public boolean isLeaf() {
-		Object referent = lock();
-		if (referent == null) {
-			return true;
-		}
-		AccessInterface access = tree.prepareAccess(param).select(referent);
-		return access.getCompositeParamCount() == 0;
-	}
-
-
-	@Override
-	public void render(TreeCellRenderer renderer) {
-		String name = param.getId();
-
-		Object child = lock();
-		if (child != null) {
-			AccessInterface access = tree.prepareAccess(param).select(child);
-
-			StringParam nameParam = Casting.tryCast(StringParam.class, access.getParam("name"));
-
-			if (nameParam != null) {
-				name = access.get(nameParam, String.class);
-			}
-
-			renderer.setToolTipText(new TooltipConstructor()
-				.append("frams", access.getId())
-				.append("java", child.getClass().getCanonicalName())
-				.append("access", access.getClass().getSimpleName())
-				.append("name", name)
-				.append("id", param.getId())
-				.append("object", Integer.toHexString(System.identityHashCode(child)))
-				.append("number", number)
-				.build());
-		} else {
-			renderer.setToolTipText("?");
-		}
-		renderer.setText(name);
-		renderer.setIcon(ImageProvider.loadImage(TreeCellRenderer.findIconName(param)));
-
-	}
-
-}
Index: java/main/src/main/java/com/framsticks/gui/console/ManagedConsole.java
===================================================================
--- java/main/src/main/java/com/framsticks/gui/console/ManagedConsole.java	(revision 98)
+++ java/main/src/main/java/com/framsticks/gui/console/ManagedConsole.java	(revision 99)
@@ -10,5 +10,4 @@
 import com.framsticks.communication.Response;
 import com.framsticks.communication.queries.ApplicationRequest;
-import com.framsticks.core.Mode;
 import com.framsticks.core.Path;
 import static com.framsticks.core.TreeOperations.*;
@@ -143,5 +142,5 @@
 
 				if (path.getTop().getParam() instanceof ListParam) {
-					tree.get(path, Mode.FETCH, new FutureHandler<Path>(ManagedConsole.this) {
+					tree.get(path, new FutureHandler<Path>(ManagedConsole.this) {
 						@Override
 						protected void result(Path result) {
Index: java/main/src/main/java/com/framsticks/gui/controls/Control.java
===================================================================
--- java/main/src/main/java/com/framsticks/gui/controls/Control.java	(revision 98)
+++ java/main/src/main/java/com/framsticks/gui/controls/Control.java	(revision 99)
@@ -6,5 +6,5 @@
 import javax.swing.JPanel;
 
-import com.framsticks.params.Flags;
+import com.framsticks.params.ParamFlags;
 import com.framsticks.params.Param;
 import com.framsticks.util.FramsticksException;
@@ -57,5 +57,5 @@
 
 	public final boolean isReadonly() {
-		return !userEnabled || param.hasFlag(Flags.READONLY);
+		return !userEnabled || param.hasFlag(ParamFlags.READONLY);
 	}
 
Index: java/main/src/main/java/com/framsticks/gui/controls/ControlOwner.java
===================================================================
--- java/main/src/main/java/com/framsticks/gui/controls/ControlOwner.java	(revision 98)
+++ java/main/src/main/java/com/framsticks/gui/controls/ControlOwner.java	(revision 99)
@@ -9,5 +9,5 @@
 public interface ControlOwner extends ExceptionResultHandler {
 
-	public JPanel getPanel();
+	public JPanel getPanelForControls();
 	public TreePath getCurrentTreePath();
 	public Frame getFrame();
Index: java/main/src/main/java/com/framsticks/gui/controls/ProcedureControl.java
===================================================================
--- java/main/src/main/java/com/framsticks/gui/controls/ProcedureControl.java	(revision 98)
+++ java/main/src/main/java/com/framsticks/gui/controls/ProcedureControl.java	(revision 99)
@@ -86,5 +86,5 @@
 
 	@Override
-	public JPanel getPanel() {
+	public JPanel getPanelForControls() {
 		return this;
 	}
Index: java/main/src/main/java/com/framsticks/gui/controls/ValueControl.java
===================================================================
--- java/main/src/main/java/com/framsticks/gui/controls/ValueControl.java	(revision 98)
+++ java/main/src/main/java/com/framsticks/gui/controls/ValueControl.java	(revision 99)
@@ -4,8 +4,10 @@
 
 import com.framsticks.params.CastFailure;
-import com.framsticks.params.Flags;
+import com.framsticks.params.ParamFlags;
 import com.framsticks.params.PrimitiveParam;
 import com.framsticks.params.ReassignResult;
+import com.framsticks.params.SetStateFlags;
 import com.framsticks.util.FramsticksException;
+import com.framsticks.util.lang.FlagsUtil;
 import com.framsticks.util.swing.TooltipConstructor;
 
@@ -33,5 +35,5 @@
 			.append("min", primitiveParam.getMin(Object.class))
 			.append("max", primitiveParam.getMax(Object.class))
-			.append("flags", Flags.write(primitiveParam.getFlags(), null))
+			.append("flags", FlagsUtil.write(ParamFlags.class, primitiveParam.getFlags(), null))
 			.append("group", primitiveParam.getGroup())
 			.append("extra", primitiveParam.getExtra())
@@ -70,5 +72,5 @@
 			ReassignResult<?> res = getParam().reassign(candidate, oldValue);
 			if (res.getFlags() != 0) {
-				log.warn("filter of param " + param + " failed: " + Flags.write(res.getFlags(), "0"));
+				log.warn("filter of param " + param + " failed: " + FlagsUtil.write(SetStateFlags.class, res.getFlags(), "0"));
 			}
 			return res.getValue();
Index: java/main/src/main/java/com/framsticks/gui/table/ColumnsConfig.java
===================================================================
--- java/main/src/main/java/com/framsticks/gui/table/ColumnsConfig.java	(revision 99)
+++ java/main/src/main/java/com/framsticks/gui/table/ColumnsConfig.java	(revision 99)
@@ -0,0 +1,58 @@
+package com.framsticks.gui.table;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import com.framsticks.params.annotations.FramsClassAnnotation;
+import com.framsticks.params.annotations.ParamAnnotation;
+import com.framsticks.util.lang.Delimeted;
+
+@FramsClassAnnotation
+public class ColumnsConfig {
+
+	protected final List<String> columnsNames = new ArrayList<>();
+
+	protected String className;
+
+	@ParamAnnotation(id = "columnsNames")
+	public void setColumnsNamesAsString(String columns) {
+		columnsNames.clear();
+		columnsNames.addAll(Arrays.asList(columns.split(" ")));
+	}
+
+	@ParamAnnotation(id = "columnsNames")
+	public String getColumnsNamesAsString() {
+		return new Delimeted<String>(" ", "").append(columnsNames.iterator()).build();
+	}
+
+	/**
+	 * @return the columnsNames
+	 */
+	public List<String> getColumnsNames() {
+		return columnsNames;
+	}
+
+	/**
+	 * @return the name
+	 */
+	@ParamAnnotation
+	public String getClassName() {
+		return className;
+	}
+
+	/**
+	 * @param name the name to set
+	 */
+	@ParamAnnotation
+	public void setClassName(String className) {
+		this.className = className;
+	}
+
+	@Override
+	public String toString() {
+		return "columns config for " + className + ": " + getColumnsNames();
+	}
+
+
+}
Index: java/main/src/main/java/com/framsticks/gui/table/ListPanel.java
===================================================================
--- java/main/src/main/java/com/framsticks/gui/table/ListPanel.java	(revision 99)
+++ java/main/src/main/java/com/framsticks/gui/table/ListPanel.java	(revision 99)
@@ -0,0 +1,73 @@
+package com.framsticks.gui.table;
+
+
+import com.framsticks.gui.ModifiablePanel;
+import com.framsticks.params.AccessInterface;
+import com.framsticks.params.ListAccess;
+import com.framsticks.params.PrimitiveParam;
+import com.framsticks.util.lang.Casting;
+import com.framsticks.util.lang.Containers;
+
+import org.apache.log4j.Logger;
+
+import javax.swing.*;
+
+/**
+ * Panel contains table and allows to manages displaying columns.
+ */
+@SuppressWarnings("serial")
+public class ListPanel extends ModifiablePanel {
+
+	private static final Logger log = Logger.getLogger(ListPanel.class.getName());
+
+	protected final TableModel tableModel;
+	protected final JTable table;
+	protected final JScrollPane scrollPane;
+
+	public ListPanel(Parameters parameters, ListPanelProvider provider) {
+		super(parameters);
+
+		final ColumnsConfig config = provider.getColumnsConfigs().get(framsClass.getName());
+		log.debug("creating ListPanel for " + parameters.framsClass + " using config " + config);
+
+		tableModel = new TableModel();
+		if (config != null) {
+			for (String id : config.getColumnsNames()) {
+				tableModel.addColumn(framsClass.getParamEntry(id, PrimitiveParam.class));
+			}
+		} else {
+			for (PrimitiveParam<?> param : Containers.filterInstanceof(framsClass.getParamEntries(), PrimitiveParam.class)) {
+				if (provider.getMaximumColumnNumber() != null && tableModel.getColumnCount() >= provider.getMaximumColumnNumber()) {
+					break;
+				}
+				tableModel.addColumn(param);
+			}
+		}
+
+		table = new JTable(tableModel);
+		scrollPane = new JScrollPane(table);
+		setupContentComponent(scrollPane);
+
+		table.getTableHeader().setReorderingAllowed(false);
+		table.setColumnSelectionAllowed(false);
+		table.setCellSelectionEnabled(false);
+		table.setColumnSelectionAllowed(false);
+
+		this.revalidate();
+	}
+
+
+	@Override
+	protected void applyChanges() {
+	}
+
+	@Override
+	public void pullValuesFromLocalToUser(AccessInterface access) {
+		tableModel.attachSource(Casting.throwCast(ListAccess.class, access));
+	}
+
+	@Override
+	public String getTitle() {
+		return "List";
+	}
+}
Index: java/main/src/main/java/com/framsticks/gui/table/ListPanelProvider.java
===================================================================
--- java/main/src/main/java/com/framsticks/gui/table/ListPanelProvider.java	(revision 99)
+++ java/main/src/main/java/com/framsticks/gui/table/ListPanelProvider.java	(revision 99)
@@ -0,0 +1,57 @@
+package com.framsticks.gui.table;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import com.framsticks.gui.Panel;
+import com.framsticks.gui.PanelProvider;
+import com.framsticks.params.annotations.AutoAppendAnnotation;
+import com.framsticks.params.annotations.FramsClassAnnotation;
+import com.framsticks.params.types.ListParam;
+
+@FramsClassAnnotation
+public class ListPanelProvider implements PanelProvider {
+
+	protected final Map<String, ColumnsConfig> columnsConfigs = new HashMap<>();
+	/**
+ 	 *
+	 * That limit is honored only when no explicit ColumnsConfig object is found.
+	 */
+	protected Integer maximumColumnNumber = 5;
+
+	@Override
+	public Panel providePanel(Panel.Parameters parameters) {
+		if (parameters.param instanceof ListParam) {
+			return new ListPanel(parameters, this);
+		}
+		return null;
+	}
+
+	@AutoAppendAnnotation
+	public void addColumnsConfig(ColumnsConfig config) {
+		columnsConfigs.put(config.getClassName(), config);
+	}
+
+	/**
+	 * @return the columnsConfigs
+	 */
+	public Map<String, ColumnsConfig> getColumnsConfigs() {
+		return Collections.unmodifiableMap(columnsConfigs);
+	}
+
+	/**
+	 * @return the maximumColumnNumber
+	 */
+	public Integer getMaximumColumnNumber() {
+		return maximumColumnNumber;
+	}
+
+	/**
+	 * @param maximumColumnNumber the maximumColumnNumber to set
+	 */
+	public void setMaximumColumnNumber(Integer maximumColumnNumber) {
+		this.maximumColumnNumber = maximumColumnNumber;
+	}
+
+}
Index: java/main/src/main/java/com/framsticks/gui/table/TableModel.java
===================================================================
--- java/main/src/main/java/com/framsticks/gui/table/TableModel.java	(revision 99)
+++ java/main/src/main/java/com/framsticks/gui/table/TableModel.java	(revision 99)
@@ -0,0 +1,107 @@
+package com.framsticks.gui.table;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+
+import javax.swing.event.TableModelEvent;
+import javax.swing.event.TableModelListener;
+
+import org.apache.log4j.Logger;
+
+import com.framsticks.params.AccessInterface;
+import com.framsticks.params.ListAccess;
+import com.framsticks.params.PrimitiveParam;
+import com.framsticks.util.UnsupportedOperationException;
+import com.framsticks.util.lang.Casting;
+
+public class TableModel implements javax.swing.table.TableModel {
+	private static final Logger log =
+		Logger.getLogger(TableModel.class);
+
+
+	protected List<TableModelListener> listeners = new LinkedList<>();
+	protected ListAccess access;
+	protected AccessInterface elementAccess;
+	protected final List<PrimitiveParam<?>> columnParams = new ArrayList<>();
+
+	protected void refreshAll() {
+		for (TableModelListener l : listeners) {
+			l.tableChanged(new TableModelEvent(this));
+		}
+
+	}
+
+	public void attachSource(ListAccess access) {
+		this.access = Casting.assertCast(ListAccess.class, access.cloneAccess().select(access.getSelected()));
+
+		this.elementAccess = this.access.getElementAccess().cloneAccess();
+		log.debug("attached " + access);
+		refreshAll();
+	}
+
+	@Override
+	public void addTableModelListener(TableModelListener listener) {
+		listeners.add(listener);
+	}
+
+	@Override
+	public Class<?> getColumnClass(int columnIndex) {
+		// log.debug("returning column type " + columnParams.get(columnIndex).getStorageType());
+		return columnParams.get(columnIndex).getStorageType();
+	}
+
+	@Override
+	public int getColumnCount() {
+		// log.debug("returning column count " + columnParams.size());
+		return columnParams.size();
+	}
+
+	@Override
+	public String getColumnName(int columnIndex) {
+		return columnParams.get(columnIndex).getName();
+	}
+
+	@Override
+	public int getRowCount() {
+		// log.debug("returning row count " + access.getParamCount());
+		return access.getParamCount();
+	}
+
+	@Override
+	public Object getValueAt(int rowIndex, int columnIndex) {
+		assert (rowIndex < access.getParamCount() && columnIndex < columnParams.size());
+
+		return elementAccess.select(access.get(rowIndex, Object.class)).get(columnParams.get(columnIndex), Object.class);
+	}
+
+	@Override
+	public boolean isCellEditable(int rowIndex, int columnIndex) {
+		return false;
+	}
+
+	@Override
+	public void removeTableModelListener(TableModelListener listener) {
+		listeners.remove(listener);
+	}
+
+	@Override
+	public void setValueAt(Object value, int rowIndex, int columnIndex) {
+		throw new UnsupportedOperationException().msg("setting value in table");
+
+	}
+
+	public void addColumn(PrimitiveParam<?> columnParam) {
+		log.debug("added " + columnParam);
+		columnParams.add(columnParam);
+	}
+
+	/**
+	 * @return the columnParams
+	 */
+	public List<PrimitiveParam<?>> getColumnParams() {
+		return Collections.unmodifiableList(columnParams);
+	}
+
+}
Index: java/main/src/main/java/com/framsticks/gui/tree/AbstractNode.java
===================================================================
--- java/main/src/main/java/com/framsticks/gui/tree/AbstractNode.java	(revision 99)
+++ java/main/src/main/java/com/framsticks/gui/tree/AbstractNode.java	(revision 99)
@@ -0,0 +1,17 @@
+package com.framsticks.gui.tree;
+
+
+
+public abstract class AbstractNode {
+
+	public AbstractNode() {
+	}
+
+	public abstract int getChildCount();
+	public abstract AbstractNode getChild(int number);
+	public abstract int getIndexOfChild(AbstractNode child);
+
+	public abstract boolean isLeaf();
+	public abstract void render(TreeCellRenderer renderer);
+
+}
Index: java/main/src/main/java/com/framsticks/gui/tree/EmptyNode.java
===================================================================
--- java/main/src/main/java/com/framsticks/gui/tree/EmptyNode.java	(revision 99)
+++ java/main/src/main/java/com/framsticks/gui/tree/EmptyNode.java	(revision 99)
@@ -0,0 +1,50 @@
+package com.framsticks.gui.tree;
+
+
+import com.framsticks.gui.ImageProvider;
+import com.framsticks.params.CompositeParam;
+
+public class EmptyNode extends AbstractNode {
+
+	protected final CompositeParam param;
+
+	/**
+	 * @param param
+	 */
+	public EmptyNode(CompositeParam param) {
+		this.param = param;
+	}
+
+	@Override
+	public int getChildCount() {
+		return 0;
+	}
+
+	@Override
+	public AbstractNode getChild(int number) {
+		return null;
+	}
+
+	@Override
+	public int getIndexOfChild(AbstractNode child) {
+		return -1;
+	}
+
+	@Override
+	public boolean isLeaf() {
+		return true;
+	}
+
+	@Override
+	public void render(TreeCellRenderer renderer) {
+		renderer.setIcon(ImageProvider.loadImage(TreeCellRenderer.findIconName(param)));
+		renderer.setText(param.getId());
+		renderer.setToolTipText("?");
+	}
+
+	@Override
+	public String toString() {
+		return param.toString();
+	}
+
+}
Index: java/main/src/main/java/com/framsticks/gui/tree/MetaNode.java
===================================================================
--- java/main/src/main/java/com/framsticks/gui/tree/MetaNode.java	(revision 99)
+++ java/main/src/main/java/com/framsticks/gui/tree/MetaNode.java	(revision 99)
@@ -0,0 +1,67 @@
+package com.framsticks.gui.tree;
+
+import java.util.LinkedList;
+import java.util.List;
+
+
+import com.framsticks.gui.ImageProvider;
+
+public class MetaNode extends AbstractNode {
+
+	protected List<AbstractNode> children = new LinkedList<>();
+	protected String name = "meta node";
+
+	/**
+	 * @return the children
+	 */
+	public List<AbstractNode> getChildren() {
+		return children;
+	}
+
+	/**
+	 * @return the name
+	 */
+	public String getName() {
+		return name;
+	}
+
+	/**
+	 * @param name the name to set
+	 */
+	public void setName(String name) {
+		this.name = name;
+	}
+
+	@Override
+	public int getChildCount() {
+		return children.size();
+	}
+
+	@Override
+	public AbstractNode getChild(int number) {
+		return children.get(number);
+	}
+
+	@Override
+	public int getIndexOfChild(AbstractNode child) {
+		return children.indexOf(child);
+	}
+
+	@Override
+	public String toString() {
+		return name;
+	}
+
+	@Override
+	public boolean isLeaf() {
+		return false;
+	}
+
+	@Override
+	public void render(TreeCellRenderer renderer) {
+		renderer.setIcon(ImageProvider.loadImage(ImageProvider.SERVER));
+		renderer.setText(name);
+		renderer.setToolTipText("?");
+	}
+
+}
Index: java/main/src/main/java/com/framsticks/gui/tree/TreeCellRenderer.java
===================================================================
--- java/main/src/main/java/com/framsticks/gui/tree/TreeCellRenderer.java	(revision 99)
+++ java/main/src/main/java/com/framsticks/gui/tree/TreeCellRenderer.java	(revision 99)
@@ -0,0 +1,95 @@
+package com.framsticks.gui.tree;
+
+import java.awt.Component;
+
+import javax.swing.JTree;
+import javax.swing.tree.DefaultTreeCellRenderer;
+
+import com.framsticks.gui.ImageProvider;
+import com.framsticks.params.CompositeParam;
+
+/**
+ * Renderer of Tree. Sets appropriate icons for nodes.
+ */
+@SuppressWarnings("serial")
+public class TreeCellRenderer extends DefaultTreeCellRenderer {
+
+	public TreeCellRenderer() {
+
+		// setOpenIcon(ImageProvider.loadImage(ImageProvider.FOLDER_OPEN));
+		// setClosedIcon(ImageProvider.loadImage(ImageProvider.FOLDER_CLOSED));
+		// setLeafIcon(ImageProvider.loadImage(ImageProvider.NODE));
+	}
+
+	@Override
+	public Component getTreeCellRendererComponent(JTree tree, Object value,
+			boolean sel, boolean expanded, boolean leaf, int row,
+			boolean hasFocus) {
+
+		super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus);
+
+		if (value == null) {
+			setText("!null value");
+			return this;
+		}
+
+		if (!(value instanceof AbstractNode)) {
+			setIcon(ImageProvider.loadImage(ImageProvider.SERVER));
+			setText("framsticks");
+			return this;
+		}
+		((AbstractNode) value).render(this);
+
+		return this;
+	}
+
+	public static String findIconName(CompositeParam param) {
+		switch (param.getFramsTypeName()) {
+			case "o Server": return ImageProvider.SERVER;
+			case "o Simulator": return ImageProvider.SIMULATOR;
+			case "o CLI": return ImageProvider.CLI;
+			case "o World": return ImageProvider.WORLD;
+			case "o GenePools": return ImageProvider.GENEPOOLS;
+			case "l GenePool": return ImageProvider.SIMULATOR; //HERE
+			case "o GenePool": return ImageProvider.GENEPOOLS_GROUP; //HERE
+
+			case "o Populations": return ImageProvider.POPULATIONS;
+			case "l Population": return ImageProvider.SIMULATOR; ///HERE
+			case "o Population": return ImageProvider.POPULATION_GROUP;
+			case "o ExpParams": return ImageProvider.EXPERIMENT;
+			case "o stats": return ImageProvider.STATISTIC;
+			case "l Genotype uid": return ImageProvider.GENOTYPES_GROUP;
+			case "o Genotype": return ImageProvider.GENOTYPES;
+
+			case "o Part": return ImageProvider.PART;
+			case "o Joint": return ImageProvider.JOINT;
+			case "o NeuroDef": return ImageProvider.NEURON_DEF;
+			case "o NeuroConn": return ImageProvider.NEURON_DEF;
+
+			case "o MechPart": return ImageProvider.MECH_PART;
+			case "o MechJoint": return ImageProvider.MECH_JOINT;
+			case "o Neuro": return ImageProvider.NEURON;
+
+			case "l Part": return ImageProvider.PART_GROUP;
+			case "l Joint": return ImageProvider.JOINT_GROUP;
+			case "l NeuroDef": return ImageProvider.NEURON_DEF_GROUP;
+			case "l NeuroConn": return ImageProvider.NEURON_DEF_GROUP;
+
+			case "l MechPart": return ImageProvider.MECH_PART_GROUP;
+			case "l MechJoint": return ImageProvider.MECH_JOINT_GROUP;
+			case "l Neuro": return ImageProvider.NEURON_GROUP;
+
+			case "o Creature": return ImageProvider.CREATURE;
+			case "l Creature uid": return ImageProvider.CREATURES_GROUP;
+			case "l Event id": return ImageProvider.EVENT;
+			case "o Event": return ImageProvider.EVENT;
+
+		}
+
+
+		return ImageProvider.SERVER;
+	}
+
+
+
+}
Index: java/main/src/main/java/com/framsticks/gui/tree/TreeModel.java
===================================================================
--- java/main/src/main/java/com/framsticks/gui/tree/TreeModel.java	(revision 99)
+++ java/main/src/main/java/com/framsticks/gui/tree/TreeModel.java	(revision 99)
@@ -0,0 +1,229 @@
+package com.framsticks.gui.tree;
+
+// import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+
+import javax.swing.event.TreeModelEvent;
+import javax.swing.event.TreeModelListener;
+import javax.swing.tree.TreePath;
+
+import org.apache.log4j.Logger;
+
+
+import com.framsticks.core.Node;
+import com.framsticks.core.Path;
+import com.framsticks.core.Tree;
+import com.framsticks.core.TreeOperations;
+import com.framsticks.gui.Frame;
+import com.framsticks.params.AccessInterface;
+import com.framsticks.util.FramsticksException;
+import com.framsticks.util.UnsupportedOperationException;
+import com.framsticks.util.dispatching.FutureHandler;
+import com.framsticks.util.lang.Casting;
+
+public class TreeModel implements javax.swing.tree.TreeModel {
+	private static final Logger log = Logger.getLogger(TreeModel.class);
+
+
+	protected List<TreeModelListener> listeners = new LinkedList<>();
+
+	protected final Frame frame;
+
+	/**
+	 * @param frame
+	 */
+	public TreeModel(Frame frame) {
+		this.frame = frame;
+	}
+
+	@Override
+	public void addTreeModelListener(TreeModelListener listener) {
+		listeners.add(listener);
+	}
+
+	@Override
+	public AbstractNode getChild(Object parent, int number) {
+		return Casting.assertCast(AbstractNode.class, parent).getChild(number);
+	}
+
+	@Override
+	public int getChildCount(Object parent) {
+		return Casting.assertCast(AbstractNode.class, parent).getChildCount();
+	}
+
+	@Override
+	public int getIndexOfChild(Object parent, Object child) {
+		if ((parent == null) || (child == null)) {
+			return -1;
+		}
+		return Casting.assertCast(AbstractNode.class, parent).getIndexOfChild(Casting.assertCast(AbstractNode.class, child));
+	}
+
+	@Override
+	public MetaNode getRoot() {
+		return frame.getRootNode();
+	}
+
+	@Override
+	public boolean isLeaf(Object node) {
+		return Casting.assertCast(AbstractNode.class, node).isLeaf();
+	}
+
+	@Override
+	public void removeTreeModelListener(TreeModelListener listener) {
+		listeners.remove(listener);
+	}
+
+	@Override
+	public void valueForPathChanged(TreePath path, Object value) {
+		throw new UnsupportedOperationException().msg("changing value of tree node");
+	}
+
+
+	protected boolean changing = false;
+
+	public void nodeStructureChanged(TreePath treePath) {
+		if (treePath == null) {
+			return;
+		}
+		assert frame.isActive();
+
+		changing = true;
+		log.debug("changing: " + treePath);
+		// Enumeration<TreePath> expanded = frame.jtree.getExpandedDescendants(treePath);
+		TreePath selection = frame.getJtree().getSelectionPath();
+
+		for (TreeModelListener listener : listeners) {
+			listener.treeStructureChanged(new TreeModelEvent(this, treePath));
+		}
+		// if (expanded != null) {
+		// 	while (expanded.hasMoreElements()) {
+		// 		TreePath expansion = expanded.nextElement();
+		// 		// log.info("reexpanding: " + expansion);
+		// 		frame.jtree.expandPath(expansion);
+		// 	}
+		// }
+		if (selection != null) {
+			frame.getJtree().setSelectionPath(selection);
+		}
+		changing = false;
+	}
+
+	public Path convertToPath(TreePath treePath) {
+		final Object[] components = treePath.getPath();
+		assert components[0] == frame.getRootNode();
+		if (components.length == 1) {
+			return null;
+		}
+		Path.PathBuilder builder = Path.build();
+		builder.tree(Casting.assertCast(TreeNode.class, components[1]).getTree());
+		List<Node> nodes = new LinkedList<>();
+		for (int i = 1; i < components.length; ++i) {
+			TreeNode treeNode = Casting.tryCast(TreeNode.class, components[i]);
+			if (treeNode == null) {
+				return null;
+			}
+			Node node = treeNode.tryCreateNode();
+			if (node == null) {
+				throw new FramsticksException().msg("failed to recreate path").arg("treePath", treePath);
+			}
+			nodes.add(node);
+		}
+		builder.buildUpTo(nodes, null);
+
+		return builder.finish();
+	}
+
+	public TreePath convertToTreePath(Path path) {
+		assert frame.isActive();
+
+		List<Object> accumulator = new LinkedList<Object>();
+		accumulator.add(getRoot());
+
+		for (AbstractNode r : getRoot().getChildren()) {
+			if (r instanceof TreeNode) {
+				TreeNode root = (TreeNode) r;
+				if (root.getTree() == path.getTree()) {
+					accumulator.add(root);
+
+					Iterator<Node> i = path.getNodes().iterator();
+					i.next();
+					TreeNode treeNode = root;
+
+					while (i.hasNext()) {
+						Node node = i.next();
+						treeNode = treeNode.getTreeNodeForChild(node.getObject());
+						if (treeNode == null) {
+							break;
+						}
+						accumulator.add(treeNode);
+					}
+
+					break;
+				}
+			}
+		}
+		return new TreePath(accumulator.toArray());
+	}
+
+	/**
+	 * @return the changing
+	 */
+	public boolean isChanging() {
+		return changing;
+	}
+
+	public void loadChildren(Path path, boolean reload) {
+		if (path == null) {
+			return;
+		}
+		AccessInterface access = TreeOperations.bindAccess(path);
+
+		int count = access.getCompositeParamCount();
+		for (int i = 0; i < count; ++i) {
+			Path childPath = path.appendParam(access.getCompositeParam(i)).tryFindResolution();
+			loadPath(childPath, reload);
+		}
+	}
+
+	public void loadPath(Path path, boolean reload) {
+		if (path == null) {
+			return;
+		}
+		if (path.isResolved() && !reload) {
+			return;
+		}
+		path.getTree().get(path, new FutureHandler<Path>(frame) {
+			@Override
+			protected void result(Path result) {
+				final TreePath treePath = convertToTreePath(result);
+
+				nodeStructureChanged(treePath);
+				frame.updatePanelIfIsLeadSelection(treePath, result);
+			}
+		});
+	}
+
+	public void chooseTreeNode(final TreePath treePath) {
+		assert frame.isActive();
+		if (treePath == null) {
+			return;
+		}
+		if (isChanging()) {
+			return;
+		}
+
+		Path path = convertToPath(treePath);
+		if (path == null) {
+			return;
+		}
+		path = path.assureResolved();
+		final Tree tree = path.getTree();
+
+		frame.getTreeAtFrames().get(tree).useOrCreatePanel(treePath);
+		loadChildren(path, false);
+
+	}
+}
Index: java/main/src/main/java/com/framsticks/gui/tree/TreeNode.java
===================================================================
--- java/main/src/main/java/com/framsticks/gui/tree/TreeNode.java	(revision 99)
+++ java/main/src/main/java/com/framsticks/gui/tree/TreeNode.java	(revision 99)
@@ -0,0 +1,349 @@
+package com.framsticks.gui.tree;
+
+import java.lang.ref.WeakReference;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import javax.swing.ImageIcon;
+import javax.swing.tree.TreePath;
+
+import org.apache.log4j.Logger;
+
+import com.framsticks.core.ListChange;
+import com.framsticks.core.Node;
+import com.framsticks.core.Path;
+import com.framsticks.core.Tree;
+import com.framsticks.gui.Frame;
+import com.framsticks.gui.ImageProvider;
+import com.framsticks.gui.TreeAtFrame;
+import com.framsticks.params.AccessInterface;
+import com.framsticks.params.CompositeParam;
+import com.framsticks.params.EventListener;
+import com.framsticks.params.FramsClass;
+import com.framsticks.params.PrimitiveParam;
+import com.framsticks.params.ValueParam;
+import com.framsticks.params.types.EventParam;
+import com.framsticks.params.types.ObjectParam;
+import com.framsticks.params.types.StringParam;
+import com.framsticks.util.FramsticksException;
+import com.framsticks.util.dispatching.FutureHandler;
+import com.framsticks.util.lang.Casting;
+import com.framsticks.util.lang.Containers;
+import com.framsticks.util.lang.Pair;
+import com.framsticks.util.swing.TooltipConstructor;
+import static com.framsticks.core.TreeOperations.*;
+
+public class TreeNode extends AbstractNode {
+	private static final Logger log = Logger.getLogger(TreeNode.class);
+
+
+	protected static final AtomicInteger counter = new AtomicInteger();
+
+	protected final WeakReference<Object> reference;
+	protected final CompositeParam param;
+	protected final TreeAtFrame treeAtFrame;
+	protected final List<Pair<WeakReference<Object>, WeakReference<TreeNode>>> children = new LinkedList<>();
+	protected final int number;
+	protected final String textualPath;
+	protected final ImageIcon imageIcon;
+	protected final TreeModel treeModel;
+
+	protected final List<EventListener<?>> listeners = new LinkedList<>();
+
+	public TreeNode(TreeAtFrame treeAtFrame, Path path) {
+		path.assureResolved();
+		this.textualPath = path.getTextual();
+		this.param = path.getTop().getParam();
+		this.treeAtFrame = treeAtFrame;
+		this.treeModel = treeAtFrame.getFrame().getTreeModel();
+		this.imageIcon = ImageProvider.loadImage(TreeCellRenderer.findIconName(param));
+
+		reference = new WeakReference<Object>(path.getTop().getObject());
+		number = counter.getAndIncrement();
+
+		/** Iterate over all EventParams and for matching ValueParams register listeners. */
+		if (param instanceof ObjectParam) {
+			AccessInterface access = bindAccess(path);
+			FramsClass framsClass = access.getFramsClass();
+			for (EventParam eventParam : Containers.filterInstanceof(framsClass.getParamEntries(), EventParam.class)) {
+				if (!eventParam.getId().endsWith("_changed")) {
+					continue;
+				}
+				String valueId = eventParam.getId().substring(0, eventParam.getId().length() - 8);
+				final ValueParam valueParam = Casting.tryCast(ValueParam.class, framsClass.getParam(valueId));
+				if (valueParam == null) {
+					continue;
+				}
+				registerForEventParam(path, eventParam, valueParam);
+			}
+		}
+	}
+
+	protected <A> void tryAddListener(final Path path, final EventParam eventParam, Class<A> argumentType, final EventListener<A> listener) {
+		treeAtFrame.getTree().addListener(path, eventParam, listener, argumentType, new FutureHandler<Void>(treeAtFrame.getFrame()) {
+			@Override
+			protected void result(Void result) {
+				assert treeAtFrame.getFrame().isActive();
+				log.debug("registered gui listener for " + eventParam + " at " + path);
+				listeners.add(listener);
+			}
+		});
+	}
+
+	protected void registerForEventParam(Path path, EventParam eventParam, ValueParam valueParam) {
+		/** TODO make this listener not bind hold the reference to this TreeNode, maybe hold WeakReference internally */
+		if (valueParam instanceof PrimitiveParam) {
+
+			tryAddListener(path, eventParam, Object.class, new EventListener<Object>() {
+				@Override
+				public void action(Object argument) {
+					treeModel.loadPath(assurePath(), true);
+				}
+			});
+
+		} else if (valueParam instanceof CompositeParam) {
+
+			final CompositeParam compositeParam = (CompositeParam) valueParam;
+
+			tryAddListener(path, eventParam, ListChange.class, new EventListener<ListChange>() {
+				@Override
+				public void action(ListChange listChange) {
+					assert treeAtFrame.getTree().isActive();
+
+					final Path listPath = assurePath().appendParam(compositeParam).tryFindResolution().assureResolved();
+					log.debug("reacting to change " + listChange + " in " + listPath);
+
+					if ((listChange.getAction().equals(ListChange.Action.Modify)) && (listChange.getPosition() == -1)) {
+						// get(listPath, future);
+						return;
+					}
+					final String id = listChange.getBestIdentifier();
+
+					AccessInterface access = bindAccess(listPath);
+					switch (listChange.getAction()) {
+						case Add: {
+							tryGet(listPath.getTree(), Path.appendString(listPath.getTextual(), id), new FutureHandler<Path>(treeAtFrame.getFrame()) {
+								@Override
+								protected void result(Path result) {
+									final Frame frame = treeAtFrame.getFrame();
+									assert frame.isActive();
+									final TreePath treePath = frame.getTreeModel().convertToTreePath(listPath);
+									treeModel.nodeStructureChanged(treePath);
+									frame.updatePanelIfIsLeadSelection(treePath, listPath);
+									log.debug("added " + id + "(" + result + ") updated " + treePath);
+								}
+							});
+							break;
+						}
+						case Remove: {
+							access.set(id, null);
+							Frame frame = treeAtFrame.getFrame();
+							treeModel.nodeStructureChanged(frame.getTreeModel().convertToTreePath(listPath));
+							break;
+						}
+						case Modify: {
+							tryGet(listPath.getTree(), Path.appendString(listPath.getTextual(), id), new FutureHandler<Path>(treeAtFrame.getFrame()) {
+								@Override
+								protected void result(Path result) {
+									final Frame frame = treeAtFrame.getFrame();
+									assert frame.isActive();
+									final TreePath treePath = frame.getTreeModel().convertToTreePath(result);
+									treeModel.nodeStructureChanged(treePath);
+									frame.updatePanelIfIsLeadSelection(treePath, listPath);
+								}
+							});
+							break;
+						}
+					}
+				}
+			});
+		}
+
+	}
+
+	protected Path assurePath() {
+		return Path.to(treeAtFrame.getTree(), textualPath).assureResolved();
+	}
+
+	public Node tryCreateNode() {
+		Object child = lock();
+		if (child == null) {
+			return null;
+		}
+		return Path.to(treeAtFrame.getTree(), textualPath).assureResolved().getTop();
+	}
+
+	@Override
+	public int getChildCount() {
+		Object referent = lock();
+		if (referent == null) {
+			return 0;
+		}
+		AccessInterface access = bindAccessFor(referent);
+		final int count = access.getCompositeParamCount();
+		return count;
+	}
+
+	public TreeNode getTreeNodeForChild(Object child) {
+		Iterator<Pair<WeakReference<Object>, WeakReference<TreeNode>>> i = children.iterator();
+		while (i.hasNext()) {
+			Pair<WeakReference<Object>, WeakReference<TreeNode>> p = i.next();
+			Object object = p.first.get();
+			if (object == null) {
+				i.remove();
+				continue;
+			}
+			TreeNode treeNode = p.second.get();
+			if (treeNode == null) {
+				i.remove();
+				continue;
+			}
+			if (object == child) {
+				return treeNode;
+			}
+		}
+		return null;
+
+		// WeakReference<GuiTreeNode> resultReference = children.get(child);
+		// if (resultReference == null) {
+		//	return null;
+		// }
+		// return resultReference.get();
+	}
+
+	@Override
+	public AbstractNode getChild(int number) {
+		Object referent = lock();
+		if (referent == null) {
+			throw new FramsticksException().msg("invalid state - missing referent");
+		}
+		AccessInterface access = bindAccessFor(referent);
+
+		final int count = access.getCompositeParamCount();
+		if (number >= count) {
+			throw new FramsticksException().msg("invalid state - no child");
+		}
+
+		CompositeParam childParam = access.getCompositeParam(number);
+		Object child = access.get(childParam, Object.class);
+		if (child == null) {
+			log.debug("returning dummy node for " + childParam + " in " + referent);
+			return new EmptyNode(childParam);
+		}
+
+		TreeNode result = getTreeNodeForChild(child);
+		if (result != null) {
+			return result;
+		}
+		Path path = Path.to(treeAtFrame.getTree(), Path.appendString(textualPath, childParam.getId())).assureResolved();
+		result = new TreeNode(treeAtFrame, path);
+
+		children.add(Pair.make(new WeakReference<Object>(child), new WeakReference<TreeNode>(result)));
+
+		return result;
+
+	}
+
+	public Object lock() {
+		return reference.get();
+	}
+
+	@Override
+	public int getIndexOfChild(AbstractNode child) {
+		final TreeNode treeChild = Casting.tryCast(TreeNode.class, child);
+		if (treeChild == null) {
+			return -1;
+		}
+		final Object childObject = treeChild.lock();
+		final Object parentObject = lock();
+		if (childObject == null || parentObject == null) {
+			return -1;
+		}
+		final AccessInterface access = bindAccessFor(parentObject);
+
+		final int count = access.getCompositeParamCount();
+		for (int i = 0; i < count; ++i) {
+			Object c = access.get(access.getCompositeParam(i), Object.class);
+			if (c == childObject) {
+				return i;
+			}
+		}
+		log.debug(child + " not found in " + this);
+		return -1;
+	}
+
+	/**
+	 * @return the param
+	 */
+	public CompositeParam getParam() {
+		return param;
+	}
+
+	/**
+	 * @return the tree
+	 */
+	public Tree getTree() {
+		return treeAtFrame.getTree();
+	}
+
+
+	@Override
+	public String toString() {
+		return param.toString();
+	}
+
+	public static Node tryGetNode(TreePath treePath) {
+		return Casting.throwCast(TreeNode.class, treePath.getLastPathComponent()).tryCreateNode();
+	}
+
+	@Override
+	public boolean isLeaf() {
+		Object referent = lock();
+		if (referent == null) {
+			return true;
+		}
+		return bindAccessFor(referent).getCompositeParamCount() == 0;
+	}
+
+	protected AccessInterface bindAccessFor(Object child) {
+		return treeAtFrame.getTree().prepareAccess(param).select(child);
+	}
+
+	@Override
+	public void render(TreeCellRenderer renderer) {
+		String name = param.getId();
+
+		Object child = lock();
+		if (child != null) {
+			AccessInterface access = bindAccessFor(child);
+
+			StringParam nameParam = Casting.tryCast(StringParam.class, access.getParam("name"));
+
+			if (nameParam != null) {
+				name = access.get(nameParam, String.class);
+			}
+
+			renderer.setToolTipText(new TooltipConstructor()
+				.append("frams", access.getId())
+				.append("java", child.getClass().getCanonicalName())
+				.append("access", access.getClass().getSimpleName())
+				.append("name", name)
+				.append("id", param.getId())
+				.append("object", Integer.toHexString(System.identityHashCode(child)))
+				.append("number", number)
+				.append("textual path", textualPath)
+				.build());
+		} else {
+			renderer.setToolTipText(new TooltipConstructor()
+				.append("param", param)
+				.append("textual path", textualPath)
+				.build());
+		}
+		renderer.setText(name);
+		renderer.setIcon(imageIcon);
+
+	}
+
+}
Index: java/main/src/main/java/com/framsticks/hosting/Cli.java
===================================================================
--- java/main/src/main/java/com/framsticks/hosting/Cli.java	(revision 99)
+++ java/main/src/main/java/com/framsticks/hosting/Cli.java	(revision 99)
@@ -0,0 +1,77 @@
+package com.framsticks.hosting;
+
+import java.util.Map;
+import java.util.TreeMap;
+
+import org.apache.log4j.Logger;
+
+import com.framsticks.communication.Response;
+import com.framsticks.communication.ServerSideResponseFuture;
+import com.framsticks.core.Path;
+import com.framsticks.core.Tree;
+import com.framsticks.params.EventListener;
+import com.framsticks.params.annotations.FramsClassAnnotation;
+import com.framsticks.params.annotations.ParamAnnotation;
+import com.framsticks.params.types.EventParam;
+import com.framsticks.util.dispatching.FutureHandler;
+import com.framsticks.util.dispatching.ThrowExceptionHandler;
+
+@FramsClassAnnotation
+public class Cli {
+	private static final Logger log =
+		Logger.getLogger(Cli.class);
+
+
+	protected int eventCounter = 0;
+	protected final Tree tree;
+	protected final ClientAtServer client;
+
+	@ParamAnnotation
+	public final Map<String, CliEvent> events = new TreeMap<>();
+
+	/**
+	 * @param tree
+	 */
+	public Cli(ClientAtServer client) {
+		this.client = client;
+		this.tree = client.getTree();
+	}
+
+	public void addListener(Path path, EventParam param, String pathPrefix, ServerSideResponseFuture responseFuture) {
+		log.debug("adding listener for " + path + ": " + param);
+
+		final CliEvent event = new CliEvent();
+		event.cli = this;
+		event.id = "e" + (eventCounter++);
+		event.path = path;
+		event.param = param;
+		event.name = pathPrefix + Path.appendString(path.getTextual(), param.getId());
+		event.pathToEvent = "/cli/events/" + event.id;
+
+		event.listener = new EventListener<Object>() {
+
+			@Override
+			public void action(Object argument) {
+				log.debug("registered event " + event + " happened with " + argument);
+
+				client.connection.sendFile(
+						"event " + event.pathToEvent + " " + event.name,
+						ClientAtServer.printToFile("", tree.getRegistry().createAccess(argument.getClass()).select(argument))
+					);
+			}
+		};
+
+		// SyncedFuture handler = new SyncedFuture<Void>(ThrowExceptionHandler.getInstance());
+		path.getTree().addListener(path, param, event.listener, Object.class, FutureHandler.doNothing(Void.class, ThrowExceptionHandler.getInstance()));
+
+		events.put(event.id, event);
+		responseFuture.pass(new Response(true, event.pathToEvent, null));
+		// handler
+	}
+
+	@Override
+	public String toString() {
+		return "CLI for " + tree;
+	}
+
+}
Index: java/main/src/main/java/com/framsticks/hosting/CliEvent.java
===================================================================
--- java/main/src/main/java/com/framsticks/hosting/CliEvent.java	(revision 99)
+++ java/main/src/main/java/com/framsticks/hosting/CliEvent.java	(revision 99)
@@ -0,0 +1,67 @@
+package com.framsticks.hosting;
+
+import com.framsticks.core.Path;
+import com.framsticks.params.EventListener;
+import com.framsticks.params.annotations.FramsClassAnnotation;
+import com.framsticks.params.annotations.ParamAnnotation;
+import com.framsticks.params.types.EventParam;
+import com.framsticks.params.types.ProcedureParam;
+import com.framsticks.util.dispatching.FutureHandler;
+import com.framsticks.util.dispatching.ThrowExceptionHandler;
+
+@FramsClassAnnotation
+public class CliEvent {
+
+	protected Cli cli;
+	protected String id;
+
+	protected Path path;
+	protected EventParam param;
+
+	protected String name;
+	protected String pathToEvent;
+
+	protected EventListener<Object> listener;
+	// protected String name;
+
+
+
+	/**
+	 * @param id
+	 * @param listener
+	 * @param tree
+	 * @param name
+	 * @param path
+	 * @param param
+	 */
+	public CliEvent() {
+	}
+
+	@ParamAnnotation(paramType = ProcedureParam.class)
+	public void remove() {
+		assert path.getTree().isActive();
+
+		//it should happen now
+		path.getTree().removeListener(path, param, listener, FutureHandler.doNothing(Void.class, ThrowExceptionHandler.getInstance()));
+		cli.events.remove(id);
+	}
+
+	/**
+	 * @return the id
+	 */
+	@ParamAnnotation
+	public String getId() {
+		return id;
+	}
+
+	@ParamAnnotation
+	public String getName() {
+		return id;
+	}
+
+	@Override
+	public String toString() {
+		return "event " + id + " of type " + param + " in " + path;
+	}
+
+}
Index: java/main/src/main/java/com/framsticks/hosting/ClientAtServer.java
===================================================================
--- java/main/src/main/java/com/framsticks/hosting/ClientAtServer.java	(revision 98)
+++ java/main/src/main/java/com/framsticks/hosting/ClientAtServer.java	(revision 99)
@@ -8,11 +8,15 @@
 import com.framsticks.communication.queries.GetRequest;
 import com.framsticks.communication.queries.InfoRequest;
+import com.framsticks.communication.queries.RegisterRequest;
 import com.framsticks.communication.queries.SetRequest;
+import com.framsticks.core.LocalTree;
 import com.framsticks.core.Tree;
 import com.framsticks.core.Path;
 import com.framsticks.params.*;
+import com.framsticks.params.types.EventParam;
 import com.framsticks.params.types.ProcedureParam;
 import com.framsticks.parsers.Savers;
 import com.framsticks.util.FramsticksException;
+import com.framsticks.util.Misc;
 import com.framsticks.util.dispatching.AbstractJoinable;
 import com.framsticks.util.dispatching.Dispatching;
@@ -22,9 +26,10 @@
 import com.framsticks.util.dispatching.JoinableParent;
 import com.framsticks.util.dispatching.JoinableState;
+import com.framsticks.util.lang.FlagsUtil;
+import com.framsticks.util.lang.Strings;
+
 import static com.framsticks.core.TreeOperations.*;
 
 import java.net.Socket;
-import java.util.LinkedList;
-import java.util.List;
 
 /**
@@ -34,11 +39,56 @@
 
 	protected final Server server;
-	protected final Tree tree;
+	protected final Tree contentTree;
+	protected final Object treeRootObject;
 	protected final ServerSideManagedConnection connection;
+
+	protected final Cli cliObject;
+	protected final LocalTree rootTree;
+
+
+	protected final FramsClass rootFramsClass;
+	protected final Object root;
+	protected final String contentPrefix;
 
 	public ClientAtServer(Server server, Socket socket) {
 		this.server = server;
-		this.tree = server.hosted;
+		this.contentTree = server.hosted;
 		this.connection = new ServerSideManagedConnection(socket, this);
+
+		treeRootObject = contentTree.getAssignedRoot().getObject();
+		Misc.throwIfNull(treeRootObject);
+
+		cliObject = new Cli(this);
+		rootTree = new LocalTree();
+		// rootTree.setDispatcher(new AtOnceDispatcher<Tree>());
+		rootTree.setDispatcher(server.getHosted().getDispatcher());
+		assert rootTree.getDispatcher() != null;
+
+		final FramsClass framsClass = bindAccess(contentTree.getAssignedRoot()).getFramsClass();
+		final String id = Strings.uncapitalize(framsClass.getName());
+		contentPrefix = "/" + id;
+		final String rootFramsClassId = id + "Root";
+
+		rootFramsClass = FramsClass.build()
+			.idAndName(rootFramsClassId)
+			.param(Param.build().id(id).name(framsClass.getName()).type("o " + framsClass.getId()))
+			.param(Param.build().id("cli").name("CLI").type("o Cli"))
+			.finish();
+
+		// rootTree.putInfoIntoCache(rootFramsClass);
+		rootTree.getRegistry().putFramsClass(rootFramsClass);
+		rootTree.getRegistry().registerAndBuild(Cli.class);
+		rootTree.getRegistry().registerAndBuild(CliEvent.class);
+
+		AccessInterface access = new PropertiesAccess(rootFramsClass);
+
+		root = access.createAccessee();
+		access.select(root);
+		access.set(id, treeRootObject);
+		access.set("cli", cliObject);
+
+		rootTree.assignRootParam(access.buildParam(new ParamBuilder()).name(rootFramsClassId).finish(CompositeParam.class));
+		rootTree.assignRootObject(root);
+
 	}
 
@@ -52,14 +102,42 @@
 		assureNotEmpty(request.getPath());
 
-		tryGet(tree, request.getPath(), new FutureHandler<Path>(responseCallback) {
+		if (request.getPath().startsWith(contentPrefix)) {
+			String p = request.getPath().substring(contentPrefix.length());
+			request.path(p.equals("") ? "/" : p);
+			handleInTree(contentTree, request, responseCallback, contentPrefix);
+			return;
+		}
+
+		handleInTree(rootTree, request, responseCallback, "");
+	}
+
+	public static File printToFile(String path, AccessInterface access) {
+		ListSink sink = new ListSink();
+		access.save(sink);
+		return new File(path, new ListSource(sink.getOut()));
+	}
+
+	protected void handleInTree(final Tree tree, final ApplicationRequest request, final ServerSideResponseFuture responseCallback, final String usedPrefix) {
+
+		tryGet(tree, request.getActualPath(), new FutureHandler<Path>(responseCallback) {
 			@Override
 			protected void result(final Path path) {
 
-				if (!path.getTextual().equals(request.getPath())) {
-					throw new FramsticksException().msg("invalid path").arg("path", request.getPath());
+				if (!path.getTextual().equals(request.getActualPath())) {
+					throw new FramsticksException().msg("invalid path").arg("path", request.getActualPath());
 				}
 
 				// final AccessInterface access = tree.prepareAccess(path);
 				final AccessInterface access = bindAccess(path);
+
+				if (request instanceof GetRequest) {
+					Object result = path.getTopObject();
+					if (result != access.getSelected()) {
+						throw new FramsticksException().msg("mismatch objects during fetch").arg("path", path);
+					}
+					responseCallback.pass(new Response(true, "", File.single(printToFile(path.getTextual(), access))));
+
+					return;
+				}
 
 				if (request instanceof SetRequest) {
@@ -69,5 +147,5 @@
 						@Override
 						protected void result(Integer flag) {
-							responseCallback.pass(new Response(true, Flags.write(flag, null), null));
+							responseCallback.pass(new Response(true, FlagsUtil.write(SetStateFlags.class, flag, null), null));
 
 						}
@@ -76,17 +154,4 @@
 				}
 
-				if (request instanceof GetRequest) {
-					Object result = path.getTopObject();
-					if (result != access.getSelected()) {
-						throw new FramsticksException().msg("mismatch objects during fetch").arg("path", path);
-					}
-					List<File> files = new LinkedList<File>();
-					ListSink sink = new ListSink();
-					access.save(sink);
-					files.add(new File(path.getTextual(), new ListSource(sink.getOut())));
-					responseCallback.pass(new Response(true, "", files));
-
-					return;
-				}
 				if (request instanceof CallRequest) {
 					final CallRequest callRequest = (CallRequest) request;
@@ -107,4 +172,5 @@
 					return;
 				}
+
 				if (request instanceof InfoRequest) {
 					FramsClass framsClass = getInfo(path);
@@ -116,4 +182,11 @@
 				}
 
+				if (request instanceof RegisterRequest) {
+					RegisterRequest register = (RegisterRequest) request;
+
+					cliObject.addListener(path, access.getFramsClass().getParamEntry(register.getEventName(), EventParam.class), usedPrefix, responseCallback);
+					return;
+				}
+
 				throw new FramsticksException().msg("invalid request type: " + request.getCommand());
 			}
@@ -148,5 +221,12 @@
 	@Override
 	public void handle(FramsticksException exception) {
-		tree.handle(exception);
+		contentTree.handle(exception);
+	}
+
+	/**
+	 * @return the tree
+	 */
+	public Tree getTree() {
+		return contentTree;
 	}
 
Index: java/main/src/main/java/com/framsticks/model/Model.java
===================================================================
--- java/main/src/main/java/com/framsticks/model/Model.java	(revision 98)
+++ java/main/src/main/java/com/framsticks/model/Model.java	(revision 99)
@@ -59,3 +59,9 @@
 	public List<NeuroConnection> getNeuroConnections() { return neuroConnections; }
 
+	@Override
+	public String toString() {
+		return "Model{" + parts.size() + ":" + joints.size() + ":" + neuroDefinitions.size() + ":" + neuroConnections.size() + "}";
+
+	}
+
 }
Index: java/main/src/main/java/com/framsticks/params/AccessInterface.java
===================================================================
--- java/main/src/main/java/com/framsticks/params/AccessInterface.java	(revision 98)
+++ java/main/src/main/java/com/framsticks/params/AccessInterface.java	(revision 99)
@@ -2,4 +2,5 @@
 
 
+import com.framsticks.params.types.EventParam;
 import com.framsticks.params.types.ProcedureParam;
 
@@ -39,4 +40,8 @@
 	<T> int set(ValueParam param, T value);
 
+	void reg(EventParam param, EventListener<?> listener);
+
+	void regRemove(EventParam param, EventListener<?> listener);
+
 	void setDefault(boolean numericOnly);
 
@@ -50,6 +55,4 @@
 
 	void setMax(int i);
-
-	void copyFrom(AccessInterface src);
 
 	void save(SinkInterface sink);
@@ -80,4 +83,6 @@
 	CompositeParam getCompositeParam(int number);
 
+	ParamBuilder buildParam(ParamBuilder builder);
+
 
 }
Index: java/main/src/main/java/com/framsticks/params/ArrayListAccess.java
===================================================================
--- java/main/src/main/java/com/framsticks/params/ArrayListAccess.java	(revision 98)
+++ java/main/src/main/java/com/framsticks/params/ArrayListAccess.java	(revision 99)
@@ -1,4 +1,5 @@
 package com.framsticks.params;
 
+import com.framsticks.params.types.ArrayListParam;
 import com.framsticks.util.UnimplementedException;
 import com.framsticks.util.lang.Numbers;
@@ -15,4 +16,5 @@
 
 	List<Object> list;
+
 
 	public ArrayListAccess(AccessInterface elementAccess) {
@@ -35,5 +37,5 @@
 			return null;
 		}
-		return Param.build().id(Integer.toString(i)).forAccess(elementAccess).finish(CompositeParam.class);
+		return paramBuilder.id(Integer.toString(i)).finish(CompositeParam.class);
 	}
 
@@ -109,8 +111,4 @@
 	}
 
-	@Override
-	public String computeIdentifierFor(Object selected) {
-		return Integer.toString(list.size());
-	}
 
 	@Override
@@ -131,5 +129,5 @@
 					@Override
 					public Param next() {
-						Param param = Param.build().id(Integer.toString(internal.nextIndex())).forAccess(elementAccess).finish();
+						Param param = paramBuilder.id(Integer.toString(internal.nextIndex())).finish(CompositeParam.class);
 						internal.next();
 						return param;
@@ -156,4 +154,8 @@
 	}
 
+	@Override
+	public ParamBuilder buildParam(ParamBuilder builder) {
+		return builder.name(containedTypeName + " list").type(ArrayListParam.class).containedTypeName(containedTypeName);
+	}
 
 }
Index: java/main/src/main/java/com/framsticks/params/EventListener.java
===================================================================
--- java/main/src/main/java/com/framsticks/params/EventListener.java	(revision 99)
+++ java/main/src/main/java/com/framsticks/params/EventListener.java	(revision 99)
@@ -0,0 +1,5 @@
+package com.framsticks.params;
+
+public interface EventListener<A> extends java.util.EventListener {
+	public void action(A argument);
+}
Index: java/main/src/main/java/com/framsticks/params/Flags.java
===================================================================
--- java/main/src/main/java/com/framsticks/params/Flags.java	(revision 98)
+++ 	(revision )
@@ -1,87 +1,0 @@
-package com.framsticks.params;
-
-import java.lang.reflect.Field;
-import org.apache.log4j.Logger;
-
-import com.framsticks.util.lang.Delimeted;
-
-/**
- * The class Flags contains constants connected with parameter features as
- * well as feedback about set operation (when setting parameter value).
- *
- * Based on c++ defines located in: cpp/gdk/param.h
- *
- * @author Jarek Szymczak <name.surname@gmail.com>
- * (please replace name and surname with my personal data)
- *
- * @@author Piotr Sniegowski
- */
-public final class Flags {
-
-	private final static Logger log = Logger.getLogger(Flags.class.getName());
-
-	public static final int READONLY = 1;
-
-	public static final int DONTSAVE = 2;
-
-	public static final int USERREADONLY = 16;
-
-	public static final int USERHIDDEN = 32;
-
-	public static final int MUTALLOCENTRY = 64;
-
-	public static final int MUTALLOCDATA = 128;
-
-	public static final int NOSTATIC = 256;
-
-	public static final int CONST = 512;
-
-	public static final int CANOMITNAME = 1024;
-
-	public static final int DONTLOAD = 2048;
-
-	public static final int PSET_RONLY = 1;
-
-	public static final int PSET_CHANGED = 2;
-
-	public static final int PSET_HITMIN = 4;
-
-	public static final int PSET_HITMAX = 8;
-
-	public static String write(int flags, String empty) {
-		Delimeted<String> d = new Delimeted<String>("+", empty);
-		try {
-			for (Field f : Flags.class.getDeclaredFields()) {
-				if (f.getType() != int.class) {
-					continue;
-				}
-				if ((flags & f.getInt(null)) != 0) {
-					d.append(f.getName());
-				}
-			}
-		} catch (IllegalArgumentException | IllegalAccessException e) {
-			e.printStackTrace();
-		}
-		return d.build();
-	}
-
-	public static Integer read(String flags) {
-		Integer allFlags = 0;
-		String[] flagsSplitted = flags.split("\\+");
-		for (String flag : flagsSplitted) {
-			try {
-				allFlags |= Integer.valueOf(flag);
-			} catch (NumberFormatException ex) {
-				try {
-					Field field = Flags.class.getDeclaredField(flag.toUpperCase());
-					allFlags |= Integer.parseInt(field.get(null).toString());
-				} catch (SecurityException e) {
-					log.warn("security exception was thrown while trying to read flag (" + flag + ")");
-				} catch (NoSuchFieldException | IllegalArgumentException | IllegalAccessException e) {
-					log.warn("selected flag is not known (" + flag + ")");
-				}
-			}
-		}
-		return allFlags;
-	}
-}
Index: java/main/src/main/java/com/framsticks/params/FramsClass.java
===================================================================
--- java/main/src/main/java/com/framsticks/params/FramsClass.java	(revision 98)
+++ java/main/src/main/java/com/framsticks/params/FramsClass.java	(revision 99)
@@ -5,4 +5,5 @@
 import com.framsticks.util.FramsticksException;
 import com.framsticks.util.lang.Containers;
+import com.framsticks.util.lang.Strings;
 // import com.framsticks.util.FramsticksException;
 
@@ -60,5 +61,5 @@
 
 		this.id = builder.getId();
-		this.name = builder.getName();
+		this.name = Strings.toStringEmptyProof(builder.getName(), this.id);
 		this.description = builder.getDescription();
 		this.groups = Containers.build(builder.groupBuilders);
Index: java/main/src/main/java/com/framsticks/params/FramsClassBuilder.java
===================================================================
--- java/main/src/main/java/com/framsticks/params/FramsClassBuilder.java	(revision 98)
+++ java/main/src/main/java/com/framsticks/params/FramsClassBuilder.java	(revision 99)
@@ -40,4 +40,7 @@
 
 	public static ParamBuilder induceParamType(ParamBuilder builder, Type type) {
+		// if (type.equals(Void.TYPE)) {
+		// 	throw new ConstructionException().msg("void is not a valid type");
+		// }
 
 		if (type instanceof ParameterizedType) {
@@ -47,22 +50,28 @@
 			//TODO make implementation here
 			boolean map = false;
+			StringBuilder b = new StringBuilder();
 			if (rawType.equals(Map.class)) {
 				containedType = p.getActualTypeArguments()[1];
 				map = true;
+				b.append("l");
 			} else if (rawType.equals(List.class)) {
 				containedType = p.getActualTypeArguments()[0];
+				b.append("l");
+			} else if (rawType.equals(EventListener.class)) {
+				containedType = p.getActualTypeArguments()[0];
+				b.append("e");
 			}
 			if (!(containedType instanceof Class)) {
 				return builder;
 			}
+			b.append(" ");
+
 			Class<?> containedClass = (Class<?>) containedType;
-			StringBuilder b = new StringBuilder();
-			b.append("l ");
 			FramsClassAnnotation fca = containedClass.getAnnotation(FramsClassAnnotation.class);
 			if (fca == null) {
-				log.error("the class is not annotated: " + containedClass);
-				return builder;
+				throw new ConstructionException().msg("the contained class is not annotated").arg("class", containedClass);
 			}
 			b.append(getName(fca, containedClass));
+			//TODO parametrize this
 			if (map) {
 				b.append(" name");
@@ -109,4 +118,5 @@
 				return builder;
 			}
+
 
 			// builder.type("o " + (cl).getCanonicalName());
@@ -174,5 +184,14 @@
 			}
 			if (argsNum == 1) {
-				return n.startsWith("set") ? Strings.uncapitalize(n.substring(3)) : n;
+				if (n.startsWith("set")) {
+					return Strings.uncapitalize(n.substring(3));
+				}
+				if (n.startsWith("add")) {
+					return Strings.uncapitalize(n.substring(3));
+				}
+				if (n.startsWith("remove")) {
+					return Strings.uncapitalize(n.substring(6));
+				}
+				return n;
 			}
 			log.error("invalid number of arguments");
Index: java/main/src/main/java/com/framsticks/params/InvalidOperationException.java
===================================================================
--- java/main/src/main/java/com/framsticks/params/InvalidOperationException.java	(revision 98)
+++ java/main/src/main/java/com/framsticks/params/InvalidOperationException.java	(revision 99)
@@ -1,8 +1,8 @@
 package com.framsticks.params;
 
-import com.framsticks.util.FramsticksException;
+import com.framsticks.util.UnsupportedOperationException;
 
 @SuppressWarnings("serial")
-public class InvalidOperationException extends FramsticksException {
+public class InvalidOperationException extends UnsupportedOperationException {
 
 }
Index: java/main/src/main/java/com/framsticks/params/ListAccess.java
===================================================================
--- java/main/src/main/java/com/framsticks/params/ListAccess.java	(revision 98)
+++ java/main/src/main/java/com/framsticks/params/ListAccess.java	(revision 99)
@@ -5,4 +5,5 @@
 import static com.framsticks.util.lang.Containers.filterInstanceof;
 
+import com.framsticks.params.types.EventParam;
 import com.framsticks.params.types.ProcedureParam;
 
@@ -13,7 +14,12 @@
 
 	final AccessInterface elementAccess;
+	final String containedTypeName;
+
+	protected final ParamBuilder paramBuilder;
 
 	public ListAccess(AccessInterface elementAccess) {
 		this.elementAccess = elementAccess;
+		this.containedTypeName = elementAccess.getId();
+		paramBuilder = elementAccess.buildParam(new ParamBuilder());
 	}
 
@@ -48,8 +54,4 @@
 
 	@Override
-	public void copyFrom(AccessInterface src) {
-	}
-
-	@Override
 	public void save(SinkInterface sink) {
 		for (CompositeParam p : filterInstanceof(getParams(), CompositeParam.class)) {
@@ -70,5 +72,10 @@
 	}
 
-	public abstract String computeIdentifierFor(Object selected);
+	/**
+	 * @return the containedTypeName
+	 */
+	public String getContainedTypeName() {
+		return containedTypeName;
+	}
 
 	@Override
@@ -85,11 +92,31 @@
 	@Override
 	public Object call(String id, Object[] arguments) {
-		throw new InvalidOperationException().msg("list access does not support calling methods").arg("id", id);
+		throw new InvalidOperationException().msg("list access does not support calling methods").arg("id", id).arg("access", this);
 	}
 
 	@Override
 	public Object call(ProcedureParam param, Object[] arguments) {
-		throw new InvalidOperationException().msg("list access does not support calling methods").arg("param", param);
+		throw new InvalidOperationException().msg("list access does not support calling methods").arg("param", param).arg("access", this);
 	}
 
+	@Override
+	public void reg(EventParam param, EventListener<?> listener) {
+		throw new InvalidOperationException().msg("list access does not support registering events").arg("param", param).arg("access", this);
+	}
+
+	@Override
+	public void regRemove(EventParam param, EventListener<?> listener) {
+		throw new InvalidOperationException().msg("list access does not support registering events").arg("param", param).arg("access", this);
+	}
+
+
+	@Override
+	public String toString() {
+		StringBuilder b = new StringBuilder();
+		b.append("list of ").append(containedTypeName);
+		if (getSelected() != null) {
+			b.append("[").append(getParamCount()).append("]");
+		}
+		return b.toString();
+	}
 };
Index: java/main/src/main/java/com/framsticks/params/Param.java
===================================================================
--- java/main/src/main/java/com/framsticks/params/Param.java	(revision 98)
+++ java/main/src/main/java/com/framsticks/params/Param.java	(revision 99)
@@ -97,5 +97,5 @@
 
 	public boolean isUserHidden() {
-		return (flags & Flags.USERHIDDEN) != 0;
+		return (flags & ParamFlags.USERHIDDEN) != 0;
 	}
 
Index: java/main/src/main/java/com/framsticks/params/ParamBuilder.java
===================================================================
--- java/main/src/main/java/com/framsticks/params/ParamBuilder.java	(revision 98)
+++ java/main/src/main/java/com/framsticks/params/ParamBuilder.java	(revision 99)
@@ -7,4 +7,5 @@
 import com.framsticks.util.FramsticksException;
 import com.framsticks.util.Misc;
+import com.framsticks.util.lang.FlagsUtil;
 import com.framsticks.util.lang.Strings;
 
@@ -66,5 +67,7 @@
 	private int extra = 0;
 
-	String containedTypeName;
+	protected String containedTypeName;
+
+	protected String eventArgumentTypeName;
 
 	protected Class<?> storageType;
@@ -116,4 +119,9 @@
 	}
 
+	public ParamBuilder containedTypeName(String containedTypeName) {
+		this.containedTypeName = containedTypeName;
+		return this;
+	}
+
 	/**
 	 * @return the resultType
@@ -160,4 +168,9 @@
 	public String getUid() {
 		return uid;
+	}
+
+	public ParamBuilder uid(String uid) {
+		this.uid = uid;
+		return this;
 	}
 
@@ -322,21 +335,27 @@
 			case 'e': {
 				type(EventParam.class);
-				break;
-			}
-			case 'l': {
-				containedTypeName = second;
-				if (third != null) {
-					type(UniqueListParam.class);
-					uid = third;
-				} else {
-					type(ArrayListParam.class);
-				}
-				break;
-			}
-			default:{
-				log.error("unknown type: " + first);
-				return this;
-			}
-		}
+			eventArgumentTypeName(second);
+			break;
+		}
+		case 'l': {
+			containedTypeName = second;
+			if (third != null) {
+				type(UniqueListParam.class);
+				uid = third;
+			} else {
+				type(ArrayListParam.class);
+			}
+			break;
+		}
+		default: {
+			log.error("unknown type: " + first);
+			return this;
+		}
+		}
+		return this;
+	}
+
+	public ParamBuilder eventArgumentTypeName(String eventArgumentTypeName) {
+		this.eventArgumentTypeName = eventArgumentTypeName;
 		return this;
 	}
@@ -438,5 +457,5 @@
 			id(paramEntryValues[0]);
 			group(Integer.valueOf(paramEntryValues[1]));
-			flags(Flags.read(paramEntryValues[2]));
+			flags(FlagsUtil.read(ParamFlags.class, paramEntryValues[2]));
 			name(paramEntryValues[3]);
 			type(paramEntryValues[4]);
@@ -464,5 +483,5 @@
 				break;
 			case FLAGS_FIELD:
-				flags(Flags.read(value));
+				flags(FlagsUtil.read(ParamFlags.class, value));
 				break;
 			case HELP_FIELD:
@@ -492,10 +511,13 @@
 	}
 
+	/**
+	 * @return the eventArgumentTypeName
+	 */
+	public String getEventArgumentTypeName() {
+		return eventArgumentTypeName;
+	}
+
 	public Class<?> getStorageType() {
 		return storageType;
-	}
-
-	public ParamBuilder forAccess(AccessInterface access) {
-		return name(access.getId()).type("o " + access.getId());
 	}
 
Index: java/main/src/main/java/com/framsticks/params/ParamCandidate.java
===================================================================
--- java/main/src/main/java/com/framsticks/params/ParamCandidate.java	(revision 98)
+++ java/main/src/main/java/com/framsticks/params/ParamCandidate.java	(revision 99)
@@ -73,4 +73,6 @@
 	protected final OneTime<Method> getter = new OneTime<>("getter");
 	protected final OneTime<Method> caller = new OneTime<>("caller");
+	protected final OneTime<Method> adder = new OneTime<>("adder");
+	protected final OneTime<Method> remover = new OneTime<>("remover");
 
 	protected final List<ParamAnnotation> annotations = new LinkedList<>();
@@ -142,4 +144,18 @@
 
 	/**
+	 * @return the getter
+	 */
+	public Method getAdder() {
+		return adder.get();
+	}
+
+	/**
+	 * @return the getter
+	 */
+	public Method getRemover() {
+		return remover.get();
+	}
+
+	/**
 	 * @return the annotations
 	 */
@@ -150,4 +166,10 @@
 	void validate() throws ConstructionException {
 		try {
+			if (adder.has() != remover.has()) {
+				throw new ConstructionException().msg("only one of event manipulator methods is defined");
+			}
+			if (adder.has() && remover.has()) {
+				return;
+			}
 			if (caller.has()) {
 				if (!isPublic(caller)) {
@@ -174,4 +196,9 @@
 				throw new ConstructionException().msg("missing getter or field");
 			}
+			if (getter.has() || field.has() || setter.has()) {
+				if (type.get().equals(Void.TYPE)) {
+					throw new ConstructionException().msg("type of field is void");
+				}
+			}
 		} catch (ConstructionException e) {
 			throw e.arg("in", this);
@@ -183,4 +210,7 @@
 			return false;
 		}
+		if (adder.has() || remover.has()) {
+			return false;
+		}
 		if (Collection.class.isAssignableFrom(getRawType())) {
 			return false;
@@ -197,4 +227,7 @@
 	boolean isReadOnly() {
 		if (caller.has()) {
+			return false;
+		}
+		if (adder.has() || remover.has()) {
 			return false;
 		}
@@ -229,5 +262,9 @@
 			}
 			Type[] ps = m.getGenericParameterTypes();
+			Class<?>[] pts = m.getParameterTypes();
 			if (ps.length == 0) {
+				if (m.getReturnType().equals(Void.TYPE)) {
+					throw new ConstructionException().msg("failed to add getter of void return type");
+				}
 				getter.set(m);
 				setType(m.getGenericReturnType());
@@ -235,4 +272,17 @@
 			}
 			if (ps.length == 1) {
+				if (pts[0].equals(EventListener.class)) {
+					if (member.getName().startsWith("add")) {
+						adder.set(m);
+						setType(ps[0]);
+						return;
+					}
+					if (member.getName().startsWith("remove")) {
+						remover.set(m);
+						setType(ps[0]);
+						return;
+					}
+					throw new ConstructionException().msg("invalid name of event manipulator").arg("method", m).arg("in", this);
+				}
 				setter.set(m);
 				setType(ps[0]);
@@ -251,5 +301,5 @@
 		int f = 0;
 		if (isReadOnly()) {
-			f |= Flags.READONLY;
+			f |= ParamFlags.READONLY;
 		}
 		return f;
Index: java/main/src/main/java/com/framsticks/params/ParamFlags.java
===================================================================
--- java/main/src/main/java/com/framsticks/params/ParamFlags.java	(revision 99)
+++ java/main/src/main/java/com/framsticks/params/ParamFlags.java	(revision 99)
@@ -0,0 +1,34 @@
+package com.framsticks.params;
+
+/** This class contains constants regarding parameter attributes.
+ *
+ * Based on c++ defines located in: cpp/gdk/param.h
+ *
+ * @author Jarek Szymczak <name.surname@gmail.com>
+ * (please replace name and surname with my personal data)
+ *
+ * @@author Piotr Sniegowski
+ */
+public final class ParamFlags {
+
+	public static final int READONLY = 1;
+
+	public static final int DONTSAVE = 2;
+
+	public static final int USERREADONLY = 16;
+
+	public static final int USERHIDDEN = 32;
+
+	public static final int MUTALLOCENTRY = 64;
+
+	public static final int MUTALLOCDATA = 128;
+
+	public static final int NOSTATIC = 256;
+
+	public static final int CONST = 512;
+
+	public static final int CANOMITNAME = 1024;
+
+	public static final int DONTLOAD = 2048;
+
+}
Index: java/main/src/main/java/com/framsticks/params/PropertiesAccess.java
===================================================================
--- java/main/src/main/java/com/framsticks/params/PropertiesAccess.java	(revision 98)
+++ java/main/src/main/java/com/framsticks/params/PropertiesAccess.java	(revision 99)
@@ -4,4 +4,5 @@
 import java.util.Map;
 
+import com.framsticks.params.types.EventParam;
 import com.framsticks.params.types.ProcedureParam;
 
@@ -97,10 +98,20 @@
 	@Override
 	public Object call(String id, Object[] arguments) {
-		throw new InvalidOperationException().msg("list access does not support calling methods").arg("id", id);
+		throw new InvalidOperationException().msg("properties access does not support calling methods").arg("id", id);
 	}
 
 	@Override
 	public Object call(ProcedureParam param, Object[] arguments) {
-		throw new InvalidOperationException().msg("list access does not support calling methods").arg("param", param);
+		throw new InvalidOperationException().msg("properties access does not support calling methods").arg("param", param);
+	}
+
+	@Override
+	public void reg(EventParam param, EventListener<?> listener) {
+		throw new InvalidOperationException().msg("properties access does not support registering events").arg("param", param).arg("access", this);
+	}
+
+	@Override
+	public void regRemove(EventParam param, EventListener<?> listener) {
+		throw new InvalidOperationException().msg("properties access does not support registering events").arg("param", param).arg("access", this);
 	}
 
Index: java/main/src/main/java/com/framsticks/params/ReflectionAccess.java
===================================================================
--- java/main/src/main/java/com/framsticks/params/ReflectionAccess.java	(revision 98)
+++ java/main/src/main/java/com/framsticks/params/ReflectionAccess.java	(revision 99)
@@ -17,4 +17,5 @@
 
 import com.framsticks.params.annotations.AutoAppendAnnotation;
+import com.framsticks.params.types.EventParam;
 import com.framsticks.params.types.ProcedureParam;
 import com.framsticks.util.FramsticksException;
@@ -57,7 +58,18 @@
 		}
 
+		public interface ReflectedAdder{
+			public void reg(Object object, EventListener<?> listener) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException;
+		}
+
+		public interface ReflectedRemover{
+			public void regRemove(Object object, EventListener<?> listener) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException;
+		}
+
 		protected final Map<ValueParam, ReflectedSetter> setters = new IdentityHashMap<>();
 		protected final Map<ValueParam, ReflectedGetter> getters = new IdentityHashMap<>();
 		protected final Map<ProcedureParam, ReflectedCaller> callers = new IdentityHashMap<>();
+		protected final Map<EventParam, ReflectedAdder> adders = new IdentityHashMap<>();
+		protected final Map<EventParam, ReflectedRemover> removers = new IdentityHashMap<>();
+
 		protected final List<Method> autoAppendMethods = new ArrayList<>();
 
@@ -100,4 +112,30 @@
 				}
 
+				for (final EventParam ep : filterInstanceof(framsClass.getParamEntries(), EventParam.class)) {
+					if (!candidates.containsKey(ep.getId())) {
+						log.trace("java class does not implement the event param " + ep);
+						continue;
+					}
+					ParamCandidate ec = candidates.get(ep.getId());
+					final Method adder = ec.getAdder();
+					final Method remover = ec.getRemover();
+
+					backend.adders.put(ep, new ReflectedAdder() {
+
+						@Override
+						public void reg(Object object, EventListener<?> listener) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
+							adder.invoke(object, listener);
+						}
+					});
+
+					backend.removers.put(ep, new ReflectedRemover() {
+
+						@Override
+						public void regRemove(Object object, EventListener<?> listener) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
+							remover.invoke(object, listener);
+						}
+					});
+				}
+
 				for (final ValueParam vp : filterInstanceof(framsClass.getParamEntries(), ValueParam.class)) {
 					if (!candidates.containsKey(vp.getId())) {
@@ -105,5 +143,5 @@
 					}
 					ParamCandidate pc = candidates.get(vp.getId());
-					if (pc.isReadOnly() && !vp.hasFlag(Flags.READONLY)) {
+					if (pc.isReadOnly() && !vp.hasFlag(ParamFlags.READONLY)) {
 						throw new ConstructionException().msg("readonly state conflict").arg("param", vp);
 					}
@@ -200,10 +238,8 @@
 	}
 
-	public ReflectionAccess(Class<?> reflectedClass) throws ConstructionException {
-		this(reflectedClass, FramsClass.build().forClass(reflectedClass));
-	}
-
 	public static boolean typeMatch(Class<?> a, Class<?> b) {
-		assert !b.isPrimitive();
+		if (b.isPrimitive()) {
+			throw new FramsticksException().msg("failed to match type, right argument is primitive").arg("left", a).arg("right", b);
+		}
 		if (!a.isPrimitive()) {
 			return a.equals(b);
@@ -219,14 +255,29 @@
 			return b.equals(Boolean.class);
 		}
-		assert false;
-		return false;
-	}
-
-	public ReflectionAccess(Class<?> reflectedClass, FramsClass framsClass) throws ConstructionException {
+		throw new FramsticksException().msg("failed to match types").arg("left", a).arg("right", b);
+	}
+
+
+
+
+	public ReflectionAccess(Class<?> javaClass) throws ConstructionException {
+		this(javaClass, FramsClass.build().forClass(javaClass));
+	}
+
+
+	public ReflectionAccess(Class<?> javaClass, FramsClass framsClass) throws ConstructionException {
+		this(javaClass, framsClass, Backend.getOrCreateFor(javaClass, framsClass));
+	}
+
+	protected ReflectionAccess(Class<?> javaClass, FramsClass framsClass, Backend backend) throws ConstructionException {
 		super(framsClass);
-		this.javaClass = reflectedClass;
-		this.backend = Backend.getOrCreateFor(reflectedClass, framsClass);
-	}
-
+		this.javaClass = javaClass;
+		this.backend = backend;
+	}
+
+	@Override
+	public ReflectionAccess cloneAccess() throws ConstructionException {
+		return new ReflectionAccess(javaClass, framsClass, backend);
+	}
 
 	@Override
@@ -268,4 +319,40 @@
 		} catch (FramsticksException e) {
 			throw e.arg("param", param).arg("value", value).arg("access", this);
+		}
+	}
+
+	@Override
+	public void reg(EventParam param, EventListener<?> listener) {
+		try {
+			try {
+				if (object == null) {
+					throw new FramsticksException().msg("no object set");
+				}
+
+				backend.adders.get(param).reg(object, listener);
+				return;
+			} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
+				throw new FramsticksException().msg("failed to add listener").cause(e);
+			}
+		} catch (FramsticksException e) {
+			throw e.arg("param", param).arg("access", this);
+		}
+	}
+
+	@Override
+	public void regRemove(EventParam param, EventListener<?> listener) {
+		try {
+			try {
+				if (object == null) {
+					throw new FramsticksException().msg("no object set");
+				}
+
+				backend.removers.get(param).regRemove(object, listener);
+				return;
+			} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
+				throw new FramsticksException().msg("failed to remove listener").cause(e);
+			}
+		} catch (FramsticksException e) {
+			throw e.arg("param", param).arg("access", this);
 		}
 	}
@@ -352,8 +439,4 @@
 	}
 
-	@Override
-	public ReflectionAccess cloneAccess() throws ConstructionException {
-		return new ReflectionAccess(javaClass, framsClass);
-	}
 
 	@Override
@@ -368,13 +451,4 @@
 	}
 
-	@Override
-	public String toString() {
-		StringBuilder b = new StringBuilder();
-		b.append(framsClass);
-		if (object != null) {
-			b.append("(").append(object).append(")");
-		}
-		return b.toString();
-	}
 
 	@Override
Index: java/main/src/main/java/com/framsticks/params/Registry.java
===================================================================
--- java/main/src/main/java/com/framsticks/params/Registry.java	(revision 98)
+++ java/main/src/main/java/com/framsticks/params/Registry.java	(revision 99)
@@ -46,4 +46,7 @@
 		register(javaClass);
 		associate(javaClass, putFramsClass(FramsClass.build().forClass(javaClass)));
+		for (Class<?> r : javaClass.getAnnotation(FramsClassAnnotation.class).register()) {
+			registerAndBuild(r);
+		}
 		return this;
 	}
@@ -122,4 +125,8 @@
 	}
 
+	public FramsClass getFramsClassForJavaClass(Class<?> javaClass) {
+		return javaToFramsAssociation.get(javaClass);
+	}
+
 	public Set<Class<?>> getReflectedClasses() {
 		return javaClasses.getValues();
Index: java/main/src/main/java/com/framsticks/params/SetStateFlags.java
===================================================================
--- java/main/src/main/java/com/framsticks/params/SetStateFlags.java	(revision 99)
+++ java/main/src/main/java/com/framsticks/params/SetStateFlags.java	(revision 99)
@@ -0,0 +1,20 @@
+package com.framsticks.params;
+
+/** This class contains constants regarding set operation state.
+ *
+ * Based on c++ defines located in: cpp/gdk/param.h
+ *
+ * @author Jarek Szymczak <name.surname@gmail.com>
+ * (please replace name and surname with my personal data)
+ *
+ * @@author Piotr Sniegowski
+ */
+public final class SetStateFlags {
+	public static final int PSET_RONLY = 1;
+
+	public static final int PSET_CHANGED = 2;
+
+	public static final int PSET_HITMIN = 4;
+
+	public static final int PSET_HITMAX = 8;
+}
Index: java/main/src/main/java/com/framsticks/params/SimpleAbstractAccess.java
===================================================================
--- java/main/src/main/java/com/framsticks/params/SimpleAbstractAccess.java	(revision 98)
+++ java/main/src/main/java/com/framsticks/params/SimpleAbstractAccess.java	(revision 99)
@@ -6,5 +6,7 @@
 import org.apache.log4j.Logger;
 
-import com.framsticks.util.UnimplementedException;
+import com.framsticks.params.types.ObjectParam;
+import com.framsticks.util.FramsticksException;
+import static com.framsticks.params.SetStateFlags.*;
 
 /**
@@ -105,5 +107,4 @@
 	@Override
 	public <T> int set(ValueParam param, T value) {
-		int flags = 0;
 
 		//String id = param.getEffectiveId();
@@ -115,9 +116,13 @@
 				internalSet(param, casted);
 			}
-			flags = result.getFlags();
+			return result.getFlags();
 		} catch (CastFailure e) {
-			log.error("casting failure while set: ", e);
-		}
-		return flags;
+			throw new FramsticksException()
+				.msg("casting failure while set")
+				.arg("param", param)
+				.arg("value", value)
+				.arg("value's type", (value == null ? "<null>" : value.getClass().getCanonicalName()))
+				.arg("in", this).cause(e);
+		}
 	}
 
@@ -167,16 +172,4 @@
 			set(i, max);
 		}
-	}
-
-	@Override
-	public void copyFrom(AccessInterface src) {
-		throw new UnimplementedException();
-		// clearValues();
-		//TODO: iterate over self, and pull from src
-		/*
-		for (int i = 0; i < src.getFramsClass().size(); i++) {
-			this.set(i, src.get(i, Object.class));
-		}
-		*/
 	}
 
@@ -257,10 +250,10 @@
 				continue;
 			}
-			if ((param.getFlags() & Flags.DONTLOAD) != 0) {
+			if ((param.getFlags() & ParamFlags.DONTLOAD) != 0) {
 				log.debug("DontLoad flag was set - not loading...");
 			} else {
 				int retFlags = this.set((ValueParam) param, entry.value);
-				if ((retFlags & (Flags.PSET_HITMIN | Flags.PSET_HITMAX)) != 0) {
-					String which = ((retFlags & Flags.PSET_HITMIN) != 0) ? "small" : "big";
+				if ((retFlags & (PSET_HITMIN | PSET_HITMAX)) != 0) {
+					String which = ((retFlags & PSET_HITMIN) != 0) ? "small" : "big";
 					log.warn("value of key '" + entry.key + "' was too " + which + ", adjusted");
 				}
@@ -304,4 +297,18 @@
 	}*/
 
+	@Override
+	public String toString() {
+		StringBuilder b = new StringBuilder();
+		b.append(framsClass);
+		if (getSelected() != null) {
+			b.append("(").append(getSelected()).append(")");
+		}
+		return b.toString();
+	}
+
+	@Override
+	public ParamBuilder buildParam(ParamBuilder builder) {
+		return builder.name(getId()).type(ObjectParam.class).containedTypeName(getId());
+	}
 
 }
Index: java/main/src/main/java/com/framsticks/params/UniqueListAccess.java
===================================================================
--- java/main/src/main/java/com/framsticks/params/UniqueListAccess.java	(revision 98)
+++ java/main/src/main/java/com/framsticks/params/UniqueListAccess.java	(revision 99)
@@ -1,4 +1,5 @@
 package com.framsticks.params;
 
+import com.framsticks.params.types.UniqueListParam;
 import com.framsticks.util.FramsticksException;
 import com.framsticks.util.UnimplementedException;
@@ -80,5 +81,16 @@
 			return null;
 		}
-		return Param.build().id(Integer.toString(i)).forAccess(elementAccess).finish(CompositeParam.class);
+		Iterator<Map.Entry<String, Object>> iterator = map.entrySet().iterator();
+		while (i > 0 && iterator.hasNext()) {
+			iterator.next();
+			--i;
+		}
+		if (i > 0) {
+			return null;
+		}
+		if (!iterator.hasNext()) {
+			return null;
+		}
+		return paramBuilder.id(getUidOf(iterator.next().getValue())).finish(CompositeParam.class);
 	}
 
@@ -96,5 +108,5 @@
 			return null;
 		}
-		return Param.build().id(id).forAccess(elementAccess).finish(CompositeParam.class);
+		return paramBuilder.id(id).finish(CompositeParam.class);
 	}
 
@@ -148,7 +160,4 @@
 		String uid = elementAccess.get(uidName, String.class);
 		elementAccess.select(tmp);
-		if (uid == null) {
-			return null;
-		}
 		return uid;
 	}
@@ -233,5 +242,4 @@
 	}
 
-	@Override
 	public String computeIdentifierFor(Object selected) {
 		String uid = getUidOf(selected);
@@ -260,5 +268,5 @@
 					@Override
 					public Param next() {
-						return Param.build().id(internal.next().getKey()).forAccess(elementAccess).finish();
+						return paramBuilder.id(internal.next().getKey()).finish();
 					}
 
@@ -282,3 +290,9 @@
 		return getParam(number);
 	}
+
+	@Override
+	public ParamBuilder buildParam(ParamBuilder builder) {
+		return builder.name(containedTypeName + " list").type(UniqueListParam.class).containedTypeName(containedTypeName).uid(uidName);
+	}
+
 }
Index: java/main/src/main/java/com/framsticks/params/Util.java
===================================================================
--- java/main/src/main/java/com/framsticks/params/Util.java	(revision 98)
+++ java/main/src/main/java/com/framsticks/params/Util.java	(revision 99)
@@ -36,5 +36,18 @@
 	}
 
-	public static int copyParams(AccessInterface to, AccessInterface from) {
+	public static int takeAllNonNullValues(AccessInterface to, AccessInterface from) {
+		int copied = 0;
+		for (ValueParam f : filterInstanceof(from.getParams(), ValueParam.class)) {
+			Object v = from.get(f, Object.class);
+			if (v == null) {
+				continue;
+			}
+			to.set(f, v);
+			++copied;
+		}
+		return copied;
+	}
+
+	public static int copyExistingParamsTypeSafe(AccessInterface to, AccessInterface from) {
 		int copied = 0;
 		for (ValueParam f : filterInstanceof(from.getParams(), ValueParam.class)) {
Index: java/main/src/main/java/com/framsticks/params/annotations/FramsClassAnnotation.java
===================================================================
--- java/main/src/main/java/com/framsticks/params/annotations/FramsClassAnnotation.java	(revision 98)
+++ java/main/src/main/java/com/framsticks/params/annotations/FramsClassAnnotation.java	(revision 99)
@@ -13,3 +13,4 @@
 
 	String[] order() default {};
+	Class<?>[] register() default {};
 }
Index: java/main/src/main/java/com/framsticks/params/types/EventParam.java
===================================================================
--- java/main/src/main/java/com/framsticks/params/types/EventParam.java	(revision 98)
+++ java/main/src/main/java/com/framsticks/params/types/EventParam.java	(revision 99)
@@ -12,4 +12,5 @@
 public class EventParam extends Param {
 
+	protected final String eventArgumentTypeName;
 
 
@@ -19,14 +20,15 @@
 	public EventParam(ParamBuilder builder) {
 		super(builder);
+		eventArgumentTypeName = builder.getEventArgumentTypeName();
 	}
 
 	@Override
 	public Class<?> getStorageType() {
-		return Void.class;
+		return Void.TYPE;
 	}
 
 	@Override
 	public String getFramsTypeName() {
-		return "e";
+		return eventArgumentTypeName != null ? "e " + eventArgumentTypeName : "e";
 	}
 }
Index: java/main/src/main/java/com/framsticks/params/types/NumberParam.java
===================================================================
--- java/main/src/main/java/com/framsticks/params/types/NumberParam.java	(revision 98)
+++ java/main/src/main/java/com/framsticks/params/types/NumberParam.java	(revision 99)
@@ -2,5 +2,4 @@
 
 import com.framsticks.params.CastFailure;
-import com.framsticks.params.Flags;
 import com.framsticks.params.ParamBuilder;
 import com.framsticks.params.PrimitiveParam;
@@ -10,4 +9,5 @@
 
 import javax.annotation.concurrent.Immutable;
+import static com.framsticks.params.SetStateFlags.*;
 
 /**
@@ -40,8 +40,8 @@
 		}
 		if (min != null && v.compareTo(getMin(type)) < 0) {
-			return new ReassignResult<T>(getMin(type), Flags.PSET_HITMIN);
+			return new ReassignResult<T>(getMin(type), PSET_HITMIN);
 		}
 		if (max != null && v.compareTo(getMax(type)) > 0) {
-			return new ReassignResult<T>(getMax(type), Flags.PSET_HITMAX);
+			return new ReassignResult<T>(getMax(type), PSET_HITMAX);
 		}
 		return ReassignResult.create(v);
Index: java/main/src/main/java/com/framsticks/params/types/ProcedureParam.java
===================================================================
--- java/main/src/main/java/com/framsticks/params/types/ProcedureParam.java	(revision 98)
+++ java/main/src/main/java/com/framsticks/params/types/ProcedureParam.java	(revision 99)
@@ -54,5 +54,5 @@
 	@Override
 	public Class<?> getStorageType() {
-		return Void.class;
+		return Void.TYPE;
 	}
 
Index: java/main/src/main/java/com/framsticks/parsers/F0Parser.java
===================================================================
--- java/main/src/main/java/com/framsticks/parsers/F0Parser.java	(revision 98)
+++ java/main/src/main/java/com/framsticks/parsers/F0Parser.java	(revision 99)
@@ -14,5 +14,4 @@
 import static com.framsticks.params.SimpleAbstractAccess.*;
 
-import com.framsticks.params.Flags;
 import com.framsticks.params.Param;
 import com.framsticks.params.PrimitiveParam;
@@ -26,4 +25,6 @@
 import com.framsticks.params.FramsClass;
 import com.framsticks.params.AccessInterface;
+import static com.framsticks.params.ParamFlags.*;
+import static com.framsticks.params.SetStateFlags.*;
 
 /**
@@ -205,5 +206,5 @@
 					}
 				} else {
-					if (nextParamNumber == null || ((params[nextParamNumber].getFlags() & Flags.CANOMITNAME) == 0)) {
+					if (nextParamNumber == null || ((params[nextParamNumber].getFlags() & CANOMITNAME) == 0)) {
 						nextParamNumber = null;
 						throw new Exception(
@@ -220,13 +221,13 @@
 						PrimitiveParam<?> vp = (PrimitiveParam<?>) currentParam;
 						int setFlag = access.set(vp, pair.value);
-						if ((setFlag & Flags.PSET_HITMIN) != 0) {
-							exceptions.add(createBoundaryHitException(access, vp, pair.value, Flags.PSET_HITMIN));
-						}
-
-						if ((setFlag & Flags.PSET_HITMAX) != 0) {
-							exceptions.add(createBoundaryHitException(access, vp, pair.value, Flags.PSET_HITMAX));
-						}
-
-						if ((setFlag & Flags.PSET_RONLY) != 0) {
+						if ((setFlag & PSET_HITMIN) != 0) {
+							exceptions.add(createBoundaryHitException(access, vp, pair.value, PSET_HITMIN));
+						}
+
+						if ((setFlag & PSET_HITMAX) != 0) {
+							exceptions.add(createBoundaryHitException(access, vp, pair.value, PSET_HITMAX));
+						}
+
+						if ((setFlag & PSET_RONLY) != 0) {
 							throw (new Exception("tried to set a read-only attribute \""
 								+ currentParam.getId()
@@ -250,5 +251,5 @@
 
 	private static Exception createBoundaryHitException(AccessInterface access, PrimitiveParam<?> param, String value, int flag) {
-		boolean minimum = (flag & Flags.PSET_HITMIN) != 0;
+		boolean minimum = (flag & PSET_HITMIN) != 0;
 		String boundary = (minimum ? param.getMin(Object.class) : param.getMax(Object.class)).toString();
 		String name =  (minimum ? "minimum" : "maximum");
Index: java/main/src/main/java/com/framsticks/parsers/F0Writer.java
===================================================================
--- java/main/src/main/java/com/framsticks/parsers/F0Writer.java	(revision 98)
+++ java/main/src/main/java/com/framsticks/parsers/F0Writer.java	(revision 99)
@@ -7,4 +7,5 @@
 import com.framsticks.util.lang.Containers;
 import static com.framsticks.util.lang.Containers.filterInstanceof;
+import static com.framsticks.params.ParamFlags.*;
 
 /**
@@ -65,5 +66,5 @@
 			}
 
-			if ((!contiguous) || ((param.getFlags() & Flags.CANOMITNAME) == 0)) {
+			if ((!contiguous) || ((param.getFlags() & CANOMITNAME) == 0)) {
 				line.append(param.getId()).append("=");
 				contiguous = true;
Index: java/main/src/main/java/com/framsticks/parsers/GenotypeLoader.java
===================================================================
--- java/main/src/main/java/com/framsticks/parsers/GenotypeLoader.java	(revision 98)
+++ java/main/src/main/java/com/framsticks/parsers/GenotypeLoader.java	(revision 99)
@@ -6,4 +6,5 @@
 
 import org.apache.log4j.Logger;
+import static com.framsticks.params.ParamFlags.*;
 
 public class GenotypeLoader extends MultiParamLoader {
@@ -24,18 +25,18 @@
 			.param(Param.build().id("genotype").group(0).name("Genotype").type(StringParam.class).min(1))
 			.param(Param.build().id("info").group(0).name("Info").type(StringParam.class).min(1).help("Additional information or comments"))
-			.param(Param.build().id("simi").group(1).flags(Flags.READONLY | Flags.DONTSAVE).name("Similarity").type(FloatParam.class))
-			.param(Param.build().id("energ0").group(1).flags(Flags.READONLY | Flags.DONTSAVE).name("Starting energy").type(FloatParam.class))
-			.param(Param.build().id("strsiz").group(1).flags(Flags.READONLY | Flags.DONTSAVE | Flags.USERHIDDEN).name("Body parts (deprecated; use numparts)").type(FloatParam.class))
-			.param(Param.build().id("strjoints").group(1).flags(Flags.READONLY | Flags.DONTSAVE | Flags.USERHIDDEN).name("Body joints (deprecated; use numjoints)").type(FloatParam.class))
-			.param(Param.build().id("nnsiz").group(1).flags(Flags.READONLY | Flags.DONTSAVE | Flags.USERHIDDEN).name("Brain size (deprecated; use numneurons)").type(FloatParam.class))
-			.param(Param.build().id("nncon").group(1).flags(Flags.READONLY | Flags.DONTSAVE | Flags.USERHIDDEN).name("Brain connections (deprecated; use numconnections)").type(FloatParam.class))
-			.param(Param.build().id("numparts").group(1).flags(Flags.READONLY | Flags.DONTSAVE).name("Body parts").type(FloatParam.class))
-			.param(Param.build().id("numjoints").group(1).flags(Flags.READONLY | Flags.DONTSAVE).name("Body joints").type(FloatParam.class))
-			.param(Param.build().id("numneurons").group(1).flags(Flags.READONLY | Flags.DONTSAVE).name("Brain size").type(FloatParam.class))
-			.param(Param.build().id("numconnections").group(1).flags(Flags.READONLY | Flags.DONTSAVE).name("Brain connections").type(FloatParam.class))
+			.param(Param.build().id("simi").group(1).flags(READONLY | DONTSAVE).name("Similarity").type(FloatParam.class))
+			.param(Param.build().id("energ0").group(1).flags(READONLY | DONTSAVE).name("Starting energy").type(FloatParam.class))
+			.param(Param.build().id("strsiz").group(1).flags(READONLY | DONTSAVE | USERHIDDEN).name("Body parts (deprecated; use numparts)").type(FloatParam.class))
+			.param(Param.build().id("strjoints").group(1).flags(READONLY | DONTSAVE | USERHIDDEN).name("Body joints (deprecated; use numjoints)").type(FloatParam.class))
+			.param(Param.build().id("nnsiz").group(1).flags(READONLY | DONTSAVE | USERHIDDEN).name("Brain size (deprecated; use numneurons)").type(FloatParam.class))
+			.param(Param.build().id("nncon").group(1).flags(READONLY | DONTSAVE | USERHIDDEN).name("Brain connections (deprecated; use numconnections)").type(FloatParam.class))
+			.param(Param.build().id("numparts").group(1).flags(READONLY | DONTSAVE).name("Body parts").type(FloatParam.class))
+			.param(Param.build().id("numjoints").group(1).flags(READONLY | DONTSAVE).name("Body joints").type(FloatParam.class))
+			.param(Param.build().id("numneurons").group(1).flags(READONLY | DONTSAVE).name("Brain size").type(FloatParam.class))
+			.param(Param.build().id("numconnections").group(1).flags(READONLY | DONTSAVE).name("Brain connections").type(FloatParam.class))
 			.param(Param.build().id("num").group(2).name("Ordinal number").type(DecimalParam.class))
 			.param(Param.build().id("gnum").group(2).name("Generation").type(DecimalParam.class))
-			.param(Param.build().id("popsiz").group(2).flags(Flags.USERHIDDEN).name("Deprecated; use entities").type(DecimalParam.class))
-			.param(Param.build().id("entities").group(2).flags(Flags.DONTSAVE).name("Instances").type(DecimalParam.class).help("Copies of this genotype"))
+			.param(Param.build().id("popsiz").group(2).flags(USERHIDDEN).name("Deprecated; use entities").type(DecimalParam.class))
+			.param(Param.build().id("entities").group(2).flags(DONTSAVE).name("Instances").type(DecimalParam.class).help("Copies of this genotype"))
 			.param(Param.build().id("lifespan").group(2).name("Life span").type(FloatParam.class).help("Average life span"))
 			.param(Param.build().id("velocity").group(2).name("Velocity").type(FloatParam.class).help("Average velocity"))
@@ -43,12 +44,12 @@
 			.param(Param.build().id("vertvel").group(2).name("Vertical velocity").type(FloatParam.class))
 			.param(Param.build().id("vertpos").group(2).name("Vertical position").type(FloatParam.class))
-			.param(Param.build().id("fit").group(3).flags(Flags.READONLY | Flags.DONTSAVE).name("Fitness").type(FloatParam.class))
-			.param(Param.build().id("fit2").group(3).flags(Flags.READONLY | Flags.DONTSAVE).name("Final fitness").type(FloatParam.class).help("Fitness shifted by (avg-n*stddev)"))
-			.param(Param.build().id("f0genotype").group(4).flags(Flags.READONLY | Flags.DONTSAVE).name("f0 genotype").type(StringParam.class).min(1).help("converted to f0 genotype"))
+			.param(Param.build().id("fit").group(3).flags(READONLY | DONTSAVE).name("Fitness").type(FloatParam.class))
+			.param(Param.build().id("fit2").group(3).flags(READONLY | DONTSAVE).name("Final fitness").type(FloatParam.class).help("Fitness shifted by (avg-n*stddev)"))
+			.param(Param.build().id("f0genotype").group(4).flags(READONLY | DONTSAVE).name("f0 genotype").type(StringParam.class).min(1).help("converted to f0 genotype"))
 			.param(Param.build().id("user1").group(2).name("User field 1").type(UniversalParam.class))
 			.param(Param.build().id("user2").group(2).name("User field 2").type(UniversalParam.class))
 			.param(Param.build().id("user3").group(2).name("User field 3").type(UniversalParam.class))
-			.param(Param.build().id("isValid").group(0).flags(Flags.READONLY | Flags.DONTSAVE | Flags.USERHIDDEN).name("Valid").type(DecimalParam.class).min(0).max(1))
-			.param(Param.build().id("uid").group(0).flags(Flags.READONLY | Flags.USERHIDDEN).name("#").type("s").help("Unique identifier"))
+			.param(Param.build().id("isValid").group(0).flags(READONLY | DONTSAVE | USERHIDDEN).name("Valid").type(DecimalParam.class).min(0).max(1))
+			.param(Param.build().id("uid").group(0).flags(READONLY | USERHIDDEN).name("#").type("s").help("Unique identifier"))
 			.finish();
 
Index: java/main/src/main/java/com/framsticks/parsers/XmlLoader.java
===================================================================
--- java/main/src/main/java/com/framsticks/parsers/XmlLoader.java	(revision 98)
+++ java/main/src/main/java/com/framsticks/parsers/XmlLoader.java	(revision 99)
@@ -19,4 +19,5 @@
 import com.framsticks.util.AutoBuilder;
 import com.framsticks.util.FramsticksException;
+import com.framsticks.util.lang.Strings;
 
 public class XmlLoader {
@@ -47,9 +48,14 @@
 	}
 
+	public String mangleName(String name) {
+		return useLowerCase ? name.toLowerCase() : name;
+	}
+
+	public String mangleAttribute(String name) {
+		return useLowerCase ? name.toLowerCase() : Strings.uncapitalize(name);
+	}
+
 	public Object processElement(Element element) {
-		String name = element.getNodeName();
-		if (useLowerCase) {
-			name = name.toLowerCase();
-		}
+		final String name = mangleName(element.getNodeName());
 		if (name.equals("import")) {
 			String className = element.getAttribute("class");
@@ -71,5 +77,5 @@
 		for (int i = 0; i < attributes.getLength(); ++i) {
 			Node attributeNode = attributes.item(i);
-			access.set(attributeNode.getNodeName().toLowerCase(), attributeNode.getNodeValue());
+			access.set(mangleAttribute(attributeNode.getNodeName()), attributeNode.getNodeValue());
 		}
 
Index: java/main/src/main/java/com/framsticks/remote/RecursiveFetcher.java
===================================================================
--- java/main/src/main/java/com/framsticks/remote/RecursiveFetcher.java	(revision 98)
+++ java/main/src/main/java/com/framsticks/remote/RecursiveFetcher.java	(revision 99)
@@ -3,5 +3,4 @@
 import static com.framsticks.core.TreeOperations.*;
 
-import com.framsticks.core.Mode;
 import com.framsticks.core.Node;
 import com.framsticks.core.Path;
@@ -67,5 +66,5 @@
 				}
 				++dispatched;
-				tree.get(childPath, Mode.FETCH, new FutureHandler<Path>(Logging.logger(log, "resolve", RecursiveFetcher.this)) {
+				tree.get(childPath, new FutureHandler<Path>(Logging.logger(log, "resolve", RecursiveFetcher.this)) {
 					@Override
 					protected void result(Path result) {
@@ -83,5 +82,5 @@
 
 	protected void fetch(final Path path) {
-		tree.get(path, Mode.FETCH, new Future<Path>() {
+		tree.get(path, new Future<Path>() {
 
 			@Override
Index: java/main/src/main/java/com/framsticks/remote/RemoteTree.java
===================================================================
--- java/main/src/main/java/com/framsticks/remote/RemoteTree.java	(revision 98)
+++ java/main/src/main/java/com/framsticks/remote/RemoteTree.java	(revision 99)
@@ -7,8 +7,7 @@
 import com.framsticks.communication.queries.SetRequest;
 import com.framsticks.core.AbstractTree;
-import com.framsticks.core.Mode;
-import com.framsticks.core.ListChange;
 import com.framsticks.core.Path;
 import com.framsticks.params.*;
+import com.framsticks.params.EventListener;
 import com.framsticks.params.annotations.AutoAppendAnnotation;
 import com.framsticks.params.annotations.FramsClassAnnotation;
@@ -28,5 +27,4 @@
 import com.framsticks.util.dispatching.ThrowExceptionHandler;
 import com.framsticks.util.lang.Casting;
-import com.framsticks.util.lang.Pair;
 import com.framsticks.util.dispatching.RunAt;
 import static com.framsticks.core.TreeOperations.*;
@@ -42,20 +40,9 @@
  */
 @FramsClassAnnotation
-public class RemoteTree extends AbstractTree implements JoinableParent {
+public final class RemoteTree extends AbstractTree implements JoinableParent {
 
 	private final static Logger log = Logger.getLogger(RemoteTree.class);
 
 	protected ClientSideManagedConnection connection;
-
-	protected final Set<Pair<Path, Subscription<?>>> subscriptions = new HashSet<>();
-
-	public Pair<Path, Subscription<?>> getSubscription(Path path) {
-		for (Pair<Path, Subscription<?>> s : subscriptions) {
-			if (s.first.isTheSameObjects(path)) {
-				return s;
-			}
-		}
-		return null;
-	}
 
 	public RemoteTree() {
@@ -88,5 +75,5 @@
 
 	@Override
-	public void get(final Path path, final ValueParam param, Mode mode, final Future<Object> future) {
+	public void get(final Path path, final ValueParam param, final Future<Object> future) {
 		assert isActive();
 		assert param != null;
@@ -166,5 +153,5 @@
 
 	@Override
-	public void get(final Path path, final Mode mode, final Future<Path> future) {
+	public void get(final Path path, final Future<Path> future) {
 		assert isActive();
 
@@ -187,119 +174,4 @@
 	}
 
-
-	@Override
-	protected void tryRegisterOnChangeEvents(final Path path) {
-		assert isActive();
-		AccessInterface access = bindAccess(path);
-		if (!(access instanceof ListAccess)) {
-			return;
-		}
-
-		assert path.size() >= 2;
-		FramsClass underFramsClass = getInfoFromCache(path.getUnder().getParam().getContainedTypeName());
-
-		EventParam changedEvent;
-		try {
-			changedEvent = underFramsClass.getParamEntry(path.getTop().getParam().getId() + "_changed", EventParam.class);
-		} catch (FramsticksException e) {
-			return;
-		}
-
-		log.debug("registering for " + changedEvent);
-		if (getSubscription(path) != null) {
-			return;
-		}
-
-		final Pair<Path, Subscription<?>> temporary = new Pair<>(path, null);
-		subscriptions.add(temporary);
-
-		connection.subscribe(path.getTextual() + "_changed", this, new SubscriptionCallback<Tree>() {
-			@Override
-			public EventCallback subscribed(final Subscription<? super Tree> subscription) {
-				if (subscription == null) {
-					log.error("failed to subscribe for change event for " + path);
-					return null;
-				}
-				log.debug("subscribed for change event for " + path);
-				// subscription.setDispatcher(RemoteInstance.this);
-				RemoteTree.this.dispatch(new RunAt<Tree>(this) {
-					@Override
-					protected void runAt() {
-						subscriptions.remove(temporary);
-						subscriptions.add(new Pair<Path, Subscription<?>>(path, subscription));
-					}
-				});
-				return new EventCallback() {
-					@Override
-					public void call(List<File> files) {
-						assert isActive();
-						assert files.size() == 1;
-						final MultiParamLoader loader = new MultiParamLoader();
-						loader.setNewSource(files.get(0).getContent());
-						loader.addBreakCondition(MultiParamLoader.Status.AfterObject);
-						loader.addListener(MultiParamLoader.Status.OnComment, new MultiParamLoader.StatusListener() {
-
-							@Override
-							public void onStatusChange() {
-								throw new FramsticksException().msg("multi param loader error").arg("line", loader.getCurrentLine());
-							}
-						});
-						ReflectionAccess access = new ReflectionAccess(ListChange.class, FramsClass.build().forClass(ListChange.class));
-						loader.addAccessInterface(access);
-
-						MultiParamLoader.Status status;
-						while ((status = loader.go()) != MultiParamLoader.Status.Finished) {
-							if (status == MultiParamLoader.Status.AfterObject) {
-								AccessInterface accessInterface = loader.getLastAccessInterface();
-								reactToChange(path, (ListChange) accessInterface.getSelected());
-							}
-						}
-					}
-				};
-			}
-		});
-	}
-
-	protected Future<Path> futureListChanger(final ListChange listChange, final String path) {
-		return new FutureHandler<Path>(Logging.logger(log, "failed to " + listChange, path)) {
-			@Override
-			protected void result(Path result) {
-				log.debug(listChange + ": " + result);
-			}
-		};
-	}
-
-	protected void reactToChange(final Path path, final ListChange listChange) {
-		assert isActive();
-		log.debug("reacting to change " + listChange + " in " + path);
-		AccessInterface access = bindAccess(path);
-		assert access != null;
-
-		if ((listChange.getAction() == ListChange.Action.Modify) && (listChange.getPosition() == -1)) {
-			final String p = path.getTextual();
-			tryGet(this, p, futureListChanger(listChange, p));
-			return;
-		}
-
-		CompositeParam childParam = Casting.tryCast(CompositeParam.class, access.getParam(listChange.getBestIdentifier()));
-		assert childParam != null;
-		switch (listChange.getAction()) {
-			case Add: {
-				final String p = path.getTextual() + "/" + childParam.getId();
-				tryGet(this, p, futureListChanger(listChange, p));
-				break;
-			}
-			case Remove: {
-				access.set(childParam, null);
-				break;
-			}
-			case Modify: {
-				final String p = path.getTextual() + "/" + childParam.getId();
-				tryGet(this, p, futureListChanger(listChange, p));
-				break;
-			}
-		}
-	}
-
 	@Override
 	public void set(final Path path, final PrimitiveParam<?> param, final Object value, final Future<Integer> future) {
@@ -380,26 +252,57 @@
 	}
 
-	// @Override
-	// public Path create(Path path) {
-	//	assert isActive();
-	//	assert !path.isResolved();
-	//	Path resolved = path.tryFindResolution();
-	//	if (!resolved.isResolved()) {
-	//		log.debug("creating: " + path);
-	//		//TODO: access parent here, check if it is valid, only then create
-	//		AccessInterface access = registry.prepareAccess(path.getTop().getParam());
-	//		assert access != null;
-	//		Object child = access.createAccessee();
-	//		assert child != null;
-	//		if (path.size() == 1) {
-	//			setRoot(new Node(getRoot().getParam(), child));
-	//		} else {
-	//			bindAccess(this, path.getUnder()).set(path.getTop().getParam(), child);
-	//		}
-	//		resolved = path.appendResolution(child);
-	//	}
-	//	tryRegisterOnChangeEvents(resolved);
-	//	return resolved;
-	// }
+	protected final Map<EventListener<?>, EventListener<File>> proxyListeners = new IdentityHashMap<>();
+
+	public <A> void addListener(Path path, EventParam param, final EventListener<A> listener, final Class<A> argumentType, final Future<Void> future) {
+		assert isActive();
+		assert path.isResolved();
+		if ((!argumentType.equals(Object.class)) && (null == registry.getFramsClassForJavaClass(argumentType))) {
+			registry.registerAndBuild(argumentType);
+		}
+
+		final EventListener<File> proxyListener = new EventListener<File>() {
+
+			@Override
+			public void action(final File file) {
+				Dispatching.dispatchIfNotActive(RemoteTree.this, new RunAt<RemoteTree>(RemoteTree.this) {
+
+					@Override
+					protected void runAt() {
+						assert isActive();
+						if (argumentType.equals(Object.class)) {
+							listener.action(Casting.tryCast(argumentType, file));
+							return;
+						}
+						AccessInterface access = registry.createAccess(argumentType);
+						Object argument = access.createAccessee();
+						access.select(argument);
+						if (!argumentType.isInstance(argument)) {
+							throw new FramsticksException().msg("created argument is of wrond type").arg("expected", argumentType).arg("created", argument.getClass());
+						}
+						A typedArgument = argumentType.cast(argument);
+
+						// log.info("executing event with argument " + argumentType);
+						MultiParamLoader loader = new MultiParamLoader();
+						loader.setNewSource(file.getContent());
+						loader.addBreakCondition(MultiParamLoader.Status.AfterObject);
+						loader.addAccessInterface(access);
+						loader.go();
+
+						listener.action(typedArgument);
+					}
+				});
+			}
+		};
+
+		proxyListeners.put(listener, proxyListener);
+
+		connection.addListener(Path.appendString(path.getTextual(), param.getId()), proxyListener, this, future);
+	}
+
+	public void removeListener(Path path, EventParam param, EventListener<?> listener, Future<Void> future) {
+		assert isActive();
+		EventListener<File> proxyListener = proxyListeners.get(listener);
+		connection.removeListener(proxyListener, this, future);
+	}
 
 }
Index: java/main/src/main/java/com/framsticks/remote/SimulatorTree.java
===================================================================
--- java/main/src/main/java/com/framsticks/remote/SimulatorTree.java	(revision 98)
+++ 	(revision )
@@ -1,116 +1,0 @@
-package com.framsticks.remote;
-
-import java.util.List;
-
-import org.apache.log4j.Logger;
-
-import static com.framsticks.core.TreeOperations.*;
-import com.framsticks.communication.EventCallback;
-import com.framsticks.communication.File;
-import com.framsticks.communication.util.LoggingSubscriptionCallback;
-import com.framsticks.core.Tree;
-import com.framsticks.core.TreeOperations;
-import com.framsticks.core.Path;
-import com.framsticks.params.annotations.FramsClassAnnotation;
-import com.framsticks.params.types.EventParam;
-import com.framsticks.util.Logging;
-import com.framsticks.util.PeriodicTask;
-import com.framsticks.util.UnaryFunctor;
-import com.framsticks.util.UnaryListenersSet;
-import com.framsticks.util.dispatching.FutureHandler;
-import com.framsticks.util.dispatching.RunAt;
-import com.framsticks.util.dispatching.ThrowExceptionHandler;
-
-@FramsClassAnnotation
-public class SimulatorTree extends RemoteTree {
-
-	private final static Logger log = Logger.getLogger(SimulatorTree.class);
-
-	protected Path simulator;
-
-	/**
-	 *
-	 */
-	public SimulatorTree() {
-		super();
-	}
-
-	public void setRunning(final boolean running) {
-		assert isActive();
-		//simulator.call(simulator.getParam(running ? "start" : "stop", ProcedureParam.class), new LoggingStateCallback(log, (running ? "starting" : "stopping") + " server"));
-	}
-
-	protected final UnaryListenersSet<Boolean> simulationRunningListeners = new UnaryListenersSet<Boolean>();
-
-	protected void updateSimulationRunning() {
-		assert isActive();
-		/*
-		fetchValue(simulator, getParam(simulator, "running", Param.class), new StateFunctor() {
-			@Override
-			public void call(Exception e) {
-				if (e != null) {
-					log.fatal("failed to query simulator running status: " + e);
-					return;
-				}
-
-				invokeLater(new Runnable() {
-					@Override
-					public void run() {
-						boolean value = bindAccess(simulator).get("running", Boolean.class);
-						log.trace("server running: " + value);
-						simulationRunningListeners.call(value);
-					}
-				});
-
-			}
-		});
-		 */
-	}
-
-	public void addRunningStateListener(UnaryFunctor<Boolean, Boolean> listener) {
-		assert isActive();
-		simulationRunningListeners.add(listener);
-	}
-
-	@Override
-	protected void joinableStart() {
-		super.joinableStart();
-
-		dispatch(new RunAt<Tree>(ThrowExceptionHandler.getInstance()) {
-			@Override
-			protected void runAt() {
-				tryGet(SimulatorTree.this, "/simulator", new FutureHandler<Path>(Logging.logger(log, "failed to resolve simulator node", SimulatorTree.this)) {
-					@Override
-					protected void result(Path path) {
-						assert isActive();
-						simulator = path;
-						log.info("resolved simulator node");
-
-						EventParam param = TreeOperations.getInfoFromCache(simulator).getParamEntry("running_changed", EventParam.class);
-
-						assert param != null;
-						connection.subscribe(simulator.getTextual() + "/" + param.getId(), SimulatorTree.this, new LoggingSubscriptionCallback<Tree>(log, "server running state change", new EventCallback() {
-							@Override
-							public void call(List<File> files) {
-								dispatch(new RunAt<Tree>(getExceptionHandler()) {
-									@Override
-									protected void runAt() {
-										updateSimulationRunning();
-									}
-								});
-							}
-						}));
-						new PeriodicTask<Tree>(getExceptionHandler(), SimulatorTree.this, 1000) {
-							@Override
-							protected void runAt() {
-								updateSimulationRunning();
-								again();
-							}
-						};
-					}
-				});
-			}
-		});
-	}
-
-}
Index: java/main/src/main/java/com/framsticks/test/ChangeEvent.java
===================================================================
--- java/main/src/main/java/com/framsticks/test/ChangeEvent.java	(revision 99)
+++ java/main/src/main/java/com/framsticks/test/ChangeEvent.java	(revision 99)
@@ -0,0 +1,17 @@
+package com.framsticks.test;
+
+import com.framsticks.params.annotations.FramsClassAnnotation;
+import com.framsticks.params.annotations.ParamAnnotation;
+
+@FramsClassAnnotation
+public class ChangeEvent {
+
+	@ParamAnnotation
+	public String history;
+
+	@Override
+	public String toString() {
+		return "[test change event: " + history + "]";
+	}
+
+}
Index: java/main/src/main/java/com/framsticks/test/TestClass.java
===================================================================
--- java/main/src/main/java/com/framsticks/test/TestClass.java	(revision 98)
+++ java/main/src/main/java/com/framsticks/test/TestClass.java	(revision 99)
@@ -1,11 +1,15 @@
 package com.framsticks.test;
+
+import java.util.LinkedList;
+import java.util.List;
 
 import org.apache.log4j.Logger;
 
+import com.framsticks.params.EventListener;
 import com.framsticks.params.annotations.FramsClassAnnotation;
 import com.framsticks.params.annotations.ParamAnnotation;
 import com.framsticks.params.types.ProcedureParam;
 
-@FramsClassAnnotation(order = {"name", "history", "appendHistory", "resetHistory"})
+@FramsClassAnnotation(order = {"name", "history", "history_changed", "appendHistory", "resetHistory"}, register = {ChangeEvent.class})
 public class TestClass {
 	private static final Logger log =
@@ -15,4 +19,5 @@
 	protected String name = "test";
 	protected String history = "initial|";
+	protected final List<EventListener<ChangeEvent>> historyListeners = new LinkedList<>();
 
 	/**
@@ -52,4 +57,5 @@
 		log.debug("appending '" + line + "'");
 		history = history + line + "|";
+		fireHistoryChange();
 		return history.length();
 	}
@@ -59,4 +65,28 @@
 		log.debug("reseting");
 		history = "";
+		fireHistoryChange();
+	}
+
+	protected void fireHistoryChange() {
+		for (EventListener<ChangeEvent> l : historyListeners) {
+			ChangeEvent event = new ChangeEvent();
+			event.history = history;
+			l.action(event);
+		}
+	}
+
+	@ParamAnnotation(id = "history_changed")
+	public void addHistoryListener(EventListener<ChangeEvent> listener) {
+		historyListeners.add(listener);
+	}
+
+	@ParamAnnotation(id = "history_changed")
+	public void removeHistoryListener(EventListener<ChangeEvent> listener) {
+		historyListeners.remove(listener);
+	}
+
+	@Override
+	public String toString() {
+		return "test class " + history;
 	}
 
Index: java/main/src/main/java/com/framsticks/util/dispatching/AtOnceDispatcher.java
===================================================================
--- java/main/src/main/java/com/framsticks/util/dispatching/AtOnceDispatcher.java	(revision 98)
+++ java/main/src/main/java/com/framsticks/util/dispatching/AtOnceDispatcher.java	(revision 99)
@@ -5,5 +5,5 @@
  * @author Piotr Sniegowski
  */
-public class AtOnceDispatcher<C> implements Dispatcher<C> {
+public class AtOnceDispatcher<C> extends AbstractJoinable implements JoinableDispatcher<C> {
 
 	@SuppressWarnings("rawtypes")
@@ -25,3 +25,28 @@
 	}
 
+	@Override
+	public String getName() {
+		return "atonce";
+	}
+
+	@Override
+	protected void joinableStart() {
+
+	}
+
+	@Override
+	protected void joinableInterrupt() {
+		finish();
+	}
+
+	@Override
+	protected void joinableFinish() {
+
+	}
+
+	@Override
+	protected void joinableJoin() throws InterruptedException {
+
+	}
+
 }
Index: java/main/src/main/java/com/framsticks/util/dispatching/Dispatching.java
===================================================================
--- java/main/src/main/java/com/framsticks/util/dispatching/Dispatching.java	(revision 98)
+++ java/main/src/main/java/com/framsticks/util/dispatching/Dispatching.java	(revision 99)
@@ -224,10 +224,12 @@
 
 		protected final double timeOut;
+		protected final ExceptionResultHandler handler;
 
 		/**
 		 * @param timeOut
 		 */
-		public Waiter(double timeOut) {
+		public Waiter(double timeOut, ExceptionResultHandler handler) {
 			this.timeOut = timeOut;
+			this.handler = handler;
 		}
 
@@ -247,6 +249,15 @@
 			}
 			if (!done) {
-				throw new FramsticksException().msg("waiter timed out");
-			}
+				handler.handle(new FramsticksException().msg("waiter timed out"));
+			}
+		}
+
+		public <T> Future<T> passInFuture(Class<T> type) {
+			return new FutureHandler<T>(handler) {
+				@Override
+				protected void result(T result) {
+					Waiter.this.pass();
+				}
+			};
 		}
 	}
@@ -254,5 +265,5 @@
 
 	public static <C> void synchronize(Dispatcher<C> dispatcher, double seconds) {
-		final Waiter waiter = new Waiter(seconds);
+		final Waiter waiter = new Waiter(seconds, ThrowExceptionHandler.getInstance());
 		dispatcher.dispatch(new RunAt<C>(ThrowExceptionHandler.getInstance()) {
 			@Override
Index: java/main/src/main/java/com/framsticks/util/dispatching/FutureHandler.java
===================================================================
--- java/main/src/main/java/com/framsticks/util/dispatching/FutureHandler.java	(revision 98)
+++ java/main/src/main/java/com/framsticks/util/dispatching/FutureHandler.java	(revision 99)
@@ -17,3 +17,13 @@
 	}
 
+	public static <T> FutureHandler<T> doNothing(Class<T> type, ExceptionResultHandler handler) {
+		return new FutureHandler<T>(handler) {
+
+			@Override
+			protected void result(T result) {
+
+			}
+		};
+	}
+
 }
Index: java/main/src/main/java/com/framsticks/util/dispatching/IgnoreExceptionHandler.java
===================================================================
--- java/main/src/main/java/com/framsticks/util/dispatching/IgnoreExceptionHandler.java	(revision 99)
+++ java/main/src/main/java/com/framsticks/util/dispatching/IgnoreExceptionHandler.java	(revision 99)
@@ -0,0 +1,23 @@
+package com.framsticks.util.dispatching;
+
+import com.framsticks.util.FramsticksException;
+
+public class IgnoreExceptionHandler implements ExceptionResultHandler {
+
+	private static final IgnoreExceptionHandler instance = new IgnoreExceptionHandler();
+
+	private IgnoreExceptionHandler() {
+	}
+
+	@Override
+	public final void handle(FramsticksException exception) {
+	}
+
+	/**
+	 * @return the instance
+	 */
+	public static IgnoreExceptionHandler getInstance() {
+		return instance;
+	}
+
+}
Index: java/main/src/main/java/com/framsticks/util/dispatching/Thread.java
===================================================================
--- java/main/src/main/java/com/framsticks/util/dispatching/Thread.java	(revision 98)
+++ java/main/src/main/java/com/framsticks/util/dispatching/Thread.java	(revision 99)
@@ -73,5 +73,5 @@
 			}
 			try {
-				task.runAt();
+				task.run();
 			} catch (Exception e) {
 				if (exceptionHandler != null) {
@@ -122,5 +122,5 @@
 				@Override
 				protected void runAt() {
-					runnable.runAt();
+					runnable.run();
 				}
 			});
Index: java/main/src/main/java/com/framsticks/util/lang/Casting.java
===================================================================
--- java/main/src/main/java/com/framsticks/util/lang/Casting.java	(revision 98)
+++ java/main/src/main/java/com/framsticks/util/lang/Casting.java	(revision 99)
@@ -6,26 +6,26 @@
  */
 public abstract class Casting {
-    public static <T> T tryCast(Class<T> class_, Object object) {
-        try {
-            return class_.cast(object);
-        } catch (ClassCastException ignored) {
-            return null;
-        }
-    }
+	public static <T> T tryCast(Class<T> class_, Object object) {
+		try {
+			return class_.cast(object);
+		} catch (ClassCastException ignored) {
+			return null;
+		}
+	}
 
-    public static <T> T assertCast(Class<T> class_, Object object) {
-        try {
-            return class_.cast(object);
-        } catch (ClassCastException ignored) {
-            assert false;
-            return null;
-        }
-    }
+	public static <T> T assertCast(Class<T> class_, Object object) {
+		try {
+			return class_.cast(object);
+		} catch (ClassCastException ignored) {
+			assert false;
+			return null;
+		}
+	}
 
-    public static <T> T throwCast(Class<T> class_, Object object) {
-        if (object == null) {
-            throw new NullPointerException();
-        }
-        return class_.cast(object);
-    }
+	public static <T> T throwCast(Class<T> class_, Object object) {
+		if (object == null) {
+			throw new NullPointerException();
+		}
+		return class_.cast(object);
+	}
 }
Index: java/main/src/main/java/com/framsticks/util/lang/FlagsUtil.java
===================================================================
--- java/main/src/main/java/com/framsticks/util/lang/FlagsUtil.java	(revision 99)
+++ java/main/src/main/java/com/framsticks/util/lang/FlagsUtil.java	(revision 99)
@@ -0,0 +1,51 @@
+package com.framsticks.util.lang;
+
+import java.lang.reflect.Field;
+import org.apache.log4j.Logger;
+
+import com.framsticks.util.lang.Delimeted;
+
+public final class FlagsUtil {
+
+	private final static Logger log = Logger.getLogger(FlagsUtil.class);
+
+	private FlagsUtil() {
+	}
+
+	public static String write(Class<?> flagsClass, int flags, String empty) {
+		Delimeted<String> d = new Delimeted<String>("+", empty);
+		try {
+			for (Field f : flagsClass.getDeclaredFields()) {
+				if (f.getType() != int.class) {
+					continue;
+				}
+				if ((flags & f.getInt(null)) != 0) {
+					d.append(f.getName());
+				}
+			}
+		} catch (IllegalArgumentException | IllegalAccessException e) {
+			e.printStackTrace();
+		}
+		return d.build();
+	}
+
+	public static Integer read(Class<?> flagsClass, String flags) {
+		Integer allFlags = 0;
+		String[] flagsSplitted = flags.split("\\+");
+		for (String flag : flagsSplitted) {
+			try {
+				allFlags |= Integer.valueOf(flag);
+			} catch (NumberFormatException ex) {
+				try {
+					Field field = flagsClass.getDeclaredField(flag.toUpperCase());
+					allFlags |= Integer.parseInt(field.get(null).toString());
+				} catch (SecurityException e) {
+					log.warn("security exception was thrown while trying to read flag (" + flag + ")");
+				} catch (NoSuchFieldException | IllegalArgumentException | IllegalAccessException e) {
+					log.warn("selected flag is not known (" + flag + ")");
+				}
+			}
+		}
+		return allFlags;
+	}
+}
Index: java/main/src/main/java/com/framsticks/util/lang/Strings.java
===================================================================
--- java/main/src/main/java/com/framsticks/util/lang/Strings.java	(revision 98)
+++ java/main/src/main/java/com/framsticks/util/lang/Strings.java	(revision 99)
@@ -36,4 +36,12 @@
 	}
 
+	public static String toStringEmptyProof(Object object, Object def) {
+		if (object == null) {
+			return def.toString();
+		}
+		String v = object.toString();
+		return notEmpty(v) ? v : def.toString();
+	}
+
 	public static String collapse(String s) {
 		if (s == null) {
Index: java/main/src/main/resources/configs/console.xml
===================================================================
--- java/main/src/main/resources/configs/console.xml	(revision 98)
+++ 	(revision )
@@ -1,8 +1,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<Framsticks>
-	<import class="com.framsticks.gui.console.DirectConsole" />
-	<import class="com.framsticks.communication.ClientSideRawConnection" />
-	<DirectConsole>
-		<ClientSideRawConnection address="localhost:9009" />
-	</DirectConsole>
-</Framsticks>
Index: java/main/src/main/resources/configs/framsticks.xml
===================================================================
--- java/main/src/main/resources/configs/framsticks.xml	(revision 98)
+++ java/main/src/main/resources/configs/framsticks.xml	(revision 99)
@@ -1,41 +1,30 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Framsticks>
-	<!-- <import class="com.framsticks.gui.console.ManagedConsole" /> -->
-	<!-- <import class="com.framsticks.remote.RemoteTree" /> -->
-	<!-- <ManagedConsole> -->
-	<!-- 	<RemoteTree name="remote" address="localhost:9009" /> -->
-	<!-- </ManagedConsole> -->
-
-	<!-- <import class="com.framsticks.gui.console.DirectConsole" /> -->
-	<!-- <import class="com.framsticks.communication.ClientSideRawConnection" /> -->
-	<!-- <DirectConsole> -->
-	<!-- 	<ClientSideRawConnection address="localhost:9009" /> -->
-	<!-- </DirectConsole> -->
-
 	<import class="com.framsticks.gui.Browser" />
 	<import class="com.framsticks.remote.RemoteTree" />
-	<import class="com.framsticks.remote.SimulatorTree" />
 	<import class="com.framsticks.model.ModelPackage" />
 	<import class="com.framsticks.model.ModelBuilder" />
 	<import class="com.framsticks.model.f0.SchemaBuilder" />
-	<import class="com.framsticks.core.ObjectTree" />
+	<import class="com.framsticks.core.LocalTree" />
 	<import class="com.framsticks.hosting.Server" />
 	<import class="com.framsticks.test.TestClass" />
+	<import class="com.framsticks.gui.table.ColumnsConfig" />
 	<Browser>
-		<SimulatorTree name="localhost:9009" address="localhost:9009">
+		<RemoteTree name="localhost:9009" address="localhost:9009">
 			<ModelPackage />
-		</SimulatorTree>
-		<!-- <ObjectTree name="model"> -->
+		</RemoteTree>
+		<!-- <LocalTree name="model"> -->
 		<!-- 	<ModelBuilder resource="/examples/f0_example.txt" /> -->
-		<!-- </ObjectTree> -->
-		<!-- <ObjectTree name="f0schema"> -->
+		<!-- </LocalTree> -->
+		<!-- <LocalTree name="f0schema"> -->
 		<!-- 	<SchemaBuilder /> -->
-		<!-- </ObjectTree> -->
-		<!-- <RemoteTree name="remote" address="localhost:9007" /> -->
+		<!-- </LocalTree> -->
+		<RemoteTree name="remote" address="localhost:9007" />
+		<ColumnsConfig className="Genotype" columnsNames="uid name" />
 	</Browser>
-	<!-- <Server name="server" port="9007"> -->
-	<!-- 	<ObjectTree name="test"> -->
-	<!-- 		<TestClass /> -->
-	<!-- 	</ObjectTree> -->
-	<!-- </Server> -->
+	<Server name="server" port="9007">
+		<LocalTree name="test">
+			<TestClass />
+		</LocalTree>
+	</Server>
 </Framsticks>
Index: java/main/src/main/resources/configs/log4j.properties
===================================================================
--- java/main/src/main/resources/configs/log4j.properties	(revision 98)
+++ java/main/src/main/resources/configs/log4j.properties	(revision 99)
@@ -29,4 +29,5 @@
 
 log4j.logger.com.framsticks=INFO
+# log4j.logger.com.framsticks.gui.table=DEBUG
 # log4j.logger.com.framsticks.gui.Panel=DEBUG
 # log4j.logger.com.framsticks.remote.RemoteTree=DEBUG
Index: java/main/src/main/resources/configs/managed-console.xml
===================================================================
--- java/main/src/main/resources/configs/managed-console.xml	(revision 99)
+++ java/main/src/main/resources/configs/managed-console.xml	(revision 99)
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Framsticks>
+	<import class="com.framsticks.gui.console.ManagedConsole" />
+	<import class="com.framsticks.remote.RemoteTree" />
+	<ManagedConsole>
+		<RemoteTree name="remote" address="localhost:9009" />
+	</ManagedConsole>
+</Framsticks>
+
Index: java/main/src/main/resources/configs/raw-console.xml
===================================================================
--- java/main/src/main/resources/configs/raw-console.xml	(revision 99)
+++ java/main/src/main/resources/configs/raw-console.xml	(revision 99)
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Framsticks>
+	<import class="com.framsticks.gui.console.DirectConsole" />
+	<import class="com.framsticks.communication.ClientSideRawConnection" />
+	<DirectConsole>
+		<ClientSideRawConnection address="localhost:9009" />
+	</DirectConsole>
+</Framsticks>
