Index: java/main/pom.xml
===================================================================
--- java/main/pom.xml	(revision 87)
+++ java/main/pom.xml	(revision 88)
@@ -40,10 +40,10 @@
 			<scope>compile</scope>
 		</dependency>
-		<dependency>
-			<groupId>commons-configuration</groupId>
-			<artifactId>commons-configuration</artifactId>
-			<version>1.9</version>
-			<scope>compile</scope>
-		</dependency>
+		<!-- <dependency> -->
+		<!-- 	<groupId>commons-configuration</groupId> -->
+		<!-- 	<artifactId>commons-configuration</artifactId> -->
+		<!-- 	<version>1.9</version> -->
+		<!-- 	<scope>compile</scope> -->
+		<!-- </dependency> -->
 		<dependency>
 			<groupId>commons-collections</groupId>
@@ -152,5 +152,5 @@
 						<argument>-classpath</argument>
 						<classpath />
-						<argument>com.framsticks.core.Program</argument>
+						<argument>com.framsticks.core.Framsticks</argument>
 					</arguments>
 				</configuration>
Index: java/main/src/main/java/com/framsticks/communication/ClientConnection.java
===================================================================
--- java/main/src/main/java/com/framsticks/communication/ClientConnection.java	(revision 87)
+++ java/main/src/main/java/com/framsticks/communication/ClientConnection.java	(revision 88)
@@ -32,9 +32,16 @@
 	protected final Map<String, Subscription<?>> subscriptions = new HashMap<>();
 
-	public String getAddress() {
-		return address;
-	}
-
-	public void connect(StateFunctor connectedFunctor) {
+	/**
+	 * @param connectedFunctor the connectedFunctor to set
+	 */
+	public void setConnectedFunctor(StateFunctor connectedFunctor) {
+		this.connectedFunctor = connectedFunctor;
+	}
+
+
+	protected StateFunctor connectedFunctor;
+
+	@Override
+	protected void joinableStart() {
 		try {
 			log.info("connecting to " + address);
@@ -46,5 +53,4 @@
 			log.info("connected to " + hostName + ":" + port);
 			connected = true;
-
 			runThreads();
 
@@ -56,7 +62,8 @@
 			log.error("buffer creation failure");
 			connectedFunctor.call(e);
-			close();
-		}
-	}
+			// close();
+		}
+	}
+
 
 	private static abstract class InboundMessage {
@@ -149,5 +156,4 @@
 
 
-	protected final String address;
 	protected final String hostName;
 	protected final int port;
@@ -156,6 +162,5 @@
 
 	public ClientConnection(String address) {
-		assert address != null;
-		this.address = address;
+		super(address);
 		Matcher matcher = addressPattern.matcher(address);
 		if (!matcher.matches()) {
@@ -235,5 +240,5 @@
 	@Override
 	public String toString() {
-		return address;
+		return "client connection " + address;
 	}
 
@@ -328,5 +333,5 @@
 	private int nextQueryId = 0;
 
-	protected void processMessage(InboundMessage inboundMessage) throws Exception {
+	protected void processMessage(InboundMessage inboundMessage) {
 		if (inboundMessage == null) {
 			log.error("failed to use any inbound message");
@@ -342,5 +347,5 @@
 	}
 
-	protected void processEvent(String rest) throws Exception {
+	protected void processEvent(String rest) {
 		Matcher matcher = eventPattern.matcher(rest);
 		if (!matcher.matches()) {
@@ -359,5 +364,5 @@
 
 
-	protected void processMessageStartingWith(String line) throws Exception {
+	protected void processMessageStartingWith(String line) {
 		Pair<String, String> command = Strings.splitIntoPair(line, ' ', "\n");
 		if (command.first.equals("event")) {
@@ -384,9 +389,14 @@
 
 	@Override
-	protected void receiverThreadRoutine() throws Exception {
+	protected void receiverThreadRoutine() {
 		while (connected) {
-			processMessageStartingWith(getLine());
-		}
-	}
+			try {
+				processMessageStartingWith(getLine());
+			} catch (Exception e) {
+				break;
+			}
+		}
+	}
+
 
 }
Index: java/main/src/main/java/com/framsticks/communication/Connection.java
===================================================================
--- java/main/src/main/java/com/framsticks/communication/Connection.java	(revision 87)
+++ java/main/src/main/java/com/framsticks/communication/Connection.java	(revision 88)
@@ -1,4 +1,5 @@
 package com.framsticks.communication;
 
+import com.framsticks.util.FramsticksException;
 import com.framsticks.util.io.Encoding;
 import com.framsticks.util.lang.Pair;
@@ -14,8 +15,14 @@
 import java.util.regex.Pattern;
 
+import com.framsticks.util.dispatching.AbstractJoinable;
+import com.framsticks.util.dispatching.Dispatching;
+import com.framsticks.util.dispatching.Joinable;
+import com.framsticks.util.dispatching.JoinableCollection;
+import com.framsticks.util.dispatching.JoinableParent;
+import com.framsticks.util.dispatching.JoinableState;
 import com.framsticks.util.dispatching.RunAt;
 import com.framsticks.util.dispatching.Thread;
 
-public abstract class Connection {
+public abstract class Connection extends AbstractJoinable implements JoinableParent {
 
 	protected final static Logger log = Logger.getLogger(Connection.class);
@@ -32,44 +39,25 @@
 	protected int protocolVersion = -1;
 
+	public String getAddress() {
+		return address;
+	}
+	protected final String address;
+
 	protected final Thread<Connection> senderThread = new Thread<>();
 	protected final Thread<Connection> receiverThread = new Thread<>();
-
+	protected final JoinableCollection<Thread<Connection>> threads = new JoinableCollection<>(true);
+
+	/**
+	 *
+	 */
+	public Connection(String address) {
+		this.address = address;
+		threads.add(senderThread);
+		threads.add(receiverThread);
+	}
 	public boolean isConnected() {
 		return connected;
 	}
 
-	public void close() {
-		protocolVersion = -1;
-		try {
-			connected = false;
-
-			senderThread.interrupt();
-			senderThread.join();
-
-			receiverThread.interrupt();
-			receiverThread.join();
-
-			if (output != null) {
-				output.close();
-				output = null;
-			}
-
-			if (input != null) {
-				input.close();
-				input = null;
-			}
-
-
-			if (socket != null) {
-				socket.close();
-				socket = null;
-			}
-
-			log.info("connection closed");
-		} catch (Exception e) {
-			log.error(e);
-		}
-
-	}
 
 	protected static final String ARGUMENT_PATTERN_FRAGMENT = "((?:\\S+)|(?:\"[^\"]*\"))";
@@ -95,34 +83,42 @@
 	char[] readBuffer = new char[BUFFER_LENGTH];
 
-	protected String getLine() throws Exception {
+	protected String getLine() {
 		StringBuilder lineBuffer = new StringBuilder();
-		while (!Thread.interrupted()) {
-			while (iterator < readChars) {
-				if (readBuffer[iterator] != '\n') {
+		try {
+			while (!Thread.interrupted()) {
+				while (iterator < readChars) {
+					if (readBuffer[iterator] != '\n') {
+						++iterator;
+						continue;
+					}
+					lineBuffer.append(readBuffer, bufferStart, iterator - bufferStart + 1);
 					++iterator;
-					continue;
+					bufferStart = iterator;
+					return lineBuffer.toString();
 				}
-				lineBuffer.append(readBuffer, bufferStart, iterator - bufferStart + 1);
-				++iterator;
-				bufferStart = iterator;
-				return lineBuffer.toString();
-			}
-			lineBuffer.append(readBuffer, bufferStart, readChars - bufferStart);
-
-			readChars = 0;
-			while (readChars == 0) {
-				try {
-					readChars = input.read(readBuffer);
-				} catch (SocketTimeoutException ignored) {
-					//timeout - continue
+				lineBuffer.append(readBuffer, bufferStart, readChars - bufferStart);
+
+				readChars = 0;
+				while (readChars == 0) {
+					try {
+						readChars = input.read(readBuffer);
+					} catch (SocketTimeoutException ignored) {
+						//timeout - continue
+					}
 				}
-			}
-			iterator = 0;
-			bufferStart = 0;
-		}
-		throw new InterruptedException();
-	}
-
-	protected abstract void receiverThreadRoutine() throws Exception;
+				iterator = 0;
+				bufferStart = 0;
+			}
+			throw new InterruptedException();
+		} catch (Exception e) {
+			throw new FramsticksException().msg("failed to read line").cause(e);
+		}
+	}
+
+	protected abstract void receiverThreadRoutine();
+
+	protected void setUpThread(Thread<Connection> thread, String name) {
+		thread.setName("connection thread " + address + " " + name);
+	}
 
 	protected void runThreads() {
@@ -132,30 +128,19 @@
 		} catch (IOException e) {
 			log.error("buffer creation failure");
-			close();
 			return;
 		}
 
-		senderThread.setName(this + "-sender");
-		receiverThread.setName(this + "-receiver");
-
-		senderThread.start();
-		receiverThread.start();
+		setUpThread(senderThread, "sender");
+		setUpThread(receiverThread, "receiver");
+		Dispatching.use(threads, this);
 
 		receiverThread.invokeLater(new RunAt<Connection>() {
 			@Override
 			public void run() {
-				try {
-					receiverThreadRoutine();
-				} catch (InterruptedException ignored) {
-					log.debug("receiver thread interrupted");
-				} catch (Exception e) {
-					log.error("error: " + e);
-					close();
-				}
+				receiverThreadRoutine();
 			}
 		});
 
 	}
-
 
 	/**
@@ -164,10 +149,52 @@
 	 * @return Query associated with query getId.
 	 */
-
 	public int getProtocolVersion() {
 		return protocolVersion;
 	}
 
-
+	@Override
+	protected void joinableInterrupt() {
+		protocolVersion = -1;
+
+		connected = false;
+		Dispatching.drop(threads, this);
+
+		// finish();
+	}
+
+	@Override
+	protected void joinableFinish() {
+		try {
+			if (output != null) {
+				output.close();
+				output = null;
+			}
+
+			if (input != null) {
+				input.close();
+				input = null;
+			}
+
+
+			if (socket != null) {
+				socket.close();
+				socket = null;
+			}
+		} catch (Exception e) {
+			log.error("failed to stop connection: ", e);
+		}
+		log.debug("connection closed");
+	}
+
+	@Override
+	public void childChangedState(Joinable joinable, JoinableState state) {
+		proceedToState(state);
+	}
+
+	@Override
+	protected void joinableJoin() throws InterruptedException {
+		Dispatching.join(threads);
+
+	}
 
 }
Index: java/main/src/main/java/com/framsticks/communication/ServerConnection.java
===================================================================
--- java/main/src/main/java/com/framsticks/communication/ServerConnection.java	(revision 87)
+++ java/main/src/main/java/com/framsticks/communication/ServerConnection.java	(revision 88)
@@ -20,12 +20,9 @@
 
 	public ServerConnection(Socket socket, RequestHandler requestHandler) {
+		super("todo");
 		this.socket = socket;
 		this.requestHandler = requestHandler;
 		connected = true;
 
-	}
-
-	public void start() {
-		runThreads();
 	}
 
@@ -36,5 +33,5 @@
 
 	@Override
-	protected void receiverThreadRoutine() throws Exception {
+	protected void receiverThreadRoutine() {
 		while (connected) {
 			processNextRequest();
@@ -98,5 +95,5 @@
 	}
 
-	protected void processNextRequest() throws Exception {
+	protected void processNextRequest() {
 		String line = getLine();
 		Pair<String, String> command = Strings.splitIntoPair(line, ' ', "\n");
@@ -124,3 +121,9 @@
 		});
 	}
+
+	@Override
+	protected void joinableStart() {
+		// TODO Auto-generated method stub
+
+	}
 }
Index: java/main/src/main/java/com/framsticks/core/AbstractInstanceListener.java
===================================================================
--- java/main/src/main/java/com/framsticks/core/AbstractInstanceListener.java	(revision 88)
+++ java/main/src/main/java/com/framsticks/core/AbstractInstanceListener.java	(revision 88)
@@ -0,0 +1,25 @@
+package com.framsticks.core;
+
+public abstract class AbstractInstanceListener implements InstanceListener {
+
+	@Override
+	public void onListChange(Path path, ListChange change) {
+
+	}
+
+	@Override
+	public void onFetch(Path path) {
+
+	}
+
+	@Override
+	public void onRun(Exception e) {
+
+	}
+
+	@Override
+	public void onStop(Exception e) {
+
+	}
+
+}
Index: java/main/src/main/java/com/framsticks/core/Entity.java
===================================================================
--- java/main/src/main/java/com/framsticks/core/Entity.java	(revision 87)
+++ java/main/src/main/java/com/framsticks/core/Entity.java	(revision 88)
@@ -1,14 +1,7 @@
 package com.framsticks.core;
 
-import javax.annotation.OverridingMethodsMustInvokeSuper;
 
 import com.framsticks.params.annotations.FramsClassAnnotation;
-import com.framsticks.params.annotations.ParamAnnotation;
-import com.framsticks.util.dispatching.Thread;
-import com.framsticks.util.dispatching.Dispatcher;
-
-import org.apache.commons.configuration.Configuration;
-import org.apache.log4j.Logger;
-import com.framsticks.util.dispatching.RunAt;
+import com.framsticks.util.dispatching.Joinable;
 
 /**
@@ -16,99 +9,35 @@
  */
 @FramsClassAnnotation
-public abstract class Entity implements Dispatcher<Entity> {
+public interface Entity extends Joinable {
 
-	private final static Logger log = Logger.getLogger(Entity.class);
+	public String getName();
 
-	@ParamAnnotation
-	protected String name = "entity";
-	protected EntityOwner owner;
-	protected Dispatcher<Entity> dispatcher;
-
-	public Entity() {
-	}
-
-	public final String getName() {
-		return name;
-	}
-
-	/**
-	 * @param name the name to set
-	 */
-	public final void setName(String name) {
-		this.name = name;
-		if (dispatcher instanceof Thread) {
-			((Thread<Entity>) dispatcher).setName(name);
-		}
-	}
-
-	/**
-	 * @return the owner
-	 */
-	public EntityOwner getOwner() {
-		return owner;
-	}
-
-	/**
-	 * @param owner the owner to set
-	 */
-	public void setOwner(EntityOwner owner) {
-		this.owner = owner;
-	}
-
-	@Override
-	public final boolean isActive() {
-		return dispatcher == null || dispatcher.isActive();
-	}
-
-	@Override
-	public final void invokeLater(RunAt<? extends Entity> runnable) {
-		assert dispatcher != null;
-		dispatcher.invokeLater(runnable);
-	}
-
-	public Dispatcher<Entity> createDefaultDispatcher() {
-		return new Thread<Entity>(name).start();
-	}
-
-	@OverridingMethodsMustInvokeSuper
-	protected void run() {
-		assert isActive();
-		log.info("running: " + this);
-	}
+	// /**
+	//  * @param name the name to set
+	//  */
+	// @ParamAnnotation
+	// public final void setName(String name) {
+	// 	this.name = name;
+	// 	if (dispatcher instanceof Thread) {
+	// 		((Thread<Entity>) dispatcher).setName(name);
+	// 	}
+	// }
 
 
-	public void configure(Configuration config) {
-	}
+	// public Dispatcher<Entity> createDefaultDispatcher() {
+	// 	return new Thread<Entity>().setName(name).start();
+	// }
 
-	public Dispatcher<Entity> getDispatcher() {
-		return dispatcher;
-	}
-
-	/**
-	 * @param dispatcher the dispatcher to set
-	 */
-	public void setDispatcher(Dispatcher<Entity> dispatcher) {
-		this.dispatcher = dispatcher;
-	}
-
-	public final void start() {
-		if (dispatcher == null) {
-			log.debug("no dispatcher set for " + this + ", creating default one");
-			setDispatcher(createDefaultDispatcher());
-		}
-		invokeLater(new RunAt<Entity>() {
-			@Override
-			public void run() {
-				Entity.this.run();
-			}
-		});
-	}
-
-	public final void done() {
-		log.info("stopping entity");
-		if (owner != null) {
-			owner.onDone();
-		}
-	}
-
+	// public void start() {
+	// 	if (dispatcher == null) {
+	// 		log.debug("no dispatcher set for " + this + ", creating default one");
+	// 		dispatcher = createDefaultDispatcher();
+	// 	}
+	// 	invokeLater(new RunAt<Entity>() {
+	// 		@Override
+	// 		public void run() {
+	// 			Entity.this.run();
+	// 		}
+	// 	});
+	// }
 }
Index: java/main/src/main/java/com/framsticks/core/EntityOwner.java
===================================================================
--- java/main/src/main/java/com/framsticks/core/EntityOwner.java	(revision 87)
+++ 	(revision )
@@ -1,8 +1,0 @@
-package com.framsticks.core;
-
-/**
- * @author Piotr Sniegowski
- */
-public interface EntityOwner {
-	void onDone();
-}
Index: java/main/src/main/java/com/framsticks/core/Framsticks.java
===================================================================
--- java/main/src/main/java/com/framsticks/core/Framsticks.java	(revision 88)
+++ java/main/src/main/java/com/framsticks/core/Framsticks.java	(revision 88)
@@ -0,0 +1,47 @@
+package com.framsticks.core;
+
+import com.framsticks.params.annotations.FramsClassAnnotation;
+import com.framsticks.parsers.XmlLoader;
+import com.framsticks.util.dispatching.JoinableCollection;
+import com.framsticks.util.dispatching.JoinableMonitor;
+
+import org.apache.log4j.Logger;
+import org.apache.log4j.PropertyConfigurator;
+
+import java.io.InputStream;
+
+/**
+ * @author Piotr Sniegowski
+ */
+@FramsClassAnnotation
+public class Framsticks extends JoinableCollection<Entity> {
+	private static final Logger log = Logger.getLogger(Framsticks.class);
+
+	public Framsticks() {
+		PropertyConfigurator.configure(getClass().getResource("/configs/log4j.properties"));
+	}
+
+	public static Framsticks loadConfiguration(InputStream stream) {
+		return new XmlLoader().load(stream, Framsticks.class);
+	}
+
+	public static void main(final String[] args) {
+
+		final Framsticks framsticks = loadConfiguration(Framsticks.class.getResourceAsStream("/configs/framsticks.xml"));
+
+		new JoinableMonitor(framsticks).use().waitFor().drop().join();
+
+		// monitor.use();
+		// monitor.waitFor();
+		// monitor.drop();
+		// monitor.join();
+
+		log.info("exiting main");
+	}
+
+	@Override
+	public String toString() {
+		return "framsticks";
+	}
+
+}
Index: java/main/src/main/java/com/framsticks/core/Instance.java
===================================================================
--- java/main/src/main/java/com/framsticks/core/Instance.java	(revision 87)
+++ java/main/src/main/java/com/framsticks/core/Instance.java	(revision 88)
@@ -1,23 +1,40 @@
 package com.framsticks.core;
 
-import com.framsticks.communication.*;
-import com.framsticks.params.*;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+
+import javax.annotation.Nonnull;
+import javax.annotation.OverridingMethodsMustInvokeSuper;
+
+import org.apache.log4j.Logger;
+
+import com.framsticks.communication.File;
+import com.framsticks.params.AccessInterface;
+import com.framsticks.params.ConstructionException;
+import com.framsticks.params.FramsClass;
+import com.framsticks.params.ListAccess;
+import com.framsticks.params.Param;
+import com.framsticks.params.Registry;
+import com.framsticks.params.ValueParam;
+import com.framsticks.params.annotations.FramsClassAnnotation;
 import com.framsticks.params.types.ObjectParam;
 import com.framsticks.parsers.Loaders;
 import com.framsticks.parsers.MultiParamLoader;
-import com.framsticks.util.*;
+import com.framsticks.util.StateFunctor;
 import com.framsticks.util.UnsupportedOperationException;
 import com.framsticks.util.dispatching.Dispatching;
 import com.framsticks.util.dispatching.Future;
+import com.framsticks.util.dispatching.RunAt;
+import com.framsticks.util.dispatching.Thread;
 import com.framsticks.util.lang.Casting;
-import org.apache.log4j.Logger;
-import com.framsticks.util.dispatching.RunAt;
-
-import java.util.*;
 
 /**
  * @author Piotr Sniegowski
  */
-public abstract class Instance extends Entity {
+@FramsClassAnnotation
+public abstract class Instance extends Thread<Instance> implements Entity {
 
 	private static final Logger log = Logger.getLogger(Instance.class.getName());
@@ -25,14 +42,8 @@
 	protected Node root;
 
-	public Set<InstanceListener> listeners = new HashSet<InstanceListener>();
+	protected Set<InstanceListener> listeners = new HashSet<InstanceListener>();
 
 	public Instance() {
-	}
-
-	@Override
-	protected void run() {
-		super.run();
-		root = new Node(Param.build().name("Instance").id(name).type("o"), null);
-		com.framsticks.model.Package.register(registry);
+		setName("entity");
 	}
 
@@ -262,10 +273,10 @@
 
 
-	public FramsClass processFetchedInfo(File file) {
+	public @Nonnull FramsClass processFetchedInfo(File file) {
 		assert isActive();
 		FramsClass framsClass = Loaders.loadFramsClass(file.getContent());
 		if ("/".equals(file.getPath())) {
 			if (root.getParam().getContainedTypeName() == null) {
-				root = new Node(Param.build().name("Instance").id(name).type("o " + framsClass.getId()), root.getObject());
+				root = new Node(Param.build().name("Instance").id(getName()).type("o " + framsClass.getId()), root.getObject());
 			}
 		}
@@ -346,4 +357,12 @@
 		return getPath("/");
 	}
+
+	@Override
+	@OverridingMethodsMustInvokeSuper
+	protected void firstTask() {
+		root = new Node(Param.build().name("Instance").id(getName()).type("o"), null);
+		com.framsticks.model.Package.register(registry);
+	}
+
 }
 
Index: java/main/src/main/java/com/framsticks/core/LocalInstance.java
===================================================================
--- java/main/src/main/java/com/framsticks/core/LocalInstance.java	(revision 87)
+++ java/main/src/main/java/com/framsticks/core/LocalInstance.java	(revision 88)
@@ -4,5 +4,4 @@
 import com.framsticks.util.dispatching.Thread;
 
-import org.apache.commons.configuration.Configuration;
 import org.apache.log4j.Logger;
 
@@ -27,18 +26,18 @@
 	}
 
-	@Override
-	public void configure(Configuration config) {
-		Integer accept = config.getInteger("accept", null);
-		if (accept != null) {
-			try {
-				acceptSocket = new ServerSocket();
-				acceptSocket.setReuseAddress(true);
-				acceptThread = new Thread<Accept>(name + "-accept").start();
-				tryBind(accept);
-			} catch (IOException e) {
-				log.fatal("failed to create accept socket: " + e);
-			}
-		}
-	}
+	// @Override
+	// public void configure(Configuration config) {
+	// 	Integer accept = config.getInteger("accept", null);
+	// 	if (accept != null) {
+	// 		try {
+	// 			acceptSocket = new ServerSocket();
+	// 			acceptSocket.setReuseAddress(true);
+	// 			acceptThread = new Thread<Accept>().setName(name + "-accept").start();
+	// 			tryBind(accept);
+	// 		} catch (IOException e) {
+	// 			log.fatal("failed to create accept socket: " + e);
+	// 		}
+	// 	}
+	// }
 
 	protected final Set<InstanceClient> clients = new HashSet<InstanceClient>();
Index: java/main/src/main/java/com/framsticks/core/Program.java
===================================================================
--- java/main/src/main/java/com/framsticks/core/Program.java	(revision 87)
+++ 	(revision )
@@ -1,113 +1,0 @@
-package com.framsticks.core;
-
-import com.framsticks.util.lang.IterableIterator;
-import com.framsticks.util.lang.Pair;
-import com.framsticks.util.lang.Strings;
-import org.apache.commons.configuration.*;
-import org.apache.log4j.Logger;
-import org.apache.log4j.PropertyConfigurator;
-
-import java.lang.reflect.Constructor;
-import java.util.*;
-import com.framsticks.util.dispatching.RunAt;
-
-/**
- * @author Piotr Sniegowski
- */
-public class Program extends com.framsticks.util.dispatching.Thread<Program> {
-
-	private final static Logger log = Logger.getLogger(Program.class.getName());
-
-	protected Entity entity;
-
-	Configuration config;
-
-	public Program(String name) {
-		super(name, java.lang.Thread.currentThread());
-	}
-
-	public static Entity configureEntity(Configuration config) {
-		String typeName = config.getString("class");
-		log.info("configuring instance " + typeName);
-		try {
-			Class<?> type = Class.forName(typeName);
-			Constructor<?> constructor = type.getConstructor();
-			Entity entity = (Entity) constructor.newInstance();
-			return entity;
-		} catch (Exception e) {
-			log.error("failed to instantiate: " + e);
-		}
-		return null;
-	}
-
-	protected static void resolve(Configuration config, String prefix) {
-		for (String p : new IterableIterator<String>(prefix == null ? config.getKeys() : config.getKeys(prefix))) {
-			if (p.endsWith(".mount")) {
-				String source = config.getString(p);
-				log.info("mounting " + source + " at " + p);
-				config.clearProperty(p);
-				Configuration mount = config.subset(source);
-				for (String mk : new IterableIterator<String>(mount.getKeys())) {
-					config.addProperty(p.substring(0, p.length() - 6) + "."	+ mk, mount.getProperty(mk));
-				}
-			}
-		}
-	}
-
-	public void run(String[] args) {
-
-		PropertyConfigurator.configure(getClass().getResource("/configs/log4j.properties"));
-		log.debug("started in " + System.getProperty("user.dir"));
-		try {
-			config = new PropertiesConfiguration(getClass().getResource("/configs/framsticks.properties"));
-
-			for (String a : args) {
-				Pair<String, String> p = Strings.splitIntoPair(a, '=', "true");
-				config.setProperty(p.first, p.second);
-			}
-
-			resolve(config, null);
-
-			Iterator<?> i = config.getKeys();
-			while (i.hasNext()) {
-				String p = (String) i.next();
-				log.debug(p + " = " + config.getProperty(p));
-			}
-
-		} catch (ConfigurationException e) {
-			System.err.print("failed to parse configuration:" + e);
-			return;
-		}
-		Configuration entityConfig = config.subset("com.framsticks.entity");
-
-		entity = configureEntity(entityConfig);
-		entity.setOwner(new EntityOwner() {
-			@Override
-			public void onDone() {
-				log.info("exiting");
-				Runtime.getRuntime().exit(0);
-			}
-		});
-		entity.setName("main");
-		try {
-			entity.configure(entityConfig);
-		} catch (Exception e) {
-			log.fatal("exception caught during configuration: " + e);
-		}
-		log.info("all entities were configured");
-		entity.start();
-	}
-
-	public static void main(final String[] args) {
-
-		final Program program = new Program("program");
-		program.invokeLater(new RunAt<Program>() {
-			@Override
-			public void run() {
-				program.run(args);
-			}
-		});
-		program.routine();
-	}
-
-}
Index: java/main/src/main/java/com/framsticks/diagnostics/Diagnostics.java
===================================================================
--- java/main/src/main/java/com/framsticks/diagnostics/Diagnostics.java	(revision 87)
+++ java/main/src/main/java/com/framsticks/diagnostics/Diagnostics.java	(revision 88)
@@ -1,13 +1,34 @@
 package com.framsticks.diagnostics;
 
-import org.apache.commons.configuration.Configuration;
 
-import com.framsticks.observers.Endpoint;
-import com.framsticks.observers.Observer;
+import java.util.Date;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.text.SimpleDateFormat;
+
+import org.apache.log4j.Logger;
+
+import com.framsticks.core.AbstractInstanceListener;
+import com.framsticks.core.Instance;
+import com.framsticks.dumping.PrintWriterSink;
+import com.framsticks.dumping.SaveStream;
+import com.framsticks.params.annotations.AutoAppendAnnotation;
+import com.framsticks.remote.RecursiveFetcher;
+import com.framsticks.util.Logging;
+import com.framsticks.util.PeriodicTask;
+import com.framsticks.util.StateFunctor;
+import com.framsticks.util.dispatching.JoinableCollection;
+import com.framsticks.util.io.Encoding;
 
 /**
  * @author Piotr Sniegowski
  */
-public class Diagnostics extends Observer {
+public class Diagnostics extends JoinableCollection<Instance> {
+	private static final Logger log =
+		Logger.getLogger(Diagnostics.class);
+
 
 	Integer dumpsInterval;
@@ -19,18 +40,65 @@
 	}
 
+
 	@Override
-	public void configure(Configuration config) {
-		super.configure(config);
-		dumpsInterval = config.getInteger("dumps.interval", null);
-		dumpsPath = config.getString("dumps.path", null);
-		dumpsFormat = config.getString("dumps.format", null);
+	@AutoAppendAnnotation
+	public void add(final Instance instance) {
+		super.add(instance);
+
+		instance.addListener(new AbstractInstanceListener() {
+			@Override
+			public void onRun(Exception e) {
+				if (e != null) {
+					return;
+				}
+
+				if (dumpsInterval != null) {
+					new PeriodicTask<Instance>(instance, dumpsInterval * 1000) {
+						@Override
+						public void run() {
+
+							log.info("starting periodic dump");
+							new RecursiveFetcher(instance, instance.getRootPath(), new StateFunctor() {
+								@Override
+								public void call(Exception e) {
+									if (Logging.log(log, "recursively fetch", instance, e)) {
+										again();
+										return;
+									}
+									log.info("instance resolved, saving");
+									try {
+										final String fileName = dumpsPath + "/" + instance + "_" + new SimpleDateFormat(dumpsFormat).format(new Date()) + ".param";
+										File file = new File(fileName);
+										new SaveStream(new PrintWriterSink(new PrintWriter(new OutputStreamWriter(new FileOutputStream(file), Encoding.getFramsticksCharset()))), instance, instance.getRootPath(), new StateFunctor() {
+											@Override
+											public void call(Exception e) {
+												Logging.log(log, "periodic dump in " + fileName + " of", instance, e);
+												again();
+											}
+										});
+									} catch (IOException ex) {
+										log.info("failed to initiate dump: " + ex);
+										again();
+									}
+
+								}
+							});
+						}
+					};
+				}
+			}
+		});
+
+
+
 	}
 
-
-	@Override
-	protected Endpoint createEndpoint() {
-		return new DiagnosticsEndpoint();
-	}
-
+	// @Override
+	// public void configure(Configuration config) {
+	//	super.configure(config);
+	//	dumpsInterval = config.getInteger("dumps.interval", null);
+	//	dumpsPath = config.getString("dumps.path", null);
+	//	dumpsFormat = config.getString("dumps.format", null);
+	// }
 
 }
Index: java/main/src/main/java/com/framsticks/diagnostics/DiagnosticsEndpoint.java
===================================================================
--- java/main/src/main/java/com/framsticks/diagnostics/DiagnosticsEndpoint.java	(revision 87)
+++ 	(revision )
@@ -1,88 +1,0 @@
-package com.framsticks.diagnostics;
-
-import com.framsticks.core.Instance;
-import com.framsticks.dumping.PrintWriterSink;
-import com.framsticks.dumping.SaveStream;
-import com.framsticks.observers.Endpoint;
-import com.framsticks.remote.RecursiveFetcher;
-import com.framsticks.util.Logging;
-import com.framsticks.util.PeriodicTask;
-import com.framsticks.util.StateFunctor;
-import com.framsticks.util.io.Encoding;
-
-import org.apache.log4j.Logger;
-
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.OutputStreamWriter;
-import java.io.PrintWriter;
-import java.text.SimpleDateFormat;
-import java.util.Date;
-
-/**
- * @author Piotr Sniegowski
- */
-public class DiagnosticsEndpoint extends Endpoint {
-
-	private final static Logger log = Logger.getLogger(DiagnosticsEndpoint.class.getName());
-
-	public DiagnosticsEndpoint() {
-		super();
-	}
-
-	@Override
-	public Diagnostics getObserver() {
-		return (Diagnostics)observer;
-	}
-
-
-	@Override
-	public void start() {
-		super.start();
-
-		if (getObserver().dumpsInterval != null) {
-			new PeriodicTask<Instance>(instance, getObserver().dumpsInterval * 1000) {
-				@Override
-				public void run() {
-
-					log.info("starting periodic dump");
-					new RecursiveFetcher(instance, instance.getRootPath(), new StateFunctor() {
-						@Override
-						public void call(Exception e) {
-							if (Logging.log(log, "recursively fetch", instance, e)) {
-								again();
-								return;
-							}
-							log.info("instance resolved, saving");
-							try {
-								final String fileName = getObserver().dumpsPath + "/" + instance + "_" + new SimpleDateFormat(getObserver().dumpsFormat).format(new Date()) + ".param";
-								File file = new File(fileName);
-								new SaveStream(new PrintWriterSink(new PrintWriter(new OutputStreamWriter(new FileOutputStream(file), Encoding.getFramsticksCharset()))), instance, instance.getRootPath(), new StateFunctor() {
-									@Override
-									public void call(Exception e) {
-										Logging.log(log, "periodic dump in " + fileName + " of", DiagnosticsEndpoint.this.instance, e);
-										again();
-									}
-								});
-							} catch (IOException ex) {
-								log.info("failed to initiate dump: " + ex);
-								again();
-							}
-
-						}
-					});
-
-
-				}
-			};
-		}
-	}
-
-	/*
-	@Override
-	public void onChange(Path path) {
-		super.onChange(path);    //To change body of overridden methods use File | Settings | File Templates.
-	}
-	*/
-}
Index: java/main/src/main/java/com/framsticks/dumping/FileInstance.java
===================================================================
--- java/main/src/main/java/com/framsticks/dumping/FileInstance.java	(revision 87)
+++ java/main/src/main/java/com/framsticks/dumping/FileInstance.java	(revision 88)
@@ -4,8 +4,9 @@
 import com.framsticks.core.Path;
 import com.framsticks.core.Instance;
+import com.framsticks.params.annotations.FramsClassAnnotation;
+import com.framsticks.params.annotations.ParamAnnotation;
 import com.framsticks.util.dispatching.Future;
 import com.framsticks.util.io.Encoding;
 
-import org.apache.commons.configuration.Configuration;
 import org.apache.log4j.Logger;
 
@@ -16,7 +17,10 @@
 import java.io.InputStreamReader;
 
+import javax.annotation.OverridingMethodsMustInvokeSuper;
+
 /**
  * @author Piotr Sniegowski
  */
+@FramsClassAnnotation
 public class FileInstance extends LocalInstance {
 
@@ -27,14 +31,19 @@
 	}
 
-	@Override
-	public void configure(Configuration config) {
-		super.configure(config);
-		file = new File(config.getString("filename"));
+	@ParamAnnotation
+	public void setFilename(String filename) {
+		file = new File(filename);
+	}
+
+	@ParamAnnotation
+	public String getFilename() {
+		return file.getName();
 	}
 
 	@Override
-	public void run() {
+	@OverridingMethodsMustInvokeSuper
+	protected void firstTask() {
 		assert isActive();
-		super.run();
+		super.firstTask();
 		try {
 			LoadStream stream = new LoadStream(this.getRootPath(), new BufferedReader(new InputStreamReader(new FileInputStream(file), Encoding.getFramsticksCharset())), this, new Future<Path>() {
Index: java/main/src/main/java/com/framsticks/examples/GenotypeBrowser.java
===================================================================
--- java/main/src/main/java/com/framsticks/examples/GenotypeBrowser.java	(revision 87)
+++ java/main/src/main/java/com/framsticks/examples/GenotypeBrowser.java	(revision 88)
@@ -2,14 +2,11 @@
 
 import com.framsticks.core.Instance;
-import com.framsticks.core.Node;
 import com.framsticks.dumping.PrintWriterSink;
 import com.framsticks.model.*;
-import com.framsticks.model.Package;
+import com.framsticks.model.f0.Schema;
 import com.framsticks.params.*;
 import com.framsticks.parsers.F0Parser;
 import com.framsticks.parsers.F0Writer;
-import com.framsticks.parsers.Schema;
 
-import org.apache.commons.configuration.Configuration;
 import org.apache.log4j.Logger;
 
@@ -17,4 +14,6 @@
 import java.io.StringWriter;
 import java.util.List;
+
+import javax.annotation.OverridingMethodsMustInvokeSuper;
 
 /**
@@ -31,27 +30,29 @@
 	}
 
-	@Override
-	public void configure(Configuration config) {
-		super.configure(config);
-		try {
-			schema = new Schema(Schema.getDefaultDefinitionAsStream());
-		} catch (Exception e) {
-			log.error("failed to load schema: " + e);
-		}
-		this.registry = schema.getRegistry();
-		Package.register(this.getRegistry());
+	// @Override
+	// public void configure(Configuration config) {
+	// 	super.configure(config);
+	// 	try {
+	// 		schema = Schema.load(Schema.getDefaultDefinitionAsStream());
+	// 	} catch (Exception e) {
+	// 		log.error("failed to load schema: " + e);
+	// 	}
+	// 	this.registry = schema.getRegistry();
+	// 	Package.register(this.getRegistry());
 
-		registry.putInfoIntoCache(FramsClass.build()
-				.idAndName("ModelBuilderRoot")
-				.param(Param.build().id("model").type("o Model").name("model"))
-				.param(Param.build().id("genotype").type("s 1").name("genotype"))
-				.finish()
-		);
-		root = new Node(Param.build().type("o ModelBuilderRoot").id(name).name("Instance"), PropertiesAccess.createPropertiesMap());
-	}
+	// 	registry.putInfoIntoCache(FramsClass.build()
+	// 			.idAndName("ModelBuilderRoot")
+	// 			.param(Param.build().id("model").type("o Model").name("model"))
+	// 			.param(Param.build().id("genotype").type("s 1").name("genotype"))
+	// 			.finish()
+	// 	);
+	// 	root = new Node(Param.build().type("o ModelBuilderRoot").id(name).name("Instance"), PropertiesAccess.createPropertiesMap());
+	// }
 
 	@Override
-	protected void run() {
+	@OverridingMethodsMustInvokeSuper
+	protected void firstTask() {
 		assert isActive();
+		super.firstTask();
 
 		try {
Index: java/main/src/main/java/com/framsticks/gui/Browser.java
===================================================================
--- java/main/src/main/java/com/framsticks/gui/Browser.java	(revision 87)
+++ java/main/src/main/java/com/framsticks/gui/Browser.java	(revision 88)
@@ -2,21 +2,25 @@
 
 import com.framsticks.core.*;
-import com.framsticks.observers.Endpoint;
-import com.framsticks.observers.Observer;
+import com.framsticks.params.annotations.AutoAppendAnnotation;
+import com.framsticks.params.annotations.FramsClassAnnotation;
+import com.framsticks.params.annotations.ParamAnnotation;
 import com.framsticks.util.Logging;
+import com.framsticks.util.dispatching.AbstractJoinable;
 import com.framsticks.util.dispatching.Dispatcher;
+import com.framsticks.util.dispatching.Dispatching;
 import com.framsticks.util.dispatching.Future;
-
-import org.apache.commons.configuration.Configuration;
-import org.apache.commons.lang.ArrayUtils;
+import com.framsticks.util.dispatching.Joinable;
+import com.framsticks.util.dispatching.JoinableCollection;
+import com.framsticks.util.dispatching.JoinableParent;
+import com.framsticks.util.dispatching.JoinableState;
+
+import javax.swing.*;
+
 import org.apache.log4j.Logger;
-
-import javax.swing.*;
 
 import java.awt.Dimension;
 import java.util.ArrayList;
-import java.util.HashSet;
 import java.util.List;
-import java.util.Set;
+import java.util.Map;
 import com.framsticks.util.dispatching.RunAt;
 
@@ -24,13 +28,18 @@
  * @author Piotr Sniegowski
  */
-public class Browser extends Observer {
+@FramsClassAnnotation
+public class Browser extends AbstractJoinable implements Dispatcher<Browser>, Entity, JoinableParent {
 
 	private static final Logger log = Logger.getLogger(Browser.class.getName());
 
-	protected final Set<Frame> frames = new HashSet<Frame>();
+	protected JoinableCollection<Frame> frames = new JoinableCollection<Frame>().setObservableName("frames");
+	protected JoinableCollection<Instance> instances = new JoinableCollection<Instance>().setObservableName("instances");
+
 	protected MainFrame mainFrame;
 	public List<PanelProvider> panelProviders = new ArrayList<PanelProvider>();
 	protected Dimension defaultFrameDimension;
 
+	String name;
+
 	public void addFrame(Frame frame) {
 		frames.add(frame);
@@ -38,38 +47,13 @@
 
 	public Browser() {
+		setName("browser");
 		JPopupMenu.setDefaultLightWeightPopupEnabled(false);
 		addPanelProvider(new StandardPanelProvider());
-	}
-
-	@Override
-	public void configure(Configuration config) {
-		super.configure(config);
-
-		defaultFrameDimension = new Dimension(config.getInteger("size.width", 1000), config.getInteger("size.height", 500));
-
-		for (String name : config.getStringArray("panel_providers")) {
-			try {
-				Class<?> c = Class.forName(name);
-				if (ArrayUtils.indexOf(c.getInterfaces(), PanelProvider.class) == -1) {
-					continue;
-				}
-				PanelProvider p = (PanelProvider)c.newInstance();
-				addPanelProvider(p);
-			} catch (Exception e) {
-				log.error("failed to load PanelProvider " + name + ": " + e);
-			}
-		}
-
-		// for (final String path : config.getStringArray("resolve_paths")) {
-		//	invokeLater()
-		//	autoResolvePath(path, new Future<Path>() {
-		//		@Override
-		//		public void result(Path p, Exception e) {
-		//			Logging.log(log, "auto resolve path", path, e);
-		//		}
-		//	});
-		// }
-	}
-
+
+		mainFrame = new MainFrame(Browser.this);
+		addFrame(mainFrame);
+	}
+
+	@AutoAppendAnnotation
 	public void addPanelProvider(PanelProvider panelProvider) {
 		log.debug("added panel provider of type: " + panelProvider.getClass().getCanonicalName());
@@ -77,6 +61,12 @@
 	}
 
+	@AutoAppendAnnotation
+	public void addInstance(Instance instance) {
+		log.info("adding instance: " + instance);
+		instances.add(instance);
+	}
+
 	public void autoResolvePath(final String path, final Future<Path> future) {
-		final Instance i = endpoints.get("localhost").getInstance();
+		final Instance i = instances.get("localhost");
 		i.invokeLater(new RunAt<Instance>() {
 			@Override
@@ -110,9 +100,7 @@
 	}
 
-	@Override
-	public void run() {
-		super.run();
-
+	protected void firstTask() {
 		assert isActive();
+		log.info("executing first task");
 
 		try {
@@ -135,6 +123,4 @@
 		javax.swing.JFrame.setDefaultLookAndFeelDecorated(true);
 
-		mainFrame = new MainFrame(Browser.this);
-		addFrame(mainFrame);
 
 		for (Frame f : frames) {
@@ -142,13 +128,13 @@
 		}
 
-		for (final Endpoint e : getEndpoints().values()) {
-			e.invokeLater(new RunAt<Instance>() {
+		for (final Instance i : instances) {
+			i.invokeLater(new RunAt<Instance>() {
 				@Override
 				public void run() {
-					final Path p = e.getInstance().getRootPath();
+					final Path p = i.getRootPath();
 					invokeLater(new RunAt<Browser>() {
 						@Override
 						public void run() {
-							mainFrame.addRootPath((BrowserEndpoint) e, p);
+							mainFrame.addRootPath(p);
 						}
 					});
@@ -158,5 +144,5 @@
 
 		for (Frame f : frames) {
-			f.setVisible(true);
+			f.getSwing().setVisible(true);
 		}
 
@@ -169,37 +155,45 @@
 		//assert instance.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() {
+		/*
+		 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() {
+		Dispatching.use(frames, this);
+		Dispatching.use(instances, this);
+
+		invokeLater(new RunAt<Browser>() {
 			@Override
 			public void run() {
-				parentTreeNode.getOrCreateChildTreeNodeFor(child);
+				firstTask();
 			}
 		});
-*/
-	}
-
-
-	@Override
-	protected Endpoint createEndpoint() {
-		return new BrowserEndpoint();
-	}
-
-	@Override
-	public Dispatcher<Entity> createDefaultDispatcher() {
-		return SwingDispatcher.getInstance();
+	}
+
+	/**
+	 * @return the instances
+	 */
+	public Map<String, Instance> getInstances() {
+		return instances.getObservables();
 	}
 
@@ -211,3 +205,66 @@
 	}
 
+	/**
+	 * @return the name
+	 */
+	@ParamAnnotation
+	public String getName() {
+		return name;
+	}
+
+	/**
+	 * @param name the name to set
+	 */
+	@ParamAnnotation
+	public void setName(String name) {
+		this.name = name;
+	}
+
+	@Override
+	public boolean isActive() {
+		return SwingDispatcher.getInstance().isActive();
+	}
+
+	@Override
+	public void invokeLater(RunAt<? extends Browser> runnable) {
+		SwingDispatcher.getInstance().invokeLater(runnable);
+	}
+
+	@Override
+	protected void joinableJoin() throws InterruptedException {
+		Dispatching.join(frames);
+		Dispatching.join(instances);
+		// super.join();
+	}
+
+	@Override
+	protected void joinableInterrupt() {
+		Dispatching.drop(frames, this);
+		Dispatching.drop(instances, this);
+	}
+
+	@Override
+	public void childChangedState(Joinable joinable, JoinableState state) {
+		if (joinable == frames) {
+			proceedToState(state);
+		}
+
+	}
+
+	@Override
+	protected void joinableFinish() {
+		// TODO Auto-generated method stub
+
+	}
+
+	@Override
+	public String toString() {
+		return getName();
+	}
+
+
+	// @Override
+	// public boolean isDone() {
+	//	return frames.isDone() && instances.isDone();
+	// }
 }
Index: java/main/src/main/java/com/framsticks/gui/BrowserEndpoint.java
===================================================================
--- java/main/src/main/java/com/framsticks/gui/BrowserEndpoint.java	(revision 87)
+++ 	(revision )
@@ -1,14 +1,0 @@
-package com.framsticks.gui;
-
-import com.framsticks.observers.Endpoint;
-
-/**
- * @author Piotr Sniegowski
- */
-public class BrowserEndpoint extends Endpoint {
-
-    public BrowserEndpoint() {
-    	
-    }
-
-}
Index: java/main/src/main/java/com/framsticks/gui/EndpointAtFrame.java
===================================================================
--- java/main/src/main/java/com/framsticks/gui/EndpointAtFrame.java	(revision 87)
+++ 	(revision )
@@ -1,179 +1,0 @@
-package com.framsticks.gui;
-
-import org.apache.log4j.Logger;
-
-import com.framsticks.core.Instance;
-import com.framsticks.core.InstanceListener;
-import com.framsticks.core.ListChange;
-import com.framsticks.core.Node;
-import com.framsticks.core.Path;
-import com.framsticks.params.CompositeParam;
-import com.framsticks.params.FramsClass;
-
-import java.util.*;
-
-import javax.swing.tree.TreePath;
-import com.framsticks.util.dispatching.RunAt;
-
-/**
- * @author Piotr Sniegowski
- */
-public class EndpointAtFrame implements InstanceListener {
-
-	private static final Logger log = Logger.getLogger(EndpointAtFrame.class);
-
-	protected final BrowserEndpoint endpoint;
-	protected final Frame frame;
-	protected final Instance instance;
-	protected final Map<String, Panel> knownPanels = new HashMap<String, Panel>();
-	protected TreeNode rootTreeNode;
-
-	public EndpointAtFrame(BrowserEndpoint endpoint, Frame frame) {
-		this.endpoint = endpoint;
-		this.frame = frame;
-		this.instance = endpoint.getInstance();
-	}
-
-	public BrowserEndpoint getEndpoint() {
-		return endpoint;
-	}
-
-	public Frame getFrame() {
-		return frame;
-	}
-
-	public void registerPanel(Panel panel) {
-	}
-
-	public Panel findPanel(String accessId) {
-		assert frame.isActive();
-		return (knownPanels.containsKey(accessId) ? knownPanels.get(accessId) : null);
-	}
-
-	public final String getName() {
-		return endpoint.getName();
-	}
-
-	public Panel preparePanel(CompositeParam param, FramsClass framsClass) {
-		assert frame.isActive();
-		Panel panel = preparePanelImpl(param, framsClass);
-		assert panel != null;
-		String accessId = param.computeAccessId();
-		panel.uniqueName = accessId + "@" + endpoint.getName();
-		knownPanels.put(accessId, panel);
-		frame.cardPanel.add(panel, panel.uniqueName);
-		log.debug("prepared panel for " + panel);
-		return panel;
-	}
-
-	protected Panel preparePanelImpl(CompositeParam param, FramsClass framsClass) {
-		assert frame.isActive();
-		List<Panel> panels = new ArrayList<Panel>();
-
-		Panel.Parameters parameters = new Panel.Parameters(this, param,
-				framsClass);
-		for (PanelProvider pp : frame.browser.panelProviders) {
-			Panel p = pp.providePanel(parameters);
-			if (p != null) {
-				panels.add(p);
-			}
-		}
-
-		if (panels.isEmpty()) {
-			return new EmptyPanel(parameters);
-		}
-		if (panels.size() == 1) {
-			return panels.get(0);
-		}
-		return new MultiPanel(parameters, panels);
-
-	}
-
-	@Override
-	public void onListChange(Path path, ListChange change) {
-
-	}
-
-	public TreePath getTreePath(Path path, boolean create) {
-		assert frame.isActive();
-		TreeNode t = rootTreeNode;
-		TreePath result = new TreePath(frame.rootNode).pathByAddingChild(rootTreeNode);
-		List<Node> nodes = path.getNodes();
-		Iterator<Node> i = nodes.iterator();
-		i.next();
-		// Node first = i.next();
-
-		// if (!t.path.isResolved()) {
-		// 	t.path = new Path(path.getInstance(), nodes, first);
-		// }
-		while (i.hasNext()) {
-			Node n = i.next();
-			TreeNode r = null;
-			for (TreeNode c : t.childrenIterable()) {
-				if (c.paramId.equals(n.getParam().getId())) {
-					r = c;
-					break;
-				}
-			}
-			if (r == null) {
-				log.debug("missing " + n.getParam().getId() + " in " + t);
-				if (!create) {
-					return result;
-				}
-				Path p = Path.build().instance(path.getInstance()).buildUpTo(nodes, n).finish();
-
-
-				log.debug("forced resolution: creating treenode for " + p);
-				TreeNode childNode = new TreeNode(EndpointAtFrame.this, p);
-
-				frame.addNode(childNode, t);
-				// frame.treeModel.reload();
-				// t.add(childNode);
-				// frame.treeModel.nodeStructureChanged(t);
-
-				r = childNode;
-			} else {
-				// if (!r.path.isResolved()) {
-				// 	r.path = new Path(path.getInstance(), nodes, n);
-				// }
-			}
-			result = result.pathByAddingChild(r);
-			t = r;
-		}
-		return result;
-	}
-
-	@Override
-	public void onFetch(final Path path) {
-		assert instance.isActive();
-		log.trace("fetched " + path);
-
-		frame.invokeLater(new RunAt<Frame>() {
-			@Override
-			public void run() {
-
-				TreePath treePath = getTreePath(path, true);
-				assert treePath.getPathCount() == path.size() + 1;
-
-				final TreeNode result = (TreeNode) treePath.getLastPathComponent();
-				// log.trace("found " + result + " == " + path);
-				instance.invokeLater(new RunAt<Instance>() {
-					@Override
-					public void run() {
-						result.reactForFetchResult(path, null);
-					}
-				});
-			}
-		});
-	}
-
-	@Override
-	public void onRun(Exception e) {
-
-	}
-
-	@Override
-	public void onStop(Exception e) {
-
-	}
-}
Index: java/main/src/main/java/com/framsticks/gui/Frame.java
===================================================================
--- java/main/src/main/java/com/framsticks/gui/Frame.java	(revision 87)
+++ java/main/src/main/java/com/framsticks/gui/Frame.java	(revision 88)
@@ -1,4 +1,5 @@
 package com.framsticks.gui;
 
+import com.framsticks.core.Entity;
 import com.framsticks.core.Instance;
 import com.framsticks.core.Path;
@@ -6,6 +7,9 @@
 import com.framsticks.gui.view.TreeCellRenderer;
 import com.framsticks.util.dispatching.Dispatcher;
+import com.framsticks.util.dispatching.JoinableCollection;
 import com.framsticks.util.lang.ScopeEnd;
 import com.framsticks.util.swing.KeyboardModifier;
+import com.framsticks.util.swing.MenuConstructor;
+
 import org.apache.log4j.Logger;
 
@@ -28,5 +32,5 @@
  */
 @SuppressWarnings("serial")
-public class Frame extends JFrame implements Dispatcher<Frame> {
+public class Frame extends JoinableCollection<Instance> implements Entity, Dispatcher<Frame> {
 
 	private static final Logger log = Logger.getLogger(Frame.class.getName());
@@ -34,10 +38,11 @@
 	protected final Browser browser;
 
-	protected final Dimension screenDimension = Toolkit.getDefaultToolkit()
-			.getScreenSize();
-
-	final protected CardLayout cardPanelLayout = new CardLayout();
-	protected final JPanel cardPanel = new JPanel();
-
+	protected final Dimension screenDimension = Toolkit.getDefaultToolkit().getScreenSize();
+
+	protected CardLayout cardPanelLayout;
+	protected JPanel cardPanel;
+
+	protected final String title;
+	protected JFrame swing;
 	protected JScrollPane treeScrollPane;
 	protected JTree tree;
@@ -63,20 +68,30 @@
 	protected JMenu helpMenu;
 
-	protected final Map<BrowserEndpoint, EndpointAtFrame> endpoints = new HashMap<BrowserEndpoint, EndpointAtFrame>();
-	protected final Map<Instance, EndpointAtFrame> endpointsByInstance = new HashMap<Instance, EndpointAtFrame>();
+	protected final Map<Instance, InstanceAtFrame> instancesAtFrames = new HashMap<Instance, InstanceAtFrame>();
 
 	public Frame(String title, Browser browser) {
-		super(title);
+		this.title = title;
+		this.browser = browser;
+	}
+
+	public void configure() {
+		swing = new JFrame(title);
+		swing.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
+		swing.addWindowListener(new WindowAdapter() {
+			@Override
+			public void windowClosing(WindowEvent e) {
+				log.info("received closing");
+				joinableFinish();
+			}
+		});
 		/** this is done to remove the current value label from above the slider,
 		 * because it cannot put to work properly with floating-point value sliders,
 		 * nor it can be removed in normal way through JSlider methods  */
 		UIManager.put("Slider.paintValue", false);
-		this.browser = browser;
 		log.debug("creating " + this);
-	}
-
-	public void configure() {
-
-		Container contentPane = this.getContentPane();
+
+		statusBar = new JLabel("not connected");
+
+		Container contentPane = swing.getContentPane();
 		contentPane.setLayout(new BorderLayout());
 
@@ -95,15 +110,12 @@
 		treePopupMenu.add(new JMenuItem("Refresh"));
 		treePopupMenu.add(new JMenuItem("Open in new frame as root"));
-		addNodeActionToTreePopupMenu("Copy path to clipboard",
-				new NodeAction() {
-					@Override
-					public void actionPerformed(TreeNode treeNode) {
-						Path path = treeNode.getInstancePath();
-						StringSelection selection = new StringSelection(path
-								.toString());
-						getToolkit().getSystemClipboard().setContents(
-								selection, selection);
-					}
-				});
+		addNodeActionToTreePopupMenu("Copy path to clipboard", new NodeAction() {
+			@Override
+			public void actionPerformed(TreeNode treeNode) {
+				Path path = treeNode.getInstancePath();
+				StringSelection selection = new StringSelection(path.toString());
+				swing.getToolkit().getSystemClipboard().setContents(selection, selection);
+			}
+		});
 		//this.add(createMenuItem("Add to favourites", null));
 		//this.add(createMenuItem("Remove from favourites", null));
@@ -171,10 +183,5 @@
 		});
 
-		new KeyboardModifier(tree, JComponent.WHEN_FOCUSED)
-			.join(KeyStroke.getKeyStroke('h'), KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0))
-			.join(KeyStroke.getKeyStroke('j'), KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0))
-			.join(KeyStroke.getKeyStroke('k'), KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0))
-			.join(KeyStroke.getKeyStroke('l'), KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0))
-			;
+		new KeyboardModifier(tree, JComponent.WHEN_FOCUSED).join(KeyStroke.getKeyStroke('h'), KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0)).join(KeyStroke.getKeyStroke('j'), KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0)).join(KeyStroke.getKeyStroke('k'), KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0)).join(KeyStroke.getKeyStroke('l'), KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0));
 
 		tree.setCellRenderer(new TreeCellRenderer());
@@ -214,12 +221,13 @@
 		leftPanel.setLayout(new BorderLayout());
 		//leftPanel.add(new ViewerTest(), BorderLayout.PAGE_START);
-//        JPanel leftTopPanel = createLeftTopPanel();
-//        if (leftTopPanel != null) {
-//            leftPanel.add(leftTopPanel, BorderLayout.PAGE_START);
-//        }
+		//        JPanel leftTopPanel = createLeftTopPanel();
+		//        if (leftTopPanel != null) {
+		//            leftPanel.add(leftTopPanel, BorderLayout.PAGE_START);
+		//        }
 		leftPanel.add(treePanel, BorderLayout.CENTER);
 		leftPanel.setBackground(Color.WHITE);
 		leftPanel.setForeground(Color.WHITE);
 
+		cardPanel = new JPanel();
 		cardPanel.setName("card");
 		JSplitPane split = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, leftPanel, cardPanel);
@@ -236,10 +244,18 @@
 		mainPanelLayout.show(mainPanel, "browser");
 
+		cardPanelLayout = new CardLayout();
 		cardPanel.setLayout(cardPanelLayout);
 
-		this.pack();
+		swing.pack();
 		tree.requestFocusInWindow();
 
-		log.debug("frame configured");
+		log.debug("frame configured: " + this);
+
+		new MenuConstructor(fileMenu).add(KeyStroke.getKeyStroke(KeyEvent.VK_O, ActionEvent.CTRL_MASK), new AbstractAction("Close") {
+			@Override
+			public void actionPerformed(ActionEvent actionEvent) {
+				interrupt();
+			}
+		});
 
 	}
@@ -249,12 +265,12 @@
 	}
 
-	public void addRootPath(BrowserEndpoint endpoint, Path path) {
-		assert isActive();
-		assert !endpoints.containsKey(endpoint);
-
-		EndpointAtFrame e = new EndpointAtFrame(endpoint, this);
-		endpoint.getInstance().addListener(e);
-		endpoints.put(endpoint, e);
-		endpointsByInstance.put(endpoint.getInstance(), e);
+	public void addRootPath(Path path) {
+		assert isActive();
+		Instance instance = path.getInstance();
+		assert browser.getInstances().containsValue(instance);
+
+		InstanceAtFrame e = new InstanceAtFrame(instance, this);
+		instance.addListener(e);
+		instancesAtFrames.put(instance, e);
 		TreeNode node = new TreeNode(e, path);
 		e.rootTreeNode = node;
@@ -299,5 +315,4 @@
 	}
 
-
 	private void showPopup(MouseEvent e) {
 		assert isActive();
@@ -314,9 +329,15 @@
 	}
 
+	/**
+	 * @return the swing
+	 */
+	public JFrame getSwing() {
+		return swing;
+	}
+
 	public TreeNode getCurrentlyPoppedTreeNode() {
 		assert isActive();
 		return currentlyPoppedTreeNode;
 	}
-
 
 	public void clear() {
@@ -342,11 +363,11 @@
 	public void selectTreeNode(final TreeNode treeNode) {
 		assert isActive();
-/*		final Panel panel = treeNode.getOrCreatePanel();
-		if (panel == null) {
-			return;
-		}
-		panel.setCurrentTreeNode(treeNode);
-		treeNode.updateData();
-		showPanel(panel);*/
+		/*		final Panel panel = treeNode.getOrCreatePanel();
+		 if (panel == null) {
+		 return;
+		 }
+		 panel.setCurrentTreeNode(treeNode);
+		 treeNode.updateData();
+		 showPanel(panel);*/
 	}
 
@@ -359,5 +380,5 @@
 			return null;
 		}
-		return (TreeNode)treePath.getLastPathComponent();
+		return (TreeNode) treePath.getLastPathComponent();
 	}
 
@@ -373,5 +394,5 @@
 	public void goTo(Path path) {
 		assert isActive();
-		final TreePath treePath = endpointsByInstance.get(path.getInstance()).getTreePath(path, false);
+		final TreePath treePath = instancesAtFrames.get(path.getInstance()).getTreePath(path, false);
 		log.info("go to path: " + path + "(" + treePath + ")");
 
@@ -388,5 +409,4 @@
 	}
 
-
 	public void addNode(TreeNode child, DefaultMutableTreeNode parent) {
 		assert isActive();
@@ -399,6 +419,38 @@
 	@Override
 	public String toString() {
-		return getTitle() + "@" + browser.getName();
-	}
+		return title + "@" + browser.getName();
+	}
+
+	@Override
+	protected void joinableInterrupt() {
+		assert isActive();
+		super.joinableInterrupt();
+
+		invokeLater(new RunAt<Frame>() {
+			@Override
+			public void run() {
+				finish();
+			}
+		});
+	}
+
+	@Override
+	protected void joinableFinish() {
+		assert isActive();
+		log.debug("disposing frame " + this);
+		swing.dispose();
+	}
+
+	// @Override
+	// public boolean isDone() {
+	//	return super.isDone() && !swing.isDisplayable();
+	// }
+
+
+	@Override
+	public String getName() {
+		return title;
+	}
+
 
 }
Index: java/main/src/main/java/com/framsticks/gui/InstanceAtFrame.java
===================================================================
--- java/main/src/main/java/com/framsticks/gui/InstanceAtFrame.java	(revision 88)
+++ java/main/src/main/java/com/framsticks/gui/InstanceAtFrame.java	(revision 88)
@@ -0,0 +1,180 @@
+package com.framsticks.gui;
+
+import org.apache.log4j.Logger;
+
+import com.framsticks.core.Instance;
+import com.framsticks.core.InstanceListener;
+import com.framsticks.core.ListChange;
+import com.framsticks.core.Node;
+import com.framsticks.core.Path;
+import com.framsticks.params.CompositeParam;
+import com.framsticks.params.FramsClass;
+
+import java.util.*;
+
+import javax.swing.tree.TreePath;
+import com.framsticks.util.dispatching.RunAt;
+
+/**
+ * @author Piotr Sniegowski
+ */
+public class InstanceAtFrame implements InstanceListener {
+
+	private static final Logger log = Logger.getLogger(InstanceAtFrame.class);
+
+	protected final Frame frame;
+	protected final Instance instance;
+	protected final Map<String, Panel> knownPanels = new HashMap<String, Panel>();
+	protected TreeNode rootTreeNode;
+
+	public InstanceAtFrame(Instance instance, Frame frame) {
+		this.frame = frame;
+		this.instance = instance;
+	}
+
+	public Frame getFrame() {
+		return frame;
+	}
+
+	/**
+	 * @return the instance
+	 */
+	public Instance getInstance() {
+		return instance;
+	}
+
+	public void registerPanel(Panel panel) {
+	}
+
+	public Panel findPanel(String accessId) {
+		assert frame.isActive();
+		return (knownPanels.containsKey(accessId) ? knownPanels.get(accessId) : null);
+	}
+
+	public final String getName() {
+		return instance.getName();
+	}
+
+	public Panel preparePanel(CompositeParam param, FramsClass framsClass) {
+		assert frame.isActive();
+		Panel panel = preparePanelImpl(param, framsClass);
+		assert panel != null;
+		String accessId = param.computeAccessId();
+		panel.uniqueName = accessId + "@" + instance.getName();
+		knownPanels.put(accessId, panel);
+		frame.cardPanel.add(panel, panel.uniqueName);
+		log.debug("prepared panel for " + panel);
+		return panel;
+	}
+
+	protected Panel preparePanelImpl(CompositeParam param, FramsClass framsClass) {
+		assert frame.isActive();
+		List<Panel> panels = new ArrayList<Panel>();
+
+		Panel.Parameters parameters = new Panel.Parameters(this, param,
+				framsClass);
+		for (PanelProvider pp : frame.browser.panelProviders) {
+			Panel p = pp.providePanel(parameters);
+			if (p != null) {
+				panels.add(p);
+			}
+		}
+
+		if (panels.isEmpty()) {
+			return new EmptyPanel(parameters);
+		}
+		if (panels.size() == 1) {
+			return panels.get(0);
+		}
+		return new MultiPanel(parameters, panels);
+
+	}
+
+	@Override
+	public void onListChange(Path path, ListChange change) {
+
+	}
+
+	public TreePath getTreePath(Path path, boolean create) {
+		assert frame.isActive();
+		TreeNode t = rootTreeNode;
+		TreePath result = new TreePath(frame.rootNode).pathByAddingChild(rootTreeNode);
+		List<Node> nodes = path.getNodes();
+		Iterator<Node> i = nodes.iterator();
+		i.next();
+		// Node first = i.next();
+
+		// if (!t.path.isResolved()) {
+		//	t.path = new Path(path.getInstance(), nodes, first);
+		// }
+		while (i.hasNext()) {
+			Node n = i.next();
+			TreeNode r = null;
+			for (TreeNode c : t.childrenIterable()) {
+				if (c.paramId.equals(n.getParam().getId())) {
+					r = c;
+					break;
+				}
+			}
+			if (r == null) {
+				log.debug("missing " + n.getParam().getId() + " in " + t);
+				if (!create) {
+					return result;
+				}
+				Path p = Path.build().instance(path.getInstance()).buildUpTo(nodes, n).finish();
+
+
+				log.debug("forced resolution: creating treenode for " + p);
+				TreeNode childNode = new TreeNode(InstanceAtFrame.this, p);
+
+				frame.addNode(childNode, t);
+				// frame.treeModel.reload();
+				// t.add(childNode);
+				// frame.treeModel.nodeStructureChanged(t);
+
+				r = childNode;
+			} else {
+				// if (!r.path.isResolved()) {
+				//	r.path = new Path(path.getInstance(), nodes, n);
+				// }
+			}
+			result = result.pathByAddingChild(r);
+			t = r;
+		}
+		return result;
+	}
+
+	@Override
+	public void onFetch(final Path path) {
+		assert instance.isActive();
+		log.trace("fetched " + path);
+
+		frame.invokeLater(new RunAt<Frame>() {
+			@Override
+			public void run() {
+
+				TreePath treePath = getTreePath(path, true);
+				assert treePath.getPathCount() == path.size() + 1;
+
+				final TreeNode result = (TreeNode) treePath.getLastPathComponent();
+				// log.trace("found " + result + " == " + path);
+				instance.invokeLater(new RunAt<Instance>() {
+					@Override
+					public void run() {
+						result.reactForFetchResult(path, null);
+					}
+				});
+			}
+		});
+	}
+
+	@Override
+	public void onRun(Exception e) {
+
+	}
+
+	@Override
+	public void onStop(Exception e) {
+
+	}
+}
Index: java/main/src/main/java/com/framsticks/gui/MainFrame.java
===================================================================
--- java/main/src/main/java/com/framsticks/gui/MainFrame.java	(revision 87)
+++ java/main/src/main/java/com/framsticks/gui/MainFrame.java	(revision 88)
@@ -28,8 +28,7 @@
 	 */
 	public MainFrame(final Browser browser) {
-		super("Framsticks Network Client", browser);
+		super("framsticks", browser);
 		log.debug("creating main frame");
 
-		statusBar = new JLabel("not connected");
 	}
 
@@ -234,14 +233,14 @@
 	private void setFrameProperties() {
 		assert isActive();
-		setMinimumSize(this.getPreferredSize());
-		setSize(this.getPreferredSize());
-		setMaximumSize(screenDimension);
-		setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
-
-		setIconImage(ImageProvider.loadImage(ImageProvider.LOGO)
+		swing.setMinimumSize(swing.getPreferredSize());
+		swing.setSize(swing.getPreferredSize());
+		swing.setMaximumSize(screenDimension);
+		swing.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
+
+		swing.setIconImage(ImageProvider.loadImage(ImageProvider.LOGO)
 				.getImage());
 
 
-		addWindowListener(new WindowAdapter() {
+		swing.addWindowListener(new WindowAdapter() {
 			public void windowClosing(WindowEvent e) {
 				assert isActive();
@@ -252,5 +251,5 @@
 				*/
 				onWindowClosing();
-				dispose();
+				swing.dispose();
 			}
 		});
Index: java/main/src/main/java/com/framsticks/gui/MultiPanel.java
===================================================================
--- java/main/src/main/java/com/framsticks/gui/MultiPanel.java	(revision 87)
+++ java/main/src/main/java/com/framsticks/gui/MultiPanel.java	(revision 88)
@@ -24,5 +24,5 @@
 		for (Panel p : panels) {
 			assert p.getClassName().equals(getClassName());
-			assert p.getEndpointAtFrame() == getEndpointAtFrame();
+			assert p.getInstanceAtFrame() == getInstanceAtFrame();
 			tabbedPane.add(p.getTitle(), p);
 		}
Index: java/main/src/main/java/com/framsticks/gui/Panel.java
===================================================================
--- java/main/src/main/java/com/framsticks/gui/Panel.java	(revision 87)
+++ java/main/src/main/java/com/framsticks/gui/Panel.java	(revision 88)
@@ -15,10 +15,10 @@
 
 	public static class Parameters {
-		public final EndpointAtFrame endpoint;
+		public final InstanceAtFrame instanceAtFrame;
 		public final CompositeParam param;
 		public final FramsClass framsClass;
 
-		public Parameters(EndpointAtFrame endpoint, CompositeParam param, FramsClass framsClass) {
-			this.endpoint = endpoint;
+		public Parameters(InstanceAtFrame instanceAtFrame, CompositeParam param, FramsClass framsClass) {
+			this.instanceAtFrame = instanceAtFrame;
 			this.param = param;
 			this.framsClass = framsClass;
@@ -29,5 +29,5 @@
 
 	protected TreeNode currentTreeNode;
-	protected final EndpointAtFrame endpoint;
+	protected final InstanceAtFrame instanceAtFrame;
 	protected final Frame frame;
 	protected final String className;
@@ -37,6 +37,6 @@
 
 	public Panel(Parameters parameters) {
-		this.endpoint = parameters.endpoint;
-		this.frame = parameters.endpoint.getFrame();
+		this.instanceAtFrame = parameters.instanceAtFrame;
+		this.frame = parameters.instanceAtFrame.getFrame();
 		this.framsClass = parameters.framsClass;
 		this.param = parameters.param;
@@ -57,6 +57,6 @@
 	}
 
-	public final EndpointAtFrame getEndpointAtFrame() {
-		return endpoint;
+	public final InstanceAtFrame getInstanceAtFrame() {
+		return instanceAtFrame;
 	}
 
Index: java/main/src/main/java/com/framsticks/gui/StandardPanelProvider.java
===================================================================
--- java/main/src/main/java/com/framsticks/gui/StandardPanelProvider.java	(revision 87)
+++ java/main/src/main/java/com/framsticks/gui/StandardPanelProvider.java	(revision 88)
@@ -22,5 +22,5 @@
 		}
 //		if (param instanceof ListParam) {
-//			return new ListPanel(endpoint);
+//			return new ListPanel();
 //		}
 		return null;
Index: java/main/src/main/java/com/framsticks/gui/TreeNode.java
===================================================================
--- java/main/src/main/java/com/framsticks/gui/TreeNode.java	(revision 87)
+++ java/main/src/main/java/com/framsticks/gui/TreeNode.java	(revision 88)
@@ -41,5 +41,5 @@
 
 	final protected Frame frame;
-	final protected EndpointAtFrame endpoint;
+	final protected InstanceAtFrame instanceAtFrame;
 
 	final protected Map<EventParam, Subscription<?>> userSubscriptions = new HashMap<>();
@@ -51,6 +51,6 @@
 	protected Path path;
 
-	public TreeNode(EndpointAtFrame endpoint, final Path path) {
-		this.frame = endpoint.getFrame();
+	public TreeNode(InstanceAtFrame instanceAtFrame, final Path path) {
+		this.frame = instanceAtFrame.getFrame();
 		assert frame.isActive();
 		this.paramId = path.getLastElement();
@@ -58,5 +58,5 @@
 		log.debug("creating treenode " + name + ": " + path);
 		this.path = path;
-		this.endpoint = endpoint;
+		this.instanceAtFrame = instanceAtFrame;
 
 		iconName = TreeCellRenderer.findIconName(name, path.getTextual());
@@ -171,5 +171,5 @@
 						}
 						log.debug("update: treenode for " + p);
-						TreeNode childNode = new TreeNode(endpoint, childPath);
+						TreeNode childNode = new TreeNode(instanceAtFrame, childPath);
 
 						frame.addNode(childNode, TreeNode.this);
@@ -336,5 +336,5 @@
 
 		CompositeParam param = path.getTop().getParam();
-		panel = endpoint.findPanel(param.computeAccessId());
+		panel = instanceAtFrame.findPanel(param.computeAccessId());
 		if (panel != null) {
 			log.debug("found prepared panel for: " + path);
@@ -353,5 +353,5 @@
 					@Override
 					public void run() {
-						panel = endpoint.preparePanel(param, framsClass);
+						panel = instanceAtFrame.preparePanel(param, framsClass);
 						fillPanelWithValues();
 					}
@@ -503,5 +503,5 @@
 		final Map<ValueControl, Object> changes = localChanges;
 		localChanges = null;
-		endpoint.getEndpoint().invokeLater(new RunAt<Instance>() {
+		instanceAtFrame.getInstance().invokeLater(new RunAt<Instance>() {
 			@Override
 			public void run() {
@@ -509,5 +509,5 @@
 					final ValueControl key = e.getKey();
 					final Path p = path;
-					endpoint.getEndpoint().getInstance().storeValue(p, e.getKey().getParam(), e.getValue(), new StateFunctor() {
+					instanceAtFrame.getInstance().storeValue(p, e.getKey().getParam(), e.getValue(), new StateFunctor() {
 						@Override
 						public void call(Exception e) {
Index: java/main/src/main/java/com/framsticks/hosting/InstanceClient.java
===================================================================
--- java/main/src/main/java/com/framsticks/hosting/InstanceClient.java	(revision 87)
+++ java/main/src/main/java/com/framsticks/hosting/InstanceClient.java	(revision 88)
@@ -10,5 +10,10 @@
 import com.framsticks.parsers.Savers;
 import com.framsticks.core.LocalInstance;
+import com.framsticks.util.dispatching.AbstractJoinable;
+import com.framsticks.util.dispatching.Dispatching;
 import com.framsticks.util.dispatching.Future;
+import com.framsticks.util.dispatching.Joinable;
+import com.framsticks.util.dispatching.JoinableParent;
+import com.framsticks.util.dispatching.JoinableState;
 
 import java.net.Socket;
@@ -21,5 +26,5 @@
  * @author Piotr Sniegowski
  */
-public class InstanceClient implements RequestHandler {
+public class InstanceClient extends AbstractJoinable implements RequestHandler, JoinableParent {
 
 	protected final LocalInstance instance;
@@ -29,5 +34,4 @@
 		this.instance = instance;
 		connection = new ServerConnection(socket, this);
-		connection.start();
 	}
 
@@ -36,5 +40,4 @@
 		return instance + "|" + connection.toString();
 	}
-
 
 	@Override
@@ -94,3 +97,28 @@
 
 	}
+
+	@Override
+	protected void joinableStart() {
+		Dispatching.use(connection, this);
+	}
+
+	@Override
+	protected void joinableInterrupt() {
+		Dispatching.drop(connection, this);
+	}
+
+	@Override
+	protected void joinableFinish() {
+	}
+
+	@Override
+	protected void joinableJoin() throws InterruptedException {
+		Dispatching.join(connection);
+	}
+
+	@Override
+	public void childChangedState(Joinable joinable, JoinableState state) {
+		proceedToState(state);
+	}
+
 }
Index: java/main/src/main/java/com/framsticks/hosting/ServerInstance.java
===================================================================
--- java/main/src/main/java/com/framsticks/hosting/ServerInstance.java	(revision 87)
+++ java/main/src/main/java/com/framsticks/hosting/ServerInstance.java	(revision 88)
@@ -4,9 +4,11 @@
 import com.framsticks.params.ConstructionException;
 import com.framsticks.params.FramsClass;
-import com.framsticks.params.Param;
 import com.framsticks.core.LocalInstance;
+import com.framsticks.util.dispatching.Dispatching;
 import com.framsticks.util.dispatching.Future;
+import com.framsticks.util.dispatching.Joinable;
+import com.framsticks.util.dispatching.JoinableParent;
+import com.framsticks.util.dispatching.JoinableState;
 
-import org.apache.commons.configuration.Configuration;
 import org.apache.log4j.Logger;
 
@@ -14,5 +16,5 @@
  * @author Piotr Sniegowski
  */
-public class ServerInstance extends LocalInstance {
+public class ServerInstance extends LocalInstance implements JoinableParent {
 
 	private final static Logger log = Logger.getLogger(ServerInstance.class.getName());
@@ -24,24 +26,24 @@
 
 	@Override
-	protected void run() {
-		super.run();
+	protected void firstTask() {
+		super.firstTask();
 		assert hosted != null;
-		hosted.start();
+		Dispatching.use(hosted, this);
 	}
 
-	@Override
-	public void configure(Configuration config) {
-		super.configure(config);
+	// @Override
+	// public void configure(Configuration config) {
+	//	super.configure(config);
 
-		Configuration hostedConfig = config.subset("hosted.entity");
-		hosted = Program.configureEntity(hostedConfig);
-		if (hosted == null) {
-			log.fatal("failed to create hosted entity");
-			return;
-		}
-		hosted.setName("hosted");
-		hosted.configure(hostedConfig);
-		root = new Node(Param.build().name("root").id("root").type("o" + hosted.getClass().getCanonicalName()), hosted);
-	}
+	//	Configuration hostedConfig = config.subset("hosted.entity");
+	//	hosted = Program.configureEntity(hostedConfig);
+	//	if (hosted == null) {
+	//		log.fatal("failed to create hosted entity");
+	//		return;
+	//	}
+	//	hosted.setName("hosted");
+	//	hosted.configure(hostedConfig);
+	//	root = new Node(Param.build().name("root").id("root").type("o" + hosted.getClass().getCanonicalName()), hosted);
+	// }
 
 	@Override
@@ -93,3 +95,19 @@
 	}
 
+	@Override
+	public void childChangedState(Joinable joinable, JoinableState state) {
+		proceedToState(state);
+
+	}
+
+	@Override
+	protected void joinableInterrupt() {
+		Dispatching.drop(hosted, this);
+	}
+
+	@Override
+	protected void joinableFinish() {
+
+	}
+
 }
Index: java/main/src/main/java/com/framsticks/leftovers/FavouritesXMLFactory.java
===================================================================
--- java/main/src/main/java/com/framsticks/leftovers/FavouritesXMLFactory.java	(revision 87)
+++ java/main/src/main/java/com/framsticks/leftovers/FavouritesXMLFactory.java	(revision 88)
@@ -3,6 +3,9 @@
 import java.io.BufferedWriter;
 import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
 import java.io.IOException;
+import java.io.InputStream;
 import java.io.OutputStreamWriter;
 import java.nio.file.Files;
@@ -26,4 +29,5 @@
 import org.xml.sax.SAXException;
 
+import com.framsticks.util.FramsticksException;
 import com.framsticks.util.io.Encoding;
 
@@ -36,20 +40,25 @@
 	private static final String TYPE_MARK = "type";
 
-	protected Node readDocument(String filename) {
+	public static Node readDocument(InputStream stream) {
+		DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance();
+		try {
+			DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder();
+			Document doc = docBuilder.parse(stream);
+			doc.getDocumentElement().normalize();
+			return doc.getFirstChild();
+		} catch (ParserConfigurationException | SAXException | IOException e) {
+			throw new FramsticksException().cause(e);
+		}
+	}
+
+	public static Node readDocument(String filename) {
 		File file = new File(filename);
 		if (!file.exists()) {
-			return null;
-		}
-		DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory
-				.newInstance();
+			throw new FramsticksException().msg("file does not exist");
+		}
 		try {
-			DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder();
-			Document doc = docBuilder.parse(file);
-			doc.getDocumentElement().normalize();
-			return doc.getFirstChild();
-
-		} catch (ParserConfigurationException | SAXException | IOException e) {
-			log.error(e);
-			return null;
+			return readDocument(new FileInputStream(file));
+		} catch (FileNotFoundException e) {
+			throw new FramsticksException().cause(e);
 		}
 	}
Index: java/main/src/main/java/com/framsticks/model/f0/NeuroClass.java
===================================================================
--- java/main/src/main/java/com/framsticks/model/f0/NeuroClass.java	(revision 88)
+++ java/main/src/main/java/com/framsticks/model/f0/NeuroClass.java	(revision 88)
@@ -0,0 +1,84 @@
+package com.framsticks.model.f0;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import javax.annotation.concurrent.Immutable;
+
+import com.framsticks.params.FramsClass;
+import com.framsticks.params.annotations.FramsClassAnnotation;
+
+import static com.framsticks.util.Misc.throwIfNull;
+import static com.framsticks.util.Misc.returnNotNull;
+
+@Immutable
+@FramsClassAnnotation(id = "neuroclass", name = "neuroclass")
+public class NeuroClass extends FramsClass {
+
+
+	public NeuroClass(NeuroClassBuilder builder) {
+		super(builder);
+
+		preferredInputs = throwIfNull(builder.getPreferredInputs());
+		preferredOutput = throwIfNull(builder.getPreferredOutput());
+		preferredLocation = throwIfNull(builder.getPreferredLocation());
+		visualHints = returnNotNull(builder.getVisualHints(), 0);
+
+		if (builder.getSymbolGlyph() != null) {
+			symbolGlyph = new ArrayList<>();
+			for (String s : builder.getSymbolGlyph().split(",")) {
+				symbolGlyph.add(Integer.valueOf(s));
+			}
+		} else {
+			symbolGlyph = null;
+		}
+
+	}
+
+	protected final int preferredInputs;
+
+	protected final int preferredOutput;
+
+	protected final int preferredLocation;
+
+	protected final int visualHints;
+
+	protected final List<Integer> symbolGlyph;
+
+	/**
+	 * @return the preferredInputs
+	 */
+	public int getPreferredInputs() {
+		return preferredInputs;
+	}
+
+	/**
+	 * @return the preferredOutput
+	 */
+	public int getPreferredOutput() {
+		return preferredOutput;
+	}
+
+	/**
+	 * @return the preferredLocation
+	 */
+	public int getPreferredLocation() {
+		return preferredLocation;
+	}
+
+	/**
+	 * @return the visualHints
+	 */
+	public int getVisualHints() {
+		return visualHints;
+	}
+
+	/**
+	 * @return the symbolGlyph
+	 */
+	public List<Integer> getSymbolGlyph() {
+		return Collections.unmodifiableList(symbolGlyph);
+	}
+
+}
Index: java/main/src/main/java/com/framsticks/model/f0/NeuroClassBuilder.java
===================================================================
--- java/main/src/main/java/com/framsticks/model/f0/NeuroClassBuilder.java	(revision 88)
+++ java/main/src/main/java/com/framsticks/model/f0/NeuroClassBuilder.java	(revision 88)
@@ -0,0 +1,130 @@
+package com.framsticks.model.f0;
+
+import com.framsticks.params.FramsClassBuilder;
+import com.framsticks.params.annotations.FramsClassAnnotation;
+import com.framsticks.params.annotations.ParamAnnotation;
+
+@FramsClassAnnotation(id = "neuroclass", name = "neuroclass")
+public class NeuroClassBuilder extends FramsClassBuilder {
+
+	/**
+	 *
+	 */
+	public NeuroClassBuilder() {
+		super();
+	}
+
+	protected Integer preferredInputs;
+
+	protected Integer preferredOutput;
+
+	protected Integer preferredLocation;
+
+	protected Integer visualHints;
+
+	protected String symbolGlyph;
+
+	/** That method is just an alias needed by f0def.xml in current shape.
+	 *
+	 */
+	@ParamAnnotation(id = "description")
+	public NeuroClassBuilder descriptionAlias(String description) {
+		description(description);
+		return this;
+	}
+
+	/** That method is just an alias needed by f0def.xml in current shape.
+	 *
+	 */
+	@ParamAnnotation(id = "description")
+	public String descriptionAlias() {
+		return description;
+	}
+
+	@Override
+	public NeuroClass finish() {
+		return new NeuroClass(this);
+	}
+
+	/**
+	 * @return the preferredInputs
+	 */
+	@ParamAnnotation(id = "inputs")
+	public Integer getPreferredInputs() {
+		return preferredInputs;
+	}
+
+	/**
+	 * @param preferredInputs the preferredInputs to set
+	 */
+	@ParamAnnotation(id = "inputs")
+	public void setPreferredInputs(Integer preferredInputs) {
+		this.preferredInputs = preferredInputs;
+	}
+
+	/**
+	 * @return the preferredOutput
+	 */
+	@ParamAnnotation(id = "output")
+	public Integer getPreferredOutput() {
+		return preferredOutput;
+	}
+
+	/**
+	 * @param preferredOutput the preferredOutput to set
+	 */
+	@ParamAnnotation(id = "output")
+	public void setPreferredOutput(Integer preferredOutput) {
+		this.preferredOutput = preferredOutput;
+	}
+
+	/**
+	 * @return the preferredLocation
+	 */
+	@ParamAnnotation(id = "location")
+	public Integer getPreferredLocation() {
+		return preferredLocation;
+	}
+
+	/**
+	 * @param preferredLocation the preferredLocation to set
+	 */
+	@ParamAnnotation(id = "location")
+	public void setPreferredLocation(Integer preferredLocation) {
+		this.preferredLocation = preferredLocation;
+	}
+
+	/**
+	 * @return the visualHints
+	 */
+	@ParamAnnotation(id = "visualhints")
+	public Integer getVisualHints() {
+		return visualHints;
+	}
+
+	/**
+	 * @param visualHints the visualHints to set
+	 */
+	@ParamAnnotation(id = "visualhints")
+	public void setVisualHints(Integer visualHints) {
+		this.visualHints = visualHints;
+	}
+
+	/**
+	 * @return the symbolGlyph
+	 */
+	@ParamAnnotation(id = "symbol")
+	public String getSymbolGlyph() {
+		return symbolGlyph;
+	}
+
+	/**
+	 * @param symbolGlyph the symbolGlyph to set
+	 */
+	@ParamAnnotation(id = "symbol")
+	public void setSymbolGlyph(String symbolGlyph) {
+		this.symbolGlyph = symbolGlyph;
+	}
+
+
+}
Index: java/main/src/main/java/com/framsticks/model/f0/NeuroConnection.java
===================================================================
--- java/main/src/main/java/com/framsticks/model/f0/NeuroConnection.java	(revision 88)
+++ java/main/src/main/java/com/framsticks/model/f0/NeuroConnection.java	(revision 88)
@@ -0,0 +1,27 @@
+package com.framsticks.model.f0;
+
+import com.framsticks.params.annotations.FramsClassAnnotation;
+import com.framsticks.params.annotations.ParamAnnotation;
+
+/**
+ * The Class NeuroConnection.
+ */
+@FramsClassAnnotation
+public class NeuroConnection {
+
+	@ParamAnnotation(id = "n1")
+	public Integer thisNeuro;
+
+	@ParamAnnotation(id = "n2")
+	public Integer connectedNeuro;
+
+	@ParamAnnotation(id = "w")
+	public Double weight;
+
+	@ParamAnnotation(id = "i")
+	public String info;
+
+	@ParamAnnotation(id = "Vstyle")
+	public String visStyle;
+
+}
Index: java/main/src/main/java/com/framsticks/model/f0/NeuroParamBuilder.java
===================================================================
--- java/main/src/main/java/com/framsticks/model/f0/NeuroParamBuilder.java	(revision 88)
+++ java/main/src/main/java/com/framsticks/model/f0/NeuroParamBuilder.java	(revision 88)
@@ -0,0 +1,15 @@
+package com.framsticks.model.f0;
+
+import com.framsticks.params.ParamBuilder;
+import com.framsticks.params.annotations.FramsClassAnnotation;
+
+@FramsClassAnnotation(id = "neuroprop", name="neuroprop")
+public class NeuroParamBuilder extends ParamBuilder {
+
+	/**
+	 *
+	 */
+	public NeuroParamBuilder() {
+	}
+
+}
Index: java/main/src/main/java/com/framsticks/model/f0/Schema.java
===================================================================
--- java/main/src/main/java/com/framsticks/model/f0/Schema.java	(revision 88)
+++ java/main/src/main/java/com/framsticks/model/f0/Schema.java	(revision 88)
@@ -0,0 +1,96 @@
+package com.framsticks.model.f0;
+
+import java.io.InputStream;
+import java.util.Set;
+
+import com.framsticks.params.*;
+import com.framsticks.params.annotations.AutoAppendAnnotation;
+import com.framsticks.params.annotations.FramsClassAnnotation;
+import com.framsticks.parsers.XmlLoader;
+import com.framsticks.util.DoubleMap;
+import com.framsticks.util.FramsticksException;
+
+import com.framsticks.model.Package;
+
+/**
+ * The Class Schema, which represent f0 schema (it contains all the possible
+ * classes definitions that can be used in f0 representation). Definitions are
+ * loaded from XML stream.
+ *
+ * @author Jarek Szymczak <name.surname@gmail.com>
+ * (please replace name and surname with my personal data)
+ */
+@FramsClassAnnotation(id = "f0classes", name = "f0classes")
+public class Schema {
+
+	protected final Registry registry = new Registry();
+
+	/** The neuro classes (classess representing different types of neurons). */
+	private DoubleMap<String, FramsClass> framsClasses = new DoubleMap<>();
+	private DoubleMap<String, NeuroClass> neuroClasses = new DoubleMap<>();
+
+	public static InputStream getDefaultDefinitionAsStream() {
+		//return new FileInputStream(new File(Schema.class.getResource("/parsers/f0def.xml").getPath()));
+		return Schema.class.getResourceAsStream("/parsers/f0def.xml");
+	}
+
+	public static Schema load(InputStream stream) {
+
+		XmlLoader xmlLoader = new XmlLoader();
+		xmlLoader.setUseLowerCase(true);
+		xmlLoader.getRegistry()
+			.registerAndBuild(Schema.class)
+			.registerAndBuild(FramsClassBuilder.class)
+			.registerAndBuild(NeuroClassBuilder.class)
+			.registerAndBuild(ParamBuilder.class)
+			.registerAndBuild(NeuroParamBuilder.class)
+			.registerAndBuild(GroupBuilder.class)
+			;
+
+		Package.register(xmlLoader.getRegistry());
+
+		Object object = xmlLoader.load(Schema.getDefaultDefinitionAsStream());
+		if (!(object instanceof Schema)) {
+			throw new FramsticksException().msg("failed to load schema");
+		}
+		return (Schema) object;
+	}
+
+	public Schema() {
+	}
+
+	public void addClass(FramsClass framsClass) {
+		registry.putInfoIntoCache(framsClass);
+		if (framsClass instanceof NeuroClass) {
+			neuroClasses.put(framsClass.getId(), framsClass.getName(), (NeuroClass) framsClass);
+			return;
+		}
+		framsClasses.put(framsClass.getId(), framsClass.getName(), framsClass);
+	}
+
+	@AutoAppendAnnotation
+	public void addClass(FramsClassBuilder builder) {
+		addClass(builder.finish());
+	}
+
+	public Set<NeuroClass> getNeuroClasses() {
+		return neuroClasses.getValues();
+	}
+
+	public Set<FramsClass> getFramsClasses() {
+		return framsClasses.getValues();
+	}
+
+	public NeuroClass getNeuroClass(String identifier) {
+		return neuroClasses.get(identifier);
+	}
+
+	public FramsClass getFramsClass(String identifier) {
+		return framsClasses.get(identifier);
+	}
+
+	public final Registry getRegistry() {
+		return registry;
+	}
+
+}
Index: java/main/src/main/java/com/framsticks/model/f0/VisualHints.java
===================================================================
--- java/main/src/main/java/com/framsticks/model/f0/VisualHints.java	(revision 88)
+++ java/main/src/main/java/com/framsticks/model/f0/VisualHints.java	(revision 88)
@@ -0,0 +1,28 @@
+package com.framsticks.model.f0;
+
+/**
+ * The Class with VisualHints constants.
+ */
+public final class VisualHints {
+
+	/** don't draw class name label below the neuron. */
+	public static final int DONT_SHOW_CLASS = 2;
+	
+	/** draw the neuron at the first part when attached to joint (default is in the middle). */
+	public static final int AT_FIRST_PART = 4;
+	
+	/** draw the neuron at the second part when attached to joint (default is in the middle). */
+	public static final int AT_SECOND_PART = 8;
+	
+	/** use effector color for this neuro unit. */
+	public static final int EFFECTOR_CLASS = 16;
+	
+	/** use receptor color for this neuro unit. */
+	public static final int RECEPTOR_CLASS = 32;
+	
+	/** The Constant V1_BEND_MUSCLE. */
+	public static final int V1_BEND_MUSCLE = 64;
+	
+	/** The Constant V1_ROT_MUSCLE. */
+	public static final int V1_ROT_MUSCLE = 128;
+}
Index: java/main/src/main/java/com/framsticks/params/FramsClass.java
===================================================================
--- java/main/src/main/java/com/framsticks/params/FramsClass.java	(revision 87)
+++ java/main/src/main/java/com/framsticks/params/FramsClass.java	(revision 88)
@@ -3,4 +3,5 @@
 import com.framsticks.params.annotations.FramsClassAnnotation;
 import com.framsticks.params.annotations.ParamAnnotation;
+import com.framsticks.util.FramsticksException;
 // import com.framsticks.util.FramsticksException;
 
@@ -26,5 +27,5 @@
 @Immutable
 @FramsClassAnnotation(id = "class", name = "class")
-public final class FramsClass {
+public class FramsClass {
 
 	private final static Logger log = Logger.getLogger(FramsClass.class);
@@ -54,13 +55,13 @@
 	}
 
-	public FramsClass(String id, String name, String description, List<Param> params, List<Group> groups) {
+	public FramsClass(FramsClassBuilder builder) {
 
-		this.id = id;
-		this.name = name;
-		this.description = description;
-		this.groups = groups;
-		this.paramList = params;
+		this.id = builder.getId();
+		this.name = builder.getName();
+		this.description = builder.getDescription();
+		this.groups = builder.groups;
+		this.paramList = builder.params;
 
-		for (Param param : params) {
+		for (Param param : paramList) {
 			paramEntryMap.put(param.getId(), param);
 			try {
@@ -133,10 +134,10 @@
 	public <T extends Param> T castedParam(@Nonnull final Param param, @Nonnull final Class<T> type, Object name) {
 		if (param == null) {
-			return null;
-			// throw new FramsticksException().msg("param is missing").arg("name", name).arg("in", this);
+			// return null;
+			throw new FramsticksException().msg("param is missing").arg("name", name).arg("in", this);
 		}
 		if (!type.isInstance(param)) {
-			return null;
-			// throw new FramsticksException().msg("wrong type of param").arg("actual", param.getClass()).arg("requested", type).arg("in", this);
+			// return null;
+			throw new FramsticksException().msg("wrong type of param").arg("actual", param.getClass()).arg("requested", type).arg("in", this);
 		}
 		return type.cast(param);
Index: java/main/src/main/java/com/framsticks/params/FramsClassBuilder.java
===================================================================
--- java/main/src/main/java/com/framsticks/params/FramsClassBuilder.java	(revision 87)
+++ java/main/src/main/java/com/framsticks/params/FramsClassBuilder.java	(revision 88)
@@ -21,8 +21,10 @@
 import com.framsticks.parsers.FileSource;
 import com.framsticks.parsers.Loaders;
+import com.framsticks.util.Builder;
+import com.framsticks.util.FramsticksException;
 import com.framsticks.util.lang.Strings;
 
 @FramsClassAnnotation(id = "class", name = "class")
-public class FramsClassBuilder {
+public class FramsClassBuilder implements Builder<FramsClass> {
 	private static final Logger log =
 		Logger.getLogger(FramsClassBuilder.class);
@@ -163,5 +165,5 @@
 	}
 
-	public static Map<Class<?>, FramsClass> synchronizedCacheForBasedOnForJavaClass = Collections.synchronizedMap(new HashMap<Class<?>, FramsClass>());
+	public static final Map<Class<?>, FramsClass> synchronizedCacheForBasedOnForJavaClass = Collections.synchronizedMap(new HashMap<Class<?>, FramsClass>());
 
 	public FramsClass forClass(Class<?> javaClass) throws ConstructionException {
@@ -171,5 +173,5 @@
 		}
 
-		log.info("building for class " + javaClass);
+		log.debug("building for class " + javaClass);
 
 		FramsClassAnnotation fca = javaClass.getAnnotation(FramsClassAnnotation.class);
@@ -184,5 +186,9 @@
 
 		for (ParamCandidate pc : candidates.values()) {
-			param(Param.build().id(pc.getId()).name(pc.getName()).type(getParamTypeForNativeType(pc.getType())).flags(pc.getFlags()));
+			String type = getParamTypeForNativeType(pc.getType());
+			if (type == null) {
+				throw new FramsticksException().msg("failed to find type for param candidate").arg("candidate", pc);
+			}
+			param(Param.build().id(pc.getId()).name(pc.getName()).type(type).flags(pc.getFlags()));
 		}
 
@@ -233,5 +239,5 @@
 
 	public FramsClass finish() {
-		return new FramsClass(id, name, description, params, groups);
+		return new FramsClass(this);
 	}
 
@@ -244,4 +250,9 @@
 	public FramsClassBuilder param(ParamBuilder builder) {
 		return append(builder.finish());
+	}
+
+	@AutoAppendAnnotation
+	public FramsClassBuilder group(GroupBuilder builder) {
+		return group(builder.finish());
 	}
 
Index: java/main/src/main/java/com/framsticks/params/GroupBuilder.java
===================================================================
--- java/main/src/main/java/com/framsticks/params/GroupBuilder.java	(revision 88)
+++ java/main/src/main/java/com/framsticks/params/GroupBuilder.java	(revision 88)
@@ -0,0 +1,26 @@
+package com.framsticks.params;
+
+import com.framsticks.params.annotations.FramsClassAnnotation;
+import com.framsticks.params.annotations.ParamAnnotation;
+
+@FramsClassAnnotation(id = "group", name = "group")
+public class GroupBuilder {
+
+	@ParamAnnotation
+	protected String name;
+
+	public GroupBuilder() {
+	}
+
+	@ParamAnnotation
+	public GroupBuilder name(String name) {
+		this.name = name;
+		return this;
+	}
+
+	public Group finish() {
+		return new Group(name);
+	}
+
+
+}
Index: java/main/src/main/java/com/framsticks/params/Param.java
===================================================================
--- java/main/src/main/java/com/framsticks/params/Param.java	(revision 87)
+++ java/main/src/main/java/com/framsticks/params/Param.java	(revision 88)
@@ -53,5 +53,5 @@
 		group = builder.getGroup();
 		flags = builder.getFlags();
-		extra = 0;
+		extra = builder.getExtra();
 	}
 
Index: java/main/src/main/java/com/framsticks/params/ParamBuilder.java
===================================================================
--- java/main/src/main/java/com/framsticks/params/ParamBuilder.java	(revision 87)
+++ java/main/src/main/java/com/framsticks/params/ParamBuilder.java	(revision 88)
@@ -4,4 +4,5 @@
 import com.framsticks.params.annotations.ParamAnnotation;
 import com.framsticks.params.types.*;
+import com.framsticks.util.Builder;
 import com.framsticks.util.FramsticksException;
 import com.framsticks.util.lang.Strings;
@@ -23,5 +24,5 @@
 
 @FramsClassAnnotation(name = "prop", id = "prop")
-public class ParamBuilder {
+public class ParamBuilder implements Builder<Param> {
 	private final static Logger log = Logger.getLogger(ParamBuilder.class.getName());
 
@@ -63,5 +64,9 @@
 	private Object def;
 
+	private Integer extra;
+
 	String containedTypeName;
+
+	protected Class<?> storageType;
 
 	protected FramsClassBuilder classBuilder;
@@ -83,4 +88,5 @@
 	 * @return the min
 	 */
+	@ParamAnnotation
 	public Object getMin() {
 		return min;
@@ -90,4 +96,5 @@
 	 * @return the max
 	 */
+	@ParamAnnotation
 	public Object getMax() {
 		return max;
@@ -97,4 +104,5 @@
 	 * @return the def
 	 */
+	@ParamAnnotation
 	public Object getDef() {
 		return def;
@@ -135,6 +143,10 @@
 	public Param finish() {
 		try {
+			if (paramType == null) {
+				throw new FramsticksException().msg("trying to finish incomplete param");
+			}
+
 			return paramType.getConstructor(ParamBuilder.class).newInstance(this);
-		} catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException | NoSuchMethodException | SecurityException e) {
+		} catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException | NoSuchMethodException | SecurityException | FramsticksException e) {
 			throw new FramsticksException().msg("failed to create param").cause(e).arg("name", name);
 		}
@@ -219,4 +231,5 @@
 	public ParamBuilder type(String type) {
 		// typeString = type;
+		assert type != null;
 
 		log.trace("parsing type: " + type);
@@ -352,4 +365,9 @@
 	}
 
+	@ParamAnnotation(id = "xtra")
+	public Integer getExtra() {
+		return extra;
+	}
+
 	/**
 	 * @return the paramType
@@ -359,4 +377,11 @@
 	}
 
+	@ParamAnnotation(id = "xtra")
+	public ParamBuilder extra(Integer extra) {
+		this.extra = extra;
+		return this;
+	}
+
+	@ParamAnnotation
 	public ParamBuilder min(Object min) {
 		this.min = min;
@@ -364,4 +389,5 @@
 	}
 
+	@ParamAnnotation
 	public ParamBuilder max(Object max) {
 		this.max = max;
@@ -369,4 +395,5 @@
 	}
 
+	@ParamAnnotation
 	public ParamBuilder def(Object def) {
 		this.def = def;
@@ -374,8 +401,4 @@
 	}
 
-	// public Class<?> getStorageType() {
-	//	assert param != null;
-	//	return param.getStorageType();
-	// }
 
 	public Param build(String line) throws Exception {
@@ -435,5 +458,5 @@
 	}
 
-	public ParamBuilder defaultDef(Object def) {
+	public ParamBuilder fillDef(Object def) {
 		if (this.def == null) {
 			return def(def);
@@ -442,3 +465,15 @@
 	}
 
+	public ParamBuilder fillStorageType(Class<?> storageType) {
+		if (this.storageType == null) {
+			this.storageType = storageType;
+		}
+		return this;
+	}
+
+
+	public Class<?> getStorageType() {
+		return storageType;
+	}
 }
+
Index: java/main/src/main/java/com/framsticks/params/ParamCandidate.java
===================================================================
--- java/main/src/main/java/com/framsticks/params/ParamCandidate.java	(revision 87)
+++ java/main/src/main/java/com/framsticks/params/ParamCandidate.java	(revision 88)
@@ -132,5 +132,5 @@
 				return;
 			}
-			if (field.has()) {
+			if (isPublic(field)) {
 				if (setter.has()) {
 					throw new ConstructionException().msg("setter and field coexist");
@@ -138,6 +138,6 @@
 			}
 
-			if (getter.get() == null) {
-				throw new ConstructionException().msg("missing getter");
+			if (!getter.has() && !field.has()) {
+				throw new ConstructionException().msg("missing getter or field");
 			}
 		} catch (ConstructionException e) {
@@ -211,5 +211,5 @@
 	@Override
 	public String toString() {
-		return id;
+		return id + "(" + type.toString() + ")";
 	}
 
Index: java/main/src/main/java/com/framsticks/params/PrimitiveParam.java
===================================================================
--- java/main/src/main/java/com/framsticks/params/PrimitiveParam.java	(revision 87)
+++ java/main/src/main/java/com/framsticks/params/PrimitiveParam.java	(revision 88)
@@ -2,4 +2,5 @@
 
 import com.framsticks.util.FramsticksException;
+import com.framsticks.util.Misc;
 import com.framsticks.util.lang.Numbers;
 
@@ -26,7 +27,8 @@
 	public PrimitiveParam(ParamBuilder builder) {
 		super(builder);
-		min = builder.getMin();
-		max = builder.getMax();
-		def = builder.getDef();
+		Class<?> storageType = Misc.returnNotNull(builder.getStorageType(), Object.class);
+		min = tryCastAndReturn(builder.getMin(), storageType);
+		max = tryCastAndReturn(builder.getMax(), storageType);
+		def = tryCastAndReturn(builder.getDef(), storageType);
 	}
 
Index: java/main/src/main/java/com/framsticks/params/ReflectionAccess.java
===================================================================
--- java/main/src/main/java/com/framsticks/params/ReflectionAccess.java	(revision 87)
+++ java/main/src/main/java/com/framsticks/params/ReflectionAccess.java	(revision 88)
@@ -6,4 +6,6 @@
 import java.util.Collections;
 import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
 import java.util.Map;
 
@@ -37,5 +39,5 @@
 	public static class Backend {
 
-		protected static Map<Pair<Class<?>, FramsClass>, Backend> synchronizedCache = Collections.synchronizedMap(new HashMap<Pair<Class<?>, FramsClass>, Backend>());
+		protected static final Map<Pair<Class<?>, FramsClass>, Backend> synchronizedCache = Collections.synchronizedMap(new HashMap<Pair<Class<?>, FramsClass>, Backend>());
 
 		public static class ReflectedValueParam {
@@ -53,10 +55,10 @@
 
 		protected final Map<ValueParam, ReflectedValueParam> params;
-		protected final Map<Class<?>, Method> autoAppendMethods;
+		protected final List<Method> autoAppendMethods;
 
 		/**
 		 * @param params
 		 */
-		public Backend(Map<ValueParam, ReflectedValueParam> params, Map<Class<?>, Method> autoAppendMethods) {
+		public Backend(Map<ValueParam, ReflectedValueParam> params, List<Method> autoAppendMethods) {
 			// this.params = Collections.unmodifiableMap(params);
 			this.params = params;
@@ -140,5 +142,5 @@
 			}
 
-			Map<Class<?>, Method> autoAppendMethods = new HashMap<>();
+			List<Method> autoAppendMethods = new LinkedList<>();
 
 			Class<?> javaClass = reflectedClass;
@@ -154,5 +156,5 @@
 						throw new ConstructionException().msg("invalid number of arguments in AutoAppend marked method").arg("method", m).arg("arguments", args.length);
 					}
-					autoAppendMethods.put(args[0], m);
+					autoAppendMethods.add(m);
 				}
 
@@ -327,11 +329,11 @@
 	public boolean tryAutoAppend(Object value) {
 		assert object != null;
-		for (Map.Entry<Class<?>, Method> a : backend.autoAppendMethods.entrySet()) {
-			if (a.getKey().isAssignableFrom(value.getClass())) {
+		for (Method m : backend.autoAppendMethods) {
+			if (m.getParameterTypes()[0].isAssignableFrom(value.getClass())) {
 				try {
-					a.getValue().invoke(object, value);
+					m.invoke(object, value);
 					return true;
-				} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
-					throw new FramsticksException().msg("failed to auto append").cause(e).arg("value", value).arg("into object", object).arg("with method", a.getValue());
+				} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException | FramsticksException e) {
+					throw new FramsticksException().msg("failed to auto append").cause(e).arg("value", value).arg("into object", object).arg("with method", m);
 				}
 			}
Index: java/main/src/main/java/com/framsticks/params/Registry.java
===================================================================
--- java/main/src/main/java/com/framsticks/params/Registry.java	(revision 87)
+++ java/main/src/main/java/com/framsticks/params/Registry.java	(revision 88)
@@ -4,9 +4,7 @@
 
 import com.framsticks.params.annotations.FramsClassAnnotation;
+import com.framsticks.util.DoubleMap;
+import com.framsticks.util.FramsticksException;
 
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
 import java.util.Set;
 
@@ -16,47 +14,4 @@
 public class Registry {
 	private static final Logger log = Logger.getLogger(Registry.class.getName());
-
-	public static class DoubleSet<K1, K2, V> {
-		protected final Map<K1, V> byId = new HashMap<>();
-		protected final Map<K2, V> byName = new HashMap<>();
-		protected final Set<V> values = new HashSet<>();
-
-		public int size() {
-			return values.size();
-		}
-
-		public void put(K1 id, K2 name, V value) {
-			values.add(value);
-			if (id != null) {
-				byId.put(id, value);
-			}
-			if (name != null) {
-				byName.put(name, value);
-			}
-		}
-
-		public boolean containsValue(V value) {
-			return values.contains(value);
-
-		}
-
-		public boolean containsKey(String identifier) {
-			return byId.containsKey(identifier) || byName.containsKey(identifier);
-		}
-
-		public V get(String identifier) {
-			if (byId.containsKey(identifier)) {
-				return byId.get(identifier);
-			}
-			if (byName.containsKey(identifier)) {
-				return byName.get(identifier);
-			}
-			return null;
-		}
-
-		public Set<V> getValues() {
-			return Collections.unmodifiableSet(values);
-		}
-	}
 
 	// protected void internalRegisterClass(FramsClass framsClass, @Nullable Class<?> javaClass) {
@@ -71,6 +26,6 @@
 	// 	}
 	// }
-	protected final DoubleSet<String, String, Class<?>> javaClasses = new DoubleSet<>();
-	protected final DoubleSet<String, String, FramsClass> framsClasses = new DoubleSet<>();
+	protected final DoubleMap<String, Class<?>> javaClasses = new DoubleMap<>();
+	protected final DoubleMap<String, FramsClass> framsClasses = new DoubleMap<>();
 
 	public void registerReflectedClass(String name, String id, Class<?> reflectedClass) {
@@ -78,18 +33,22 @@
 	}
 
+	public Registry registerAndBuild(Class<?> reflectedClass) {
+		register(reflectedClass);
+		putInfoIntoCache(FramsClass.build().forClass(reflectedClass));
+		return this;
+	}
+
 	public Registry register(Class<?> reflectedClass) {
 		FramsClassAnnotation a = reflectedClass.getAnnotation(FramsClassAnnotation.class);
 		if (a == null) {
-			log.error("class is not annotated: " + reflectedClass);
-			return this;
+			throw new FramsticksException().msg("class is not annotated").arg("class", reflectedClass);
 		}
 
 		registerReflectedClass(FramsClassBuilder.getName(a, reflectedClass), FramsClassBuilder.getId(a, reflectedClass), reflectedClass);
-
 		return this;
 	}
 
 	public AccessInterface createAccess(String name, FramsClass framsClass) throws ConstructionException {
-		assert framsClasses.containsValue(framsClass);
+		// assert framsClasses.containsValue(framsClass);
 		if (javaClasses.containsKey(name)) {
 			return new ReflectionAccess(javaClasses.get(name), framsClass);
Index: java/main/src/main/java/com/framsticks/params/types/BooleanParam.java
===================================================================
--- java/main/src/main/java/com/framsticks/params/types/BooleanParam.java	(revision 87)
+++ java/main/src/main/java/com/framsticks/params/types/BooleanParam.java	(revision 88)
@@ -20,5 +20,5 @@
 	 */
 	public BooleanParam(ParamBuilder builder) {
-		super(builder.defaultDef(false));
+		super(builder.fillDef(false).fillStorageType(Boolean.class));
 	}
 
Index: java/main/src/main/java/com/framsticks/params/types/DecimalParam.java
===================================================================
--- java/main/src/main/java/com/framsticks/params/types/DecimalParam.java	(revision 87)
+++ java/main/src/main/java/com/framsticks/params/types/DecimalParam.java	(revision 88)
@@ -17,5 +17,5 @@
 	 */
 	public DecimalParam(ParamBuilder builder) {
-		super(builder.defaultDef(0));
+		super(builder.fillDef(0).fillStorageType(Integer.class));
 	}
 
Index: java/main/src/main/java/com/framsticks/params/types/FloatParam.java
===================================================================
--- java/main/src/main/java/com/framsticks/params/types/FloatParam.java	(revision 87)
+++ java/main/src/main/java/com/framsticks/params/types/FloatParam.java	(revision 88)
@@ -17,5 +17,5 @@
 	 */
 	public FloatParam(ParamBuilder builder) {
-		super(builder.defaultDef(0.0));
+		super(builder.fillDef(0.0).fillStorageType(Double.class));
 	}
 
Index: java/main/src/main/java/com/framsticks/parsers/F0Parser.java
===================================================================
--- java/main/src/main/java/com/framsticks/parsers/F0Parser.java	(revision 87)
+++ java/main/src/main/java/com/framsticks/parsers/F0Parser.java	(revision 88)
@@ -11,4 +11,6 @@
 
 import com.framsticks.model.Model;
+import com.framsticks.model.f0.Schema;
+
 import static com.framsticks.params.SimpleAbstractAccess.*;
 
@@ -49,5 +51,5 @@
 			Pair<String, String> p = Strings.splitIntoPair(line, ':', "");
 			String classId = p.first.trim();
-			FramsClass framsClass = schema.getRegistry().getInfoFromCache(classId);
+			FramsClass framsClass = schema.getFramsClass(classId);
 			if (framsClass == null) {
 				throw new Exception("unknown class id: " + classId);
Index: java/main/src/main/java/com/framsticks/parsers/F0Writer.java
===================================================================
--- java/main/src/main/java/com/framsticks/parsers/F0Writer.java	(revision 87)
+++ java/main/src/main/java/com/framsticks/parsers/F0Writer.java	(revision 88)
@@ -2,4 +2,5 @@
 
 import com.framsticks.model.Model;
+import com.framsticks.model.f0.Schema;
 import com.framsticks.params.*;
 import com.framsticks.util.Misc;
Index: java/main/src/main/java/com/framsticks/parsers/Loaders.java
===================================================================
--- java/main/src/main/java/com/framsticks/parsers/Loaders.java	(revision 87)
+++ java/main/src/main/java/com/framsticks/parsers/Loaders.java	(revision 88)
@@ -1,3 +1,5 @@
 package com.framsticks.parsers;
+
+import javax.annotation.Nonnull;
 
 import com.framsticks.params.*;
@@ -11,5 +13,5 @@
 	// private static final Logger log = Logger.getLogger(Loaders.class.getName());
 
-	public static FramsClass loadFramsClass(SourceInterface source) throws ConstructionException {
+	public static @Nonnull FramsClass loadFramsClass(SourceInterface source) throws ConstructionException {
 		final MultiParamLoader loader = new MultiParamLoader();
 		loader.setNewSource(source);
Index: java/main/src/main/java/com/framsticks/parsers/MultiParamLoader.java
===================================================================
--- java/main/src/main/java/com/framsticks/parsers/MultiParamLoader.java	(revision 87)
+++ java/main/src/main/java/com/framsticks/parsers/MultiParamLoader.java	(revision 88)
@@ -43,5 +43,5 @@
 	protected AccessInterface lastAccessInterface;
 
-	protected static FramsClass emptyFramsClass = FramsClass.build().idAndName("<empty>").finish();
+	protected static final FramsClass emptyFramsClass = FramsClass.build().idAndName("<empty>").finish();
 	/**
 	 * Empty Param representing unknown classes - used to omit unknown
Index: java/main/src/main/java/com/framsticks/parsers/Schema.java
===================================================================
--- java/main/src/main/java/com/framsticks/parsers/Schema.java	(revision 87)
+++ 	(revision )
@@ -1,303 +1,0 @@
-package com.framsticks.parsers;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
-
-import com.framsticks.params.*;
-import com.framsticks.params.annotations.AutoAppendAnnotation;
-import com.framsticks.params.annotations.FramsClassAnnotation;
-import com.framsticks.util.FramsticksException;
-import com.framsticks.util.lang.Numbers;
-import org.apache.log4j.Logger;
-
-import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.DocumentBuilderFactory;
-import javax.xml.parsers.ParserConfigurationException;
-
-import com.framsticks.leftovers.f0.NeuroClass;
-import org.w3c.dom.Document;
-import org.w3c.dom.NamedNodeMap;
-import org.w3c.dom.Node;
-import org.w3c.dom.NodeList;
-import org.xml.sax.SAXException;
-
-/**
- * The Class Schema, which represent f0 schema (it contains all the possible
- * classes definitions that can be used in f0 representation). Definitions are
- * loaded from XML stream.
- *
- * @author Jarek Szymczak <name.surname@gmail.com>
- * (please replace name and surname with my personal data)
- */
-@FramsClassAnnotation
-public class Schema {
-
-	private final static Logger logger = Logger.getLogger(Schema.class);
-
-	protected final Registry registry = new Registry();
-
-	/** The neuro classes (classess representing different types of neurons). */
-	private Map<String, NeuroClass> neuroClasses = new HashMap<String, NeuroClass>();
-
-	public static InputStream getDefaultDefinitionAsStream() {
-		//return new FileInputStream(new File(Schema.class.getResource("/parsers/f0def.xml").getPath()));
-		return Schema.class.getResourceAsStream("/parsers/f0def.xml");
-	}
-
-	public Schema() {
-	}
-
-	@AutoAppendAnnotation
-	public void addNeuroClass(NeuroClass neuroClass) {
-	}
-
-	/**
-	 * Instantiates a new schema.
-	 *
-	 * @param inputStream
-	 *            the xml stream with schema
-	 * @throws Exception
-	 *             the exception if one occurred while reading the stream
-	 */
-	public Schema(InputStream inputStream) {
-
-		DocumentBuilderFactory factory;
-		DocumentBuilder db;
-
-		try {
-			factory = javax.xml.parsers.DocumentBuilderFactory.newInstance();
-			db = factory.newDocumentBuilder();
-
-			Document document = db.parse(inputStream);
-			NodeList classes = document.getElementsByTagName("CLASS");
-
-			for (int i = 0; i < classes.getLength(); i++) {
-				Node classNode = classes.item(i);
-				FramsClass framsClass = processClass(classNode);
-				registry.putInfoIntoCache(framsClass);
-			}
-
-			classes = document.getElementsByTagName("NEUROCLASS");
-
-			for (int i = 0; i < classes.getLength(); i++) {
-				Node classNode = classes.item(i);
-				FramsClass framsClass = processClass(classNode);
-
-				NamedNodeMap attributes = classNode.getAttributes();
-				int prefInputs = getIntAttribute(attributes, "INPUTS");
-				int prefOutput = getIntAttribute(attributes, "OUTPUT");
-				int prefLocation = getIntAttribute(attributes, "LOCATION");
-				int visualHints = getIntAttribute(attributes, "VISUALHINTS");
-				String symbolGlymphString = getAttribute(attributes, "SYMBOL");
-				int[] symbolGlymph = null;
-
-				if (symbolGlymphString != null) {
-					String[] sgha = symbolGlymphString.split(",");
-					int length = sgha.length;
-					symbolGlymph = new int[length];
-					for (int j = 0; j < length; j++) {
-						try {
-							symbolGlymph[j] = Integer.parseInt(sgha[j]);
-						} catch (NumberFormatException e) {
-							logger.error("an error occurred while parsing symbol glymph, class getId: "
-									+ framsClass.getId()
-									+ ", glymph offset: " + j);
-						}
-					}
-				}
-
-				neuroClasses.put(framsClass.getId(), new NeuroClass(
-						framsClass, prefInputs, prefOutput, prefLocation,
-						visualHints, symbolGlymph));
-			}
-
-		} catch (IOException | ParserConfigurationException | SAXException e) {
-			throw new FramsticksException().msg("unexpected exception occurred").cause(e);
-		}
-	}
-
-	/**
-	 * Method used for convenience, it retrieves the Integer value stored in
-	 * node under certain attribute getName. If value is not present or is other
-	 * getType than integer 0 is returned.
-	 *
-	 * @return attribute value if value exists and it's integer (0 otherwise)
-	 *
-	 */
-	private static int getIntAttribute(NamedNodeMap attributes, String name) {
-		String v = getAttribute(attributes, name);
-		if (v == null) {
-			return 0;
-		}
-		try {
-			return Integer.parseInt(v);
-		} catch (NullPointerException e) {
-			return 0;
-		} catch (NumberFormatException e) {
-			logger.fatal("attribute " + name
-					+ " should be numeric: " + v);
-			return 0;
-		}
-	}
-
-	private static String getAttribute(NamedNodeMap attributes, String name) {
-		Node item = attributes.getNamedItem(name);
-		if (item == null) {
-			return null;
-		}
-		return item.getNodeValue();
-	}
-
-	/**
-	 * Method used for convenience, it retrieves the value stored in node under
-	 * certain attribute getName. If value is not present method returns null.
-	 *
-	 * @param attributeName
-	 *            the attribute getName
-	 * @param node
-	 *            the node
-	 * @return attribute value if value exists (null otherwise)
-	 *
-	 */
-	private static String getAttributeFromNode(String attributeName, Node node) {
-		if (node == null) {
-			return null;
-		}
-		return getAttribute(node.getAttributes(), attributeName);
-	}
-
-	/**
-	 * In this method analysis of single class is performed.
-	 *
-	 * @param classNode
-	 *            the class node
-	 * @return the param entry list as a class schema
-	 * @throws Exception
-	 *             the exception in case of any error
-	 */
-	private static FramsClass processClass(Node classNode) {
-		String classId = null;
-		String className = "";
-		String classDescription = "";
-		try {
-			classId = classNode.getAttributes().getNamedItem("ID").getNodeValue();
-		} catch (NullPointerException e) {
-			throw new FramsticksException().msg("class id is not defined");
-		}
-
-		className = getAttributeFromNode("NAME", classNode);
-		classDescription = getAttributeFromNode("DESCRIPTION", classNode);
-
-		FramsClassBuilder builder = FramsClass.build().id(classId).name(className).description(classDescription);
-
-		NodeList classProperties = classNode.getChildNodes();
-
-		for (int j = 0; j < classProperties.getLength(); j++) {
-			Node node = classProperties.item(j);
-
-			if ("GROUP".equals(node.getNodeName())) {
-				NamedNodeMap attributes = node.getAttributes();
-				String name = getAttribute(attributes, "NAME");
-				if (name == null) {
-					logger.warn("Group name in class \"" + classId + "\" (" + className + ") is undefined");
-				} else {
-					builder.group(new Group(name));
-				}
-			} else if ("PROP".equals(node.getNodeName())
-					|| "NEUROPROP".equals(node.getNodeName())) {
-
-				NamedNodeMap attributes = node.getAttributes();
-				processParameter(attributes, classId, builder);
-			}
-
-		}
-
-		return builder.finish();
-	}
-
-	private static <T extends Number> T extractAttribute(NamedNodeMap attributes, String name, Class<T> type) {
-		String value = getAttribute(attributes, name);
-		if (value == null) {
-			return null;
-		}
-		return Numbers.parse(value, type);
-	}
-	/**
-	 * It analyses the single property within the class
-	 *
-	 * @param attributes
-	 *            the attributes of property
-	 * @param classId
-	 *            the class getId
-	 * @return the param entry representing single parameter
-	 * @throws Exception
-	 *             the exception in case of any error
-	 */
-	private static void processParameter(NamedNodeMap attributes, String classId, FramsClassBuilder classBuilder) {
-
-		String id = getAttribute(attributes, "ID");
-		if (id == null) {
-			throw new FramsticksException().msg("Property ID in class \"" + classId + "\" is undefined");
-		}
-		String type = getAttribute(attributes, "TYPE");
-		if (type == null) {
-			throw new FramsticksException().msg("TYPE of property \"" + id + "\" is undefined");
-		}
-
-		String name = getAttribute(attributes, "NAME");
-		String description = getAttribute(attributes, "DESCRIPTION");
-		int group = getIntAttribute(attributes, "GROUP");
-		String flagsString = getAttribute(attributes, "FLAGS");
-
-		Integer flags = 0;
-
-		try {
-			if (flagsString != null)
-				for (String flag : flagsString.split("[^0-9]")) {
-					if (flag.trim().equals(""))
-						continue;
-					flags |= Integer.parseInt(flag);
-				}
-		} catch (NumberFormatException e) {
-			logger.warn("FLAGS parameter should be an Integer value or separated Integer values. FLAGS are set to: "
-					+ flags);
-		}
-
-		ParamBuilder builder = classBuilder.param(id).name(name).help(description).group(group).flags(flags);
-
-		builder.type(type);
-
-		if ("d".equals(type)) {
-			builder.min(extractAttribute(attributes, "MIN", Integer.class));
-			builder.max(extractAttribute(attributes, "MAX", Integer.class));
-			builder.def(extractAttribute(attributes, "DEF", Integer.class));
-		} else if ("f".equals(type)) {
-			builder.min(extractAttribute(attributes, "MIN", Double.class));
-			builder.max(extractAttribute(attributes, "MAX", Double.class));
-			builder.def(extractAttribute(attributes, "DEF", Double.class));
-		} else if ("s".equals(type)) {
-			builder.min(extractAttribute(attributes, "MIN", Integer.class));
-			builder.max(extractAttribute(attributes, "MAX", Integer.class));
-			builder.def(extractAttribute(attributes, "DEF", Integer.class));
-			builder.def(getAttribute(attributes, "DEF"));
-		} else {
-			builder.type(type);
-		}
-
-		classBuilder.param(builder);
-	}
-
-
-	public Map<String, NeuroClass> getNeuroClasses() {
-		return Collections.unmodifiableMap(neuroClasses);
-	}
-
-	public final Registry getRegistry() {
-		return registry;
-	}
-
-
-}
Index: java/main/src/main/java/com/framsticks/parsers/XmlLoader.java
===================================================================
--- java/main/src/main/java/com/framsticks/parsers/XmlLoader.java	(revision 87)
+++ java/main/src/main/java/com/framsticks/parsers/XmlLoader.java	(revision 88)
@@ -1,5 +1,124 @@
 package com.framsticks.parsers;
 
+import java.io.InputStream;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+
+import org.apache.log4j.Logger;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+import com.framsticks.params.AccessInterface;
+import com.framsticks.params.Registry;
+import com.framsticks.util.FramsticksException;
+
 public class XmlLoader {
+	private static final Logger log = Logger.getLogger(XmlLoader.class);
 
+	protected Registry registry = new Registry();
+
+	/**
+	 *
+	 */
+	public XmlLoader() {
+	}
+
+	/**
+	 * @return the registry
+	 */
+	public Registry getRegistry() {
+		return registry;
+	}
+
+	boolean useLowerCase = false;
+
+	/**
+	 * @param useLowerCase the useLowerCase to set
+	 */
+	public void setUseLowerCase(boolean useLowerCase) {
+		this.useLowerCase = useLowerCase;
+	}
+
+	public Object processElement(Element element) {
+		String name = element.getNodeName();
+		if (useLowerCase) {
+			name = name.toLowerCase();
+		}
+		if (name.equals("import")) {
+			String className = element.getAttribute("class");
+			try {
+				registry.registerAndBuild(Class.forName(className));
+				return null;
+			} catch (ClassNotFoundException e) {
+				throw new FramsticksException().msg("failed to import class").arg("name", name).cause(e);
+			}
+		}
+
+		AccessInterface access = registry.createAccess(name);
+
+		if (access == null) {
+			throw new FramsticksException().msg("failed to find access interface").arg("name", name);
+		}
+		Object object = access.createAccessee();
+		assert object != null;
+		access.select(object);
+
+		NamedNodeMap attributes = element.getAttributes();
+		for (int i = 0; i < attributes.getLength(); ++i) {
+			Node attributeNode = attributes.item(i);
+			access.set(attributeNode.getNodeName().toLowerCase(), attributeNode.getNodeValue());
+		}
+
+		NodeList children = element.getChildNodes();
+		log.debug("found " + children.getLength() + " children in " + object);
+		for (int i = 0; i < children.getLength(); ++i) {
+			Node childNode = children.item(i);
+			if (!(childNode instanceof Element)) {
+				continue;
+			}
+			Object childObject = processElement((Element) childNode);
+			if (childObject == null) {
+				continue;
+			}
+
+			if (!access.tryAutoAppend(childObject)) {
+				throw new FramsticksException().msg("failed to auto append").arg("child", childObject).arg("parent", object);
+			}
+		}
+		log.debug("loaded " + object);
+
+		return object;
+	}
+
+	public Object load(InputStream stream) {
+		try {
+			DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+			DocumentBuilder db = factory.newDocumentBuilder();
+
+			Document document = db.parse(stream);
+			document.getDocumentElement().normalize();
+			Element element = document.getDocumentElement();
+			assert element != null;
+
+			return processElement(element);
+
+		} catch (Exception e) {
+			throw new FramsticksException().msg("failed to load").cause(e);
+		}
+	}
+
+	public <T> T load(InputStream stream, Class<T> type) {
+		registry.registerAndBuild(type);
+
+		Object object = load(stream);
+		if (type.isAssignableFrom(object.getClass())) {
+			return type.cast(object);
+		}
+		throw new FramsticksException().msg("invalid type has been loaded");
+	}
 }
+
Index: java/main/src/main/java/com/framsticks/portals/Portal.java
===================================================================
--- java/main/src/main/java/com/framsticks/portals/Portal.java	(revision 87)
+++ java/main/src/main/java/com/framsticks/portals/Portal.java	(revision 88)
@@ -1,8 +1,16 @@
 package com.framsticks.portals;
 
-import com.framsticks.observers.Observer;
+
+import com.framsticks.core.AbstractInstanceListener;
+import com.framsticks.core.Instance;
+import com.framsticks.core.Path;
 import com.framsticks.params.annotations.FramsClassAnnotation;
 import com.framsticks.params.annotations.ParamAnnotation;
-import com.framsticks.util.PeriodicTask;
+import com.framsticks.util.Logging;
+import com.framsticks.util.dispatching.Dispatching;
+import com.framsticks.util.dispatching.Future;
+import com.framsticks.util.dispatching.JoinableCollection;
+import com.framsticks.util.dispatching.RunAt;
+
 import org.apache.log4j.Logger;
 
@@ -12,5 +20,5 @@
  */
 @FramsClassAnnotation
-public class Portal extends Observer {
+public class Portal extends JoinableCollection<Instance> {
 
 	private final static Logger log = Logger.getLogger(Portal.class.getName());
@@ -22,21 +30,45 @@
 	}
 
-	@Override
-	public void run() {
-		super.run();
-		new PeriodicTask<Portal>(this, 1000) {
+	// @Override
+	// public void run() {
+	// 	super.run();
+	// 	new PeriodicTask<Portal>(this, 1000) {
 
-			@Override
-			public void run() {
-				++counter;
-				log.debug("counter is now: " + counter);
-				again();
-			}
-		};
-	}
+	// 		@Override
+	// 		public void run() {
+	// 			++counter;
+	// 			log.debug("counter is now: " + counter);
+	// 			again();
+	// 		}
+	// 	};
+	// }
 
 	@Override
-	protected PortalEndpoint createEndpoint() {
-		return new PortalEndpoint();
+	public void add(final Instance instance) {
+		super.add(instance);
+		instance.addListener(new AbstractInstanceListener() {
+			@Override
+			public void onRun(Exception e) {
+				assert Dispatching.isThreadSafe();
+
+				super.onRun(e);
+
+				if (e != null) {
+					return;
+				}
+				final String path = "/simulator/genepools/groups/0/genotypes";
+				instance.invokeLater(new RunAt<Instance>() {
+					@Override
+					public void run() {
+						instance.resolve(path, new Future<Path>() {
+							@Override
+							public void result(Path result, Exception e) {
+								Logging.log(log, "resolve", path, e);
+							}
+						});
+					}
+				});
+			}
+		});
 	}
 
Index: java/main/src/main/java/com/framsticks/portals/PortalEndpoint.java
===================================================================
--- java/main/src/main/java/com/framsticks/portals/PortalEndpoint.java	(revision 87)
+++ 	(revision )
@@ -1,70 +1,0 @@
-package com.framsticks.portals;
-
-import com.framsticks.core.Instance;
-import com.framsticks.core.Path;
-import com.framsticks.observers.Endpoint;
-import com.framsticks.util.dispatching.Dispatching;
-import com.framsticks.util.dispatching.Future;
-import com.framsticks.util.Logging;
-import org.apache.log4j.Logger;
-import com.framsticks.util.dispatching.RunAt;
-
-/**
- * @author Piotr Sniegowski
- */
-public class PortalEndpoint extends Endpoint {
-
-	private final static Logger log = Logger.getLogger(PortalEndpoint.class.getName());
-
-	public PortalEndpoint() {
-	}
-
-	@Override
-	public Portal getObserver() {
-		return (Portal) observer;
-	}
-
-	@Override
-	public void onRun(Exception e) {
-		assert Dispatching.isThreadSafe();
-
-		super.onRun(e);
-
-		if (e != null) {
-			return;
-		}
-		final String path = "/simulator/genepools/groups/0/genotypes";
-		instance.invokeLater(new RunAt<Instance>() {
-			@Override
-			public void run() {
-				PortalEndpoint.this.instance.resolve(path, new Future<Path>() {
-					@Override
-					public void result(Path result, Exception e) {
-						Logging.log(log, "resolve", path, e);
-					}
-				});
-			}
-		});
-	}
-
-	@Override
-	public void onStop(Exception e) {
-	}
-
-
-	/*@Override
-	public void onChange(final Path path) {
-		//if path.getTop().getParam().
-		observer.invokeLater(new Runnable() {
-			@Override
-			public void run() {
-				log.debug("change at " + path);
-			}
-		});
-	}
-	*/
-
-
-
-
-}
Index: java/main/src/main/java/com/framsticks/remote/RemoteInstance.java
===================================================================
--- java/main/src/main/java/com/framsticks/remote/RemoteInstance.java	(revision 87)
+++ java/main/src/main/java/com/framsticks/remote/RemoteInstance.java	(revision 88)
@@ -9,4 +9,6 @@
 import com.framsticks.core.Path;
 import com.framsticks.params.*;
+import com.framsticks.params.annotations.FramsClassAnnotation;
+import com.framsticks.params.annotations.ParamAnnotation;
 import com.framsticks.params.types.EventParam;
 import com.framsticks.parsers.MultiParamLoader;
@@ -15,17 +17,20 @@
 import com.framsticks.util.dispatching.Dispatching;
 import com.framsticks.util.dispatching.Future;
+import com.framsticks.util.dispatching.Joinable;
+import com.framsticks.util.dispatching.JoinableParent;
+import com.framsticks.util.dispatching.JoinableState;
 import com.framsticks.util.lang.Casting;
 import com.framsticks.util.lang.Pair;
 import com.framsticks.util.dispatching.RunAt;
 
-import org.apache.commons.configuration.Configuration;
+import java.util.*;
+
 import org.apache.log4j.Logger;
-
-import java.util.*;
 
 /**
  * @author Piotr Sniegowski
  */
-public class RemoteInstance extends Instance {
+@FramsClassAnnotation
+public class RemoteInstance extends Instance implements JoinableParent {
 
 	private final static Logger log = Logger.getLogger(RemoteInstance.class.getName());
@@ -45,9 +50,20 @@
 	}
 
-	@Override
-	public void run() {
-		assert isActive();
-		super.run();
-		connection.connect(new StateFunctor() {
+	public RemoteInstance() {
+	}
+
+	@ParamAnnotation
+	public void setAddress(String address) {
+		setConnection(new ClientConnection(address));
+	}
+
+	@ParamAnnotation
+	public String getAddress() {
+		return connection == null ? "<disconnected>" : connection.getAddress();
+	}
+
+	public void setConnection(final ClientConnection connection) {
+		this.connection = connection;
+		this.connection.setConnectedFunctor(new StateFunctor() {
 			@Override
 			public void call(Exception e) {
@@ -60,8 +76,6 @@
 					public void call(Exception e) {
 						if (e != null) {
-							log.fatal("unsupported protocol version!\n minimal version is: "
-									+ "nmanager protocol is: "
-									+ connection.getProtocolVersion());
-							connection.close();
+							log.fatal("unsupported protocol version!\n minimal version is: " + "\nmanager protocol is: " + connection.getProtocolVersion());
+							Dispatching.drop(connection, RemoteInstance.this);
 							fireRun(e);
 							return;
@@ -112,22 +126,5 @@
 			}
 		});
-	}
-
-	public RemoteInstance() {
-	}
-
-
-	@Override
-	public void configure(Configuration config) {
-		super.configure(config);
-		connection = new ClientConnection(config.getString("address"));
-	}
-
-	public void setAddress(String address) {
-		setConnection(new ClientConnection(address));
-	}
-
-	public void setConnection(ClientConnection connection) {
-		this.connection = connection;
+
 	}
 
@@ -135,5 +132,5 @@
 	public String toString() {
 		assert Dispatching.isThreadSafe();
-		return getConnection().getAddress();
+		return "remote instance " + getName() + "(" + getAddress() + ")";
 	}
 
@@ -167,5 +164,5 @@
 			}
 		});
-		*/
+		 */
 	}
 
@@ -175,10 +172,10 @@
 	}
 
-	public void disconnect() {
-		assert isActive();
-		if (connection.isConnected()) {
-			connection.close();
-		}
-	}
+	// public void disconnect() {
+	//	assert isActive();
+	//	if (connection.isConnected()) {
+	//		Dispatching.stop(connection, this);
+	//	}
+	// }
 
 	public final ClientConnection getConnection() {
@@ -247,11 +244,13 @@
 				assert response.getFiles().size() == 1;
 				assert path.isTheSame(response.getFiles().get(0).getPath());
-				FramsClass framsClass = processFetchedInfo(response.getFiles().get(0));
-
-				if (framsClass == null) {
+				FramsClass framsClass;
+				try {
+					framsClass = processFetchedInfo(response.getFiles().get(0));
+				} catch (ConstructionException e) {
 					log.fatal("could not read class info");
 					finishInfoRequest(name, null, new Exception("could not read class info"));
 					return;
 				}
+
 				CompositeParam thisParam = path.getTop().getParam();
 				if (!thisParam.isMatchingContainedName(framsClass.getId())) {
@@ -335,13 +334,15 @@
 		}
 
-
 		assert path.size() >= 2;
 		FramsClass underFramsClass = getInfoFromCache(path.getUnder().getParam().getContainedTypeName());
 
-		EventParam changedEvent = underFramsClass.getParamEntry(path.getTop().getParam().getId() + "_changed", EventParam.class);
-		if (changedEvent == null) {
+		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;
@@ -394,5 +395,4 @@
 	}
 
-
 	protected void reactToChange(final Path path, final ListChange listChange) {
 		assert isActive();
@@ -416,42 +416,41 @@
 		}
 
-
 		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();
-				resolveAndFetch(p, new Future<Path>() {
-					@Override
-					public void result(Path result, Exception e) {
-						if (e != null) {
-							log.error("failed to add " + p + ": " + e);
-							return;
-						}
-						log.debug("added: " + result);
-						fireListChange(path, listChange);
-					}
-				});
-				break;
-			}
-			case Remove: {
-				access.set(childParam, null);
-				fireListChange(path, listChange);
-				break;
-			}
-			case Modify: {
-				final String p = path.getTextual() + "/" + childParam.getId();
-				resolveAndFetch(p, new Future<Path>() {
-					@Override
-					public void result(Path result, Exception e) {
-						if (e != null) {
-							log.error("failed to modify " + p + ": " + e);
-							return;
-						}
-						fireListChange(path, listChange);
-					}
-				});
-				break;
-			}
+		case Add: {
+			final String p = path.getTextual() + "/" + childParam.getId();
+			resolveAndFetch(p, new Future<Path>() {
+				@Override
+				public void result(Path result, Exception e) {
+					if (e != null) {
+						log.error("failed to add " + p + ": " + e);
+						return;
+					}
+					log.debug("added: " + result);
+					fireListChange(path, listChange);
+				}
+			});
+			break;
+		}
+		case Remove: {
+			access.set(childParam, null);
+			fireListChange(path, listChange);
+			break;
+		}
+		case Modify: {
+			final String p = path.getTextual() + "/" + childParam.getId();
+			resolveAndFetch(p, new Future<Path>() {
+				@Override
+				public void result(Path result, Exception e) {
+					if (e != null) {
+						log.error("failed to modify " + p + ": " + e);
+						return;
+					}
+					fireListChange(path, listChange);
+				}
+			});
+			break;
+		}
 		}
 	}
@@ -473,3 +472,35 @@
 		});
 	}
+
+	@Override
+	protected void joinableStart() {
+		Dispatching.use(connection, this);
+		super.joinableStart();
+	}
+
+	@Override
+	protected void joinableInterrupt() {
+		Dispatching.drop(connection, this);
+		super.joinableInterrupt();
+	}
+
+	@Override
+	protected void joinableFinish() {
+		super.joinableFinish();
+
+	}
+
+	@Override
+	public void joinableJoin() throws InterruptedException {
+		Dispatching.join(connection);
+		super.joinableJoin();
+	}
+
+
+	@Override
+	public void childChangedState(Joinable joinable, JoinableState state) {
+		proceedToState(state);
+	}
+
+
 }
Index: java/main/src/main/java/com/framsticks/running/ExternalProcess.java
===================================================================
--- java/main/src/main/java/com/framsticks/running/ExternalProcess.java	(revision 88)
+++ java/main/src/main/java/com/framsticks/running/ExternalProcess.java	(revision 88)
@@ -0,0 +1,146 @@
+package com.framsticks.running;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+
+
+import org.apache.log4j.Logger;
+
+import com.framsticks.core.Entity;
+import com.framsticks.params.annotations.FramsClassAnnotation;
+import com.framsticks.params.annotations.ParamAnnotation;
+import com.framsticks.util.FramsticksException;
+import com.framsticks.util.Misc;
+import com.framsticks.util.dispatching.Thread;
+import com.framsticks.util.io.Encoding;
+
+@FramsClassAnnotation
+public class ExternalProcess extends Thread<ExternalProcess> implements Entity {
+	private static final Logger log = Logger.getLogger(ExternalProcess.class);
+
+	protected List<String> arguments = new ArrayList<>();
+	protected Process process;
+	protected ProcessBuilder builder = new ProcessBuilder();
+	protected Thread<ExternalProcess> readerThread;
+
+	protected PrintWriter input;
+	protected BufferedReader output;
+	protected Integer exitCode;
+
+	protected final List<OutputListener> listeners = new LinkedList<>();
+
+	public void addListener(OutputListener listener) {
+		synchronized (listeners) {
+			listeners.add(listener);
+		}
+	}
+
+	/**
+	 *
+	 */
+	public ExternalProcess() {
+		super();
+		setName("process");
+		arguments.add(null);
+	}
+
+	/**
+	 * @return the command
+	 */
+	@ParamAnnotation
+	public String getCommand() {
+		return arguments.get(0);
+	}
+
+	/**
+	 * @param command the command to set
+	 */
+	@ParamAnnotation
+	public void setCommand(String command) {
+		arguments.set(0, command);
+	}
+
+	@Override
+	protected void routine() {
+
+		String line;
+		try {
+			try {
+				while ((line = output.readLine()) != null) {
+					log.trace("read line: " + line);
+					synchronized (listeners) {
+						for (OutputListener l : listeners) {
+							l.onLineRead(line);
+						}
+					}
+				}
+			} catch (IOException e) {
+				throw new FramsticksException().msg("failed to read line from output of process").cause(e);
+			}
+			try {
+				exitCode = process.waitFor();
+			} catch (InterruptedException e) {
+				throw new FramsticksException().msg("failed to wait for process").cause(e);
+			}
+			log.debug("process ended " + this);
+			process = null;
+		} catch (FramsticksException e) {
+			log.error("exception caught in process " + this, e);
+		}
+		interrupt();
+	}
+
+
+
+	@ParamAnnotation
+	public void setDirectory(String directory) {
+		builder.directory(new File(directory));
+	}
+
+	@ParamAnnotation
+	public String getDirectory() {
+		return builder.directory().getName();
+	}
+
+	@Override
+	public void joinableStart() {
+		builder = new ProcessBuilder();
+		log.debug("running process with arguments: " + arguments);
+		builder.command(arguments);
+		try {
+			process = builder.start();
+			input = new PrintWriter(new OutputStreamWriter(process.getOutputStream(), Encoding.getDefaultCharset()));
+			output = new BufferedReader(new InputStreamReader(process.getInputStream(), Encoding.getDefaultCharset()));
+		} catch (IOException e) {
+			throw new FramsticksException().msg("failed to start process").cause(e);
+		}
+		super.joinableStart();
+
+	}
+
+	@Override
+	public String toString() {
+		return super.toString() + "[" + Misc.returnNotNull(getCommand(), "?") + "]";
+	}
+
+	/**
+	 * @return the input
+	 */
+	public PrintWriter getInput() {
+		return input;
+	}
+
+	@Override
+	protected void joinableInterrupt() {
+		super.joinableInterrupt();
+		finish();
+	}
+
+}
Index: java/main/src/main/java/com/framsticks/running/FramsServer.java
===================================================================
--- java/main/src/main/java/com/framsticks/running/FramsServer.java	(revision 88)
+++ java/main/src/main/java/com/framsticks/running/FramsServer.java	(revision 88)
@@ -0,0 +1,45 @@
+package com.framsticks.running;
+
+import com.framsticks.params.annotations.FramsClassAnnotation;
+import com.framsticks.params.annotations.ParamAnnotation;
+
+@FramsClassAnnotation
+public class FramsServer extends ExternalProcess {
+
+	protected Integer port;
+
+	/**
+	 *
+	 */
+	public FramsServer() {
+		super();
+		setCommand("/home/psniegowski/mgr/Framsticks32rc5/frams.linux");
+		setDirectory("/home/psniegowski/mgr/Framsticks32rc5");
+		setName("frams");
+	}
+
+	/**
+	 * @return the port
+	 */
+	@ParamAnnotation
+	public Integer getPort() {
+		return port;
+	}
+
+	/**
+	 * @param port the port to set
+	 */
+	@ParamAnnotation
+	public void setPort(Integer port) {
+		this.port = port;
+	}
+
+	@Override
+	public void joinableStart() {
+		if (port != null) {
+			arguments.add("-p" + port);
+		}
+		super.joinableStart();
+	}
+
+}
Index: java/main/src/main/java/com/framsticks/running/OutputListener.java
===================================================================
--- java/main/src/main/java/com/framsticks/running/OutputListener.java	(revision 88)
+++ java/main/src/main/java/com/framsticks/running/OutputListener.java	(revision 88)
@@ -0,0 +1,5 @@
+package com.framsticks.running;
+
+public interface OutputListener {
+	void onLineRead(String line);
+}
Index: java/main/src/main/java/com/framsticks/util/Builder.java
===================================================================
--- java/main/src/main/java/com/framsticks/util/Builder.java	(revision 88)
+++ java/main/src/main/java/com/framsticks/util/Builder.java	(revision 88)
@@ -0,0 +1,7 @@
+package com.framsticks.util;
+
+public interface Builder<T> {
+
+	public T finish();
+
+}
Index: java/main/src/main/java/com/framsticks/util/DoubleMap.java
===================================================================
--- java/main/src/main/java/com/framsticks/util/DoubleMap.java	(revision 88)
+++ java/main/src/main/java/com/framsticks/util/DoubleMap.java	(revision 88)
@@ -0,0 +1,52 @@
+package com.framsticks.util;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+public class DoubleMap<K, V> {
+
+	protected final Map<K, V> byId = new HashMap<>();
+	protected final Map<K, V> byName = new HashMap<>();
+	protected final Set<V> values = new HashSet<>();
+
+	public int size() {
+		return values.size();
+	}
+
+	public void put(K id, K name, V value) {
+		values.add(value);
+		if (id != null) {
+			byId.put(id, value);
+		}
+		if (name != null) {
+			byName.put(name, value);
+		}
+	}
+
+	public boolean containsValue(V value) {
+		return values.contains(value);
+
+	}
+
+	public boolean containsKey(K identifier) {
+		return byId.containsKey(identifier) || byName.containsKey(identifier);
+	}
+
+	public V get(K identifier) {
+		if (byId.containsKey(identifier)) {
+			return byId.get(identifier);
+		}
+		if (byName.containsKey(identifier)) {
+			return byName.get(identifier);
+		}
+		return null;
+	}
+
+	public Set<V> getValues() {
+		return Collections.unmodifiableSet(values);
+	}
+
+}
Index: java/main/src/main/java/com/framsticks/util/FramsticksException.java
===================================================================
--- java/main/src/main/java/com/framsticks/util/FramsticksException.java	(revision 87)
+++ java/main/src/main/java/com/framsticks/util/FramsticksException.java	(revision 88)
@@ -50,6 +50,6 @@
 			b.append("(").append(d.build()).append(")");
 		}
-		if (this.getCause() instanceof FramsticksException) {
-			b.append(" caused by ").append(this.getCause().getMessage());
+		if (this.getCause() != null) {
+			b.append(" caused by: [").append(this.getCause().getMessage()).append("]");
 		}
 		return b.toString();
Index: java/main/src/main/java/com/framsticks/util/Misc.java
===================================================================
--- java/main/src/main/java/com/framsticks/util/Misc.java	(revision 87)
+++ java/main/src/main/java/com/framsticks/util/Misc.java	(revision 88)
@@ -1,3 +1,5 @@
 package com.framsticks.util;
+
+// import org.apache.log4j.Logger;
 
 /**
@@ -5,5 +7,32 @@
  */
 public class Misc {
+	// private static final Logger log =
+	// 	Logger.getLogger(Misc.class);
+
+	public static class WithType {
+		protected Object value;
+
+		/**
+		 * @param value
+		 */
+		public WithType(Object value) {
+			this.value = value;
+		}
+
+		@Override
+		public String toString() {
+			if (value == null) {
+				return "null";
+			}
+			return value + "(" + value.getClass() + ")";
+		}
+	}
+
+	public static WithType withType(Object value) {
+		return new WithType(value);
+	}
+
 	public static boolean equals(Object a, Object b) {
+		// log.info("equality of " + withType(a) + " ? " + withType(b));
 		if (a != null) {
 			return (b != null && a.equals(b));
@@ -11,3 +40,17 @@
 		return b == null;
 	}
+
+	public static <T> T returnNotNull(T first, T second) {
+		if (first != null) {
+			return first;
+		}
+		return second;
+	}
+
+	public static <T> T throwIfNull(T value) {
+		if (value == null) {
+			throw new FramsticksException().msg("value should not be null");
+		}
+		return value;
+	}
 }
Index: java/main/src/main/java/com/framsticks/util/dispatching/AbstractJoinable.java
===================================================================
--- java/main/src/main/java/com/framsticks/util/dispatching/AbstractJoinable.java	(revision 88)
+++ java/main/src/main/java/com/framsticks/util/dispatching/AbstractJoinable.java	(revision 88)
@@ -0,0 +1,187 @@
+package com.framsticks.util.dispatching;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+
+import javax.annotation.Nonnull;
+
+import org.apache.commons.collections.CollectionUtils;
+import org.apache.log4j.Logger;
+
+import com.framsticks.util.FramsticksException;
+
+
+
+public abstract class AbstractJoinable implements Joinable {
+	private static final Logger log = Logger.getLogger(AbstractJoinable.class);
+
+
+	protected final Set<JoinableParent> owners = new HashSet<JoinableParent>();
+	protected final Set<JoinableParent> joinableListeners = new HashSet<JoinableParent>();
+
+	protected static final Set<AbstractJoinable> joinablesRegistry = Collections.synchronizedSet(new HashSet<AbstractJoinable>());
+
+	JoinableState state = JoinableState.INITILIAZED;
+
+	/**
+	 *
+	 */
+	public AbstractJoinable() {
+		joinablesRegistry.add(this);
+	}
+
+	public static void report() {
+		StringBuilder b = new StringBuilder();
+		synchronized (joinablesRegistry) {
+			for (AbstractJoinable j : joinablesRegistry) {
+				b.append("\n").append(j.getState()).append(" : ").append(j);
+			}
+		}
+		log.debug("state: " + b);
+	}
+
+	private synchronized boolean changeState(JoinableState state) {
+		if (this.state.ordinal() >= state.ordinal()) {
+			return false;
+		}
+		if (this.state.ordinal() + 1 != state.ordinal()) {
+			throw new FramsticksException().msg("failed to change state").arg("from", this.state).arg("to", state).arg("joinable", this);
+		}
+		this.state = state;
+
+		synchronized (this) {
+			log.debug(this + " is notifying " + joinableListeners.size() + " parents");
+
+			List<JoinableParent> parents = new LinkedList<>();
+			CollectionUtils.addAll(parents, joinableListeners.iterator());
+
+			for (JoinableParent p : parents) {
+				if (p != null) {
+					Dispatching.childChangedState(p, this, state);
+				}
+			}
+		}
+		report();
+
+		return true;
+	}
+
+
+
+	public final boolean start() {
+		if (changeState(JoinableState.RUNNING)) {
+			joinableStart();
+			return true;
+		}
+		return false;
+	}
+
+	public final boolean interrupt() {
+		if (changeState(JoinableState.FINISHING)) {
+			joinableInterrupt();
+			return true;
+		}
+		return false;
+	}
+
+	protected final boolean finish() {
+		if (changeState(JoinableState.JOINABLE)) {
+			joinableFinish();
+			return true;
+		}
+		return false;
+	}
+
+
+
+	@Override
+	public final void join() throws InterruptedException {
+		synchronized (this) {
+			if (this.state.equals(JoinableState.JOINED)) {
+				return;
+			}
+			if (!this.state.equals(JoinableState.JOINABLE)) {
+				throw new InterruptedException();
+			}
+		}
+		joinableJoin();
+		synchronized (this) {
+			this.state = JoinableState.JOINED;
+		}
+	}
+
+	protected final boolean proceedToState(JoinableState state) {
+		switch (state) {
+			case RUNNING:
+				return start();
+			case FINISHING:
+				return interrupt();
+			case JOINABLE:
+				return finish();
+			default: return false;
+		}
+	}
+
+	protected abstract void joinableStart();
+
+	protected abstract void joinableInterrupt();
+
+	protected abstract void joinableFinish();
+
+	protected abstract void joinableJoin() throws InterruptedException;
+
+	public final boolean use(@Nonnull JoinableParent owner) {
+		boolean start = false;
+		synchronized (this) {
+			assert !owners.contains(owner);
+			start = owners.isEmpty();
+			log.debug(owner + " is using " + this);
+			owners.add(owner);
+			joinableListeners.add(owner);
+		}
+		if (start) {
+			return this.start();
+		}
+		return false;
+	}
+
+	public final boolean drop(@Nonnull JoinableParent owner) {
+		boolean stop = false;
+		synchronized (this) {
+			if (!owners.contains(owner)) {
+				return false;
+				// throw new FramsticksException().msg("object is not owning that joinable").arg("joinable", this).arg("object", owner);
+			}
+			// assert owners.containsKey(owner);
+			log.debug(owner + " is droping " + this);
+			owners.remove(owner);
+			stop = owners.isEmpty();
+		}
+		if (stop) {
+			Dispatching.dispatcherGuardedInvoke(this, new RunAt<Object>() {
+				@Override
+				public void run() {
+					interrupt();
+				}
+			});
+			return true;
+		}
+		return stop;
+	}
+
+	/**
+	 * @return the state
+	 */
+	public JoinableState getState() {
+		return state;
+	}
+
+	protected boolean isInState(JoinableState state) {
+		return this.state.equals(state);
+	}
+
+
+}
Index: java/main/src/main/java/com/framsticks/util/dispatching/AtOnceDispatcher.java
===================================================================
--- java/main/src/main/java/com/framsticks/util/dispatching/AtOnceDispatcher.java	(revision 87)
+++ java/main/src/main/java/com/framsticks/util/dispatching/AtOnceDispatcher.java	(revision 88)
@@ -23,3 +23,5 @@
 		runnable.run();
 	}
+
+
 }
Index: java/main/src/main/java/com/framsticks/util/dispatching/Dispatcher.java
===================================================================
--- java/main/src/main/java/com/framsticks/util/dispatching/Dispatcher.java	(revision 87)
+++ java/main/src/main/java/com/framsticks/util/dispatching/Dispatcher.java	(revision 88)
@@ -7,3 +7,4 @@
 	public boolean isActive();
 	public void invokeLater(RunAt<? extends C> runnable);
+
 }
Index: java/main/src/main/java/com/framsticks/util/dispatching/Dispatching.java
===================================================================
--- java/main/src/main/java/com/framsticks/util/dispatching/Dispatching.java	(revision 87)
+++ java/main/src/main/java/com/framsticks/util/dispatching/Dispatching.java	(revision 88)
@@ -1,3 +1,5 @@
 package com.framsticks.util.dispatching;
+
+import org.apache.log4j.Logger;
 
 import com.framsticks.util.StateFunctor;
@@ -7,4 +9,5 @@
  */
 public abstract class Dispatching {
+	private static final Logger log = Logger.getLogger(Dispatching.class);
 
 	public static boolean isThreadSafe() {
@@ -31,6 +34,6 @@
 
 	// public static boolean assertInvokeLater(Dispatcher dispatcher, RunAt runnable) {
-	// 	dispatcher.invokeLater(runnable);
-	// 	return true;
+	//	dispatcher.invokeLater(runnable);
+	//	return true;
 	// }
 
@@ -44,3 +47,84 @@
 	}
 
+	public static void sleep(int milliseconds) {
+		try {
+			java.lang.Thread.sleep(milliseconds, 0);
+		} catch (InterruptedException e) {
+
+		}
+	}
+
+	@SuppressWarnings("unchecked")
+	public static void dispatcherGuardedInvoke(Joinable joinable, RunAt<?> runnable) {
+		if (joinable instanceof Dispatcher) {
+			invokeLaterOrNow(Dispatcher.class.cast(joinable), runnable);
+			return;
+		}
+		runnable.run();
+	}
+
+	public static void use(final Joinable joinable, final JoinableParent owner) {
+		log.debug("using " + joinable + " by " + owner);
+		if (joinable.use(owner)) {
+			log.debug("started " + joinable);
+		} else {
+			log.debug("start of " + joinable + " already happened");
+		}
+	}
+
+
+	public static void drop(final Joinable joinable, final JoinableParent owner) {
+		log.debug("droping " + joinable + " by " + owner);
+		if (joinable.drop(owner)) {
+			log.debug("stoped " + joinable);
+		} else {
+			log.debug("stop of " + joinable + " deferred");
+		}
+	}
+
+	public static void join(Joinable joinable) throws InterruptedException {
+		log.debug("joining " + joinable);
+		try {
+			joinable.join();
+		} catch (InterruptedException e) {
+			log.debug("failed to join " + joinable);
+			throw e;
+		}
+		log.debug("joined " + joinable);
+	}
+
+	public static void childChangedState(final JoinableParent parent, final Joinable joinable, final JoinableState state) {
+		dispatcherGuardedInvoke(joinable, new RunAt<Object>() {
+			@Override
+			public void run() {
+				log.debug("joinable " + joinable + " is notifying parent " + parent + " about change to " + state);
+				parent.childChangedState(joinable, state);
+			}
+		});
+	}
+
+	public static void wait(Object object, long millis) {
+		try {
+			object.wait(millis);
+		} catch (InterruptedException e) {
+		}
+	}
+
+	public static void joinAbsolutely(Joinable joinable) {
+		log.info("joining absolutely " + joinable);
+		while (true) {
+			try {
+				Dispatching.join(joinable);
+				return;
+			} catch (InterruptedException e) {
+				// throw new FramsticksException().msg("failed to join").arg("dispatcher", dispatcher).cause(e);
+			}
+			log.info("waiting for " + joinable);
+			sleep(500);
+		}
+	}
+
+
+
+
 }
Index: java/main/src/main/java/com/framsticks/util/dispatching/Joinable.java
===================================================================
--- java/main/src/main/java/com/framsticks/util/dispatching/Joinable.java	(revision 88)
+++ java/main/src/main/java/com/framsticks/util/dispatching/Joinable.java	(revision 88)
@@ -0,0 +1,15 @@
+package com.framsticks.util.dispatching;
+
+import javax.annotation.Nonnull;
+
+
+public interface Joinable {
+
+	public boolean use(@Nonnull JoinableParent owner);
+	public boolean drop(@Nonnull JoinableParent owner);
+
+	public void join() throws InterruptedException;
+
+	public JoinableState getState();
+
+}
Index: java/main/src/main/java/com/framsticks/util/dispatching/JoinableCollection.java
===================================================================
--- java/main/src/main/java/com/framsticks/util/dispatching/JoinableCollection.java	(revision 88)
+++ java/main/src/main/java/com/framsticks/util/dispatching/JoinableCollection.java	(revision 88)
@@ -0,0 +1,139 @@
+package com.framsticks.util.dispatching;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+import com.framsticks.core.Entity;
+import com.framsticks.params.annotations.AutoAppendAnnotation;
+import com.framsticks.params.annotations.FramsClassAnnotation;
+import com.framsticks.util.FramsticksException;
+import com.framsticks.util.Misc;
+
+
+@FramsClassAnnotation
+public class JoinableCollection<T extends Joinable> extends AbstractJoinable implements JoinableParent, Iterable<T> {
+
+	protected final Set<T> joinables = new HashSet<T>();
+	protected final Map<String, T> namedJoinables = new HashMap<>();
+
+	protected boolean finishIfOne;
+
+	protected String observableName;
+
+	public JoinableCollection() {
+		this(false);
+	}
+
+	public JoinableCollection(boolean finishIfOne) {
+		this.finishIfOne = finishIfOne;
+	}
+
+	@AutoAppendAnnotation
+	public void add(T joinable) {
+		assert isInState(JoinableState.INITILIAZED);
+
+		if (joinables.contains(joinable)) {
+			throw new FramsticksException().msg("joinable is already observed").arg("joinable", joinable).arg("in", this);
+		}
+		// if (observables.containsKey(observable.getName())) {
+		// 	throw new FramsticksException().msg("observable with given name already exists").arg("name", observable.getName()).arg("in", this);
+		// }
+
+		if (joinable instanceof Entity) {
+			Entity e = (Entity) joinable;
+			if (!namedJoinables.containsKey(e.getName())) {
+				namedJoinables.put(e.getName(), joinable);
+			}
+		}
+
+		joinables.add(joinable);
+	}
+
+	@Override
+	protected void joinableStart() {
+		for (T j : joinables) {
+			Dispatching.use(j, this);
+		}
+	}
+
+	@Override
+	protected void joinableInterrupt() {
+		if (joinables.isEmpty()) {
+			finish();
+			return;
+		}
+
+		for (T j : joinables) {
+			Dispatching.drop(j, this);
+		}
+	}
+
+	@Override
+	protected void joinableFinish() {
+	}
+
+	@Override
+	protected void joinableJoin() throws InterruptedException {
+		for (T j : joinables) {
+			Dispatching.join(j);
+		}
+	}
+
+	protected JoinableState getNextState() {
+		if (joinables.isEmpty()) {
+			return state;
+		}
+		JoinableState result = finishIfOne ? JoinableState.INITILIAZED : JoinableState.JOINED;
+		for (Joinable j : joinables) {
+			JoinableState s = j.getState();
+			if (finishIfOne) {
+				if (s.ordinal() > result.ordinal()) {
+					result = s;
+				}
+			} else {
+				if (s.ordinal() < result.ordinal()) {
+					result = s;
+				}
+			}
+		}
+		return result;
+	}
+
+	@Override
+	public void childChangedState(Joinable joinable, JoinableState state) {
+		proceedToState(getNextState());
+
+	}
+
+	@Override
+	public Iterator<T> iterator() {
+		return Collections.unmodifiableSet(joinables).iterator();
+	}
+
+	@Override
+	public String toString() {
+		return Misc.returnNotNull(observableName, "collection");
+	}
+
+	/**
+	 * @param observableName the observableName to set
+	 */
+	public JoinableCollection<T> setObservableName(String observableName) {
+		this.observableName = observableName;
+		return this;
+	}
+
+	public T get(String name) {
+		return namedJoinables.get(name);
+	}
+
+
+	public Map<String, T> getObservables() {
+		return Collections.unmodifiableMap(namedJoinables);
+	}
+
+}
Index: java/main/src/main/java/com/framsticks/util/dispatching/JoinableMonitor.java
===================================================================
--- java/main/src/main/java/com/framsticks/util/dispatching/JoinableMonitor.java	(revision 88)
+++ java/main/src/main/java/com/framsticks/util/dispatching/JoinableMonitor.java	(revision 88)
@@ -0,0 +1,64 @@
+package com.framsticks.util.dispatching;
+
+import org.apache.log4j.Logger;
+// import edu.umd.cs.findbugs.annotations.SuppressWarnings;
+import com.framsticks.util.dispatching.Dispatching;
+
+public class JoinableMonitor implements JoinableParent {
+	private static final Logger log =
+		Logger.getLogger(JoinableMonitor.class);
+
+	protected final Joinable joinable;
+
+	/**
+	 * @param joinable
+	 */
+	public JoinableMonitor(Joinable joinable) {
+		this.joinable = joinable;
+	}
+
+	public JoinableMonitor waitFor() {
+		log.debug(this + " is waiting");
+		synchronized (this) {
+			while (joinable.getState().ordinal() < JoinableState.FINISHING.ordinal()) {
+				Dispatching.wait(this, 100);
+			}
+		}
+		log.debug(this + " ended waiting");
+		return this;
+	}
+
+	public JoinableMonitor use() {
+		log.debug(this + " is using");
+		Dispatching.use(joinable, this);
+		return this;
+	}
+
+	public JoinableMonitor drop() {
+		log.debug(this + " is droping");
+		Dispatching.drop(joinable, this);
+		return this;
+	}
+
+	public JoinableMonitor join() {
+		log.debug(this + " is joining");
+		Dispatching.joinAbsolutely(joinable);
+		log.debug(this + " is joined");
+		return this;
+	}
+
+	@Override
+	// @SuppressWarnings("NN_NAKED_NOTIFY")
+	public void childChangedState(Joinable joinable, JoinableState state) {
+		synchronized (this) {
+			this.notify();
+		}
+		log.debug(this + " received notification about transition to " + state);
+	}
+
+	@Override
+	public String toString() {
+		return "monitor for " + joinable;
+	}
+
+}
Index: java/main/src/main/java/com/framsticks/util/dispatching/JoinableParent.java
===================================================================
--- java/main/src/main/java/com/framsticks/util/dispatching/JoinableParent.java	(revision 88)
+++ java/main/src/main/java/com/framsticks/util/dispatching/JoinableParent.java	(revision 88)
@@ -0,0 +1,7 @@
+package com.framsticks.util.dispatching;
+
+public interface JoinableParent {
+
+	public void childChangedState(Joinable joinable, JoinableState state);
+
+}
Index: java/main/src/main/java/com/framsticks/util/dispatching/JoinableState.java
===================================================================
--- java/main/src/main/java/com/framsticks/util/dispatching/JoinableState.java	(revision 88)
+++ java/main/src/main/java/com/framsticks/util/dispatching/JoinableState.java	(revision 88)
@@ -0,0 +1,9 @@
+package com.framsticks.util.dispatching;
+
+public enum JoinableState {
+	INITILIAZED,
+	RUNNING,
+	FINISHING,
+	JOINABLE,
+	JOINED
+}
Index: java/main/src/main/java/com/framsticks/util/dispatching/Thread.java
===================================================================
--- java/main/src/main/java/com/framsticks/util/dispatching/Thread.java	(revision 87)
+++ java/main/src/main/java/com/framsticks/util/dispatching/Thread.java	(revision 88)
@@ -5,4 +5,8 @@
 import java.util.LinkedList;
 import java.util.ListIterator;
+
+import javax.annotation.OverridingMethodsMustInvokeSuper;
+
+import com.framsticks.params.annotations.ParamAnnotation;
 import com.framsticks.util.dispatching.RunAt;
 
@@ -10,5 +14,5 @@
  * @author Piotr Sniegowski
  */
-public class Thread<C> implements Dispatcher<C> {
+public class Thread<C> extends AbstractJoinable implements Dispatcher<C> {
 
 	private static final Logger log = Logger.getLogger(Thread.class.getName());
@@ -27,18 +31,15 @@
 	}
 
-	public Thread(String s) {
-		this();
-		thread.setName(s);
-		// thread.start();
+	@OverridingMethodsMustInvokeSuper
+	protected void firstTask() {
 	}
 
-	public Thread(String s, java.lang.Thread thread) {
+	public Thread(java.lang.Thread thread) {
 		this.thread = thread;
-		thread.setName(s);
 	}
 
-	public Thread<C> start() {
+	@Override
+	protected void joinableStart() {
 		thread.start();
-		return this;
 	}
 
@@ -49,4 +50,6 @@
 
 	protected void routine() {
+		log.debug("starting thread " + this);
+		firstTask();
 		while (!java.lang.Thread.interrupted()) {
 			Task<? extends C> task;
@@ -76,7 +79,8 @@
 			} catch (Exception e) {
 				log.error("error in thread: " + e);
-				e.printStackTrace();
 			}
 		}
+		log.debug("finishing thread " + this);
+		finish();
 	}
 
@@ -124,15 +128,23 @@
 	}
 
-	public void interrupt() {
+	@Override
+	protected void joinableInterrupt() {
 		thread.interrupt();
 	}
 
-	public void join() throws InterruptedException {
-		thread.join();
+	@Override
+	protected void joinableJoin() throws InterruptedException {
+		thread.join(500);
+		log.debug("joined " + this);
 	}
 
+	@ParamAnnotation
 	public void setName(String name) {
 		thread.setName(name);
+	}
 
+	@ParamAnnotation
+	public String getName() {
+		return thread.getName();
 	}
 
@@ -140,3 +152,13 @@
 		return java.lang.Thread.interrupted();
 	}
+
+	@Override
+	public String toString() {
+		return getName();
+	}
+
+	@Override
+	protected void joinableFinish() {
+	}
+
 }
Index: java/main/src/main/resources/configs/framsticks.properties
===================================================================
--- java/main/src/main/resources/configs/framsticks.properties	(revision 87)
+++ 	(revision )
@@ -1,37 +1,0 @@
-com.framsticks.entities.browser.class=com.framsticks.gui.Browser
-com.framsticks.entities.browser.size.width=1500
-com.framsticks.entities.browser.size.height=800
-# com.framsticks.entities.browser.endpoints=localhost,dump,genotype_browser
-com.framsticks.entities.browser.endpoints=localhost
-com.framsticks.entities.browser.endpoints.dump.entity.class=com.framsticks.dumping.FileInstance
-com.framsticks.entities.browser.endpoints.dump.entity.filename=dumps/localhost:9009__.param
-com.framsticks.entities.browser.endpoints.localhost.entity.mount=com.framsticks.entities.localhost
-com.framsticks.entities.browser.endpoints.remote_portal.entity.mount=com.framsticks.entities.remote_portal
-com.framsticks.entities.browser.endpoints.genotype_browser.entity.mount=com.framsticks.entities.genotype_browser
-com.framsticks.entities.browser.panel_providers=com.framsticks.visualization.SingleViewPanelProvider
-com.framsticks.entities.browser.resolve_paths=/simulator
-
-com.framsticks.entities.diagnostics.class=com.framsticks.diagnostics.Diagnostics
-com.framsticks.entities.diagnostics.dumps.path=dumps
-com.framsticks.entities.diagnostics.dumps.format=_
-com.framsticks.entities.diagnostics.dumps.interval=5
-com.framsticks.entities.diagnostics.endpoints=localhost
-com.framsticks.entities.diagnostics.endpoints.localhost.entity.mount=com.framsticks.entities.localhost
-
-com.framsticks.entities.localhost.class=com.framsticks.remote.RemoteInstance
-com.framsticks.entities.localhost.address=localhost:9009
-
-com.framsticks.entities.remote_portal.class=com.framsticks.remote.RemoteInstance
-com.framsticks.entities.remote_portal.address=localhost:9007
-
-com.framsticks.entities.portal.class=com.framsticks.portals.Portal
-com.framsticks.entities.portal.endpoints=localhost
-com.framsticks.entities.portal.endpoints.localhost.entity.mount=com.framsticks.entities.localhost
-
-com.framsticks.entities.hosted_portal.class=com.framsticks.hosting.ServerInstance
-com.framsticks.entities.hosted_portal.accept=9007
-com.framsticks.entities.hosted_portal.hosted.entity.mount=com.framsticks.entities.portal
-
-com.framsticks.entities.genotype_browser.class=com.framsticks.examples.GenotypeBrowser
-
-com.framsticks.entity.mount = com.framsticks.entities.browser
Index: java/main/src/main/resources/configs/framsticks.xml
===================================================================
--- java/main/src/main/resources/configs/framsticks.xml	(revision 87)
+++ java/main/src/main/resources/configs/framsticks.xml	(revision 88)
@@ -1,12 +1,11 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<framsticks>
-	<com.framsticks.gui.Browser>
-		<size>1500 800</size>
-		<endpoint>
-			<com.framsticks.remote.RemoteInstance>
-				<name>localhost:9009</name>
-				<address>localhost:9009</address>
-			</com.framsticks.remote.RemoteInstance>
-		</endpoint>
-	</com.framsticks.gui.Browser>
-</framsticks>
+<Framsticks>
+	<import class="com.framsticks.gui.Browser" />
+	<import class="com.framsticks.remote.RemoteInstance" />
+	<Browser>
+		<RemoteInstance name="localhost:9009" address="localhost:9009" />
+	</Browser>
+	<!-- <Browser name="other"> -->
+	<!-- 	<RemoteInstance name="localhost:9009" address="localhost:9009" /> -->
+	<!-- </Browser> -->
+</Framsticks>
Index: java/main/src/main/resources/configs/log4j.properties
===================================================================
--- java/main/src/main/resources/configs/log4j.properties	(revision 87)
+++ java/main/src/main/resources/configs/log4j.properties	(revision 88)
@@ -29,4 +29,9 @@
 
 log4j.logger.com.framsticks=INFO
+# log4j.logger.com.framsticks.util.dispatching.Dispatching=DEBUG
+# log4j.logger.com.framsticks.util.dispatching.AbstractJoinable=DEBUG
+# log4j.logger.com.framsticks.util.dispatching.JoinableCollection=DEBUG
+
+# log4j.logger.com.framsticks.gui=DEBUG
 # log4j.logger.com.framsticks.gui.controls.SliderControl=TRACE
 # log4j.logger.com.framsticks.gui.EndpointAtFrame=DEBUG
Index: java/main/src/test/java/com/framsticks/core/FramsticksTest.java
===================================================================
--- java/main/src/test/java/com/framsticks/core/FramsticksTest.java	(revision 88)
+++ java/main/src/test/java/com/framsticks/core/FramsticksTest.java	(revision 88)
@@ -0,0 +1,26 @@
+package com.framsticks.core;
+
+import java.io.InputStream;
+
+import org.testng.annotations.Test;
+
+import com.framsticks.gui.Browser;
+import com.framsticks.test.TestConfiguration;
+
+import static org.fest.assertions.Assertions.*;
+
+@Test
+public class FramsticksTest extends TestConfiguration {
+
+	@Test
+	public void testConfiguration() {
+		InputStream stream = FramsticksTest.class.getResourceAsStream("/configs/test.xml");
+		assertThat(stream).isNotNull();
+
+		Framsticks framsticks = Framsticks.loadConfiguration(stream);
+		assertThat(framsticks).isNotNull();
+		assertThat(framsticks.getObservables().size()).isEqualTo(1);
+		assertThat(framsticks.getObservables().get("browser")).isInstanceOf(Browser.class);
+	}
+
+}
Index: java/main/src/test/java/com/framsticks/core/ProgramTest.java
===================================================================
--- java/main/src/test/java/com/framsticks/core/ProgramTest.java	(revision 87)
+++ 	(revision )
@@ -1,24 +1,0 @@
-package com.framsticks.core;
-
-import java.io.InputStream;
-
-import org.testng.annotations.Test;
-
-// import com.framsticks.gui.Browser;
-import com.framsticks.test.TestConfiguration;
-
-import static org.fest.assertions.Assertions.*;
-
-@Test
-public class ProgramTest extends TestConfiguration {
-
-	@Test
-	public void testConfiguration() {
-		InputStream stream = ProgramTest.class.getResourceAsStream("/configs/test.xml");
-		assertThat(stream).isNotNull();
-
-
-		//assertThat(object).isInstanceOf(Browser.class);
-	}
-
-}
Index: java/main/src/test/java/com/framsticks/gui/BrowserTest.java
===================================================================
--- java/main/src/test/java/com/framsticks/gui/BrowserTest.java	(revision 87)
+++ java/main/src/test/java/com/framsticks/gui/BrowserTest.java	(revision 88)
@@ -3,5 +3,4 @@
 import javax.swing.JFrame;
 
-import org.apache.commons.configuration.PropertiesConfiguration;
 import org.apache.log4j.Logger;
 import org.fest.swing.edt.FailOnThreadViolationRepaintManager;
@@ -16,4 +15,7 @@
 import com.framsticks.remote.RemoteInstance;
 import com.framsticks.test.TestConfiguration;
+import com.framsticks.util.dispatching.Dispatching;
+import com.framsticks.util.dispatching.JoinableMonitor;
+// import com.framsticks.util.dispatching.Dispatching;
 
 import static org.fest.assertions.Assertions.*;
@@ -25,4 +27,5 @@
 	private static final Logger log = Logger.getLogger(BrowserTest.class);
 
+	JoinableMonitor monitor;
 	Browser browser;
 	Robot robot;
@@ -37,5 +40,5 @@
 
 		browser = new Browser();
-		browser.configure(new PropertiesConfiguration());
+		monitor = new JoinableMonitor(browser);
 
 		RemoteInstance localhost = new RemoteInstance();
@@ -43,7 +46,7 @@
 		localhost.setAddress("localhost:9009");
 
-		browser.addEndpointForInstance(localhost);
+		browser.addInstance(localhost);
 
-		browser.start();
+		monitor.use();
 		// robot.waitForIdle();
 		frame = new FrameFixture(robot,
@@ -51,5 +54,5 @@
 					@Override
 					protected JFrame executeInEDT() throws Throwable {
-						return browser.getMainFrame();
+						return browser.getMainFrame().getSwing();
 					}
 				}));
@@ -86,4 +89,10 @@
 		clickAndExpandPath(tree, "localhost/simulator/genepools/groups");
 		clickAndExpandPath(tree, "localhost/simulator/genepools/groups/Genotypes");
+
+
+
+
+
+
 		// tree.clickPath("localhost/simulator/genepools/groups/Genotypes/genotypes");
 		// robot.waitForIdle();
@@ -97,16 +106,28 @@
 	}
 
-	public void sleep(int seconds) {
-		try {
-			Thread.sleep(seconds * 1000, 0);
-		} catch (InterruptedException e) {
-			e.printStackTrace();
-		}
-	}
 
 	@AfterClass
 	public void tearDown() {
-		// frame.close();
-		frame.cleanUp();
+		log.info("before close");
+
+		monitor.drop();
+
+		Dispatching.joinAbsolutely(browser);
+		// frame.cleanUp();
+		// log.info("before close");
+		// browser.interrupt();
+
+		// try {
+		// 	// frame.close();
+		// } catch (Throwable t) {
+		// 	log.error("caught ", t);
+		// }
+		// log.info("after close");
+		// // frame.close();
+		// // frame.cleanUp();
+
+
+
+		// Dispatching.join(browser);
 	}
 
Index: java/main/src/test/java/com/framsticks/model/f0/SchemaTest.java
===================================================================
--- java/main/src/test/java/com/framsticks/model/f0/SchemaTest.java	(revision 88)
+++ java/main/src/test/java/com/framsticks/model/f0/SchemaTest.java	(revision 88)
@@ -0,0 +1,28 @@
+package com.framsticks.model.f0;
+
+import org.testng.annotations.*;
+
+import com.framsticks.params.types.FloatParam;
+import com.framsticks.test.TestConfiguration;
+import com.framsticks.model.f0.Schema;
+
+import static org.fest.assertions.Delta.*;
+
+import static org.fest.assertions.Assertions.*;
+
+public class SchemaTest extends TestConfiguration {
+
+	@Test
+	public void loadSchemaWithXmlLoader() {
+		Schema schema = Schema.load(Schema.getDefaultDefinitionAsStream());
+		assertThat(schema.getFramsClasses().size()).isEqualTo(5);
+		assertThat(schema.getNeuroClasses().size()).isEqualTo(21);
+
+		assertThat(schema.getNeuroClass("|").getName()).isEqualTo("Bend muscle");
+		assertThat(schema.getNeuroClass("VEye").getParam("p")).isInstanceOf(FloatParam.class);
+		assertThat(schema.getNeuroClass("VEye").getParamEntry("p", FloatParam.class).getMax(Double.class)).isEqualTo(10.0, delta(0.0));
+
+		assertThat(schema.getFramsClass("p").getParamEntry("as", FloatParam.class).getDef(Double.class)).isEqualTo(0.25, delta(0.0));
+	}
+
+}
Index: java/main/src/test/java/com/framsticks/params/ParamBuilderTest.java
===================================================================
--- java/main/src/test/java/com/framsticks/params/ParamBuilderTest.java	(revision 87)
+++ java/main/src/test/java/com/framsticks/params/ParamBuilderTest.java	(revision 88)
@@ -20,5 +20,5 @@
 		builderFramsClass = FramsClass.build().forClass(ParamBuilder.class);
 
-		assertThat(builderFramsClass.getParamCount()).isEqualTo(6);
+		assertThat(builderFramsClass.getParamCount()).isEqualTo(10);
 		assertThat(builderFramsClass.getName()).isEqualTo("prop");
 		assertThat(builderFramsClass.getId()).isEqualTo("prop");
Index: java/main/src/test/java/com/framsticks/parsers/F0ParserTest.java
===================================================================
--- java/main/src/test/java/com/framsticks/parsers/F0ParserTest.java	(revision 87)
+++ java/main/src/test/java/com/framsticks/parsers/F0ParserTest.java	(revision 88)
@@ -5,4 +5,5 @@
 import com.framsticks.model.*;
 import com.framsticks.model.Package;
+import com.framsticks.model.f0.Schema;
 import com.framsticks.params.*;
 import com.framsticks.params.types.FloatParam;
@@ -29,5 +30,5 @@
 	@BeforeClass
 	public void setUp() throws Exception {
-		schema = new Schema(Schema.getDefaultDefinitionAsStream());
+		schema = Schema.load(Schema.getDefaultDefinitionAsStream());
 		Package.register(schema.getRegistry());
 	}
@@ -35,5 +36,5 @@
 	@Test
 	public void primitiveParam() {
-		FramsClass joint = schema.getRegistry().getInfoFromCache("j");
+		FramsClass joint = schema.getFramsClass("j");
 		PrimitiveParam<?> dx = joint.getParamEntry("dx", PrimitiveParam.class);
 		assertThat(dx).isInstanceOf(FloatParam.class);
@@ -47,4 +48,7 @@
 	@Test
 	public void readF0() throws IOException, ParseException {
+		assertThat(schema.getFramsClass("p")).isInstanceOf(FramsClass.class);
+		assertThat(schema.getRegistry().getInfoFromCache("p").getParamEntry("as", FloatParam.class).getDef(Double.class)).isEqualTo(0.25, delta(0.0));
+
 		accesses = new F0Parser(schema, F0ParserTest.class.getResourceAsStream("/parsers/f0_example.txt")).parse();
 
@@ -75,4 +79,5 @@
 		assertThat(model.getJoints().get(0).part1).isEqualTo(0);
 		assertThat(model.getJoints().get(0).part2).isEqualTo(1);
+		assertThat(model.getNeuroDefs().size()).isEqualTo(6);
 		assertThat(model.getNeuroDefs().get(0).part).isEqualTo(1);
 		assertThat(model.getNeuroDefs().get(0).joint).isEqualTo(-1);
@@ -89,4 +94,6 @@
 	public void print() throws Exception {
 		ListSink sink = new ListSink();
+
+
 		new F0Writer(schema, model, sink).write();
 
Index: java/main/src/test/java/com/framsticks/parsers/SchemaTest.java
===================================================================
--- java/main/src/test/java/com/framsticks/parsers/SchemaTest.java	(revision 87)
+++ 	(revision )
@@ -1,23 +1,0 @@
-package com.framsticks.parsers;
-
-import org.testng.annotations.*;
-
-import com.framsticks.params.Registry;
-import com.framsticks.test.TestConfiguration;
-
-import static org.fest.assertions.Assertions.*;
-
-public class SchemaTest extends TestConfiguration {
-
-	Schema schema;
-	Registry registry;
-
-	@Test
-	public void loadSchema() {
-		schema = new Schema(Schema.getDefaultDefinitionAsStream());
-		registry = schema.getRegistry();
-		// Package.register(schema.getRegistry());
-		assertThat(registry.getInfoCache().size()).isEqualTo(5);
-	}
-
-}
Index: java/main/src/test/java/com/framsticks/running/ExternalProcessTest.java
===================================================================
--- java/main/src/test/java/com/framsticks/running/ExternalProcessTest.java	(revision 88)
+++ java/main/src/test/java/com/framsticks/running/ExternalProcessTest.java	(revision 88)
@@ -0,0 +1,49 @@
+package com.framsticks.running;
+
+
+// import java.util.Arrays;
+import java.util.Arrays;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.testng.annotations.Test;
+
+import com.framsticks.test.TestConfiguration;
+import com.framsticks.util.dispatching.JoinableMonitor;
+
+import static org.fest.assertions.Assertions.*;
+
+@Test
+public class ExternalProcessTest extends TestConfiguration {
+
+	@Test
+	public void runBash() throws InterruptedException {
+		final ExternalProcess process = new ExternalProcess();
+		process.setCommand("bash");
+
+		final List<String> input = Arrays.asList("test", "another line");
+		final List<String> output = new LinkedList<>();
+
+		process.addListener(new OutputListener() {
+			@Override
+			public void onLineRead(String line) {
+				output.add(line);
+			}
+		});
+		JoinableMonitor monitor = new JoinableMonitor(process);
+		monitor.use();
+
+		for (String l : input) {
+			process.getInput().println("echo " + l);
+		}
+
+		process.getInput().close();
+
+		monitor.waitFor();
+		monitor.drop();
+		monitor.join();
+
+		assertThat(output).isEqualTo(input);
+	}
+
+}
Index: java/main/src/test/java/com/framsticks/running/FramsServerTest.java
===================================================================
--- java/main/src/test/java/com/framsticks/running/FramsServerTest.java	(revision 88)
+++ java/main/src/test/java/com/framsticks/running/FramsServerTest.java	(revision 88)
@@ -0,0 +1,28 @@
+package com.framsticks.running;
+
+import org.testng.annotations.Test;
+
+import com.framsticks.core.Framsticks;
+import com.framsticks.remote.RemoteInstance;
+import com.framsticks.test.TestConfiguration;
+
+import static org.fest.assertions.Assertions.*;
+
+@Test
+public class FramsServerTest extends TestConfiguration {
+
+	@Test
+	public void runServer() {
+		Framsticks framsticks = Framsticks.loadConfiguration(FramsServerTest.class.getResourceAsStream("/configs/FramsServerTest.xml"));
+
+		assertThat(framsticks.getObservables().size()).isEqualTo(2);
+		assertThat(framsticks.getObservables().get("frams")).isInstanceOf(FramsServer.class);
+		assertThat(framsticks.getObservables().get("remote")).isInstanceOf(RemoteInstance.class);
+
+		// framsticks.start();
+
+		// framsticks.waitForObservables();
+
+	}
+
+}
Index: java/main/src/test/java/com/framsticks/test/TestConfiguration.java
===================================================================
--- java/main/src/test/java/com/framsticks/test/TestConfiguration.java	(revision 87)
+++ java/main/src/test/java/com/framsticks/test/TestConfiguration.java	(revision 88)
@@ -11,7 +11,7 @@
 
 	@BeforeClass
-	public static void setUpConfiguration() {
+	public void setUpConfiguration() {
 		PropertyConfigurator.configure(TestConfiguration.class.getResource("/log4j.properties"));
-		log.info("logging configured");
+		log.info("testing " + this.getClass());
 	}
 
Index: java/main/src/test/resources/configs/FramsServerTest.xml
===================================================================
--- java/main/src/test/resources/configs/FramsServerTest.xml	(revision 88)
+++ java/main/src/test/resources/configs/FramsServerTest.xml	(revision 88)
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Framsticks>
+	<import class="com.framsticks.running.FramsServer" />
+	<import class="com.framsticks.remote.RemoteInstance" />
+	<FramsServer name="frams" port="9008" />
+	<RemoteInstance name="remote" address="localhost:9008" />
+</Framsticks>
Index: java/main/src/test/resources/configs/test.xml
===================================================================
--- java/main/src/test/resources/configs/test.xml	(revision 87)
+++ java/main/src/test/resources/configs/test.xml	(revision 88)
@@ -1,10 +1,8 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<framsticks>
-	<instance class="com.framsticks.gui.Browser">
-		<!-- <size>1500 800</size> -->
-		<endpoint class="com.framsticks.remote.RemoteInstance">
-			<name>localhost:9009</name>
-			<address>localhost:9009</address>
-		</endpoint>
-	</instance>
-</framsticks>
+<Framsticks>
+	<import class="com.framsticks.gui.Browser" />
+	<import class="com.framsticks.remote.RemoteInstance" />
+	<Browser name="browser">
+		<RemoteInstance name="localhost:9009" address="localhost:9009" />
+	</Browser>
+</Framsticks>
Index: java/main/src/test/resources/log4j.properties
===================================================================
--- java/main/src/test/resources/log4j.properties	(revision 87)
+++ java/main/src/test/resources/log4j.properties	(revision 88)
@@ -27,4 +27,7 @@
 
 log4j.logger.com.framsticks=INFO
+# log4j.logger.com.framsticks.util.dispatching.JoinableMonitor=DEBUG
+# log4j.logger.com.framsticks.util.dispatching.Dispatching=DEBUG
+# log4j.logger.com.framsticks.parsers.XmlLoader=DEBUG
 # log4j.logger.com.framsticks.parsers.MultiParamLoader=TRACE
 # log4j.logger.com.framsticks.gui.controls.SliderControl=TRACE
