Index: java/main/pom.xml
===================================================================
--- java/main/pom.xml	(revision 77)
+++ java/main/pom.xml	(revision 77)
@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <groupId>framsticks</groupId>
+    <artifactId>framsticks</artifactId>
+    <version>1.0</version>
+
+	<repositories>
+		<repository>
+			<id>maven.imagej.net</id>
+			<url>http://maven.imagej.net/content/repositories/public/</url>
+		</repository>
+	</repositories>
+
+	<build>
+		<plugins>
+			<plugin>
+				<groupId>org.apache.maven.plugins</groupId>
+				<artifactId>maven-compiler-plugin</artifactId>
+				<version>3.0</version>
+				<configuration>
+					<source>1.6</source>
+					<target>1.6</target>
+				</configuration>
+			</plugin>
+		</plugins>
+	</build>
+
+	<dependencies>
+		<dependency>
+			<groupId>log4j</groupId>
+			<artifactId>log4j</artifactId>
+			<version>1.2.16</version>
+			<scope>compile</scope>
+		</dependency>
+		<dependency>
+			<groupId>commons-configuration</groupId>
+			<artifactId>commons-configuration</artifactId>
+			<version>1.7</version>
+			<scope>compile</scope>
+		</dependency>
+		<dependency>
+			<groupId>java3d</groupId>
+			<artifactId>j3d-core</artifactId>
+			<version>1.5.2</version>
+		</dependency>
+		<dependency>
+			<groupId>java3d</groupId>
+			<artifactId>vecmath</artifactId>
+			<version>1.5.2</version>
+		</dependency>
+		<dependency>
+			<groupId>java3d</groupId>
+			<artifactId>j3d-core-utils</artifactId>
+			<version>1.5.2</version>
+		</dependency>
+		<!--dependency>
+		</dependency>
+		<dependency>
+		</dependency-->
+	</dependencies>
+</project>
Index: java/main/src/main/java/com/framsticks/communication/ClientConnection.java
===================================================================
--- java/main/src/main/java/com/framsticks/communication/ClientConnection.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/communication/ClientConnection.java	(revision 77)
@@ -0,0 +1,391 @@
+package com.framsticks.communication;
+
+import com.framsticks.communication.queries.ApplicationRequest;
+import com.framsticks.communication.queries.RegistrationRequest;
+import com.framsticks.communication.queries.UseRequest;
+import com.framsticks.communication.queries.VersionRequest;
+import com.framsticks.communication.util.LoggingStateCallback;
+import com.framsticks.params.ListSource;
+import com.framsticks.util.*;
+import org.apache.log4j.Logger;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.PrintWriter;
+import java.net.Socket;
+import java.net.SocketException;
+import java.util.*;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * @author Piotr Sniegowski
+ */
+public class ClientConnection extends Connection {
+
+    private final static Logger LOGGER = Logger.getLogger(ClientConnection.class);
+
+    protected final Map<String, Subscription> subscriptions = new HashMap<String, Subscription>();
+
+    public String getAddress() {
+        return address;
+    }
+
+    public void connect(StateFunctor connectedFunctor) {
+        try {
+            LOGGER.info("connecting to " + address);
+
+            socket = new Socket(hostName, port);
+
+            socket.setSoTimeout(500);
+
+            LOGGER.info("connected to " + hostName + ":" + port);
+            connected = true;
+
+            runThreads();
+
+            connectedFunctor.call(null);
+        } catch (SocketException e) {
+            LOGGER.error("failed to connect: " + e);
+            connectedFunctor.call(e);
+        } catch (IOException e) {
+            LOGGER.error("buffer creation failure");
+            connectedFunctor.call(e);
+            close();
+        }
+    }
+
+    private static abstract class InboundMessage {
+        protected String currentFilePath;
+        protected List<String> currentFileContent;
+        protected final List<File> files = new ArrayList<File>();
+
+        public abstract void eof();
+
+        protected void initCurrentFile(String path) {
+            currentFileContent = new LinkedList<String>();
+            currentFilePath = path;
+        }
+        protected void finishCurrentFile() {
+            if (currentFileContent == null) {
+                return;
+            }
+            files.add(new File(currentFilePath, new ListSource(currentFileContent)));
+            currentFilePath = null;
+            currentFileContent= null;
+        }
+
+        public abstract void startFile(String path);
+
+        public void addLine(String line) {
+            assert line != null;
+            assert currentFileContent != null;
+            currentFileContent.add(line.substring(0, line.length() - 1));
+        }
+
+        public List<File> getFiles() {
+            return files;
+        }
+    }
+
+    private static class EventFire extends InboundMessage {
+        public final Subscription subscription;
+
+        private EventFire(Subscription subscription) {
+            this.subscription = subscription;
+        }
+
+        public void startFile(String path) {
+            assert path == null;
+            initCurrentFile(null);
+        }
+
+        @Override
+        public void eof() {
+            finishCurrentFile();
+            Dispatching.invokeLaterOrNow(subscription.getDispatcher(), new Runnable() {
+                @Override
+                public void run() {
+                    subscription.getEventCallback().call(getFiles());
+                }
+            });
+        }
+    }
+
+    private static class SentQuery extends InboundMessage {
+        Request request;
+        ResponseCallback callback;
+        Dispatcher dispatcher;
+
+        public void startFile(String path) {
+            finishCurrentFile();
+            if (path == null) {
+                assert request instanceof ApplicationRequest;
+                path = ((ApplicationRequest)request).getPath();
+            }
+            initCurrentFile(path);
+        }
+
+        public void eof() {
+            finishCurrentFile();
+            //no-operation
+        }
+
+        @Override
+        public String toString() {
+            return request.toString();
+        }
+    }
+    private Map<Integer, SentQuery> queryMap = new HashMap<Integer, SentQuery>();
+
+
+    protected final String address;
+    protected final String hostName;
+    protected final int port;
+
+    private static Pattern addressPattern = Pattern.compile("^([^:]*)(:([0-9]+))?$");
+
+    public ClientConnection(String address) {
+        assert address != null;
+        this.address = address;
+        Matcher matcher = addressPattern.matcher(address);
+        if (!matcher.matches()) {
+            LOGGER.fatal("invalid address: " + address);
+            hostName = null;
+            port = 0;
+            return;
+        }
+        hostName = matcher.group(1);
+        port = matcher.group(3) != null ? Integer.parseInt(matcher.group(3)) : 9009;
+    }
+
+    private SentQuery currentlySentQuery;
+
+    public void send(Request request, ResponseCallback callback) {
+        send(request, AtOnceDispatcher.instance, callback);
+    }
+
+    public void send(Request request, Dispatcher dispatcher, ResponseCallback callback) {
+
+        if (!isConnected()) {
+            LOGGER.fatal("not connected");
+            return;
+        }
+        final SentQuery sentQuery = new SentQuery();
+        sentQuery.request = request;
+        sentQuery.callback = callback;
+        sentQuery.dispatcher = dispatcher;
+
+        senderThread.invokeLater(new Runnable(){
+            @Override
+            public void run() {
+                synchronized (ClientConnection.this) {
+
+                    while (!(requestIdEnabled || currentlySentQuery == null)) {
+                        try {
+                            ClientConnection.this.wait();
+                        } catch (InterruptedException ignored) {
+                            break;
+                        }
+                    }
+                }
+                Integer id = stashQuery(sentQuery);
+                String command = sentQuery.request.getCommand();
+                StringBuilder message = new StringBuilder();
+                message.append(command);
+                if (id != null) {
+                    message.append(" ").append(id);
+                }
+                sentQuery.request.construct(message);
+                String out = message.toString();
+
+                output.println(out);
+                LOGGER.debug("sending query: " + out);
+
+            }
+        });
+        /*
+        synchronized (this) {
+            LOGGER.debug("queueing query: " + query);
+            queryQueue.offer(sentQuery);
+            notifyAll();
+        }
+        */
+    }
+
+
+    @Override
+    public String toString() {
+        return address;
+    }
+
+    public void subscribe(final String path, final SubscriptionCallback callback) {
+        send(new RegistrationRequest().setPath(path), new ResponseCallback() {
+            @Override
+            public void process(Response response) {
+                if (!response.getOk()) {
+                    LOGGER.error("failed to register on event: " + path);
+                    callback.subscribed(null);
+                    return;
+                }
+                assert response.getFiles().isEmpty();
+                Subscription subscription = new Subscription(ClientConnection.this, path, response.getComment());
+                LOGGER.debug("registered on event: " + subscription);
+                synchronized (subscriptions) {
+                    subscriptions.put(subscription.getRegisteredPath(), subscription);
+                }
+                subscription.setEventCallback(callback.subscribed(subscription));
+                if (subscription.getEventCallback() == null) {
+                    LOGGER.info("subscription for " + path + " aborted");
+                    subscription.unsubscribe(new LoggingStateCallback(LOGGER, "abort subscription"));
+                }
+            }
+        });
+    }
+
+    public void negotiateProtocolVersion(StateFunctor stateFunctor) {
+        protocolVersion = -1;
+        sendQueryVersion(1, stateFunctor);
+    }
+
+    public void sendQueryVersion(final int version, final StateFunctor stateFunctor) {
+        send(new VersionRequest().version(version), new StateCallback() {
+            @Override
+            public void call(Exception e) {
+                if (e != null) {
+                    LOGGER.fatal("failed to upgrade protocol to version: " + version);
+                    return;
+                }
+                protocolVersion = version;
+                if (version < 4) {
+                    /** it is an implicit loop here*/
+                    sendQueryVersion(version + 1, stateFunctor);
+                    return;
+                }
+                send(new UseRequest().feature("request_id"), new StateCallback() {
+                    @Override
+                    public void call(Exception e) {
+                        requestIdEnabled = e == null;
+                        /*
+                        synchronized (ClientConnection.this) {
+                            ClientConnection.this.notifyAll();
+                        }
+                        */
+                        if (!requestIdEnabled) {
+                            LOGGER.fatal("protocol negotiation failed");
+                            stateFunctor.call(new Exception("protocol negotiation failed", e));
+                            return;
+                        }
+                        stateFunctor.call(null);
+                    }
+                });
+
+            }
+        });
+    }
+
+
+    private synchronized SentQuery fetchQuery(Integer id, boolean remove) {
+        if (id == null) {
+            if (requestIdEnabled) {
+                return null;
+            }
+            SentQuery result = currentlySentQuery;
+            if (remove) {
+                currentlySentQuery = null;
+                notifyAll();
+            }
+            return result;
+        }
+        if (queryMap.containsKey(id)) {
+            SentQuery result = queryMap.get(id);
+            if (remove) {
+                queryMap.remove(id);
+            }
+            return result;
+        }
+        return null;
+    }
+
+    private int nextQueryId = 0;
+
+    private Integer stashQuery(SentQuery sentQuery) {
+        if (!requestIdEnabled) {
+            currentlySentQuery = sentQuery;
+            return null;
+        }
+        queryMap.put(nextQueryId, sentQuery);
+        return nextQueryId++;
+    }
+
+    protected void processMessage(InboundMessage inboundMessage) throws Exception {
+        if (inboundMessage == null) {
+            LOGGER.error("failed to use any inbound message");
+            return;
+        }
+
+        String line;
+        while (!(line = getLine()).startsWith("eof")) {
+            inboundMessage.addLine(line);
+        }
+        inboundMessage.eof();
+    }
+
+    protected void processEvent(String rest) throws Exception {
+        Matcher matcher = eventPattern.matcher(rest);
+        if (!matcher.matches()) {
+            LOGGER.error("invalid event line: " + rest);
+            return;
+        }
+        Subscription subscription = subscriptions.get(matcher.group(1));
+        if (subscription == null) {
+            LOGGER.error("non subscribed event: " + matcher.group(1));
+            return;
+        }
+        EventFire event = new EventFire(subscription);
+        event.startFile(null);
+        processMessage(event);
+    }
+
+
+    protected void processMessageStartingWith(String line) throws Exception {
+        Pair<String, String> command = Strings.splitIntoPair(line, ' ', "\n");
+        if (command.first.equals("event")) {
+            processEvent(command.second);
+            return;
+        }
+        Pair<Integer, String> rest = parseRest(command.second);
+
+        if (command.first.equals("file")) {
+            SentQuery sentQuery = fetchQuery(rest.first, false);
+            sentQuery.startFile(rest.second);
+            processMessage(sentQuery);
+            return;
+        }
+
+        SentQuery sentQuery = fetchQuery(rest.first, true);
+        if (sentQuery == null) {
+            return;
+        }
+        LOGGER.debug("parsing response for request " + sentQuery);
+
+        final Response response = new Response(command.first.equals("ok"), rest.second, sentQuery.getFiles());
+        final ResponseCallback callback = sentQuery.callback;
+
+        Dispatching.invokeLaterOrNow(sentQuery.dispatcher, new Runnable() {
+            @Override
+            public void run() {
+                callback.process(response);
+            }
+        });
+    }
+
+    @Override
+    protected void receiverThreadRoutine() throws Exception {
+        while (connected) {
+            processMessageStartingWith(getLine());
+        }
+    }
+
+}
Index: java/main/src/main/java/com/framsticks/communication/Connection.java
===================================================================
--- java/main/src/main/java/com/framsticks/communication/Connection.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/communication/Connection.java	(revision 77)
@@ -0,0 +1,169 @@
+package com.framsticks.communication;
+
+import com.framsticks.util.Pair;
+import org.apache.log4j.Logger;
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.PrintWriter;
+import java.lang.Thread;
+import java.net.Socket;
+import java.net.SocketTimeoutException;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public abstract class Connection {
+
+	protected final static Logger LOGGER = Logger.getLogger(Connection.class);
+
+	protected PrintWriter output = null;
+	protected BufferedReader input = null;
+
+	protected Socket socket = null;
+
+	protected volatile boolean connected = false;
+
+	public boolean requestIdEnabled = false;
+
+	protected int protocolVersion = -1;
+
+	protected final com.framsticks.util.Thread senderThread = new com.framsticks.util.Thread();
+	protected Thread receiverThread;
+
+	public boolean isConnected() {
+		return connected;
+	}
+
+	public void close() {
+		protocolVersion = -1;
+		try {
+			connected = false;
+
+            senderThread.interrupt();
+            senderThread.join();
+			if (receiverThread != null) {
+				receiverThread.interrupt();
+				receiverThread.join();
+				receiverThread = null;
+			}
+
+			if (output != null) {
+				output.close();
+				output = null;
+			}
+
+			if (input != null) {
+				input.close();
+				input = null;
+			}
+
+
+			if (socket != null) {
+				socket.close();
+				socket = null;
+			}
+
+			LOGGER.info("connection closed");
+		} catch (Exception e) {
+			LOGGER.error(e);
+		}
+
+	}
+
+	protected static final String ARGUMENT_PATTERN_FRAGMENT = "((?:\\S+)|(?:\"[^\"]*\"))";
+	protected static Pattern requestIdEnabledPattern = Pattern.compile("^\\s*([0-9]+)(?:\\s+" + ARGUMENT_PATTERN_FRAGMENT + ")?\\n$");
+	protected static Pattern requestIDisabledPattern = Pattern.compile("^\\s*" + ARGUMENT_PATTERN_FRAGMENT + "?\\n$");
+	protected static Pattern eventPattern = Pattern.compile("^\\s*(\\S+)\\s*(\\S+)\\n");
+
+
+    protected final Pair<Integer, String> parseRest(String rest) {
+        Matcher matcher = (requestIdEnabled ? requestIdEnabledPattern : requestIDisabledPattern).matcher(rest);
+        if (!matcher.matches()) {
+            LOGGER.fatal("unmatched first line of input: " + rest);
+            return null;
+        }
+        return new Pair<Integer, String>(requestIdEnabled ? Integer.parseInt(matcher.group(1)) : null, matcher.group(requestIdEnabled ? 2 : 1));
+    }
+
+    static final int BUFFER_LENGTH = 1024;
+
+    int readChars = 0;
+    int iterator = 0;
+    int bufferStart = 0;
+    char[] readBuffer = new char[BUFFER_LENGTH];
+
+    protected String getLine() throws Exception {
+        StringBuilder lineBuffer = new StringBuilder();
+        while (!Thread.interrupted()) {
+            while (iterator < readChars) {
+                if (readBuffer[iterator] != '\n') {
+                    ++iterator;
+                    continue;
+                }
+                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
+                }
+            }
+            iterator = 0;
+            bufferStart = 0;
+        }
+        throw new InterruptedException();
+    }
+
+    protected abstract void receiverThreadRoutine() throws Exception;
+
+    protected void runThreads() {
+        try {
+            output = new PrintWriter(socket.getOutputStream(), true);
+            input = new BufferedReader(new InputStreamReader(socket.getInputStream()));
+        } catch (IOException e) {
+            LOGGER.error("buffer creation failure");
+            close();
+            return;
+        }
+
+        senderThread.setName(this + "-sender");
+        receiverThread = new Thread(new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    receiverThreadRoutine();
+                } catch (InterruptedException ignored) {
+                    LOGGER.debug("receiver thread interrupted");
+                } catch (Exception e) {
+                    LOGGER.error("error: " + e);
+                    close();
+                }
+            }
+        });
+        receiverThread.setName(this + "-receiver");
+
+        senderThread.start();
+        receiverThread.start();
+    }
+
+
+	/**
+	 * Returns Query associated with query getId.
+	 *
+	 * @return Query associated with query getId.
+	 */
+
+	public int getProtocolVersion() {
+		return protocolVersion;
+	}
+
+
+
+}
Index: java/main/src/main/java/com/framsticks/communication/EventCallback.java
===================================================================
--- java/main/src/main/java/com/framsticks/communication/EventCallback.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/communication/EventCallback.java	(revision 77)
@@ -0,0 +1,12 @@
+package com.framsticks.communication;
+
+import com.framsticks.params.SourceInterface;
+
+import java.util.List;
+
+/**
+ * @author Piotr Sniegowski
+ */
+public interface EventCallback {
+	public void call(List<File> files);
+}
Index: java/main/src/main/java/com/framsticks/communication/File.java
===================================================================
--- java/main/src/main/java/com/framsticks/communication/File.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/communication/File.java	(revision 77)
@@ -0,0 +1,24 @@
+package com.framsticks.communication;
+
+import com.framsticks.params.SourceInterface;
+
+/**
+ * @author Piotr Sniegowski
+ */
+public final class File {
+    protected final String path;
+    protected final SourceInterface content;
+
+    public File(String path, SourceInterface content) {
+        this.path = path;
+        this.content = content;
+    }
+
+    public String getPath() {
+        return path;
+    }
+
+    public SourceInterface getContent() {
+        return content;
+    }
+}
Index: java/main/src/main/java/com/framsticks/communication/Request.java
===================================================================
--- java/main/src/main/java/com/framsticks/communication/Request.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/communication/Request.java	(revision 77)
@@ -0,0 +1,55 @@
+package com.framsticks.communication;
+
+import com.framsticks.communication.queries.*;
+
+import java.util.Collection;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Class stores information about query sent to manager.
+ */
+public abstract class Request {
+
+    public static void quoteValue(StringBuilder builder, String value) {
+		String quote = ((value.indexOf(' ') > 0) || (value.length() == 0) ? "\"" : "");
+		builder.append(quote).append(value).append(quote);
+	}
+
+	public abstract String getCommand();
+
+    protected abstract StringBuilder construct(StringBuilder buffer);
+	//private static Pattern queryPattern = Pattern.compile("^(\\S+)\\s+(\\S+)(?:\\s+(\\S+))?$");
+
+	public static Request createRequestByTypeString(String type) {
+		if (type.equals("get")) {
+			return new GetRequest();
+		}
+		if (type.equals("set")) {
+			return new SetRequest();
+		}
+		if (type.equals("info")) {
+			return new InfoRequest();
+		}
+		if (type.equals("call")) {
+			return new CallRequest();
+		}
+        if (type.equals("reg")) {
+            return new RegistrationRequest();
+        }
+        if (type.equals("use")) {
+            return new UseRequest();
+        }
+        if (type.equals("version")) {
+            return new VersionRequest();
+        }
+        return null;
+	}
+
+    public abstract void parseRest(String rest);
+
+    @Override
+    public String toString() {
+        return construct(new StringBuilder().append(getCommand())).toString();
+    }
+}
Index: java/main/src/main/java/com/framsticks/communication/RequestHandler.java
===================================================================
--- java/main/src/main/java/com/framsticks/communication/RequestHandler.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/communication/RequestHandler.java	(revision 77)
@@ -0,0 +1,10 @@
+package com.framsticks.communication;
+
+import com.framsticks.communication.queries.ApplicationRequest;
+
+/**
+ * @author Piotr Sniegowski
+ */
+public interface RequestHandler {
+    public void handle(ApplicationRequest request, ResponseCallback responseCallback);
+}
Index: java/main/src/main/java/com/framsticks/communication/Response.java
===================================================================
--- java/main/src/main/java/com/framsticks/communication/Response.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/communication/Response.java	(revision 77)
@@ -0,0 +1,34 @@
+package com.framsticks.communication;
+
+import java.util.List;
+
+/**
+ * @author Piotr Sniegowski
+ */
+public class Response {
+    protected final boolean ok;
+    protected final String comment;
+    protected final List<File> files;
+
+    public Response(boolean ok, String comment, List<File> files) {
+        this.ok = ok;
+        this.comment = comment;
+        this.files = files;
+    }
+
+    public final String getComment() {
+        return comment;
+    }
+
+    public final boolean getOk() {
+        return ok;
+    }
+
+    public final List<File> getFiles() {
+        return files;
+    }
+
+    public final boolean hasFiles() {
+        return files != null && !files.isEmpty();
+    }
+}
Index: java/main/src/main/java/com/framsticks/communication/ResponseCallback.java
===================================================================
--- java/main/src/main/java/com/framsticks/communication/ResponseCallback.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/communication/ResponseCallback.java	(revision 77)
@@ -0,0 +1,12 @@
+package com.framsticks.communication;
+
+import com.framsticks.params.SourceInterface;
+
+import java.util.List;
+
+/**
+ * @author Piotr Sniegowski
+ */
+public interface ResponseCallback {
+	public void process(Response response);
+}
Index: java/main/src/main/java/com/framsticks/communication/ServerConnection.java
===================================================================
--- java/main/src/main/java/com/framsticks/communication/ServerConnection.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/communication/ServerConnection.java	(revision 77)
@@ -0,0 +1,131 @@
+package com.framsticks.communication;
+
+import com.framsticks.communication.queries.*;
+import com.framsticks.params.SourceInterface;
+import com.framsticks.util.Pair;
+import com.framsticks.util.Strings;
+import org.apache.log4j.Logger;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.PrintWriter;
+import java.net.Socket;
+
+/**
+ * @author Piotr Sniegowski
+ */
+public class ServerConnection extends Connection {
+
+    private final static Logger LOGGER = Logger.getLogger(ServerConnection.class);
+
+    RequestHandler requestHandler;
+
+    public ServerConnection(Socket socket, RequestHandler requestHandler) {
+        this.socket = socket;
+        this.requestHandler = requestHandler;
+        connected = true;
+
+    }
+
+    public void start() {
+
+
+        runThreads();
+    }
+
+    @Override
+    public String toString() {
+        return socket.getInetAddress().getHostAddress();
+    }
+
+    @Override
+    protected void receiverThreadRoutine() throws Exception {
+        while (connected) {
+            processNextRequest();
+        }
+    }
+
+    protected void handleRequest(Request request, ResponseCallback responseCallback) {
+        if (request instanceof ApplicationRequest) {
+            requestHandler.handle((ApplicationRequest)request, responseCallback);
+            return;
+        }
+        if (request instanceof ProtocolRequest) {
+            if (request instanceof VersionRequest) {
+                responseCallback.process(new Response(true, null, null));
+                return;
+            }
+            if (request instanceof UseRequest) {
+                String feature = ((UseRequest)request).getFeature();
+                if (feature.equals("request_id")) {
+                    requestIdEnabled = true;
+                    responseCallback.process(new Response(true, null, null));
+                    return;
+                }
+                responseCallback.process(new Response(false, "\"unknown feature: " + feature + "\"", null));
+                return;
+            }
+
+        }
+        LOGGER.error("unhandled request: " + request);
+        responseCallback.process(new Response(false, "unhandled", null));
+    }
+
+    protected final void respond(final Response response, final Integer id) {
+        senderThread.invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                String outId = id != null ? " " + id : "";
+                if (response.getFiles() != null) {
+                    for (File f : response.getFiles()) {
+                        output.print("file" + outId/* + " " + f.getPath()*/ + "\n");
+                        SourceInterface content = f.getContent();
+                        String line;
+                        while ((line = content.readLine()) != null) {
+                            output.print(line);
+                            output.print('\n');
+                        }
+                        output.print("eof\n");
+                    }
+                }
+                output.print(response.getOk() ? "ok" : "error");
+                output.print(outId);
+                if (Strings.notEmpty(response.getComment())) {
+                    output.print(' ');
+                    output.print(response.getComment());
+                }
+                output.print('\n');
+                output.flush();
+            }
+        });
+
+    }
+
+    protected void processNextRequest() throws Exception {
+        String line = getLine();
+        Pair<String, String> command = Strings.splitIntoPair(line, ' ', "\n");
+        final Pair<Integer, String> rest = parseRest(command.second);
+        if (rest == null) {
+            respond(new Response(false, "\"invalid input\"", null), null);
+            return;
+        }
+
+        final Request request = Request.createRequestByTypeString(command.first);
+        if (request == null) {
+            respond(new Response(false, "\"invalid input\"", null), null);
+            return;
+        }
+        request.parseRest(rest.second);
+        if (LOGGER.isTraceEnabled()) {
+            LOGGER.trace("read request: " + request);
+        }
+
+        handleRequest(request, new ResponseCallback() {
+            @Override
+            public void process(Response response) {
+                respond(response, rest.first);
+            }
+        });
+    }
+}
Index: java/main/src/main/java/com/framsticks/communication/StateCallback.java
===================================================================
--- java/main/src/main/java/com/framsticks/communication/StateCallback.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/communication/StateCallback.java	(revision 77)
@@ -0,0 +1,13 @@
+package com.framsticks.communication;
+
+import com.framsticks.util.StateFunctor;
+
+/**
+ * @author Piotr Sniegowski
+ */
+public abstract class StateCallback implements ResponseCallback, StateFunctor {
+	@Override
+	public void process(Response response) {
+		call(response.getOk() ? null : new Exception(response.getComment()));
+	}
+}
Index: java/main/src/main/java/com/framsticks/communication/Subscription.java
===================================================================
--- java/main/src/main/java/com/framsticks/communication/Subscription.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/communication/Subscription.java	(revision 77)
@@ -0,0 +1,75 @@
+package com.framsticks.communication;
+
+import com.framsticks.communication.queries.RegistrationRequest;
+import com.framsticks.util.AtOnceDispatcher;
+import com.framsticks.util.Dispatcher;
+import com.framsticks.util.StateFunctor;
+import org.apache.log4j.Logger;
+
+
+/**
+ * @author Piotr Sniegowski
+ */
+public class Subscription {
+
+    private final static Logger LOGGER = Logger.getLogger(Subscription.class);
+
+    private final ClientConnection connection;
+    private final String path;
+	private final String registeredPath;
+    private Dispatcher dispatcher = AtOnceDispatcher.instance;
+
+	private EventCallback eventCallback;
+
+	public Subscription(ClientConnection connection, String path, String registeredPath) {
+		this.connection = connection;
+        this.path = path;
+		this.registeredPath = registeredPath;
+	}
+
+	public String getPath () {
+		return path;
+	}
+
+	public String getRegisteredPath() {
+		return registeredPath;
+	}
+
+	@Override
+	public String toString() {
+		return path + "(" + registeredPath + ")";
+	}
+
+    public void setDispatcher(Dispatcher dispatcher) {
+        this.dispatcher = dispatcher;
+    }
+
+    public void unsubscribe(final StateFunctor stateFunctor) {
+        //@todo remove that /cli/ prefix, when registeredPath will be a fully qualified path
+        connection.send(new RegistrationRequest().register(false).setPath(registeredPath), new ResponseCallback() {
+            @Override
+            public void process(Response response) {
+                if (!response.getOk()) {
+                    LOGGER.error("failed to unsunscribe " + this + ": " + response.getComment());
+                    stateFunctor.call(new Exception(response.getComment()));
+                    return;
+                }
+                assert response.hasFiles();
+                LOGGER.debug("unsunscribed " + this);
+                stateFunctor.call(null);
+            }
+        });
+    }
+
+    public EventCallback getEventCallback() {
+        return eventCallback;
+    }
+
+    public Dispatcher getDispatcher() {
+        return dispatcher;
+    }
+
+    public void setEventCallback(EventCallback eventCallback) {
+        this.eventCallback = eventCallback;
+    }
+}
Index: java/main/src/main/java/com/framsticks/communication/SubscriptionCallback.java
===================================================================
--- java/main/src/main/java/com/framsticks/communication/SubscriptionCallback.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/communication/SubscriptionCallback.java	(revision 77)
@@ -0,0 +1,8 @@
+package com.framsticks.communication;
+
+/**
+ * @author Piotr Sniegowski
+ */
+public interface SubscriptionCallback {
+	EventCallback subscribed(Subscription subscription);
+}
Index: java/main/src/main/java/com/framsticks/communication/queries/ApplicationRequest.java
===================================================================
--- java/main/src/main/java/com/framsticks/communication/queries/ApplicationRequest.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/communication/queries/ApplicationRequest.java	(revision 77)
@@ -0,0 +1,60 @@
+package com.framsticks.communication.queries;
+
+import com.framsticks.communication.Request;
+
+import java.util.Collection;
+
+/**
+ * @author Piotr Sniegowski
+ */
+public abstract class ApplicationRequest extends Request {
+
+    protected String path;
+    protected String fields;
+
+    public ApplicationRequest setPath(String path) {
+        assert path != null;
+        this.path = path;
+        return this;
+    }
+
+    public ApplicationRequest setField(String field) {
+        this.fields = field;
+        return this;
+    }
+
+    public ApplicationRequest setFields(Collection<String> fields) {
+        StringBuilder fieldString = new StringBuilder();
+        boolean notFirst = false;
+        for (String field : fields) {
+            if (notFirst) {
+                fieldString.append(",");
+
+            } else {
+                notFirst = true;
+            }
+            fieldString.append(field);
+        }
+        return setField(fieldString.toString());
+    }
+
+
+    public String getPath() {
+        return path;
+    }
+
+    @Override
+    protected StringBuilder construct(StringBuilder buffer) {
+        buffer.append(' ').append(path);
+        if (fields != null) {
+            buffer.append(' ').append(fields);
+        }
+        return buffer;
+    }
+
+    @Override
+    public void parseRest(String rest) {
+        path = rest;
+    }
+
+}
Index: java/main/src/main/java/com/framsticks/communication/queries/CallRequest.java
===================================================================
--- java/main/src/main/java/com/framsticks/communication/queries/CallRequest.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/communication/queries/CallRequest.java	(revision 77)
@@ -0,0 +1,52 @@
+package com.framsticks.communication.queries;
+
+import com.framsticks.communication.Request;
+
+import java.util.List;
+
+/**
+ * @author Piotr Sniegowski
+ */
+public class CallRequest extends ApplicationRequest {
+	protected String arguments;
+	protected String method;
+
+
+	public CallRequest setArguments(String arguments) {
+		this.arguments = arguments;
+		return this;
+	}
+
+	public CallRequest setArguments(List<String> arguments) {
+		StringBuilder buffer = new StringBuilder();
+		for (String a : arguments) {
+			String arg = a.trim();
+			buffer.append(" ");
+			Request.quoteValue(buffer, arg);
+		}
+		return this.setArguments(buffer.toString());
+	}
+
+	public CallRequest setMethod(String method) {
+		this.method = method;
+		return this;
+	}
+
+	@Override
+	protected StringBuilder construct(StringBuilder buffer) {
+		super.construct(buffer);
+		if (method != null) {
+			buffer.append(" ").append(method);
+		}
+		if (arguments != null) {
+			buffer.append(arguments);
+		}
+        return buffer;
+	}
+
+	@Override
+	public String getCommand() {
+		return "call";
+	}
+
+}
Index: java/main/src/main/java/com/framsticks/communication/queries/GetRequest.java
===================================================================
--- java/main/src/main/java/com/framsticks/communication/queries/GetRequest.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/communication/queries/GetRequest.java	(revision 77)
@@ -0,0 +1,16 @@
+package com.framsticks.communication.queries;
+
+import com.framsticks.communication.Request;
+
+/**
+ * @author Piotr Sniegowski
+ */
+public class GetRequest extends ApplicationRequest {
+	public GetRequest() {
+	}
+
+	@Override
+	public String getCommand() {
+		return "get";
+	}
+}
Index: java/main/src/main/java/com/framsticks/communication/queries/InfoRequest.java
===================================================================
--- java/main/src/main/java/com/framsticks/communication/queries/InfoRequest.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/communication/queries/InfoRequest.java	(revision 77)
@@ -0,0 +1,18 @@
+package com.framsticks.communication.queries;
+
+import com.framsticks.communication.Request;
+
+/**
+ * @author Piotr Sniegowski
+ */
+public class InfoRequest extends ApplicationRequest {
+
+	public InfoRequest() {
+	}
+
+	@Override
+	public String getCommand() {
+		return "info";
+	}
+
+}
Index: java/main/src/main/java/com/framsticks/communication/queries/ProtocolRequest.java
===================================================================
--- java/main/src/main/java/com/framsticks/communication/queries/ProtocolRequest.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/communication/queries/ProtocolRequest.java	(revision 77)
@@ -0,0 +1,9 @@
+package com.framsticks.communication.queries;
+
+import com.framsticks.communication.Request;
+
+/**
+ * @author Piotr Sniegowski
+ */
+public abstract class ProtocolRequest extends Request {
+}
Index: java/main/src/main/java/com/framsticks/communication/queries/RegistrationRequest.java
===================================================================
--- java/main/src/main/java/com/framsticks/communication/queries/RegistrationRequest.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/communication/queries/RegistrationRequest.java	(revision 77)
@@ -0,0 +1,32 @@
+package com.framsticks.communication.queries;
+
+import com.framsticks.communication.Request;
+
+/**
+ * @author Piotr Sniegowski
+ */
+public class RegistrationRequest extends ApplicationRequest {
+	boolean register = true;
+
+	public RegistrationRequest() {
+	}
+
+	public RegistrationRequest register(boolean register) {
+		this.register = register;
+		return this;
+	}
+
+    @Override
+	protected StringBuilder construct(StringBuilder buffer) {
+        super.construct(buffer);
+		if (!register) {
+			buffer.append(" remove");
+		}
+        return buffer;
+	}
+
+	public String getCommand() {
+		return register ? "reg" : "call";
+	}
+
+}
Index: java/main/src/main/java/com/framsticks/communication/queries/SetRequest.java
===================================================================
--- java/main/src/main/java/com/framsticks/communication/queries/SetRequest.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/communication/queries/SetRequest.java	(revision 77)
@@ -0,0 +1,31 @@
+package com.framsticks.communication.queries;
+
+import com.framsticks.communication.Request;
+
+/**
+ * @author Piotr Sniegowski
+ */
+public class SetRequest extends ApplicationRequest {
+	protected String value;
+
+	public SetRequest() {
+	}
+
+	public SetRequest value(String value) {
+		this.value = value;
+		return this;
+	}
+
+	@Override
+	protected StringBuilder construct(StringBuilder buffer) {
+		super.construct(buffer);
+		if (value != null) {
+			buffer.append(" \"").append(value).append("\"");
+		}
+        return buffer;
+	}
+	@Override
+	public String getCommand() {
+		return "set";
+	}
+}
Index: java/main/src/main/java/com/framsticks/communication/queries/UseRequest.java
===================================================================
--- java/main/src/main/java/com/framsticks/communication/queries/UseRequest.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/communication/queries/UseRequest.java	(revision 77)
@@ -0,0 +1,34 @@
+package com.framsticks.communication.queries;
+
+import com.framsticks.communication.Request;
+
+/**
+ * @author Piotr Sniegowski
+ */
+public class UseRequest extends ProtocolRequest {
+	protected String feature;
+
+	public UseRequest feature(String feature) {
+		this.feature = feature;
+		return this;
+	}
+
+    @Override
+	public String getCommand() {
+		return "use";
+	}
+
+    @Override
+	protected StringBuilder construct(StringBuilder buffer) {
+		return buffer.append(' ').append(feature);
+	}
+
+    @Override
+    public void parseRest(String rest) {
+        feature = rest;
+    }
+
+    public final String getFeature() {
+        return feature;
+    }
+}
Index: java/main/src/main/java/com/framsticks/communication/queries/VersionRequest.java
===================================================================
--- java/main/src/main/java/com/framsticks/communication/queries/VersionRequest.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/communication/queries/VersionRequest.java	(revision 77)
@@ -0,0 +1,36 @@
+package com.framsticks.communication.queries;
+
+import com.framsticks.communication.Request;
+import com.framsticks.util.Numbers;
+import com.sun.j3d.loaders.ParsingErrorException;
+
+/**
+ * @author Piotr Sniegowski
+ */
+public class VersionRequest extends ProtocolRequest {
+	protected Integer version;
+
+	public VersionRequest() {
+	}
+
+	public VersionRequest version(Integer version) {
+		this.version = version;
+		return this;
+	}
+
+    @Override
+	public String getCommand() {
+		return "version";
+	}
+
+    @Override
+    public void parseRest(String rest) {
+        version = Numbers.parse(rest, Integer.class);
+    }
+
+    @Override
+    protected StringBuilder construct(StringBuilder buffer) {
+		return buffer.append(' ').append(version);
+	}
+
+}
Index: java/main/src/main/java/com/framsticks/communication/util/LoggingStateCallback.java
===================================================================
--- java/main/src/main/java/com/framsticks/communication/util/LoggingStateCallback.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/communication/util/LoggingStateCallback.java	(revision 77)
@@ -0,0 +1,28 @@
+package com.framsticks.communication.util;
+
+import com.framsticks.communication.StateCallback;
+import org.apache.log4j.Logger;
+import org.apache.log4j.Priority;
+
+/**
+ * @author Piotr Sniegowski
+ */
+public class LoggingStateCallback extends StateCallback {
+
+	protected final Logger logger;
+	protected final String message;
+
+	public LoggingStateCallback(Logger logger, String message) {
+		this.logger = logger;
+		this.message = message;
+	}
+
+	@Override
+	public void call(Exception e) {
+		if (e != null) {
+			logger.error("failed to " + message + " with " + e);
+			return;
+		}
+        logger.debug(message);
+	}
+}
Index: java/main/src/main/java/com/framsticks/communication/util/LoggingSubscriptionCallback.java
===================================================================
--- java/main/src/main/java/com/framsticks/communication/util/LoggingSubscriptionCallback.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/communication/util/LoggingSubscriptionCallback.java	(revision 77)
@@ -0,0 +1,32 @@
+package com.framsticks.communication.util;
+
+import com.framsticks.communication.EventCallback;
+import com.framsticks.communication.Subscription;
+import com.framsticks.communication.SubscriptionCallback;
+import org.apache.log4j.Logger;
+
+/**
+ * @author Piotr Sniegowski
+ */
+public class LoggingSubscriptionCallback implements SubscriptionCallback {
+
+    protected final Logger logger;
+    protected final String message;
+    private final EventCallback eventCallback;
+
+    public LoggingSubscriptionCallback(Logger logger, String message, EventCallback eventCallback) {
+        this.logger = logger;
+        this.message = message;
+        this.eventCallback = eventCallback;
+    }
+
+    @Override
+    public EventCallback subscribed(Subscription subscription) {
+        if (subscription == null) {
+            logger.error("failed to subscribe for " + message);
+            return null;
+        }
+        logger.info("successfuly subscribed for " + message);
+        return eventCallback;
+    }
+}
Index: java/main/src/main/java/com/framsticks/core/Entity.java
===================================================================
--- java/main/src/main/java/com/framsticks/core/Entity.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/core/Entity.java	(revision 77)
@@ -0,0 +1,61 @@
+package com.framsticks.core;
+
+import com.framsticks.util.*;
+import com.framsticks.util.Thread;
+import org.apache.log4j.Logger;
+
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * @author Piotr Sniegowski
+ */
+public abstract class Entity extends Parameters implements Dispatcher {
+
+    private final static Logger LOGGER = Logger.getLogger(Entity.class.getName());
+
+    public Entity(Parameters parameters) {
+        super(parameters);
+        if (dispatcher == null) {
+            dispatcher = new Thread(name);
+        }
+    }
+
+    @Override
+    public final boolean isActive() {
+        return dispatcher.isActive();
+    }
+
+    @Override
+    public final void invokeLater(Runnable runnable) {
+        dispatcher.invokeLater(runnable);
+    }
+
+    protected void run() {
+        assert isActive();
+        LOGGER.info("running: " + this);
+    }
+
+    public final void configurePublic() {
+        configure();
+    }
+
+    protected void configure() {
+
+    }
+
+    public Dispatcher getDispatcher() {
+        return dispatcher;
+    }
+
+    public final void start() {
+        invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                Entity.this.run();
+            }
+        });
+    }
+
+
+}
Index: java/main/src/main/java/com/framsticks/core/EntityListener.java
===================================================================
--- java/main/src/main/java/com/framsticks/core/EntityListener.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/core/EntityListener.java	(revision 77)
@@ -0,0 +1,8 @@
+package com.framsticks.core;
+
+/**
+ * @author Piotr Sniegowski
+ */
+public interface EntityListener {
+
+}
Index: java/main/src/main/java/com/framsticks/core/Instance.java
===================================================================
--- java/main/src/main/java/com/framsticks/core/Instance.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/core/Instance.java	(revision 77)
@@ -0,0 +1,361 @@
+package com.framsticks.core;
+
+import com.framsticks.communication.*;
+import com.framsticks.params.*;
+import com.framsticks.params.types.CompositeParam;
+import com.framsticks.params.types.ObjectParam;
+import com.framsticks.parsers.Loaders;
+import com.framsticks.parsers.MultiParamLoader;
+import com.framsticks.util.*;
+import com.framsticks.util.UnsupportedOperationException;
+import org.apache.log4j.Logger;
+
+import java.util.*;
+
+/**
+ * @author Piotr Sniegowski
+ */
+public abstract class Instance extends Entity {
+
+	private static final Logger LOGGER = Logger.getLogger(Instance.class.getName());
+
+
+    protected Node root;
+
+	protected final Map<String, FramsClass> infoCache = new HashMap<String, FramsClass>();
+    public Set<InstanceListener> listeners = new HashSet<InstanceListener>();
+
+    public Instance(Parameters parameters) {
+        super(parameters);
+        root = new Node((CompositeParam)new ParamBuilder().setName("Instance").setId(name).setType("o").build(), null);
+	}
+
+    @Override
+    protected void run() {
+        super.run();
+        registerTypicalReflectedClasses();
+    }
+
+    @Override
+    protected void configure() {
+        super.configure();
+    }
+
+    protected abstract void fetchInfo(Path path, Future<FramsClass> future);
+    public abstract void resolve(Path path, Future<Path> future);
+    public abstract void fetchValue(Path path, Param param, StateFunctor stateFunctor);
+    public abstract void fetchValues(Path path, StateFunctor stateFunctor);
+    protected abstract void tryRegisterOnChangeEvents(Path path);
+
+	public void storeValue(Path path, Param param, Object value, final StateFunctor stateFunctor) {
+		assert isActive();
+		invokeLater(new Runnable() {
+			@Override
+			public void run() {
+				stateFunctor.call(new UnsupportedOperationException());
+			}
+		});
+	}
+
+    protected void fireRun(Exception e) {
+        for (InstanceListener l : this.listeners) {
+            l.onRun(e);
+        }
+    }
+
+    protected void fireStop(Exception e) {
+        for (InstanceListener l : this.listeners) {
+            l.onStop(e);
+        }
+    }
+
+    public void addListener(final InstanceListener listener) {
+        assert Dispatching.isThreadSafe();
+        Dispatching.invokeLaterOrNow(this, new Runnable() {
+            @Override
+            public void run() {
+                listeners.add(listener);
+            }
+        });
+    }
+
+    public void removeListener(final InstanceListener listener) {
+        assert Dispatching.isThreadSafe();
+        Dispatching.invokeLaterOrNow(this, new Runnable() {
+            @Override
+            public void run() {
+                listeners.remove(listener);
+            }
+        });
+    }
+
+
+    protected void fireListChange(Path path, ListChange change) {
+        assert isActive();
+        for (InstanceListener l : this.listeners) {
+			l.onListChange(path, change);
+		}
+	}
+
+	public void putInfoIntoCache(FramsClass framsClass) {
+        assert isActive();
+        if (infoCache.containsKey(framsClass.getId())) {
+            LOGGER.info("already cached " + framsClass);
+            return;
+        }
+        LOGGER.debug("caching info for " + framsClass);
+		infoCache.put(framsClass.getId(), framsClass);
+	}
+
+    public final FramsClass getInfoFromCache(Path path) {
+        return getInfoFromCache(path.getTop().getParam().getContainedTypeName());
+    }
+
+
+    public FramsClass getInfoFromCache(String id) {
+        assert isActive();
+        if (id == null) {
+			return null;
+		}
+        if (infoCache.containsKey(id)) {
+            return infoCache.get(id);
+        }
+		return null;
+	}
+
+	protected final Map<String, Class> reflectedClasses = new HashMap<String, Class>();
+
+    public final void registerReflectedClass(String name, String className) {
+        assert isActive();
+        try {
+            registerReflectedClass(name, Class.forName(className));
+        } catch (ClassNotFoundException e) {
+            LOGGER.fatal("class not found during registration: " + e);
+        }
+    }
+
+    public void registerReflectedClass(String name, Class reflectedClass) {
+        assert isActive();
+        reflectedClasses.put(name, reflectedClass);
+	}
+
+	public AccessInterface createAccess(String name) {
+        assert isActive();
+        if (name == null) {
+			return null;
+		}
+		FramsClass framsClass = getInfoFromCache(name);
+		if (framsClass == null) {
+			return null;
+		}
+
+		if (reflectedClasses.containsKey(name)) {
+			return new ReflectionAccess(reflectedClasses.get(name), framsClass);
+		}
+
+		return new PropertiesAccess(framsClass);
+	}
+
+	public static AccessInterface wrapAccessWithListIfNeeded(CompositeParam param, AccessInterface access) {
+        if (access == null) {
+			return null;
+		}
+        return param.prepareAccessInterface(access);
+	}
+
+    public AccessInterface prepareAccess(CompositeParam param) {
+        return wrapAccessWithListIfNeeded(param, createAccess(param.getContainedTypeName()));
+    }
+
+    public <T> T get(Node node, Param childParam, Class<T> type) {
+        return bindAccess(node).get(childParam, type);
+    }
+
+    public void findInfo(final Path path, final Future<FramsClass> future) {
+        assert isActive();
+        final String name = path.getTop().getParam().getContainedTypeName();
+        final FramsClass framsClass = getInfoFromCache(name);
+        if (framsClass != null) {
+            LOGGER.trace("info for " + name + " found in cache");
+            future.result(framsClass, null);
+            return;
+        }
+        fetchInfo(path, future);
+    }
+
+    public final AccessInterface bindAccess(Node node) {
+        assert node.getObject() != null;
+        AccessInterface access = prepareAccess(node.getParam());
+        if (access == null) {
+            return null;
+        }
+        access.select(node.getObject());
+        return access;
+    }
+
+    public final <T> T getParam(Path path, String id, Class<T> type) {
+        return Casting.tryCast(type, prepareAccess(path.getTop().getParam()).getParam(id));
+    }
+
+    public final AccessInterface bindAccess(Path path) {
+        assert path.isResolved();
+        return bindAccess(path.getTop());
+    }
+
+    public void resolve(final String targetPath, final Future<Path> future) {
+        assert isActive();
+        final Path path = new Path(this, targetPath);
+        resolve(path, new Future<Path>() {
+            @Override
+            public void result(Path result, Exception e) {
+                assert isActive();
+                if (e != null) {
+                    future.result(path, e);
+                    return;
+                }
+                if (path.isResolved(targetPath)) {
+                    future.result(path, null);
+                    return;
+                }
+                if (path.isResolved()) {
+                    future.result(path, new Exception("testing"));
+                    return;
+                }
+                resolve(targetPath, future);
+            }
+        });
+    }
+
+    public void resolveAndFetch(final String targetPath, final Future<Path> future) {
+        assert isActive();
+        resolve(targetPath, new Future<Path>() {
+            @Override
+            public void result(final Path path, Exception e) {
+                if (e != null) {
+                    future.result(path, e);
+                    return;
+                }
+                assert path.isResolved(targetPath);
+                fetchValues(path, new StateFunctor() {
+                    @Override
+                    public void call(Exception e) {
+                        future.result(path, e);
+                    }
+                });
+            }
+        });
+    }
+
+    public Path createIfNeeded(String path) {
+        Path p;
+        while (!(p = new Path(this, path)).isResolved(path)) {
+            create(p);
+        }
+        return p;
+    }
+
+    public Path create(Path path) {
+        assert isActive();
+        assert !path.isResolved();
+        Path resolved = path.findResolution();
+        if (!resolved.isResolved()) {
+            LOGGER.debug("creating: " + path);
+            AccessInterface access = prepareAccess(path.getTop().getParam());
+            assert access != null;
+            Object child = access.createAccessee();
+            assert child != null;
+            if (path.size() == 1) {
+                root = new Node(root.getParam(), child);
+            } else {
+                bindAccess(path.getUnder()).set(path.getTop().getParam(), child);
+            }
+            resolved = path.appendResolution(child);
+        }
+        tryRegisterOnChangeEvents(resolved);
+        return resolved;
+    }
+
+
+
+
+    public FramsClass processFetchedInfo(File file) {
+        assert isActive();
+        FramsClass framsClass = Loaders.loadFramsClass(file.getContent());
+        if ("/".equals(file.getPath())) {
+            if (root.getParam().getContainedTypeName() == null) {
+                root = new Node((CompositeParam)new ParamBuilder().setName("Instance").setId(name).setType("o " + framsClass.getId()).build(), root.getObject());
+            }
+        }
+        putInfoIntoCache(framsClass);
+        return framsClass;
+    }
+
+    public void processFetchedValues(Path path, List<File> files) {
+        assert isActive();
+        assert files.size() == 1;
+        assert path.isTheSame(files.get(0).getPath());
+        Node node = path.getTop();
+        MultiParamLoader loader = new MultiParamLoader();
+        loader.setNewSource(files.get(0).getContent());
+        loader.addBreakCondition(MultiParamLoader.Status.AfterObject);
+
+        try {
+            if (node.getParam() instanceof ObjectParam) {
+                loader.addAccessInterface(bindAccess(node));
+                loader.go();
+    //            for (NodeListener l : listeners) {
+    //                l.onChange(this);
+    //            }
+                return;
+            }
+
+            ListAccess listAccess = ((ListAccess)bindAccess(node));
+            assert listAccess != null;
+            listAccess.clearValues();
+
+            AccessInterface elementAccess = listAccess.getElementAccess();
+            loader.addAccessInterface(elementAccess);
+            MultiParamLoader.Status status;
+            while ((status = loader.go()) != MultiParamLoader.Status.Finished) {
+                if (status == MultiParamLoader.Status.AfterObject) {
+                    AccessInterface accessInterface = loader.getLastAccessInterface();
+
+                    String id = listAccess.computeIdentifierFor(accessInterface.getSelected());
+                    Param param = new ParamBuilder().setType("o " + accessInterface.getId()).setId(id).build();
+                    Object child = accessInterface.getSelected();
+                    accessInterface.select(null);
+                    assert child != null;
+                    bindAccess(node).set(param, child);
+                }
+            }
+    //        for (NodeListener l : listeners) {
+    //            l.onChange(this);
+    //        }
+        } catch (Exception e) {
+            LOGGER.error("exception occurred while loading: " + e);
+        }
+
+    }
+
+    public void registerTypicalReflectedClasses() {
+        registerReflectedClass("MechPart", "com.framsticks.model.MechPart");
+        registerReflectedClass("Joint", "com.framsticks.model.Joint");
+        registerReflectedClass("MechJoint", "com.framsticks.model.MechJoint");
+        registerReflectedClass("Neuro", "com.framsticks.model.Neuro");
+        registerReflectedClass("NeuroDef", "com.framsticks.model.NeuroDef");
+        registerReflectedClass("Part", "com.framsticks.model.Part");
+        registerReflectedClass("Creature", "com.framsticks.model.Creature");
+        registerReflectedClass("Genotype", "com.framsticks.model.Genotype");
+    }
+
+    public static Iterator<String> splitPath(String path) {
+        List<String> list = new LinkedList<String>();
+        for (String s : path.split("/")) {
+            if (!s.isEmpty()) {
+                list.add(s);
+            }
+        }
+        return list.iterator();
+    }
+
+}
Index: java/main/src/main/java/com/framsticks/core/InstanceListener.java
===================================================================
--- java/main/src/main/java/com/framsticks/core/InstanceListener.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/core/InstanceListener.java	(revision 77)
@@ -0,0 +1,10 @@
+package com.framsticks.core;
+
+/**
+ * @author Piotr Sniegowski
+ */
+public interface InstanceListener {
+    public void onListChange(Path path, ListChange change);
+    public void onRun(Exception e);
+    public void onStop(Exception e);
+}
Index: java/main/src/main/java/com/framsticks/core/ListChange.java
===================================================================
--- java/main/src/main/java/com/framsticks/core/ListChange.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/core/ListChange.java	(revision 77)
@@ -0,0 +1,73 @@
+package com.framsticks.core;
+
+import com.framsticks.params.FramsClass;
+import com.framsticks.params.ListSource;
+import com.framsticks.params.ParamBuilder;
+import com.framsticks.params.types.DecimalParam;
+import com.framsticks.params.types.EnumParam;
+import com.framsticks.params.types.StringParam;
+import com.framsticks.util.Strings;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+
+/**
+ * @author Piotr Sniegowski
+ */
+public class ListChange {
+
+    public Action getAction() {
+        return action;
+    }
+
+    public Integer getPosition() {
+        return position;
+    }
+
+    public String getIdentifier() {
+        return identifier;
+    }
+
+    public static enum Action {
+        Add,
+        Remove,
+        Modify
+    }
+
+    private Action action;
+    private Integer position;
+    private String identifier;
+
+    public Integer getType() { return action.ordinal(); }
+    public void setType(Integer type) { action = Action.values()[type]; }
+
+	public Integer getPos() { return position; }
+	public void setPos(Integer pos) { position = pos; }
+
+	public String getId() { return identifier; }
+	public void setId(String id) { identifier = id; }
+
+    public String getBestIdentifier() {
+        if (Strings.notEmpty(identifier)) {
+            return identifier;
+        }
+        return position.toString();
+    }
+
+    public static FramsClass getFramsClass() {
+
+        ArrayList<String> actions = new ArrayList<String>();
+        actions.add("Add");
+        actions.add("Remove");
+        actions.add("Modify");
+        return new FramsClass("ListChange", "ListChange", null)
+                .append(new ParamBuilder().setId("type").setName("type").setType(new EnumParam(actions)).build())
+                .append(new ParamBuilder().setId("id").setName("identifier").setType(StringParam.class).build())
+                .append(new ParamBuilder().setId("pos").setName("position").setType(DecimalParam.class).build());
+    }
+
+    @Override
+    public String toString() {
+        return action + " " + identifier + " " + position;
+    }
+}
Index: java/main/src/main/java/com/framsticks/core/ListChangeHandler.java
===================================================================
--- java/main/src/main/java/com/framsticks/core/ListChangeHandler.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/core/ListChangeHandler.java	(revision 77)
@@ -0,0 +1,8 @@
+package com.framsticks.core;
+
+/**
+ * @author Piotr Sniegowski
+ */
+public interface ListChangeHandler {
+    public void handle(ListChange change);
+}
Index: java/main/src/main/java/com/framsticks/core/LocalInstance.java
===================================================================
--- java/main/src/main/java/com/framsticks/core/LocalInstance.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/core/LocalInstance.java	(revision 77)
@@ -0,0 +1,130 @@
+package com.framsticks.core;
+
+import com.framsticks.hosting.InstanceClient;
+import com.framsticks.params.AccessInterface;
+import com.framsticks.params.Param;
+import com.framsticks.util.*;
+import com.framsticks.util.Thread;
+import org.apache.log4j.Logger;
+
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.util.HashSet;
+import java.util.Set;
+
+
+/**
+ * @author Piotr Sniegowski
+ */
+public abstract class LocalInstance extends Instance {
+
+    private static final Logger LOGGER = Logger.getLogger(LocalInstance.class.getName());
+
+    public LocalInstance(Parameters parameters) {
+        super(parameters);
+
+        Integer accept = config.getInteger("accept", null);
+        if (accept != null) {
+            try {
+                acceptSocket = new ServerSocket();
+                acceptSocket.setReuseAddress(true);
+                acceptThread = new Thread(name + "-accept");
+                tryBind(accept);
+            } catch (IOException e) {
+                LOGGER.fatal("failed to create accept socket: " + e);
+            }
+        }
+    }
+
+    @Override
+    protected void run() {
+        super.run();
+    }
+
+    @Override
+    protected void configure() {
+        super.configure();
+    }
+
+    protected final Set<InstanceClient> clients = new HashSet<InstanceClient>();
+    ServerSocket acceptSocket;
+    Thread acceptThread;
+
+    protected void acceptNext() {
+        acceptThread.invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    final Socket socket = acceptSocket.accept();
+                    assert socket != null;
+                    LOGGER.debug("accepted socket: " + socket.getInetAddress().getHostAddress());
+                    invokeLater(new Runnable() {
+                        @Override
+                        public void run() {
+                            InstanceClient client = new InstanceClient(LocalInstance.this, socket);
+                            clients.add(client);
+                            LOGGER.info("client connected: " + client);
+                        }
+                    });
+                } catch (IOException e) {
+                    LOGGER.error("failed to accept socket: " + e);
+                }
+                acceptNext();
+            }
+        });
+    }
+
+    public void tryBind(final Integer accept) {
+        acceptThread.invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    acceptSocket.bind(new InetSocketAddress(accept));
+                    LOGGER.debug("started accepting on port " + accept);
+                    acceptNext();
+                } catch (IOException e) {
+                    LOGGER.fatal("failed to accept on port " + accept + ": " + e);
+                }
+                try {
+                    java.lang.Thread.sleep(1000);
+                } catch (InterruptedException ignored) {
+                }
+                tryBind(accept);
+            }
+        });
+    }
+
+
+
+    @Override
+    public void resolve(Path path, Future<Path> future) {
+        assert isActive();
+        assert path.isOwner(this);
+        if (path.getTop().getObject() != null) {
+            future.result(path, null);
+            return;
+        }
+        AccessInterface access = bindAccess(path.getUnder());
+        Object object = access.get(path.getTop().getParam(), Object.class);
+        if (object == null) {
+            future.result(path, null);
+            return;
+        }
+        future.result(path.appendResolution(object), null);
+    }
+
+
+    @Override
+    public void fetchValue(Path path, Param param, StateFunctor stateFunctor) {
+        stateFunctor.call(null);
+    }
+
+    @Override
+    public void fetchValues(Path path, StateFunctor stateFunctor) {
+        stateFunctor.call(null);
+    }
+
+
+}
Index: java/main/src/main/java/com/framsticks/core/Node.java
===================================================================
--- java/main/src/main/java/com/framsticks/core/Node.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/core/Node.java	(revision 77)
@@ -0,0 +1,36 @@
+package com.framsticks.core;
+
+import com.framsticks.params.types.CompositeParam;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @author Piotr Sniegowski
+ */
+public class Node {
+
+    protected final CompositeParam param;
+    protected final Object object;
+    //protected final Map<String, Node> children = new HashMap<String, Node>();
+
+    public Node() {
+        param = null;
+        object = null;
+    }
+
+    public Node(CompositeParam param, Object object) {
+        assert param != null;
+        this.param = param;
+        this.object = object;
+    }
+
+    public final CompositeParam getParam() {
+        return param;
+    }
+
+    public final Object getObject() {
+        return object;
+    }
+
+}
Index: java/main/src/main/java/com/framsticks/core/ObjectListener.java
===================================================================
--- java/main/src/main/java/com/framsticks/core/ObjectListener.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/core/ObjectListener.java	(revision 77)
@@ -0,0 +1,11 @@
+package com.framsticks.core;
+
+import com.framsticks.params.Param;
+
+/**
+ * @author Piotr Sniegowski
+ */
+public interface ObjectListener {
+    public void onChange(Param param);
+    public void onRemove();
+}
Index: java/main/src/main/java/com/framsticks/core/Parameters.java
===================================================================
--- java/main/src/main/java/com/framsticks/core/Parameters.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/core/Parameters.java	(revision 77)
@@ -0,0 +1,38 @@
+package com.framsticks.core;
+
+import com.framsticks.params.FramsClass;
+import com.framsticks.util.Dispatcher;
+import org.apache.commons.configuration.Configuration;
+
+/**
+ * @author Piotr Sniegowski
+ */
+public class Parameters {
+    protected Configuration config;
+    protected String name;
+    protected Dispatcher dispatcher;
+
+    public Parameters(Configuration config, String name, Dispatcher dispatcher) {
+        this.config = config;
+        this.name = name;
+        this.dispatcher = dispatcher;
+    }
+
+    public Parameters(Parameters parameters) {
+        config = parameters.config;
+        name = parameters.name;
+        dispatcher = parameters.dispatcher;
+    }
+
+    public final Configuration getConfig() {
+        return config;
+    }
+
+    public final String getName() {
+        return name;
+    }
+
+    public static void constructFramsClass(FramsClass.Constructor constructor) {
+        constructor.method("getName");
+    }
+}
Index: java/main/src/main/java/com/framsticks/core/Path.java
===================================================================
--- java/main/src/main/java/com/framsticks/core/Path.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/core/Path.java	(revision 77)
@@ -0,0 +1,168 @@
+package com.framsticks.core;
+
+import com.framsticks.params.AccessInterface;
+import com.framsticks.params.Param;
+import com.framsticks.params.types.CompositeParam;
+import com.framsticks.util.Dispatching;
+import org.apache.log4j.Logger;
+
+import java.util.Iterator;
+import java.util.LinkedList;
+
+/**
+ * @author Piotr Sniegowski
+ */
+public class Path {
+    private final static Logger LOGGER = Logger.getLogger(Path.class.getName());
+
+    final LinkedList<Node> nodes = new LinkedList<Node>();
+    String textual;
+    Instance instance;
+
+    protected Object getKnownChild(AccessInterface access, CompositeParam param) {
+        Object child = access.get(param, Object.class);
+        if (child == null) {
+            return null;
+        }
+        return (instance.prepareAccess(param) != null) ? child : null;
+    }
+
+    public Path(Instance instance, String textual) {
+        assert instance.isActive();
+        this.instance = instance;
+        StringBuilder b = new StringBuilder();
+        nodes.add(instance.root);
+        Node current = instance.root;
+        Iterator<String> i = Instance.splitPath(textual);
+        while (i.hasNext() && current.getObject() != null) {
+            AccessInterface access = instance.prepareAccess(current.getParam());
+            if (access == null) {
+                break;
+            }
+            String e = i.next();
+            Param p = access.getParam(e);
+            if (!(p instanceof CompositeParam)) {
+                //entries.add(new Entry());
+                break;
+            }
+            CompositeParam c = (CompositeParam)p;
+            b.append("/").append(e);
+            access.select(current.getObject());
+            current = new Node(c, getKnownChild(access, c));
+            nodes.add(current);
+        }
+        this.textual = (size() == 1) ? "/" : b.toString();
+    }
+
+    protected Path() {
+
+    }
+
+    public Path appendNode(Node node) {
+        assert isResolved();
+        Path result = new Path();
+        result.textual = textual + ((size() == 1) ? "" : "/") + node.getParam().getId();
+        result.instance = instance;
+        result.nodes.addAll(nodes);
+        result.nodes.add(node);
+        return result;
+    }
+
+    public Path appendParam(CompositeParam param) {
+        assert isResolved();
+        return appendNode(new Node(param, null));
+    }
+
+    public Path appendResolution(Object object) {
+        assert !isResolved();
+        Path result = new Path();
+        result.textual = textual;
+        result.instance = instance;
+        result.nodes.addAll(nodes);
+        result.nodes.add(new Node(result.nodes.pollLast().getParam(), object));
+        return result;
+    }
+
+    public final Object getTopObject() {
+        return getTop().getObject();
+    }
+
+    public final Node getTop() {
+        return nodes.getLast();
+    }
+
+    public final Node getUnder() {
+        assert nodes.size() >= 2;
+        return nodes.get(nodes.size() - 2);
+    }
+
+    public final String getTextual() {
+        return textual;
+    }
+
+    public String toString() {
+        return instance + textual + (!isResolved() ? "!" : "");
+    }
+
+    public final int size() {
+        assert Dispatching.isThreadSafe();
+        return nodes.size();
+    }
+
+    public final boolean isResolved() {
+        assert Dispatching.isThreadSafe();
+        return getTop().getObject() != null;
+    }
+
+    public final boolean isResolved(String textual) {
+        assert Dispatching.isThreadSafe();
+        return isTheSame(textual) && isResolved();
+    }
+
+    public final boolean isTheSame(String textual) {
+        assert Dispatching.isThreadSafe();
+        return this.textual.equals(textual);
+    }
+
+    public final Instance getInstance() {
+        assert Dispatching.isThreadSafe();
+        return instance;
+    }
+
+    public Path findResolution() {
+        assert instance.isActive();
+        assert !isResolved();
+        if (size() == 1) {
+			return new Path(instance, "/");//appendResolution(instance.root.object);
+        }
+        Object child = getKnownChild(instance.bindAccess(getUnder()), getTop().getParam());
+        if (child == null) {
+            return this;
+        }
+        return appendResolution(child);
+    }
+
+    public boolean matches(Path p) {
+        assert Dispatching.isThreadSafe();
+        assert instance == p.instance;
+        Iterator<Node> a = nodes.iterator();
+        Iterator<Node> b = p.nodes.iterator();
+        while (a.hasNext() && b.hasNext()) {
+            Node an = a.next();
+            Node bn = b.next();
+            if (an.object != bn.object) {
+                return false;
+            }
+        }
+        return a.hasNext() == b.hasNext();
+    }
+
+    public String getLastElement() {
+        return getTop().getParam().getId();
+    }
+
+    public final boolean isOwner(Instance instance) {
+        return this.instance == instance;
+    }
+}
+
Index: java/main/src/main/java/com/framsticks/core/PathListener.java
===================================================================
--- java/main/src/main/java/com/framsticks/core/PathListener.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/core/PathListener.java	(revision 77)
@@ -0,0 +1,10 @@
+package com.framsticks.core;
+
+import com.framsticks.params.Param;
+
+/**
+ * @author Piotr Sniegowski
+ */
+public interface PathListener {
+    void onChange(Param param);
+}
Index: java/main/src/main/java/com/framsticks/core/Program.java
===================================================================
--- java/main/src/main/java/com/framsticks/core/Program.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/core/Program.java	(revision 77)
@@ -0,0 +1,115 @@
+package com.framsticks.core;
+
+import com.framsticks.util.Pair;
+import com.framsticks.util.Strings;
+import org.apache.commons.configuration.*;
+import org.apache.log4j.Logger;
+import org.apache.log4j.PropertyConfigurator;
+import sun.misc.Signal;
+import sun.misc.SignalHandler;
+
+import java.lang.reflect.Constructor;
+import java.util.*;
+
+/**
+ * @author Piotr Sniegowski
+ */
+public class Program extends com.framsticks.util.Thread {
+
+    private final static Logger LOGGER = Logger.getLogger(Program.class.getName());
+
+    protected SignalHandler signalHandler = new SignalHandler() {
+        @Override
+        public void handle(Signal signal) {
+            LOGGER.info("caught " + signal);
+            Runtime.getRuntime().exit(0);
+        }
+    };
+
+    protected Entity entity;
+
+    Configuration config;
+
+
+    public Program(String name) {
+        super(name, java.lang.Thread.currentThread());
+        Signal.handle(new Signal("INT"), signalHandler);
+        Signal.handle(new Signal("TERM"), signalHandler);
+    }
+
+    public static Entity configureEntity(Parameters parameters) {
+        String typeName = parameters.getConfig().getString("class");
+        LOGGER.info("configuring instance " + typeName);
+        try {
+            Class type = Class.forName(typeName);
+            Constructor constructor = type.getConstructor(Parameters.class);
+            Entity entity = (Entity) constructor.newInstance(parameters);
+            return entity;
+        } catch (Exception e) {
+            LOGGER.error("failed to instantiate: " + e);
+        }
+        return null;
+    }
+
+    protected static void resolve(Configuration config, String prefix) {
+
+        Iterator i = prefix == null ? config.getKeys() : config.getKeys(prefix);
+        while (i.hasNext()) {
+            String p = (String) i.next();
+            if (p.endsWith(".mount")) {
+                String source = config.getString(p);
+                LOGGER.info("mounting " + source + " at " + p);
+                config.clearProperty(p);
+                Configuration mount = config.subset(source);
+                Iterator mi = mount.getKeys();
+                while (mi.hasNext()) {
+                    String mk = (String) mi.next();
+                    config.addProperty(p.substring(0, p.length() - 6) + "." + mk, mount.getProperty(mk));
+                }
+            }
+        }
+    }
+
+    public void run(String[] args) {
+
+		PropertyConfigurator.configure(getClass().getResource("/configs/log4j.properties"));
+		LOGGER.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();
+                LOGGER.debug(p + " = " + config.getProperty(p));
+            }
+
+        } catch (ConfigurationException e) {
+            System.err.print("failed to parse configuration:" + e);
+            return;
+        }
+
+        entity = configureEntity(new Parameters(config.subset("com.framsticks.entity"), "main", null));
+        entity.configurePublic();
+        LOGGER.info("all entities were configured");
+        entity.start();
+    }
+
+    public static void main(final String[] args) {
+        final Program program = new Program("program");
+        program.invokeLater(new Runnable() {
+            @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 77)
+++ java/main/src/main/java/com/framsticks/diagnostics/Diagnostics.java	(revision 77)
@@ -0,0 +1,37 @@
+package com.framsticks.diagnostics;
+
+import com.framsticks.core.Parameters;
+import com.framsticks.observers.Endpoint;
+import com.framsticks.observers.Observer;
+
+/**
+ * @author Piotr Sniegowski
+ */
+public class Diagnostics extends Observer {
+
+    final Integer dumpsInterval;
+    final String dumpsPath;
+    final String dumpsFormat;
+
+
+    public Diagnostics(Parameters parameters) {
+        super(parameters);
+        dumpsInterval = config.getInteger("dumps.interval", null);
+        dumpsPath = config.getString("dumps.path", null);
+        dumpsFormat = config.getString("dumps.format", null);
+    }
+
+    @Override
+    protected void configure() {
+
+        super.configure();
+    }
+
+
+    @Override
+    protected Endpoint createEndpoint() {
+        return new DiagnosticsEndpoint();
+    }
+
+
+}
Index: java/main/src/main/java/com/framsticks/diagnostics/DiagnosticsEndpoint.java
===================================================================
--- java/main/src/main/java/com/framsticks/diagnostics/DiagnosticsEndpoint.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/diagnostics/DiagnosticsEndpoint.java	(revision 77)
@@ -0,0 +1,85 @@
+package com.framsticks.diagnostics;
+
+import com.framsticks.core.Path;
+import com.framsticks.dumping.SaveStream;
+import com.framsticks.observers.Endpoint;
+import com.framsticks.dumping.PrintStreamSink;
+import com.framsticks.remote.RecursiveFetcher;
+import com.framsticks.util.Logging;
+import com.framsticks.util.PeriodicTask;
+import com.framsticks.util.StateFunctor;
+import org.apache.log4j.Logger;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+/**
+ * @author Piotr Sniegowski
+ */
+public class DiagnosticsEndpoint extends Endpoint {
+
+    private final static Logger LOGGER = Logger.getLogger(DiagnosticsEndpoint.class.getName());
+
+
+    public DiagnosticsEndpoint() {
+        super();
+    }
+
+    @Override
+    public Diagnostics getObserver() {
+        return (Diagnostics)observer;
+    }
+
+
+    @Override
+    protected void configure() {
+        super.configure();
+
+        if (getObserver().dumpsInterval != null) {
+            new PeriodicTask(instance, getObserver().dumpsInterval * 1000) {
+                @Override
+                public void run() {
+
+                    LOGGER.info("starting periodic dump");
+                    new RecursiveFetcher(instance, new Path(instance, "/"), new StateFunctor() {
+                        @Override
+                        public void call(Exception e) {
+                            if (Logging.log(LOGGER, "recursively fetch", instance, e)) {
+                                again();
+                                return;
+                            }
+                            LOGGER.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 PrintStreamSink(new PrintStream(file)), instance, new Path(instance, "/"), new StateFunctor() {
+                                    @Override
+                                    public void call(Exception e) {
+                                        Logging.log(LOGGER, "periodic dump in " + fileName + " of", DiagnosticsEndpoint.this.instance, e);
+                                        again();
+                                    }
+                                });
+                            } catch (IOException ex) {
+                                LOGGER.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 77)
+++ java/main/src/main/java/com/framsticks/dumping/FileInstance.java	(revision 77)
@@ -0,0 +1,73 @@
+package com.framsticks.dumping;
+
+import com.framsticks.core.LocalInstance;
+import com.framsticks.core.Parameters;
+import com.framsticks.core.Path;
+import com.framsticks.params.FramsClass;
+import com.framsticks.core.Instance;
+import com.framsticks.util.*;
+import com.framsticks.util.UnsupportedOperationException;
+import org.apache.log4j.Logger;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+
+/**
+ * @author Piotr Sniegowski
+ */
+public class FileInstance extends LocalInstance {
+
+    private static final Logger LOGGER = Logger.getLogger(Instance.class.getName());
+    protected final File file;
+
+    public FileInstance(Parameters parameters) {
+        super(parameters);
+        file = new File(config.getString("filename"));
+    }
+
+    @Override
+    public void run() {
+        assert isActive();
+        super.run();
+        try {
+            FileReader fileReader = new FileReader(file);
+            LoadStream stream = new LoadStream(new Path(this, "/"), new BufferedReader(fileReader), this, new Future<Path>() {
+                @Override
+                public void result(Path result, Exception e) {
+                    if (e != null) {
+                        LOGGER.error("failed to load file instance " + FileInstance.this + ": " + e);
+                        fireRun(e);
+                        return;
+                    }
+                    LOGGER.info("loaded file instance " + FileInstance.this);
+                    fireRun(null);
+                }
+            });
+            stream.load();
+        } catch (IOException e) {
+            LOGGER.error("io failure: " + e);
+            fireRun(e);
+        }
+    }
+
+
+    @Override
+    protected void fetchInfo(Path path, Future<FramsClass> future) {
+        future.result(null, new UnsupportedOperationException());
+    }
+
+    @Override
+    protected void tryRegisterOnChangeEvents(Path path) {
+    }
+
+
+    @Override
+    public String toString() {
+        return "file@" + file.getName();
+    }
+
+
+
+}
Index: java/main/src/main/java/com/framsticks/dumping/LoadStream.java
===================================================================
--- java/main/src/main/java/com/framsticks/dumping/LoadStream.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/dumping/LoadStream.java	(revision 77)
@@ -0,0 +1,89 @@
+package com.framsticks.dumping;
+
+import com.framsticks.communication.File;
+import com.framsticks.core.Path;
+import com.framsticks.params.ListSource;
+import com.framsticks.core.Instance;
+import com.framsticks.util.*;
+import org.apache.log4j.Logger;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * @author Piotr Sniegowski
+ */
+public class LoadStream {
+
+    private final static Logger LOGGER = Logger.getLogger(LoadStream.class.getName());
+
+    protected final Instance instance;
+    protected final Path mountPath;
+    protected final BufferedReader stream;
+    protected final Future<Path> future;
+    protected final Stopwatch stopwatch = new Stopwatch();
+
+
+    public LoadStream(Path mountPath, BufferedReader stream, Instance instance, Future<Path> future) {
+        this.instance = instance;
+        this.mountPath = mountPath;
+        this.stream = stream;
+        this.future = future;
+    }
+
+    public void load() {
+        try {
+            String line;
+            Pair<String, String> query = null;
+            List<File> files = null;
+            List<String> content = null;
+            //File file;
+            while ((line = stream.readLine()) != null) {
+                if (query == null) {
+                    query = Strings.splitIntoPair(line, ' ', "\n");
+                    files = new LinkedList<File>();
+                    LOGGER.trace("loading " + line);
+                    continue;
+                }
+                if (content == null) {
+                    if (line.equals("file")) {
+                        content = new LinkedList<String>();
+                        continue;
+                    }
+                    if (line.equals("ok")) {
+                        if (query.first.equals("get")) {
+                            Path path = instance.createIfNeeded(query.second);
+                            instance.processFetchedValues(path, files);
+                        } else if (query.first.equals("info")) {
+                            assert files.size() == 1;
+                            instance.processFetchedInfo(files.get(0));
+                        } else {
+                            assert false;
+                        }
+                        query = null;
+                        files = null;
+                        continue;
+                    }
+                    assert false;
+                    continue;
+                }
+                if (line.equals("eof")) {
+                    files.add(new File(query.second, new ListSource(content)));
+                    content = null;
+                    continue;
+                }
+                content.add(line);
+            }
+        } catch (IOException e) {
+            LOGGER.error("failed to load: " + e);
+            future.result(null, e);
+            return;
+        }
+        LOGGER.info("loaded in: " + stopwatch);
+        future.result(new Path(instance, mountPath.getTextual()), null);
+    }
+
+
+}
Index: java/main/src/main/java/com/framsticks/dumping/PrintStreamSink.java
===================================================================
--- java/main/src/main/java/com/framsticks/dumping/PrintStreamSink.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/dumping/PrintStreamSink.java	(revision 77)
@@ -0,0 +1,38 @@
+package com.framsticks.dumping;
+
+import com.framsticks.params.SinkInterface;
+
+import java.io.PrintStream;
+
+/**
+ * @author Piotr Sniegowski
+ */
+public class PrintStreamSink implements SinkInterface {
+
+    protected final PrintStream stream;
+
+    public PrintStreamSink(PrintStream stream) {
+        this.stream = stream;
+    }
+
+    @Override
+    public PrintStreamSink print(String str) {
+        stream.print(str);
+        return this;
+    }
+
+    @Override
+    public PrintStreamSink print(Object obj) {
+        stream.print(obj);
+        return this;
+    }
+
+    @Override
+    public void breakLine() {
+        stream.print('\n');
+    }
+
+    @Override
+    public void close() {
+    }
+}
Index: java/main/src/main/java/com/framsticks/dumping/SaveStream.java
===================================================================
--- java/main/src/main/java/com/framsticks/dumping/SaveStream.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/dumping/SaveStream.java	(revision 77)
@@ -0,0 +1,96 @@
+package com.framsticks.dumping;
+
+import com.framsticks.core.Node;
+import com.framsticks.core.Path;
+import com.framsticks.params.AccessInterface;
+import com.framsticks.params.FramsClass;
+import com.framsticks.params.ListAccess;
+import com.framsticks.params.Param;
+import com.framsticks.params.types.CompositeParam;
+import com.framsticks.params.SinkInterface;
+import com.framsticks.parsers.Savers;
+import com.framsticks.core.Instance;
+import com.framsticks.util.*;
+import org.apache.log4j.Logger;
+
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * @author Piotr Sniegowski
+ */
+public class SaveStream {
+
+    private final static Logger LOGGER = Logger.getLogger(SaveStream.class.getName());
+
+    protected final SinkInterface sink;
+    protected final Instance instance;
+    protected final StateFunctor stateFunctor;
+    protected final Stopwatch stopwatch = new Stopwatch();
+    protected final Set<FramsClass> storedInfo = new HashSet<FramsClass>();
+
+    private int dispatched = 0;
+
+    public SaveStream(SinkInterface sink, Instance instance, Path root, StateFunctor stateFunctor) {
+        assert Dispatching.isThreadSafe();
+        this.sink = sink;
+        this.instance = instance;
+        this.stateFunctor = stateFunctor;
+        dispatched = 1;
+        write(root);
+    }
+
+    protected void finished() {
+        assert instance.isActive();
+        LOGGER.info("stored in " + stopwatch);
+        stateFunctor.call(null);
+    }
+
+    public void write(final Path path) {
+        assert instance.isActive();
+        if (!path.isResolved()) {
+            LOGGER.debug("path " + path + " is not resolved - skipping");
+        } else {
+            AccessInterface access = instance.bindAccess(path);
+            FramsClass framsClass = access.getFramsClass();
+            assert framsClass != null;
+            if (!storedInfo.contains(framsClass)) {
+                storedInfo.add(framsClass);
+                sink.print("info ").print(path.getTextual()).breakLine();
+                sink.print("file").breakLine();
+                Savers.saveFramsClass(sink, framsClass);
+                sink.print("eof").breakLine();
+                sink.print("ok").breakLine();
+            }
+            if (!(access instanceof ListAccess)) {
+                sink.print("get ").print(path.getTextual()).breakLine();
+                sink.print("file").breakLine();
+                //stream.print("#" + access.getSelected().getClass().getCanonicalName() + "\n");
+                access.save(sink);
+                sink.print("eof").breakLine();
+                sink.print("ok").breakLine();
+            }
+            for (Param p : access.getParams()) {
+                if (p instanceof CompositeParam) {
+                    CompositeParam childParam = (CompositeParam)p;
+                    final Path childPath = path.appendNode(new Node(childParam, access.get(childParam, Object.class)));
+                    if (childPath.isResolved() && instance.getInfoFromCache(childPath) != null) {
+                        ++dispatched;
+                        instance.invokeLater(new Runnable() {
+                            @Override
+                            public void run() {
+                                write(childPath);
+                            }
+                        });
+                    }
+                }
+            }
+        }
+        --dispatched;
+        if (dispatched == 0) {
+            finished();
+        }
+    }
+
+
+}
Index: java/main/src/main/java/com/framsticks/gui/Browser.java
===================================================================
--- java/main/src/main/java/com/framsticks/gui/Browser.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/gui/Browser.java	(revision 77)
@@ -0,0 +1,125 @@
+package com.framsticks.gui;
+
+import com.framsticks.core.*;
+import com.framsticks.observers.Endpoint;
+import com.framsticks.observers.Observer;
+import com.framsticks.util.Dispatcher;
+import org.apache.log4j.Logger;
+
+import javax.swing.*;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * @author Piotr Sniegowski
+ */
+public class Browser extends Observer implements Dispatcher {
+
+    private static final Logger LOGGER = Logger.getLogger(Browser.class.getName());
+
+    protected final Set<Frame> frames = new HashSet<Frame>();
+    protected MainFrame mainFrame;
+
+    public void addFrame(Frame frame) {
+        frames.add(frame);
+    }
+
+	public Browser(Parameters parameters) {
+        super(parameters);
+        dispatcher = SwingDispatcher.instance;
+        invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                assert isActive();
+
+            }
+        });
+	}
+
+	public void clear() {
+        assert isActive();
+        for (Frame f : frames) {
+            f.clear();
+        }
+	}
+
+    @Override
+    protected void configure() {
+        super.configure();
+    }
+
+
+    @Override
+    public void run() {
+        super.run();
+
+        try {
+            UIManager.setLookAndFeel("com.sun.java.swing.plaf.gtk.GTKLookAndFeel");
+        } catch (Exception ex) {
+            LOGGER.warn("failed loading Look&Feel: ", ex);
+        }
+        javax.swing.JFrame.setDefaultLookAndFeelDecorated(true);
+
+        mainFrame = new MainFrame(Browser.this);
+        addFrame(mainFrame);
+
+        for (Frame f : frames) {
+            f.configure();
+        }
+
+        for (final Endpoint e : getEndpoints().values()) {
+            e.invokeLater(new Runnable() {
+                @Override
+                public void run() {
+                    final Path p = new Path(e.getInstance(), "/");
+                    invokeLater(new Runnable() {
+                        @Override
+                        public void run() {
+                            mainFrame.addRootPath((BrowserEndpoint) e, p);
+                        }
+                    });
+                }
+            });
+
+        }
+
+        for (Frame f : frames) {
+            f.setVisible(true);
+        }
+    }
+
+    public void createTreeNodeForChild(final Path path) {
+        assert !isActive();
+        //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;
+        }
+        LOGGER.debug(child.getClass().getSimpleName() + " created: " + child);
+
+
+        invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                parentTreeNode.getOrCreateChildTreeNodeFor(child);
+            }
+        });
+*/
+	}
+
+
+    @Override
+    protected Endpoint createEndpoint() {
+        return new BrowserEndpoint();
+    }
+
+}
Index: java/main/src/main/java/com/framsticks/gui/BrowserEndpoint.java
===================================================================
--- java/main/src/main/java/com/framsticks/gui/BrowserEndpoint.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/gui/BrowserEndpoint.java	(revision 77)
@@ -0,0 +1,13 @@
+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 77)
+++ java/main/src/main/java/com/framsticks/gui/EndpointAtFrame.java	(revision 77)
@@ -0,0 +1,42 @@
+package com.framsticks.gui;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @author Piotr Sniegowski
+ */
+public class EndpointAtFrame {
+    protected final BrowserEndpoint endpoint;
+    protected final Frame frame;
+    protected final Map<String, Panel> knownPanels = new HashMap<String, Panel>();
+
+    public EndpointAtFrame(BrowserEndpoint endpoint, Frame frame) {
+        this.endpoint = endpoint;
+        this.frame = frame;
+    }
+
+
+    public BrowserEndpoint getEndpoint() {
+        return endpoint;
+    }
+
+    public Frame getFrame() {
+        return frame;
+    }
+
+    public void registerPanel(Panel panel) {
+        assert frame.isActive();
+        knownPanels.put(panel.getClassName(), panel);
+        frame.cardPanel.add(panel, panel.getFullName());
+    }
+
+    public Panel findPanel(String className) {
+        assert frame.isActive();
+        return (knownPanels.containsKey(className) ? knownPanels.get(className) : null);
+    }
+
+    public final String getName() {
+        return endpoint.getName();
+    }
+}
Index: java/main/src/main/java/com/framsticks/gui/Frame.java
===================================================================
--- java/main/src/main/java/com/framsticks/gui/Frame.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/gui/Frame.java	(revision 77)
@@ -0,0 +1,308 @@
+package com.framsticks.gui;
+
+import com.framsticks.core.Path;
+import com.framsticks.gui.view.*;
+import com.framsticks.gui.view.TreeCellRenderer;
+import com.framsticks.util.Dispatcher;
+import org.apache.log4j.Logger;
+
+import javax.swing.*;
+import javax.swing.event.TreeSelectionEvent;
+import javax.swing.event.TreeSelectionListener;
+import javax.swing.tree.*;
+import java.awt.*;
+import java.awt.event.ActionEvent;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @author Piotr Sniegowski
+ */
+public class Frame extends JFrame implements Dispatcher {
+
+    private static final Logger LOGGER = Logger.getLogger(Frame.class.getName());
+
+    protected final Browser browser;
+
+    protected final Dimension screenDimension = Toolkit.getDefaultToolkit().getScreenSize();
+
+
+    final protected CardLayout cardPanelLayout = new CardLayout();
+    protected final JPanel cardPanel = new JPanel();
+
+    protected JScrollPane treeScrollPane;
+    protected JTree tree;
+    protected DefaultTreeModel treeModel;
+    protected javax.swing.tree.MutableTreeNode rootNode;
+    //final Instance instance;
+    protected JPanel treePanel;
+    protected  JPopupMenu treePopupMenu;
+    protected JMenuItem treePopupMenuHeader;
+
+    TreeNode currentlyPoppedTreeNode;
+    protected JLabel statusBar;
+    protected JPanel mainPanel;
+    protected JPanel leftPanel;
+    protected JPanel normalWorkPanel;
+    protected CardLayout mainPanelLayout;
+
+    protected final Map<BrowserEndpoint, EndpointAtFrame> endpoints = new HashMap<BrowserEndpoint, EndpointAtFrame>();
+
+    public Frame(String title, Browser browser) {
+		super(title);
+        this.browser = browser;
+    }
+
+    public void configure() {
+
+        Container contentPane = this.getContentPane();
+        contentPane.setLayout(new BorderLayout());
+
+        treePopupMenu = new JPopupMenu("title");
+        treePopupMenu.setName("popup");
+        treePopupMenuHeader = new JMenuItem();
+        treePopupMenuHeader.setForeground(Color.BLUE);
+        treePopupMenu.add(treePopupMenuHeader);
+        treePopupMenu.addSeparator();
+        //TODO: add to favourites
+        //TODO: remove from favourites
+        //TODO: open in new window as root
+        //TODO: refresh
+        //TODO: open in console
+
+        treePopupMenu.add(new JMenuItem("Refresh"));
+        treePopupMenu.add(new JMenuItem("Open in new frame as root"));
+        //this.add(createMenuItem("Add to favourites", null));
+        //this.add(createMenuItem("Remove from favourites", null));
+
+        treePanel = new JPanel();
+        treePanel.setLayout(new BorderLayout());
+
+        treeModel = new DefaultTreeModel(null);
+
+        tree = new JTree(treeModel);
+        tree.setRootVisible(false);
+        ToolTipManager.sharedInstance().registerComponent(tree);
+
+        tree.addTreeSelectionListener(new TreeSelectionListener() {
+            @Override
+            public void valueChanged(TreeSelectionEvent e) {
+                chooseTreeNode(e.getNewLeadSelectionPath());
+            }
+        });
+
+        tree.setExpandsSelectedPaths(true);
+        tree.setEditable(false);
+        tree.setDoubleBuffered(true);
+        tree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
+        tree.setShowsRootHandles(true);
+        tree.setRowHeight(26);
+        tree.setDoubleBuffered(true);
+        tree.addMouseListener(new MouseAdapter() {
+            @Override
+            public void mousePressed(MouseEvent e) {
+                assert isActive();
+                showPopup(e);
+            }
+
+            @Override
+            public void mouseReleased(MouseEvent e) {
+                assert isActive();
+                showPopup(e);
+            }
+        });
+        tree.setCellRenderer(new TreeCellRenderer());
+
+        treeScrollPane = new JScrollPane(tree);
+        treeScrollPane.setBorder(BorderFactory.createEmptyBorder());
+
+        treePanel.add(treeScrollPane);
+
+        rootNode = new DefaultMutableTreeNode();
+        treeModel.setRoot(rootNode);
+
+        normalWorkPanel = new JPanel();
+        normalWorkPanel.setLayout(new BorderLayout());
+
+        mainPanel = new JPanel();
+        mainPanelLayout = new CardLayout();
+        mainPanel.setLayout(mainPanelLayout);
+        mainPanel.add(normalWorkPanel, "browser");
+
+        contentPane.add(createMenu(), BorderLayout.NORTH);
+        contentPane.add(mainPanel, BorderLayout.CENTER);
+        contentPane.add(statusBar, BorderLayout.SOUTH);
+
+        leftPanel = new JPanel();
+        leftPanel.setLayout(new BorderLayout());
+        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);
+
+        JSplitPane split = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, leftPanel, cardPanel);
+        split.setPreferredSize(new Dimension(this.browser.getConfig().getInteger("size.width", 1000), this.browser.getConfig().getInteger("size.height", 500)));
+        split.setMaximumSize(screenDimension);
+        split.setOneTouchExpandable(true);
+        split.setDividerLocation(250);
+        split.setDividerSize(5);
+
+        normalWorkPanel.add(split);
+
+        //this.setVisible(true);
+        mainPanelLayout.show(mainPanel, "browser");
+
+        cardPanel.setLayout(cardPanelLayout);
+
+		this.pack();
+		tree.requestFocusInWindow();
+
+    }
+
+    protected JMenuBar createMenu() {
+        return new JMenuBar();
+    }
+
+    protected JPanel createLeftTopPanel() {
+        return null;
+    }
+
+    public void repaintTree() {
+        //LOGGER.debug("repainting");
+        //tree.repaint();
+    }
+
+    public EndpointAtFrame getOrCreateEndpointAtFrame(BrowserEndpoint endpoint) {
+        assert isActive();
+        if (endpoints.containsKey(endpoint)) {
+            return endpoints.get(endpoint);
+        }
+        EndpointAtFrame e = new EndpointAtFrame(endpoint, this);
+        endpoints.put(endpoint, e);
+        return e;
+    }
+
+    public void addRootPath(BrowserEndpoint endpoint, Path path) {
+        assert isActive();
+        TreeNode node = new TreeNode(this, getOrCreateEndpointAtFrame(endpoint), path);
+        treeModel.insertNodeInto(node, rootNode, rootNode.getChildCount());
+        tree.expandPath(new TreePath(rootNode));
+    }
+
+    @Override
+    public boolean isActive() {
+        return SwingDispatcher.instance.isActive();
+    }
+
+    @Override
+    public void invokeLater(Runnable runnable) {
+        SwingDispatcher.instance.invokeLater(runnable);
+    }
+
+    public Action addActionToTreePopupMenu(Action action) {
+        assert isActive();
+        treePopupMenu.add(action);
+        return action;
+    }
+
+    public Action addNodeActionToTreePopupMenu(String title, final NodeAction nodeAction) {
+        assert isActive();
+        return addActionToTreePopupMenu(new AbstractAction(title) {
+            @Override
+            public void actionPerformed(ActionEvent e) {
+                TreeNode treeNode = getCurrentlyPoppedTreeNode();
+                if (treeNode == null) {
+                    return;
+                }
+                nodeAction.actionPerformed(treeNode);
+            }
+        });
+    }
+
+
+    public void showPanel(Panel panel) {
+        assert isActive();
+        assert panel != null;
+        cardPanelLayout.show(cardPanel, panel.getFullName());
+    }
+
+    private void showPopup(MouseEvent e) {
+        assert isActive();
+        if (!e.isPopupTrigger()) {
+            return;
+        }
+        currentlyPoppedTreeNode = findTreeNodeByTreePath(tree.getPathForLocation(e.getX(), e.getY()));
+        if (currentlyPoppedTreeNode == null) {
+            return;
+        }
+        treePopupMenu.show(e.getComponent(), e.getX(), e.getY());
+        //currentlyPoppedPanel.getNode().getFramsClass().getName()
+        //treePopupMenuHeader.setText(currentlyPoppedTreeNode.getNode().getPath());
+    }
+
+    public TreeNode getCurrentlyPoppedTreeNode() {
+        assert isActive();
+        return currentlyPoppedTreeNode;
+    }
+
+
+    public void clear() {
+        treeModel.setRoot(null);
+        cardPanel.removeAll();
+        cardPanel.updateUI();
+        tree.setEnabled(false);
+    }
+
+
+    public void markNodeChanged(MutableTreeNode treeNode, TreePath path) {
+        assert isActive();
+        treeModel.nodeStructureChanged(treeNode);
+        tree.setSelectionPath(path);
+        tree.repaint();
+    }
+
+    public TreePath startChange() {
+        return tree.getSelectionPath();
+    }
+
+
+    public void selectTreeNode(final TreeNode treeNode) {
+        assert isActive();
+/*		final Panel panel = treeNode.getOrCreatePanel();
+		if (panel == null) {
+			return;
+		}
+		panel.setCurrentTreeNode(treeNode);
+		treeNode.updateData();
+		showPanel(panel);*/
+    }
+
+    public TreeNode findTreeNodeByTreePath(TreePath treePath) {
+        assert isActive();
+        if (treePath == null) {
+            return null;
+        }
+        if (!(treePath.getLastPathComponent() instanceof TreeNode)) {
+            return null;
+        }
+        return (TreeNode)treePath.getLastPathComponent();
+    }
+
+
+
+    public void chooseTreeNode(TreePath treePath) {
+        assert isActive();
+        final TreeNode treeNode = findTreeNodeByTreePath(treePath);
+        if (treeNode == null) {
+            return;
+        }
+        treeNode.select();
+    }
+
+
+}
Index: java/main/src/main/java/com/framsticks/gui/ImageProvider.java
===================================================================
--- java/main/src/main/java/com/framsticks/gui/ImageProvider.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/gui/ImageProvider.java	(revision 77)
@@ -0,0 +1,93 @@
+/**
+ *
+ */
+package com.framsticks.gui;
+
+import org.apache.log4j.Logger;
+
+import javax.swing.*;
+import java.net.URL;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+
+/**
+ * Class provides icons images.
+ */
+public class ImageProvider {
+
+    private final static Logger LOGGER = Logger.getLogger(ImageProvider.class.getName());
+
+
+    /**
+	 * HashMap stores icons. Key is icon path, Value is icon.
+	 */
+	private static HashMap<String, ImageIcon> icons = new LinkedHashMap<String, ImageIcon>();
+
+	public static final String IMAGE = "image.png";
+	public static final String LOGO = "logo.png";
+
+	//public static final String FOLDER_OPEN = "folder_open.png";
+	//public static final String FOLDER_CLOSED = "folder_close.png";
+	//public static final String NODE = "node.png";
+
+	public static final String SERVER = "server.png";
+
+	public static final String CLI = "cli.png";
+	public static final String EVENT = "event.png";
+	public static final String SIMULATOR = "simulator.png";
+
+	public static final String WORLD = "World.png";
+	public static final String GENEPOOLS = "genepools.png";
+	public static final String GENEPOOLS_GROUP = "genepoolsgroup.png";
+	public static final String POPULATIONS = "populations.png";
+	public static final String POPULATION_GROUP = "populationgroup.png";
+	public static final String STATISTIC = "statistic.png";
+	public static final String EXPERIMENT = "experiment.png";
+
+	public static final String CREATURES_GROUP = "CreaturesGroup.png";
+	public static final String CREATURE = "Creature.png";
+
+	public static final String GENOTYPES_GROUP = "GenotypeGroup.png";
+	public static final String GENOTYPES = "Genotype.png";
+
+	public static final String JOINT_GROUP = "l_Joint.png";
+	public static final String JOINT = "Joint.png";
+	public static final String MECH_JOINT_GROUP = "l_MechJoint.png";
+	public static final String MECH_JOINT = "MechJoint.png";
+	public static final String PART_GROUP = "l_Part.png";
+	public static final String PART = "Part.png";
+	public static final String MECH_PART_GROUP = "l_MechPart.png";
+	public static final String MECH_PART = "MechPart.png";
+	public static final String NEURON_GROUP = "l_Neuro.png";
+	public static final String NEURON = "Neuro.png";
+	public static final String NEURON_DEF_GROUP = "l_NeuroDef.png";
+	public static final String NEURON_DEF = "NeuroDef.png";
+
+	public static final String FAVORITES = "stats.png";
+	public static final String FAVORITE_FIELDS = "FavouriteFields.png";
+
+	public static final String SIM_START = "sim_start.png";
+	public static final String SIM_STEP = "sim_step.png";
+	public static final String SIM_STOP = "sim_stop.png";
+
+	/**
+	 * Loads image icon with the given getName(path).
+	 *
+	 * @param imageName Name of the image(including extension) which will be loaded.
+	 * @return Loaded image.
+	 */
+	public static ImageIcon loadImage(final String imageName) {
+		if (icons.containsKey(imageName)) {
+			return icons.get(imageName);
+		}
+        String resourceName = "/shared/res/network/" + imageName;
+		try {
+            ImageIcon icon = new ImageIcon(ImageProvider.class.getResource(resourceName));
+			icons.put(imageName, icon);
+            return icon;
+		} catch (Exception ignored) {
+            LOGGER.error("failed to read icon: " + resourceName);
+		}
+		return null;
+	}
+}
Index: java/main/src/main/java/com/framsticks/gui/ListPanel.java
===================================================================
--- java/main/src/main/java/com/framsticks/gui/ListPanel.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/gui/ListPanel.java	(revision 77)
@@ -0,0 +1,110 @@
+package com.framsticks.gui;
+
+import com.framsticks.gui.view.TableModel;
+import com.framsticks.params.AccessInterface;
+import org.apache.log4j.Logger;
+
+import javax.swing.*;
+import javax.swing.table.TableColumn;
+
+/**
+ * Panel contains table and allows to manages displaying columns.
+ */
+@SuppressWarnings("serial")
+public class ListPanel extends Panel {
+
+	private static final Logger LOGGER = Logger.getLogger(ListPanel.class.getName());
+
+	final protected TableModel tableModel = new TableModel();
+	final protected JTable table = new JTable(tableModel);
+
+	public ListPanel(EndpointAtFrame endpoint) {
+		super(endpoint, "list");
+
+		table.getTableHeader().setReorderingAllowed(false);
+		table.setColumnSelectionAllowed(false);
+		table.setCellSelectionEnabled(false);
+		table.setColumnSelectionAllowed(false);
+
+		contentPanel.add(table);
+
+        /*
+		AccessInterface elementAccess = ((ListAccess)access).getElementAccess();
+		if (elementAccess == null) {
+			LOGGER.error("no type class");
+			return;
+		}
+		List<String> list = new ArrayList<String>();
+		addColumn(elementAccess.getId(), elementAccess.getId(), 0);
+		list.add(elementAccess.getId());
+		for (int p = 0; p < elementAccess.getParamCount(); ++p) {
+			Param param = elementAccess.getParam(p);
+			if (param.isUserHidden()) {
+				continue;
+			}
+			if (param instanceof CompositeParam) {
+				continue;
+			}
+			addColumn(param.getId(), param.getId(), 0);
+			list.add(param.getId());
+		}
+		tableModel.addRow(list.toArray());
+        */
+		/*
+		JMenuBar menuBar = new JMenuBar();
+		selectColumnMenu = new JMenu("Columns");
+		menuBar.add(selectColumnMenu);
+		createTable();
+		this.setLayout(new BorderLayout());
+		this.add(menuBar, BorderLayout.PAGE_START);
+		*/
+
+	}
+
+	/**
+	 * Adds column to table.
+	 *
+	 * @param columnName Name of column.
+	 * @param columnId   Column getId.
+	 * @param index      Column index.
+	 */
+	public void addColumn(String columnName, String columnId, int index) {
+		TableColumn tableColumn = new TableColumn();
+		tableColumn.setHeaderValue(columnName);
+		tableColumn.setIdentifier(columnId);
+		tableColumn.setModelIndex(index);
+		tableModel.addColumn(tableColumn);
+
+		//userColumnsConfig.addColumn(getPath(), columnId);
+	}
+
+	/**
+	 * Removes column from table.
+	 *
+	 * @param columnId Id of column.
+	 */
+	public void removeColumn(String columnId) {
+		tableModel.removeColumn(columnId);
+		//userColumnsConfig.removeColumn(getPath(), columnId);
+	}
+
+	/**
+	 * Clears table.
+	 */
+	public void clearTable() {
+		tableModel.setRowCount(0);
+	}
+
+	public void refreshTable() {
+		clearTable();
+	}
+
+	@Override
+	protected void applyChanges() {
+	}
+
+	@Override
+	public void refreshComponents(AccessInterface access) {
+
+	}
+}
Index: java/main/src/main/java/com/framsticks/gui/MainFrame.java
===================================================================
--- java/main/src/main/java/com/framsticks/gui/MainFrame.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/gui/MainFrame.java	(revision 77)
@@ -0,0 +1,322 @@
+package com.framsticks.gui;
+
+import com.framsticks.gui.components.Control;
+import com.framsticks.gui.view.*;
+import com.framsticks.gui.windows.console.ConsoleFrame;
+import org.apache.log4j.Logger;
+
+import javax.swing.*;
+import javax.swing.border.TitledBorder;
+import java.awt.*;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+
+/**
+ * Application Main Frame.
+ */
+public class MainFrame extends Frame {
+
+	private final static Logger LOGGER = Logger.getLogger(MainFrame.class.getName());
+
+	JButton start, stop, step;
+
+	/**
+	 * Builds main frame.
+	 */
+	public MainFrame(final Browser browser) {
+		super("Framsticks Network Client", browser);
+		LOGGER.debug("creating main frame");
+
+		statusBar = new JLabel("not connected");
+
+
+	}
+
+	@Override
+	public void configure() {
+		super.configure();
+		setFrameProperties();
+	}
+
+	private void onConnectionEstablished() {
+        assert isActive();
+
+        addNodeActionToTreePopupMenu("Open in console", new NodeAction() {
+            @Override
+            public void actionPerformed(TreeNode treeNode) {
+                assert isActive();
+                //showConsoleFrame().setCommandLine("info " + treeNode.getNode().getPath());
+            }
+        });
+
+
+
+/*
+        browser.addNodeActionToTreePopupMenu("Resolve recursively", new NodeAction() {
+            @Override
+            public void actionPerformed(TreeNode treeNode) {
+                final Child child = treeNode.getChild();
+                //server.invokeLater(new Runnable() {
+                    @Override
+                    public void run() {
+                        resolveRecursively(child);
+                    }
+                });
+            }
+        });
+*/
+
+        addNodeActionToTreePopupMenu("Store in file", new NodeAction() {
+            @Override
+            public void actionPerformed(final TreeNode treeNode) {
+
+/*
+                final Node node = treeNode.getNode();
+                server.invokeLater(new Runnable() {
+                    @Override
+                    public void run() {
+                        try {
+                            LOGGER.info("storing");
+                            //File file = new File();
+                            PrintStream file = new PrintStream("/home/piotr/Desktop/test.param");
+                            StoreStream stream = new StoreStream(file, server.getManager());
+                            stream.store(node);
+
+                        } catch (FileNotFoundException e) {
+                            e.printStackTrace();
+                        }
+                    }
+                });
+*/
+            }
+        });
+
+/*
+        arguments.forEach("resolve", new UnaryFunctor<Boolean, String>() {
+            @Override
+            public Boolean call(final String s) {
+                server.getManager().resolvePath(s, new StateFunctor() {
+                    @Override
+                    public void call(Exception e) {
+                        if (e != null) {
+                            LOGGER.error("failed to resolve: " + s);
+                            return;
+                        }
+                        LOGGER.info("succeeded to resolve: " + s);
+
+                    }
+                });
+                return true;
+            }
+        });
+*/
+
+        /*
+        arguments.forEach("console", new UnaryFunctor<Boolean, String>() {
+			@Override
+			public Boolean call(String s) {
+				showConsoleFrame().setCommandLine(s);
+				return true;
+			}
+		});
+		*/
+	}
+
+	public void setSimulationRunning(final boolean run) {
+        assert isActive();
+        /*
+        remoteInstance.invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                remoteInstance.setRunning(run);
+            }
+        });
+        */
+	}
+
+	/**
+	 * Creates panel with start, step, stop buttons.
+	 */
+    @Override
+	protected JPanel createLeftTopPanel() {
+        assert isActive();
+        Dimension buttonDimension = new Dimension(45, 45);
+
+		JPanel panel = new JPanel();
+
+		stop = new JButton(ImageProvider.loadImage(ImageProvider.SIM_STOP));
+		stop.addActionListener(new ActionListener() {
+
+			public void actionPerformed(ActionEvent e) {
+				setSimulationRunning(false);
+			}
+
+		});
+
+		stop.setPreferredSize(buttonDimension);
+		stop.setToolTipText("Simulation Stop");
+		stop.setEnabled(false);
+
+		step = new JButton(ImageProvider.loadImage(ImageProvider.SIM_STEP));
+        /*
+		step.addActionListener(new ActionListener() {
+
+			public void actionPerformed(ActionEvent e) {
+				connection.send(new CallQuery().setMethod("step").setPath("/simulator"));
+			}
+
+		});
+		*/
+
+		step.setPreferredSize(buttonDimension);
+		step.setToolTipText("Simulation Step");
+
+		start = new JButton(ImageProvider.loadImage(ImageProvider.SIM_START));
+		start.addActionListener(new ActionListener() {
+
+			public void actionPerformed(ActionEvent e) {
+				setSimulationRunning(true);
+			}
+
+		});
+
+		start.setPreferredSize(buttonDimension);
+		start.setToolTipText("Start Simulation");
+
+		JPanel buttonPanel = new JPanel();
+		buttonPanel.setLayout(new BoxLayout(buttonPanel, BoxLayout.LINE_AXIS));
+		buttonPanel.add(Box.createHorizontalStrut(5));
+		buttonPanel.add(stop);
+		buttonPanel.add(Box.createHorizontalStrut(10));
+		buttonPanel.add(step);
+		buttonPanel.add(Box.createHorizontalStrut(10));
+		buttonPanel.add(start);
+		buttonPanel.add(Box.createHorizontalStrut(5));
+
+		buttonPanel.setBorder(BorderFactory.createTitledBorder(BorderFactory
+				.createRaisedBevelBorder(), "Simulation Control",
+				TitledBorder.CENTER, TitledBorder.DEFAULT_POSITION
+				));
+
+		panel.setLayout(new BoxLayout(panel, BoxLayout.LINE_AXIS));
+		panel.add(Box.createHorizontalGlue());
+		panel.add(buttonPanel);
+		panel.add(Box.createHorizontalGlue());
+		return panel;
+	}
+
+	/**
+	 * Sets frame properties.
+	 */
+	private void setFrameProperties() {
+        assert isActive();
+        setMinimumSize(this.getPreferredSize());
+		setSize(this.getPreferredSize());
+		setMaximumSize(screenDimension);
+		setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
+
+		setIconImage(ImageProvider.loadImage(ImageProvider.LOGO)
+				.getImage());
+
+
+		addWindowListener(new WindowAdapter() {
+			public void windowClosing(WindowEvent e) {
+                assert isActive();
+                /*
+                if (connection != null) {
+					connection.close();
+				}
+				*/
+				onWindowClosing();
+				dispose();
+			}
+		});
+	}
+
+	public ConsoleFrame showConsoleFrame() {
+        assert isActive();
+        /*
+        ConsoleFrame consoleFrame = new ConsoleFrame(connection);
+		consoleFrame.show(MainFrame.this);
+		return consoleFrame;
+		*/
+        return null;
+	}
+
+	/**
+	 * Creates menu bar.
+	 *
+	 * @return JMenuBar Menu bar.
+	 */
+    @Override
+	protected JMenuBar createMenu() {
+        assert isActive();
+        final JMenuBar menuBar = new JMenuBar();
+		final JMenu menu = new JMenu("Main");
+
+		final JMenuItem consoleItem = new JMenuItem("Console");
+		consoleItem.addActionListener(new ActionListener() {
+
+			public void actionPerformed(ActionEvent e) {
+				showConsoleFrame();
+			}
+
+		});
+
+        /*
+		final JMenuItem serverLogItem = new JMenuItem("Sever Log");
+		serverLogItem.addActionListener(new ActionListener() {
+
+			public void actionPerformed(ActionEvent e) {
+				serverLogFrame.show(MainFrame.this);
+			}
+
+		});
+		*/
+
+		final JMenuItem disconnectItem = new JMenuItem("Disconnect");
+		disconnectItem.addActionListener(new ActionListener() {
+
+			public void actionPerformed(ActionEvent e) {
+				disconnect();
+			}
+		});
+
+		/** @todo do something proper with UI on close */
+		menu.add(consoleItem);
+		//menu.add(serverLogItem);
+		menu.add(disconnectItem);
+		menuBar.add(menu);
+		return menuBar;
+	}
+
+	/**
+	 * Closes connection with manager.
+	 */
+	private void disconnect() {
+        assert isActive();
+        //remoteInstance.disconnect();
+		browser.clear();
+		onWindowClosing();
+		statusBar.setText("You are disconnected");
+	}
+
+	/**
+	 * Method used while window is closing.
+	 */
+	private void onWindowClosing() {
+        assert isActive();
+
+	}
+
+	public void setRunningButtons(boolean running) {
+        assert isActive();
+        step.setEnabled(!running);
+		stop.setEnabled(running);
+		start.setEnabled(!running);
+	}
+
+}
+
Index: java/main/src/main/java/com/framsticks/gui/ObjectPanel.java
===================================================================
--- java/main/src/main/java/com/framsticks/gui/ObjectPanel.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/gui/ObjectPanel.java	(revision 77)
@@ -0,0 +1,155 @@
+package com.framsticks.gui;
+
+import com.framsticks.gui.components.Control;
+import com.framsticks.gui.components.ValueControl;
+import com.framsticks.gui.components.ValueControlListener;
+import com.framsticks.params.AccessInterface;
+import com.framsticks.params.types.CompositeParam;
+import com.framsticks.params.Param;
+import com.framsticks.util.Strings;
+import org.apache.log4j.Logger;
+
+import javax.swing.*;
+import java.awt.*;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.List;
+
+@SuppressWarnings("serial")
+public class ObjectPanel extends com.framsticks.gui.Panel {
+
+	private static final Logger LOGGER = Logger.getLogger(ObjectPanel.class.getName());
+
+	final protected Map<Param, Control> components = new HashMap<Param, Control>();
+	final protected Map<Param, ValueControl> valueComponents = new HashMap<Param, ValueControl>();
+
+	public static void fillWithComponents(JPanel panel, Collection<Param> params, Map<Param, Control> components) {
+		for (Param param : params) {
+			if (param.isUserHidden()) {
+				continue;
+			}
+			assert !(param instanceof CompositeParam);
+			Control control = Control.createSuitable(param);
+			if (control != null) {
+				LOGGER.debug("add component for " + param);
+				JPanel line = new JPanel();
+				line.setLayout(new BoxLayout(line, BoxLayout.LINE_AXIS));
+				line.setAlignmentX(LEFT_ALIGNMENT);
+				JLabel label = new JLabel(Strings.notEmpty(param.getName()) ? param.getName() : "? (" + param.getId() + ")");
+				label.setToolTipText(label.getText());
+				label.setHorizontalAlignment(JLabel.RIGHT);
+				Dimension labelSize = new Dimension(150, 30);
+				label.setMaximumSize(labelSize);
+				label.setMinimumSize(labelSize);
+				label.setPreferredSize(labelSize);
+				line.add(label);
+				line.add(Box.createRigidArea(new Dimension(8, 0)));
+				line.add(control);
+				line.revalidate();
+				panel.add(line);
+				panel.add(Box.createRigidArea(new Dimension(0, 8)));
+				//component.setAlignmentX(LEFT_ALIGNMENT);
+				components.put(param, control);
+				continue;
+			}
+			LOGGER.error("component for param " + param + " of type " + param.getClass().getSimpleName() + " was not added");
+		}
+
+	}
+
+	public ObjectPanel(EndpointAtFrame endpoint, String className, List<Param> params) {
+		super(endpoint, className);
+
+		fillWithComponents(contentPanel, params, components);
+
+		for (Map.Entry<Param, Control> e : components.entrySet()) {
+			Control control = e.getValue();
+			Param param = e.getKey();
+			if (control instanceof ValueControl) {
+				final ValueControl valueComponent = (ValueControl) control;
+				valueComponents.put(param, valueComponent);
+				valueComponent.setListener(new ValueControlListener() {
+					@Override
+					public boolean onChange(Object newValue) {
+						if (currentTreeNode == null) {
+							return true;
+						}
+						boolean result = currentTreeNode.changeValue(valueComponent, newValue);
+						refreshControlButtons();
+						return result;
+					}
+				});
+			}
+		}
+		contentPanel.add(Box.createVerticalGlue());
+		this.revalidate();
+	}
+
+	@Override
+	protected void applyChanges() {
+		assert frame.isActive();
+		assert currentTreeNode != null;
+		currentTreeNode.applyChanges();
+	}
+
+	protected void refreshControlButtons() {
+		assert frame.isActive();
+		applyButton.setEnabled(currentTreeNode.changedValues != null);
+	}
+
+	@Override
+	public void refreshComponents(AccessInterface access) {
+        assert currentTreeNode.path.getInstance().isActive();
+        assert currentTreeNode != null;
+        LOGGER.debug("refreshing components");
+
+        final Map<ValueControl, Object> values = new HashMap<ValueControl, Object>();
+        for (ValueControl vc : valueComponents.values()) {
+            Object value = access.get(vc.getParam().getId(), Object.class);
+            values.put(vc, value);
+        }
+
+        frame.invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                for (Map.Entry<ValueControl, Object> e : values.entrySet()) {
+                    e.getKey().setValue(e.getValue());
+                }
+				if (currentTreeNode.changedValues != null) {
+					for (Map.Entry<ValueControl, Object> e : currentTreeNode.changedValues.entrySet()) {
+						e.getKey().setValue(e.getValue());
+					}
+				}
+				refreshControlButtons();
+                ObjectPanel.this.revalidate();
+            }
+        });
+
+	}
+
+
+
+/*	public void updateValue() {
+		//assert panel.getFrame().isActive();
+
+        final Node n = panel.getCurrentNode();
+        panel.getBrowser().getManager().invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                Object v = n.getAccess().get(param, Object.class);
+                if (v == null) {
+                    v = param.getDef(Object.class);
+                }
+                final Object fv = v;
+                panel.getBrowser().invokeLater(new Runnable() {
+                    @Override
+                    public void run() {
+                        setValueImpl(fv);
+                    }
+                });
+            }
+        });
+	}*/
+
+}
Index: java/main/src/main/java/com/framsticks/gui/Panel.java
===================================================================
--- java/main/src/main/java/com/framsticks/gui/Panel.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/gui/Panel.java	(revision 77)
@@ -0,0 +1,104 @@
+package com.framsticks.gui;
+
+import com.framsticks.params.AccessInterface;
+import org.apache.log4j.Logger;
+
+import javax.swing.*;
+import java.awt.*;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+
+/**
+ * @author Piotr Sniegowski
+ */
+public abstract class Panel extends JPanel {
+
+	private static final Logger LOGGER = Logger.getLogger(Panel.class.getName());
+
+	/**
+	 * Pane to which components will be added.
+	 */
+	protected JPanel contentPanel;
+
+	protected TreeNode currentTreeNode;
+    protected EndpointAtFrame endpoint;
+    protected final Frame frame;
+	protected final String className;
+	final protected JLabel label;
+	final protected JButton applyButton;
+
+	public Panel(EndpointAtFrame endpoint, String className) {
+        this.endpoint = endpoint;
+		this.frame = endpoint.getFrame();
+		this.className = className;
+		LOGGER.debug("create panel for type: " + className);
+
+        endpoint.registerPanel(this);
+
+		contentPanel = new JPanel();
+		contentPanel.setLayout(new BoxLayout(contentPanel, BoxLayout.PAGE_AXIS));
+		JScrollPane scroll = new JScrollPane(contentPanel);
+		//scroll.setBorder(BorderFactory.createEtchedBorder());
+
+		JPanel pageEndPanel = new JPanel();
+		pageEndPanel.setLayout(new BoxLayout(pageEndPanel, BoxLayout.X_AXIS));
+		pageEndPanel.add(Box.createHorizontalGlue());
+
+		applyButton = new JButton("Apply");
+		applyButton.addActionListener(new ActionListener() {
+			public void actionPerformed(ActionEvent e) {
+				applyChanges();
+			}
+		});
+		pageEndPanel.add(applyButton);
+
+		pageEndPanel.add(Box.createHorizontalStrut(10));
+		pageEndPanel.setPreferredSize(new Dimension(0, 30));
+
+		label = new JLabel();
+		JPanel centerPanel = new JPanel();
+		centerPanel.setLayout(new BorderLayout());
+		centerPanel.add(Box.createHorizontalStrut(10), BorderLayout.LINE_START);
+		centerPanel.add(Box.createHorizontalStrut(10), BorderLayout.LINE_END);
+		centerPanel.add(label, BorderLayout.PAGE_START);
+		centerPanel.add(scroll, BorderLayout.CENTER);
+		centerPanel.add(pageEndPanel, BorderLayout.PAGE_END);
+
+		this.setLayout(new BorderLayout());
+		this.add(centerPanel, BorderLayout.CENTER);
+
+
+	}
+
+	public void setCurrentTreeNode(TreeNode node) {
+		currentTreeNode = node;
+		//label.setText(node.getNode().getPath());
+		//this.revalidate();
+	}
+
+	public TreeNode getCurrentTreeNode() {
+		return currentTreeNode;
+	}
+
+	protected abstract void applyChanges();
+	public abstract void refreshComponents(AccessInterface access);
+
+	@Override
+	public String toString() {
+		return currentTreeNode == null ? "?" : currentTreeNode.toString();
+	}
+
+    public final Frame getFrame() {
+        return frame;
+    }
+
+
+    public final String getClassName() {
+        return className;
+    }
+
+    public final String getFullName() {
+        return className + "@" + endpoint.getName();
+    }
+
+}
Index: java/main/src/main/java/com/framsticks/gui/SwingDispatcher.java
===================================================================
--- java/main/src/main/java/com/framsticks/gui/SwingDispatcher.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/gui/SwingDispatcher.java	(revision 77)
@@ -0,0 +1,36 @@
+package com.framsticks.gui;
+
+import com.framsticks.util.Dispatcher;
+import com.framsticks.util.Task;
+
+import javax.swing.*;
+import java.awt.*;
+
+/**
+ * @author Piotr Sniegowski
+ */
+public class SwingDispatcher implements Dispatcher {
+
+    public static final SwingDispatcher instance = new SwingDispatcher();
+
+    public SwingDispatcher() {
+        invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                Thread.currentThread().setName("gui");
+            }
+        });
+    }
+
+    @Override
+    public final boolean isActive() {
+        return SwingUtilities.isEventDispatchThread();
+    }
+
+    @Override
+    public final void invokeLater(Runnable runnable) {
+        assert !(runnable instanceof Task);
+        SwingUtilities.invokeLater(runnable);
+    }
+
+}
Index: java/main/src/main/java/com/framsticks/gui/TreeNode.java
===================================================================
--- java/main/src/main/java/com/framsticks/gui/TreeNode.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/gui/TreeNode.java	(revision 77)
@@ -0,0 +1,532 @@
+package com.framsticks.gui;
+
+import com.framsticks.communication.Subscription;
+import com.framsticks.communication.util.LoggingStateCallback;
+import com.framsticks.core.ListChange;
+import com.framsticks.core.Path;
+import com.framsticks.gui.components.ValueControl;
+import com.framsticks.gui.view.TreeCellRenderer;
+import com.framsticks.params.AccessInterface;
+import com.framsticks.params.Param;
+import com.framsticks.params.types.*;
+import com.framsticks.remote.*;
+import com.framsticks.util.Casting;
+import com.framsticks.util.Future;
+import com.framsticks.util.Logging;
+import com.framsticks.util.StateFunctor;
+import org.apache.log4j.Logger;
+
+import javax.swing.tree.DefaultMutableTreeNode;
+import javax.swing.tree.TreePath;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author Piotr Sniegowski
+ */
+public class TreeNode extends DefaultMutableTreeNode implements NodeListener {
+
+	private static final Logger LOGGER = Logger.getLogger(TreeNode.class.getName());
+
+	Panel panel;
+
+	final protected Frame frame;
+    final protected EndpointAtFrame endpoint;
+
+    final protected Map<EventParam, Subscription> userSubscriptions = new HashMap<EventParam, Subscription>();
+	protected Map<ValueControl, Object> changedValues = null;
+    protected String tooltip;
+    protected String name;
+    protected String iconName;
+    protected Path path;
+
+
+    public TreeNode(Frame frame, EndpointAtFrame endpoint, final Path path) {
+        assert frame.isActive();
+        this.frame = frame;
+		LOGGER.debug("creating treenode for: " + path);
+        this.path = path;
+        this.endpoint = endpoint;
+
+        name = path.getTop().getParam().getId();
+        iconName = TreeCellRenderer.findIconName(name, path.getTextual());
+        tooltip = "?";
+        path.getInstance().invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                updateDescriptions(path);
+            }
+        });
+	}
+
+    public void fetch(final Path p) {
+        assert p.getInstance().isActive();
+        LOGGER.debug("fetching: " + p);
+        p.getInstance().fetchValues(p, new StateFunctor() {
+            @Override
+            public void call(Exception e) {
+                assert p.getInstance().isActive();
+                if (Logging.log(LOGGER, "fetch", TreeNode.this, e)) {
+                    frame.invokeLater(new Runnable() {
+                        @Override
+                        public void run() {
+                            LOGGER.debug("removing node from tree: " + p);
+                            TreeNode.this.removeFromParent();
+                            frame.repaintTree();
+                        }
+                    });
+                    return;
+                }
+                updateChildren(p);
+                frame.invokeLater(new Runnable() {
+                    @Override
+                    public void run() {
+                        //TODO maybe this should be called from some better place
+                        useOrCreatePanel();
+                    }
+                });
+
+            }
+        });
+    }
+
+    protected void postUpdatePath(final Path newPath) {
+        assert !frame.isActive();
+        /** TODO those two actions could be merged into single closure */
+        frame.invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                updatePath(newPath);
+            }
+        });
+        updateDescriptions(newPath);
+    }
+
+    protected void updatePath(Path newPath) {
+        assert frame.isActive();
+        if (!path.isResolved()) {
+            path = newPath;
+			LOGGER.debug("updated treenode's path: " + path);
+            return;
+        }
+        if (path.matches(newPath)) {
+            return;
+        }
+        this.removeAllChildren();
+    }
+
+    /** Update children, by removing non existing and adding new ones.
+     */
+    protected void updateChildren(final Path p) {
+        assert p.getInstance().isActive();
+        LOGGER.debug("updating children of " + this);
+        AccessInterface access = p.getInstance().bindAccess(p.getTop());
+        final List<Path> childrenPaths = new LinkedList<Path>();
+        /**Prepare path for each child.*/
+        for (Param param : access.getParams()) {
+            if (!(param instanceof CompositeParam)) {
+                continue;
+            }
+            Path childPath = p.appendParam((CompositeParam)param);
+            childrenPaths.add(childPath);
+        }
+        /**If some child were found, update in frame context.*/
+        if (childrenPaths.size() > 0) {
+            frame.invokeLater(new Runnable() {
+                @Override
+                public void run() {
+                    TreePath treePath = frame.startChange();
+                    updatePath(p);
+                    Map<String, TreeNode> current = new HashMap<String, TreeNode>();
+                    for (int c = 0; c < TreeNode.this.getChildCount(); ++c) {
+                        TreeNode n = (TreeNode)TreeNode.this.getChildAt(c);
+                        current.put(n.path.getLastElement(), n);
+                    }
+                    for (final Path childPath : childrenPaths) {
+                        String e = childPath.getLastElement();
+                        if (current.containsKey(e)) {
+                            /*
+                            final TreeNode n = current.get(e);
+                            childPath.getInstance().invokeLater(new Runnable() {
+                                @Override
+                                public void run() {
+                                    n.updateChildren(childPath);
+                                }
+                            });
+                            */
+                            current.remove(e);
+                            continue;
+                        }
+                        TreeNode childNode = new TreeNode(frame, endpoint, childPath);
+                        TreeNode.this.add(childNode);
+                    }
+                    for (TreeNode n : current.values()) {
+                        TreeNode.this.remove(n);
+                    }
+                    frame.markNodeChanged(TreeNode.this, treePath);
+                    frame.repaintTree();
+                    LOGGER.debug("updated children of " + TreeNode.this);
+                }
+            });
+        } else {
+            LOGGER.debug("no children in " + TreeNode.this);
+        }
+    }
+
+    public void select() {
+        final Path p = path;
+
+        p.getInstance().invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                final Path updated = (p.isResolved()) ? p : p.findResolution();
+                if (updated.isResolved()) {
+                    Logging.log(LOGGER, "update", updated, null);
+                    fetch(updated);
+                    postUpdatePath(updated);
+                    return;
+                }
+                p.getInstance().resolve(updated, new Future<Path>() {
+                    @Override
+                    public void result(final Path result, Exception e) {
+                        if (Logging.log(LOGGER, "resolve and select", TreeNode.this, e)) {
+                            return;
+                        }
+
+                        fetch(result);
+                        postUpdatePath(result);
+                    }
+                });
+            }
+        });
+
+    }
+
+    @Override
+    public String toString() {
+        return path.toString();
+    }
+
+
+	public final Panel getPanel() {
+        assert frame.isActive();
+		return panel;
+	}
+
+    protected void updateDescriptions(final Path p) {
+        assert p.getInstance().isActive();
+        if (!p.isResolved()) {
+            return;
+        }
+        AccessInterface access = p.getInstance().bindAccess(p);
+        assert access != null;
+        StringBuilder t = new StringBuilder();
+        /** html formatting is used here, since tooltips in swing do not support simple \n line breaks */
+        t.append("<html>");
+        t.append("frams: ").append(access.getId()).append("<br/>");
+        t.append("java: ").append(p.getTopObject().getClass().getCanonicalName()).append("<br/>");
+        t.append("access: ").append(access.getClass().getSimpleName());
+        t.append("</html>");
+        final String tooltip = t.toString();
+
+        StringParam nameParam = Casting.tryCast(StringParam.class, access.getParam("name"));
+        final String name = (nameParam != null ? access.get(nameParam, String.class) : path.getTop().getParam().getId());
+
+        frame.invokeLater(new Runnable() {
+            @Override
+            public void run() {
+
+                TreeNode.this.tooltip = tooltip;
+                TreeNode.this.name = name;
+            }
+        });
+    }
+
+/*
+	public void updateData() {
+        assert browser.isActive();
+		final Node node = getNode();
+        browser.manager.invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                node.fetchValues(new StateFunctor() {
+                    @Override
+                    public void call(Exception e) {
+                        if (e != null) {
+                            return;
+                        }
+                        browser.invokeLater(new Runnable() {
+                            @Override
+                            public void run() {
+                                assert browser.isActive();
+                                if (panel.getCurrentTreeNode() == TreeNode.this) {
+                                    panel.refreshComponents();
+                                }
+
+                                browser.tree.repaint();
+                                panel.refreshComponents();
+                            }
+                        });
+                    }
+                });
+            }
+        });
+	}
+*/
+
+    public void showPanel() {
+        assert frame.isActive();
+        assert panel != null;
+        frame.showPanel(panel);
+    }
+
+    public void fillPanelWithValues() {
+        assert frame.isActive();
+        final Path p = path;
+        assert p.isResolved();
+        assert panel != null;
+        panel.setCurrentTreeNode(this);
+        p.getInstance().invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                AccessInterface access = p.getInstance().bindAccess(p);
+                panel.refreshComponents(access);
+
+                frame.invokeLater(new Runnable() {
+                    @Override
+                    public void run() {
+                        showPanel();
+                    }
+                });
+            }
+        });
+
+    }
+
+	public void useOrCreatePanel() {
+        assert frame.isActive();
+		if (panel != null) {
+            LOGGER.trace("panel is already attached: " + path);
+            fillPanelWithValues();
+			return;
+		}
+        if (!path.isResolved()) {
+            LOGGER.trace("path is not resolved: " + path);
+            return;
+        }
+
+        CompositeParam param = path.getTop().getParam();
+        panel = endpoint.findPanel(param.computeAccessId());
+        if (panel != null) {
+            LOGGER.debug("found prepared panel for: " + path);
+            fillPanelWithValues();
+            return;
+        }
+        final Path p = path;
+        LOGGER.debug("preparing panel: " + p);
+        p.getInstance().invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                assert p.getInstance().isActive();
+                final CompositeParam param = p.getTop().getParam();
+                if (param instanceof ObjectParam) {
+                    AccessInterface access = p.getInstance().prepareAccess(param);
+                    final List<Param> params = new LinkedList<Param>();
+                    for (Param p : access.getParams()) {
+                        if (p instanceof CompositeParam) {
+                            continue;
+                        }
+                        params.add(p);
+                    }
+                    frame.invokeLater(new Runnable() {
+                        @Override
+                        public void run() {
+                            panel = new ObjectPanel(endpoint, param.getContainedTypeName(), params);
+                            fillPanelWithValues();
+                        }
+                    });
+                    return;
+                }
+                if (param instanceof ListParam) {
+					frame.invokeLater(new Runnable() {
+						@Override
+						public void run() {
+							panel = new ListPanel(endpoint);
+							fillPanelWithValues();
+						}
+					});
+					return;
+                    //return panel = new ListPanel(browser, access);
+                }
+                assert false;
+            }
+        });
+	}
+
+    public String getTooltip() {
+        assert frame.isActive();
+        return tooltip;
+    }
+
+
+
+
+    /*public void subscribe(final EventParam eventParam) {
+        assert browser.isActive();
+        if (hasSubscribed(eventParam)) {
+            LOGGER.error(eventParam + " is already subscribed for " + this);
+            return;
+        }
+        Node node = getNode();
+        node.getConnection().subscribe(node.getPath() + "/" + eventParam.getId(), new SubscriptionCallback() {
+            @Override
+            public EventCallback subscribed(final Subscription subscription) {
+                if (subscription == null) {
+                    LOGGER.error("subscription failed");
+                    return null;
+                }
+                if (hasSubscribed(eventParam)) {
+                    //abort subscription
+                    return null;
+                }
+                userSubscriptions.put(eventParam, subscription);
+                LOGGER.debug("subscription succeeded: " + subscription);
+                subscription.setDispatcher(browser);
+                return new EventCallback() {
+                    @Override
+                    public void call(SourceInterface content) {
+                        assert browser.isActive();
+                        LOGGER.info("event " + subscription + " occurred");
+                    }
+                };
+            }
+        });
+
+    }*/
+
+    public boolean hasSubscribed(EventParam param) {
+        assert frame.isActive();
+        return userSubscriptions.containsKey(param);
+    }
+
+    public void unsubscribe(EventParam eventParam) {
+        assert frame.isActive();
+        if (!hasSubscribed(eventParam)) {
+            LOGGER.error("could not unsubscribe from " + eventParam);
+            return;
+        }
+        userSubscriptions.get(eventParam).unsubscribe(new LoggingStateCallback(LOGGER, "unsubscribed " + eventParam));
+        userSubscriptions.remove(eventParam);
+    }
+
+/*
+
+    @Override
+    public void onChildChange(final Child child, ListChange.Action action) {
+        assert browser.manager.isActive();
+
+        switch (action) {
+            case Remove: {
+                Dispatching.invokeDispatch(browser, browser.manager, new Runnable() {
+                    @Override
+                    public void run() {
+                        assert browser.manager.isActive();
+                        final TreeNode treeNode = (TreeNode) child.getUserObject();
+                        if (treeNode == null) {
+                            LOGGER.error("child " + child + " had no tree node attached");
+                            return;
+                        }
+                        browser.invokeLater(new Runnable() {
+                            @Override
+                            public void run() {
+                                assert browser.isActive();
+                                TreePath path = browser.startChange();
+                                //assert treeNode.getParent() == TreeNode.this;
+                                if (treeNode.getParent() != null) {
+                                    browser.treeModel.removeNodeFromParent(treeNode);
+                                }
+                                //remove(treeNode);
+                                browser.markNodeChanged(TreeNode.this, path);
+                            }
+                        });
+                    }
+                });
+                break;
+            }
+        }
+
+    }
+*/
+
+    public String getName() {
+        return name;
+    }
+
+    public String getIconName() {
+        return iconName;
+    }
+
+    @Override
+    public void onUpgrade(Path path) {
+    }
+
+    @Override
+    public void onChange(Path path) {
+    }
+
+    @Override
+    public void onChildChange(Path path, ListChange.Action action) {
+    }
+
+    public final Frame getFrame() {
+        return frame;
+    }
+
+	public boolean changeValue(ValueControl component, Object newValue) {
+		LOGGER.debug("changing value of " + component + " to '" + newValue + "'");
+
+		if (changedValues == null) {
+			changedValues = new HashMap<ValueControl, Object>();
+		}
+		changedValues.put(component, newValue);
+
+		return true;
+	}
+
+	public void applyChanges() {
+		assert frame.isActive();
+		if (changedValues == null) {
+			return;
+		}
+		final Map<ValueControl, Object> changes = changedValues;
+		changedValues = null;
+		endpoint.getEndpoint().invokeLater(new Runnable() {
+			@Override
+			public void run() {
+				for (Map.Entry<ValueControl, Object> e : changes.entrySet()) {
+					final ValueControl key = e.getKey();
+					final Path p = path;
+					endpoint.getEndpoint().getInstance().storeValue(p, e.getKey().getParam(), e.getValue(), new StateFunctor() {
+						@Override
+						public void call(Exception e) {
+							changes.remove(key);
+							if (!changes.isEmpty()) {
+								return;
+							}
+							LOGGER.debug("applied changes for: " + p);
+							frame.invokeLater(new Runnable() {
+								@Override
+								public void run() {
+									fillPanelWithValues();
+								}
+							});
+						}
+					});
+				}
+			}
+		});
+	}
+
+}
Index: java/main/src/main/java/com/framsticks/gui/components/CheckBoxControl.java
===================================================================
--- java/main/src/main/java/com/framsticks/gui/components/CheckBoxControl.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/gui/components/CheckBoxControl.java	(revision 77)
@@ -0,0 +1,47 @@
+package com.framsticks.gui.components;
+
+import com.framsticks.params.types.BooleanParam;
+import org.apache.log4j.Logger;
+
+import javax.swing.*;
+import java.awt.*;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+
+@SuppressWarnings("serial")
+public class CheckBoxControl extends ValueControl {
+
+	private static final Logger LOGGER = Logger.getLogger(CheckBoxControl.class.getName());
+
+	private JCheckBox checkBox;
+
+	public CheckBoxControl(BooleanParam booleanParam) {
+		super(booleanParam);
+		checkBox = new JCheckBox();
+        checkBox.setEnabled(!isReadOnly());
+		checkBox.addActionListener(new ActionListener() {
+
+			@Override
+			public void actionPerformed(ActionEvent actionEvent) {
+				LOGGER.debug("change to: " + checkBox.isSelected());
+				notifyOfChange();
+			}
+		});
+		this.setMaximumSize(new Dimension(Integer.MAX_VALUE, Control.LINE_HEIGHT));
+		addAsOnlyChild(checkBox);
+	}
+
+	@Override
+	public void setValueImpl(Object value) {
+		if (value == null) {
+			return;
+		}
+		checkBox.setSelected((Boolean) value);
+	}
+
+	@Override
+	public Object getValue() {
+		return checkBox.isSelected();
+	}
+
+}
Index: java/main/src/main/java/com/framsticks/gui/components/Control.java
===================================================================
--- java/main/src/main/java/com/framsticks/gui/components/Control.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/gui/components/Control.java	(revision 77)
@@ -0,0 +1,105 @@
+package com.framsticks.gui.components;
+
+import com.framsticks.params.Flags;
+import com.framsticks.params.Param;
+import com.framsticks.params.types.*;
+import org.apache.log4j.Logger;
+
+import javax.swing.*;
+import java.awt.*;
+
+/**
+ * Interface that each class that want to be component must implement.
+ */
+public abstract class Control extends JPanel {
+
+	public static final int LINE_HEIGHT = 36;
+
+	private static final Logger LOGGER = Logger.getLogger(Control.class.getName());
+
+    protected Frame frame;
+	protected Param param;
+
+	public Control(Param param) {
+		this.param = param;
+
+		String help = param.getHelp();
+		if (help != null) {
+			this.setToolTipText(help);
+		}
+
+		if (param.getHelp() != null) {
+			this.setToolTipText(param.getHelp());
+		}
+		this.setEnabled(!param.hasFlag(Flags.READONLY));
+		// TODO: take care of textField exception: setEditable
+	}
+
+	public Param getParam() {
+		return param;
+	}
+
+    public void setFrame(Frame frame) {
+        this.frame = frame;
+    }
+
+	public static Control createComponentForText(ValueParam valueParam) {
+		if (valueParam.getMin(Object.class) != null) {
+			return new TextAreaControl(valueParam);
+		}
+		return new TextFieldControl(valueParam);
+	}
+
+	public static Control createSuitable(Param param) {
+
+		if (param instanceof EnumParam) {
+			return new EnumControl((EnumParam) param);
+		}
+        if (param instanceof BooleanParam) {
+            return new CheckBoxControl((BooleanParam) param);
+        }
+        if (param instanceof DecimalParam) {
+			DecimalParam decimalParam = (DecimalParam)param;
+			if (param.getMin(Integer.class) != null && param.getMax(Integer.class) != null) {
+				return new SliderControl(decimalParam);
+			}
+			return createComponentForText(decimalParam);
+		}
+		if (param instanceof FloatParam) {
+			FloatParam floatParam = (FloatParam)param;
+			if (param.getMin(Double.class) != null && param.getMax(Double.class) != null) {
+				return new SliderControl(floatParam);
+			}
+			return createComponentForText(floatParam);
+		}
+		if (param instanceof StringParam) {
+			return createComponentForText((StringParam)param);
+		}
+		if (param instanceof ProcedureParam) {
+			return new ProcedureControl((ProcedureParam)param);
+		}
+		if (param instanceof BinaryParam) {
+			return createComponentForText((BinaryParam)param);
+		}
+		if (param instanceof ColorParam) {
+			return createComponentForText((ColorParam) param);
+		}
+		if (param instanceof UniversalParam) {
+			return new TextAreaControl((UniversalParam)param);
+		}
+		if (param instanceof EventParam) {
+			return new EventControl((EventParam)param);
+		}
+		return null;
+	}
+
+	protected void addAsOnlyChild(JComponent component) {
+		this.setLayout(new BorderLayout());
+		this.add(component, BorderLayout.CENTER);
+	}
+
+	@Override
+	public String toString() {
+		return param.toString();
+	}
+}
Index: java/main/src/main/java/com/framsticks/gui/components/ControlPopupListener.java
===================================================================
--- java/main/src/main/java/com/framsticks/gui/components/ControlPopupListener.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/gui/components/ControlPopupListener.java	(revision 77)
@@ -0,0 +1,40 @@
+package com.framsticks.gui.components;
+
+import javax.swing.*;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+
+/**
+ * Listener for component's JPopup menu.
+ */
+public class ControlPopupListener extends MouseAdapter {
+
+	private JPopupMenu popup;
+
+	public ControlPopupListener(JPopupMenu popup) {
+		this.popup = popup;
+	}
+
+	@Override
+	public void mousePressed(MouseEvent e) {
+		if (e.isPopupTrigger()) {
+			showPopup(e);
+		}
+	}
+
+	@Override
+	public void mouseReleased(MouseEvent e) {
+		if (e.isPopupTrigger()) {
+			showPopup(e);
+		}
+	}
+
+	/**
+	 * Shows popup menu if popup trigger fires.
+	 *
+	 * @param e MouseEvent on which popup menu will be showed.
+	 */
+	private void showPopup(MouseEvent e) {
+		popup.show(e.getComponent(), e.getX(), e.getY());
+	}
+}
Index: java/main/src/main/java/com/framsticks/gui/components/EnumControl.java
===================================================================
--- java/main/src/main/java/com/framsticks/gui/components/EnumControl.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/gui/components/EnumControl.java	(revision 77)
@@ -0,0 +1,63 @@
+package com.framsticks.gui.components;
+
+import com.framsticks.params.types.EnumParam;
+import com.framsticks.util.Numbers;
+import org.apache.log4j.Logger;
+
+import javax.swing.*;
+import java.awt.event.ItemEvent;
+import java.awt.event.ItemListener;
+
+@SuppressWarnings("serial")
+public class EnumControl extends ValueControl {
+
+	private JComboBox list;
+
+	private static final Logger LOGGER = Logger.getLogger(EnumControl.class.getName());
+
+	/**
+	 * Minimum value index of list.
+	 * TODO is it a base number?
+	 */
+	private int min;
+
+	public EnumControl(EnumParam enumParam) {
+		super(enumParam);
+
+		this.min = param.getMin(Integer.class);
+
+		list = new JComboBox();
+		for (String item : enumParam.getElements()) {
+			list.addItem(item);
+		}
+		list.setEditable(false);
+		list.setEnabled(!isReadOnly());
+		list.addItemListener(new ItemListener() {
+			@Override
+			public void itemStateChanged(ItemEvent itemEvent) {
+				notifyOfChange();
+			}
+		});
+		addAsOnlyChild(list);
+
+	}
+
+	@Override
+	public void setValueImpl(Object value) {
+		Integer x = Numbers.cast(value, Integer.class);
+		if (x == null) {
+			return;
+		}
+		try {
+			list.setSelectedIndex(x - min);
+		} catch (IllegalArgumentException e) {
+			LOGGER.error("failed to set value");
+		}
+	}
+
+	@Override
+	public Object getValue() {
+		return list.getSelectedIndex();
+	}
+
+}
Index: java/main/src/main/java/com/framsticks/gui/components/EventControl.java
===================================================================
--- java/main/src/main/java/com/framsticks/gui/components/EventControl.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/gui/components/EventControl.java	(revision 77)
@@ -0,0 +1,48 @@
+package com.framsticks.gui.components;
+
+import com.framsticks.params.types.EventParam;
+import org.apache.log4j.Logger;
+
+import javax.swing.*;
+import java.awt.*;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+
+/**
+ * @author Piotr Sniegowski
+ */
+public class EventControl extends Control {
+	private static final Logger LOGGER = Logger.getLogger(EventControl.class.getName());
+
+	JButton button;
+    boolean subscribed = true;
+
+	public EventControl(final EventParam eventParam) {
+		super(eventParam);
+
+		button = new JButton("subscribe");
+		this.add(button);
+		this.setMaximumSize(new Dimension(Integer.MAX_VALUE, Control.LINE_HEIGHT));
+
+		button.addActionListener(new ActionListener() {
+			@Override
+			public void actionPerformed(ActionEvent e) {
+                if (subscribed) {
+                    //panel.getCurrentTreeNode().unsubscribe(eventParam);
+                } else {
+                    //panel.getCurrentTreeNode().subscribe(eventParam);
+                }
+			}
+		});
+
+	}
+
+    /*
+    @Override
+    public void refresh() {
+        subscribed = panel.getCurrentTreeNode().hasSubscribed((EventParam)param);
+        button.setText(subscribed ? "unsubscribe" : "subscribe");
+        this.revalidate();
+    }
+    */
+}
Index: java/main/src/main/java/com/framsticks/gui/components/ProcedureControl.java
===================================================================
--- java/main/src/main/java/com/framsticks/gui/components/ProcedureControl.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/gui/components/ProcedureControl.java	(revision 77)
@@ -0,0 +1,66 @@
+package com.framsticks.gui.components;
+
+import com.framsticks.gui.ObjectPanel;
+import com.framsticks.params.Param;
+import com.framsticks.params.types.ProcedureParam;
+import org.apache.log4j.Logger;
+
+import javax.swing.*;
+import javax.swing.border.BevelBorder;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.util.HashMap;
+import java.util.Map;
+
+@SuppressWarnings("serial")
+public class ProcedureControl extends Control {
+	private static final Logger LOGGER = Logger.getLogger(Control.class.getName());
+
+	JButton procedureButton;
+
+	final protected Map<Param, Control> components = new HashMap<Param, Control>();
+
+	public ProcedureControl(ProcedureParam procedureParam) {
+		super(procedureParam);
+
+		procedureButton = new JButton("Call");
+
+		this.setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS));
+
+		ObjectPanel.fillWithComponents(this, procedureParam.getArgumentsType(), components);
+
+		if (components.size() != procedureParam.getArgumentsType().size()) {
+			procedureButton.setEnabled(false);
+		}
+		if (!components.isEmpty()) {
+			this.setBorder(new BevelBorder(BevelBorder.RAISED));
+		}
+
+		procedureButton.addActionListener(new ActionListener() {
+			@Override
+			public void actionPerformed(ActionEvent e) {
+
+/*
+				Node node = panel.getCurrentNode();
+				if (argumentWindow != null) {
+					argumentWindow.askForArguments();
+					return;
+				}
+				node.getConnection().send(new CallQuery().setMethod(param.getId()).setPath(node.getPath()).setCallback(new QueryCallback() {
+					@Override
+					public void call(boolean ok, String comment, SourceInterface content) {
+						if (!ok) {
+							LOGGER.error("failed to call method: " + param);
+							return;
+						}
+						LOGGER.debug("successful call of method: " + param);
+					}
+				}));
+*/
+			}
+		});
+		this.add(procedureButton);
+
+	}
+
+}
Index: java/main/src/main/java/com/framsticks/gui/components/SliderControl.java
===================================================================
--- java/main/src/main/java/com/framsticks/gui/components/SliderControl.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/gui/components/SliderControl.java	(revision 77)
@@ -0,0 +1,285 @@
+package com.framsticks.gui.components;
+
+import com.framsticks.params.Flags;
+import com.framsticks.params.types.DecimalParam;
+import com.framsticks.params.types.FloatParam;
+import com.framsticks.params.types.ValueParam;
+import com.framsticks.util.Layout;
+import com.framsticks.util.Numbers;
+
+import javax.swing.*;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+import java.awt.*;
+import java.awt.event.FocusEvent;
+import java.awt.event.FocusListener;
+import java.awt.event.KeyEvent;
+import java.awt.event.KeyListener;
+import java.util.Hashtable;
+
+
+@SuppressWarnings("serial")
+public class SliderControl extends ValueControl {
+
+	private JSlider slider;
+
+	private JTextField sliderValue;
+
+	/**
+	 * Division factor used to implement float value slider.
+	 */
+	private final int div = 10;
+
+	/**
+	 * Old value of slider used when user press ESCAPE key.
+	 */
+	private int oldValue;
+
+	public SliderControl(ValueParam valueParam) {
+		super(valueParam);
+		slider = new JSlider();
+        slider.setEnabled(!isReadOnly());
+		slider.addChangeListener(new ChangeListener() {
+			@Override
+			public void stateChanged(ChangeEvent changeEvent) {
+				notifyOfChange();
+			}
+		});
+		if (param instanceof DecimalParam) {
+			int min = param.getMin(Integer.class);
+			int max = param.getMax(Integer.class);
+			slider.setMinimum(min);
+			slider.setMaximum(max);
+			if (param.getDef(Integer.class) != null) {
+				slider.setValue(param.getDef(Integer.class));
+			} else {
+				slider.setValue(min);
+			}
+			slider.setMajorTickSpacing((int) ((max - min) / 5));
+			slider.setMinorTickSpacing((int) ((max - min) / 10));
+			slider.setPaintLabels(true);
+			slider.setPaintTicks(true);
+		}
+		if (param instanceof FloatParam) {
+			double min = param.getMin(Double.class) * div;
+			slider.setMinimum((int) min);
+			double max = param.getMax(Double.class) * div;
+			slider.setMaximum((int) max);
+
+			Hashtable<Integer, java.awt.Component> labels = new Hashtable<Integer, java.awt.Component>();
+			for (int i = 0; i < 6; i++) {
+				double val = 0;
+				if (min < 0) {
+					val = (((Math.abs(max) - min) / 5) * i) + min;
+				} else {
+					val = (((Math.abs(max) - Math.abs(min)) / 5) * i) + Math.abs(min);
+				}
+				String label = String.format("%1$.1f", (val / 10)).replace(",", ".");
+				labels.put(new Integer((int) val), new JLabel(label, JLabel.CENTER));
+			}
+			slider.setLabelTable(labels);
+			slider.setPaintLabels(true);
+			slider.setMajorTickSpacing((int) ((max - Math.abs(min)) / 5));
+			slider.setMinorTickSpacing((int) ((max - Math.abs(min)) / 10));
+			slider.setPaintTicks(true);
+			if (param.getDef(Double.class) != null) {
+				double defaultValue = param.getDef(Double.class) * div;
+				slider.setValue((int) defaultValue);
+			}
+		}
+		//TODO: actually set the value
+		/*
+		if (property.getValue() != null) {
+			setValueImpl(property.getValue());
+		}
+		*/
+
+
+
+		createPanel();
+	}
+
+	/**
+	 * Creates panel with description in label, slider value and slider next to description.
+	 */
+	private void createPanel() {
+		this.setLayout(new BoxLayout(this, BoxLayout.LINE_AXIS));
+		this.setAlignmentX(Box.CENTER_ALIGNMENT);
+		this.setAlignmentY(Box.CENTER_ALIGNMENT);
+
+		JPanel sliderPanel = new JPanel();
+		sliderPanel.setLayout(new BoxLayout(sliderPanel, BoxLayout.LINE_AXIS));
+
+		createSliderValue();
+
+		JPanel sVPanel = new JPanel();
+		sVPanel.setLayout(new BoxLayout(sVPanel, BoxLayout.LINE_AXIS));
+		sVPanel.add(sliderValue);
+		Layout.copyComponentDimensions(sVPanel, sliderValue);
+
+		JPanel sPanel = new JPanel();
+		sPanel.setLayout(new BoxLayout(sPanel, BoxLayout.LINE_AXIS));
+
+		sliderPanel.setLayout(new BorderLayout());
+		sliderPanel.add(slider, BorderLayout.CENTER);
+		sliderPanel.setMaximumSize(new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE));
+		sliderPanel.setMinimumSize(new Dimension(0, 60));
+
+		sPanel.add(sVPanel);
+		sPanel.add(sliderPanel);
+
+		this.add(sPanel);
+	}
+
+	/**
+	 * Creates slider value text field
+	 */
+	private void createSliderValue() {
+		if (param instanceof DecimalParam) {
+			sliderValue = new JTextField(Integer.toString(slider.getValue()));
+			sliderValue.setText(Integer.toString(slider.getValue()));
+		} else {
+			sliderValue = new JTextField(Double.toString(slider.getValue() / div));
+			sliderValue.setText(Double.toString(slider.getValue() / div));
+		}
+		Layout.fixComponentSize(sliderValue, new Dimension(60, Control.LINE_HEIGHT));
+		sliderValue.setHorizontalAlignment(JSlider.CENTER);
+
+		if (param.hasFlag(Flags.READONLY)) {
+			sliderValue.setEnabled(false);
+		}
+
+		if (param.getDef(Object.class) != null) {
+			sliderValue.setText(param.getDef(Object.class).toString());
+		}
+
+		slider.addChangeListener(new ChangeListener() {
+
+			public void stateChanged(ChangeEvent e) {
+				if (param instanceof DecimalParam) {
+					sliderValue.setText(Integer.toString(slider.getValue()));
+				}
+				if (param instanceof FloatParam) {
+					float val = (float) slider.getValue() / (float) div;
+					sliderValue.setText(Double.toString(val));
+				}
+			}
+		});
+
+		sliderValue.addFocusListener(new FocusListener() {
+
+			public void focusGained(FocusEvent e) {
+				oldValue = slider.getValue();
+			}
+
+			public void focusLost(FocusEvent e) {
+				applyNewValue();
+			}
+
+		});
+
+		sliderValue.addKeyListener(new KeyListener() {
+
+			public void keyPressed(KeyEvent e) {
+			}
+
+			public void keyReleased(KeyEvent e) {
+				if (e.getKeyCode() == KeyEvent.VK_ENTER) {
+					applyNewValue();
+				}
+				if (e.getKeyCode() == KeyEvent.VK_ESCAPE) {
+					if (param instanceof DecimalParam) {
+						sliderValue.setText(Integer.toString(oldValue));
+					}
+					if (param instanceof FloatParam) {
+						sliderValue.setText(Double.toString((float) oldValue / (float) div));
+					}
+					sliderValue.setBackground(Color.WHITE);
+					sliderValue.invalidate();
+				}
+			}
+
+			public void keyTyped(KeyEvent e) {
+			}
+
+		});
+	}
+
+	/**
+	 * Applies new Value of slider if typed value is correct
+	 */
+	private void applyNewValue() {
+		try {
+			if (param instanceof DecimalParam) {
+				int min = param.getMin(Integer.class);
+				int max = param.getMax(Integer.class);
+
+				int val = Integer.parseInt(sliderValue.getText());
+				if (val < min) {
+					val = min;
+				}
+				if (val > max) {
+					val = max;
+				}
+				slider.setValue(val);
+				sliderValue.setBackground(Color.WHITE);
+			}
+			if (param instanceof FloatParam) {
+				double val = Double.parseDouble(sliderValue.getText());
+				int min = param.getMin(Double.class).intValue();
+				int max = param.getMax(Double.class).intValue();
+
+				int intVal = (int) (val * div);
+				min = min * div;
+				max = max * div;
+				if (intVal < min) {
+					intVal = min;
+				}
+				if (intVal > max) {
+					intVal = max;
+				}
+				slider.setValue(intVal);
+				sliderValue.setBackground(Color.WHITE);
+			}
+		} catch (NumberFormatException e) {
+			sliderValue.setText(getStringValue());
+		}
+	}
+
+
+
+	private String getStringValue() {
+		if (param instanceof DecimalParam) {
+			return Integer.toString((Integer)getValue());
+		}
+		if (param instanceof FloatParam) {
+			return Double.toString((Double)getValue());
+		}
+		return null;
+	}
+
+	@Override
+	public void setValueImpl(Object value) {
+		if (value == null) {
+			return;
+		}
+		if (param instanceof DecimalParam) {
+			slider.setValue(Numbers.cast(value, Integer.class));
+		} else if (param instanceof FloatParam) {
+			slider.setValue((int) ((Numbers.cast(value, Double.class)) * div));
+		}
+	}
+
+	@Override
+	public Object getValue() {
+		if (param instanceof DecimalParam) {
+			return slider.getValue();
+		}
+		if (param instanceof FloatParam) {
+			return (double) slider.getValue() / (double) div;
+		}
+		return null;
+	}
+
+
+}
Index: java/main/src/main/java/com/framsticks/gui/components/TextAreaControl.java
===================================================================
--- java/main/src/main/java/com/framsticks/gui/components/TextAreaControl.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/gui/components/TextAreaControl.java	(revision 77)
@@ -0,0 +1,65 @@
+package com.framsticks.gui.components;
+
+import com.framsticks.params.types.ValueParam;
+import org.apache.log4j.Logger;
+
+import javax.swing.*;
+import java.awt.*;
+
+
+@SuppressWarnings("serial")
+public class TextAreaControl extends ValueControl {
+
+	private static final Logger LOGGER = Logger.getLogger(TextAreaControl.class.getName());
+
+	private JTextArea textArea;
+	private JScrollPane textScrollPane;
+
+	public TextAreaControl(ValueParam valueParam) {
+		super(valueParam);
+		textArea = new JTextArea();
+		//textArea.setFont(FONT);
+		textArea.setLineWrap(true);
+		textArea.setWrapStyleWord(true);
+        textArea.setEditable(!isReadOnly());
+		textArea.getDocument().addDocumentListener(createDocumentListener(this));
+		//textArea.setBackground(new Color(255, 0, 0));
+
+		textScrollPane = new JScrollPane(textArea);
+		//textScrollPane.setMaximumSize(new Dimension(Integer.MAX_VALUE, LINE_HEIGHT * 3));
+		//textArea.setMaximumSize(new Dimension(Integer.MAX_VALUE, LINE_HEIGHT * 3));
+		//this.setLayout(new BorderLayout());
+		//this.add(textScrollPane, BorderLayout.CENTER);
+		//this.add(Box.createRigidArea(new Dimension(5, 0)), BorderLayout.PAGE_START);
+		//this.add(Box.createRigidArea(new Dimension(5, 0)), BorderLayout.PAGE_END);
+		this.setLayout(new BorderLayout());
+		this.add(textScrollPane, BorderLayout.CENTER);
+		this.setMaximumSize(new Dimension(Integer.MAX_VALUE, LINE_HEIGHT * 3));
+		textArea.setMaximumSize(new Dimension(Integer.MAX_VALUE, LINE_HEIGHT * 3));
+
+		this.revalidate();
+	}
+
+	@Override
+	public Dimension getPreferredSize() {
+		Dimension result = super.getPreferredSize();
+		return new Dimension(result.width, Math.min(result.height, this.getMaximumSize().height));
+	}
+
+	@Override
+	public void setValueImpl(Object value) {
+		textArea.setText((String) value);
+		this.revalidate();
+		//textArea.set
+		//textArea.setRows(Math.min(textArea.getLineCount(), 5));
+		//textArea.setColumns(50);
+		//textArea.getDocument().
+		//textArea.revalidate();
+	}
+
+	@Override
+	public Object getValue() {
+		return textArea.getText();
+	}
+
+}
Index: java/main/src/main/java/com/framsticks/gui/components/TextFieldControl.java
===================================================================
--- java/main/src/main/java/com/framsticks/gui/components/TextFieldControl.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/gui/components/TextFieldControl.java	(revision 77)
@@ -0,0 +1,48 @@
+package com.framsticks.gui.components;
+
+import com.framsticks.params.types.ValueParam;
+import com.framsticks.util.Strings;
+
+import javax.swing.*;
+import java.awt.*;
+
+@SuppressWarnings("serial")
+public class TextFieldControl extends ValueControl {
+
+
+	private static final Color CORRECT_COLOR = new Color(180, 255, 215);
+	private static final Color WRONG_COLOR = new Color(255, 180, 215);
+
+	private JTextField textField = new JTextField();
+
+	@Override
+	protected boolean notifyOfChange() {
+		boolean result = super.notifyOfChange();
+		textField.setBackground(result ? CORRECT_COLOR : WRONG_COLOR);
+		return result;
+	}
+
+	public TextFieldControl(ValueParam valueParam) {
+		super(valueParam);
+
+		textField.setMinimumSize(new Dimension(0, Control.LINE_HEIGHT));
+		this.setMaximumSize(new Dimension(Integer.MAX_VALUE, Control.LINE_HEIGHT));
+
+        textField.setEditable(!isReadOnly());
+
+		textField.getDocument().addDocumentListener(createDocumentListener(this));
+
+		addAsOnlyChild(textField);
+	}
+
+	@Override
+	public void setValueImpl(Object text) {
+		textField.setText(Strings.toStringNullProof(text));
+	}
+
+	@Override
+	public Object getValue() {
+		return textField.getText();
+	}
+
+}
Index: java/main/src/main/java/com/framsticks/gui/components/ValueControl.java
===================================================================
--- java/main/src/main/java/com/framsticks/gui/components/ValueControl.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/gui/components/ValueControl.java	(revision 77)
@@ -0,0 +1,83 @@
+package com.framsticks.gui.components;
+
+import com.framsticks.params.CastFailure;
+import com.framsticks.params.Flags;
+import com.framsticks.params.types.ValueParam;
+
+import javax.swing.event.DocumentEvent;
+import javax.swing.event.DocumentListener;
+
+/**
+ * @author Piotr Sniegowski
+ */
+public abstract class ValueControl extends Control {
+
+	protected ValueControlListener listener;
+
+	public ValueControl(ValueParam valueParamEntry) {
+		super(valueParamEntry);
+	}
+
+	protected abstract void setValueImpl(Object value);
+
+	/** I consider this an ugly solution, but I was unable to find proper
+	 * action listeners for underlying swing controls, that would only fire
+	 * on user change and on programmatic change.
+	 */
+	protected boolean programmaticChange = false;
+
+	public void setValue(Object value) {
+		programmaticChange = true;
+		setValueImpl(value);
+		programmaticChange = false;
+	}
+
+	public abstract Object getValue();
+
+	public void setListener(ValueControlListener listener) {
+		this.listener = listener;
+	}
+
+	protected boolean notifyOfChange() {
+		Object c = getValue();
+		try {
+			Object v = param.reassign(c, null);
+			if (!programmaticChange) {
+				return listener == null || listener.onChange(v);
+			}
+			return true;
+		} catch (CastFailure castFailure) {
+			return false;
+		}
+	}
+
+	public boolean isReadOnly() {
+		return (param.getFlags() & Flags.READONLY) != 0;
+	}
+
+    @Override
+    public ValueParam getParam() {
+        assert param instanceof ValueParam;
+        return (ValueParam)param;
+    }
+
+	protected static DocumentListener createDocumentListener(final ValueControl component) {
+		return new DocumentListener() {
+			@Override
+			public void insertUpdate(DocumentEvent documentEvent) {
+				component.notifyOfChange();
+			}
+
+			@Override
+			public void removeUpdate(DocumentEvent documentEvent) {
+				component.notifyOfChange();
+			}
+
+			@Override
+			public void changedUpdate(DocumentEvent documentEvent) {
+				component.notifyOfChange();
+			}
+		};
+	}
+
+}
Index: java/main/src/main/java/com/framsticks/gui/components/ValueControlListener.java
===================================================================
--- java/main/src/main/java/com/framsticks/gui/components/ValueControlListener.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/gui/components/ValueControlListener.java	(revision 77)
@@ -0,0 +1,8 @@
+package com.framsticks.gui.components;
+
+/**
+ * @author Piotr Sniegowski
+ */
+public interface ValueControlListener {
+	public boolean onChange(Object newValue);
+}
Index: java/main/src/main/java/com/framsticks/gui/view/ColumnMenuItem.java
===================================================================
--- java/main/src/main/java/com/framsticks/gui/view/ColumnMenuItem.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/gui/view/ColumnMenuItem.java	(revision 77)
@@ -0,0 +1,72 @@
+package com.framsticks.gui.view;
+
+import com.framsticks.gui.ListPanel;
+
+import javax.swing.*;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.ItemEvent;
+import java.awt.event.ItemListener;
+
+/**
+ * Menu item allows to adding and removing column from table in group template.
+ */
+@SuppressWarnings("serial")
+public class ColumnMenuItem extends JCheckBoxMenuItem {
+
+	/**
+	 * Name of column.
+	 */
+	private final String columnName;
+	/**
+	 * Column getId.
+	 */
+	private final String columnId;
+	/**
+	 * Column index.
+	 */
+	private final int index;
+
+	/**
+	 * Constructor sets name of column, column getId, index and reference to group template panel.
+	 *
+	 * @param columnName    Name of column.
+	 * @param columnId      Column getId.
+	 * @param index         Index of column.
+	 * @param columnManager Reference to panel instantiate ListPanel.
+	 */
+	//@SuppressWarnings("static-access")
+	public ColumnMenuItem(String columnName, String columnId, int index,
+	                      final ListPanel columnManager) {
+		super(columnName);
+		this.columnName = columnName;
+		this.columnId = columnId;
+		this.index = index;
+
+		this.addItemListener(new ItemListener() {
+			public void itemStateChanged(ItemEvent e) {
+				if (e.getStateChange() == e.SELECTED) {
+					columnManager.addColumn(ColumnMenuItem.this.columnName,
+							ColumnMenuItem.this.columnId,
+							ColumnMenuItem.this.index);
+				} else {
+					columnManager.removeColumn(ColumnMenuItem.this.columnId);
+				}
+			}
+
+		});
+
+		this.addActionListener(new ActionListener() {
+
+			public void actionPerformed(ActionEvent e) {
+				columnManager.refreshTable();
+			}
+
+		});
+	}
+
+	@Override
+	public String toString() {
+		return columnName;
+	}
+}
Index: java/main/src/main/java/com/framsticks/gui/view/NodeAction.java
===================================================================
--- java/main/src/main/java/com/framsticks/gui/view/NodeAction.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/gui/view/NodeAction.java	(revision 77)
@@ -0,0 +1,11 @@
+package com.framsticks.gui.view;
+
+
+import com.framsticks.gui.TreeNode;
+
+/**
+ * @author Piotr Sniegowski
+ */
+public interface NodeAction {
+    public void actionPerformed(TreeNode treeNode);
+}
Index: java/main/src/main/java/com/framsticks/gui/view/TableModel.java
===================================================================
--- java/main/src/main/java/com/framsticks/gui/view/TableModel.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/gui/view/TableModel.java	(revision 77)
@@ -0,0 +1,88 @@
+package com.framsticks.gui.view;
+
+import javax.swing.table.DefaultTableModel;
+import javax.swing.table.TableColumn;
+import java.util.Iterator;
+import java.util.Vector;
+
+/**
+ * Table model for manages column in JTable on ListPanel.
+ */
+@SuppressWarnings("serial")
+public class TableModel extends DefaultTableModel {
+
+	/**
+	 * List of columns.
+	 */
+	Vector<TableColumn> columns = new Vector<TableColumn>();
+
+	/**
+	 * Adds column to list.
+	 *
+	 * @param column TableColumn with getName, getId and index.
+	 */
+	public void addColumn(TableColumn column) {
+		Iterator<TableColumn> iterator = columns.iterator();
+		int index = 0;
+		boolean inserted = false;
+		while (iterator.hasNext()) {
+			if (iterator.next().getModelIndex() < column.getModelIndex()) {
+				index++;
+			} else {
+				columns.insertElementAt(column, index);
+				inserted = true;
+				break;
+			}
+		}
+		if (!inserted) {
+			columns.add(column);
+		}
+		setIdentifiers();
+	}
+
+	/**
+	 * Removes column from list.
+	 *
+	 * @param identifier Column identifier.
+	 */
+	public void removeColumn(String identifier) {
+		Iterator<TableColumn> iterator = columns.iterator();
+		while (iterator.hasNext()) {
+			if (iterator.next().getIdentifier().toString().equals(identifier)) {
+				iterator.remove();
+				break;
+			}
+		}
+		setIdentifiers();
+	}
+
+	/**
+	 * Returns list of columns.
+	 *
+	 * @return List of columns.
+	 */
+	public Vector<String> getColumns() {
+		Vector<String> columnsId = new Vector<String>();
+		for (TableColumn column : columns) {
+			columnsId.add(column.getIdentifier().toString());
+		}
+		return columnsId;
+	}
+
+	/**
+	 * Sets this model column identifiers.
+	 */
+	private void setIdentifiers() {
+		Vector<String> newIdentifiers = new Vector<String>();
+		for (TableColumn column : columns) {
+			newIdentifiers.add(column.getHeaderValue().toString());
+		}
+		setColumnIdentifiers(newIdentifiers);
+	}
+
+	@Override
+	public boolean isCellEditable(int arg0, int arg1) {
+		return false;
+	}
+
+}
Index: java/main/src/main/java/com/framsticks/gui/view/TreeCellRenderer.java
===================================================================
--- java/main/src/main/java/com/framsticks/gui/view/TreeCellRenderer.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/gui/view/TreeCellRenderer.java	(revision 77)
@@ -0,0 +1,137 @@
+package com.framsticks.gui.view;
+
+import com.framsticks.gui.ImageProvider;
+import com.framsticks.gui.TreeNode;
+
+import javax.swing.*;
+import javax.swing.tree.DefaultTreeCellRenderer;
+import java.awt.*;
+
+/**
+ * Renderer of Tree. Sets appropriate icons for nodes.
+ */
+@SuppressWarnings("serial")
+public class TreeCellRenderer extends DefaultTreeCellRenderer {
+
+    public TreeCellRenderer() {
+        setOpenIcon(null);
+        setClosedIcon(null);
+        setLeafIcon(null);
+    }
+
+	@Override
+	public Component getTreeCellRendererComponent(JTree tree, Object value,
+	                                              boolean sel, boolean expanded, boolean leaf, int row,
+	                                              boolean hasFocus) {
+
+		//super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf,
+		//		row, hasFocus);
+		if (value == null) {
+			return this;
+		}
+		if (!(value instanceof TreeNode)) {
+            setIcon(ImageProvider.loadImage(ImageProvider.SERVER));
+            setText("framsticks");
+			return this;
+		}
+		TreeNode treeNode = (TreeNode)value;
+        assert treeNode.getFrame().isActive();
+        setToolTipText(treeNode.getTooltip());
+        setIcon(ImageProvider.loadImage(treeNode.getIconName()));
+        setText(treeNode.getName());
+		return this;
+	}
+
+	public static String findIconName(String nodeName, String path) {
+        if (path == null || nodeName == null) {
+            return null;
+        }
+        if (path.equals("/")) {
+			return ImageProvider.SERVER;
+		}
+		if (path.endsWith("simulator")) {
+			return ImageProvider.SIMULATOR;
+		}
+		if (path.endsWith("cli")) {
+			return ImageProvider.CLI;
+		}
+		if (path.endsWith("world")) {
+			return ImageProvider.WORLD;
+		}
+		if (path.endsWith("genepools")) {
+			return ImageProvider.GENEPOOLS;
+		}
+		if (path.endsWith("populations")) {
+			return ImageProvider.POPULATIONS;
+		}
+		if (path.endsWith("experiment")) {
+			return ImageProvider.EXPERIMENT;
+		}
+		if (path.endsWith("stats")) {
+			return ImageProvider.STATISTIC;
+		}
+		if (nodeName.equals("creatures") || path.endsWith("creatures")) {
+			return ImageProvider.CREATURES_GROUP;
+		}
+		if (nodeName.equals("Favourite Fields")) {
+			return ImageProvider.FAVORITE_FIELDS;
+		}
+		if (nodeName.equals("genotypes") || path.endsWith("creatures")) {
+			return ImageProvider.GENOTYPES_GROUP;
+		}
+		if (nodeName.equals("parts") || path.endsWith("parts")) {
+			return ImageProvider.PART_GROUP;
+		}
+		if (nodeName.equals("joints") || path.endsWith("joints")) {
+			return ImageProvider.JOINT_GROUP;
+		}
+		if (nodeName.equals("neurodefs") || path.endsWith("neurodefs")) {
+			return ImageProvider.NEURON_DEF_GROUP;
+		}
+		if (nodeName.equals("mechparts") || path.endsWith("mechparts")) {
+			return ImageProvider.MECH_PART_GROUP;
+		}
+		if (nodeName.equals("mechjoints") || path.endsWith("mechjoints")) {
+			return ImageProvider.MECH_JOINT_GROUP;
+		}
+		if (nodeName.equals("neurons") || path.endsWith("neurons")) {
+			return ImageProvider.NEURON_GROUP;
+		}
+		if (path.matches("^.*parts/[0-9]+$")) {
+			return ImageProvider.PART;
+		}
+		if (path.matches("^.*joints/[0-9]+$")) {
+			return ImageProvider.JOINT;
+		}
+		if (path.matches("^.*neurodefs/[0-9]+$")) {
+			return ImageProvider.NEURON_DEF;
+		}
+		if (path.matches("^.*mechparts/[0-9]+$")) {
+			return ImageProvider.MECH_PART;
+		}
+		if (path.matches("^.*mechjoints/[0-9]+$")) {
+			return ImageProvider.MECH_JOINT;
+		}
+		if (path.matches("^.*neurons/[0-9]+$")) {
+			return ImageProvider.NEURON;
+		}
+		if (path.matches("^.*creatures/c[0-9]+$")) {
+			return ImageProvider.CREATURE;
+		}
+		if (path.matches("^.*genotypes/g[0-9]+$")) {
+			return ImageProvider.GENOTYPES;
+		}
+		if (path.matches("^.*populations/groups/[0-9]+$")) {
+			return ImageProvider.POPULATION_GROUP;
+		}
+		if (path.matches("^.*genepools/groups/[0-9]+$")) {
+			return ImageProvider.GENEPOOLS_GROUP;
+		}
+		if (path.matches("^.*events/e[0-9]+$")) {
+			return ImageProvider.EVENT;
+		}
+		return ImageProvider.SERVER;
+	}
+	
+	
+}
Index: java/main/src/main/java/com/framsticks/gui/windows/ServerLogFrame.java
===================================================================
--- java/main/src/main/java/com/framsticks/gui/windows/ServerLogFrame.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/gui/windows/ServerLogFrame.java	(revision 77)
@@ -0,0 +1,110 @@
+package com.framsticks.gui.windows;
+
+import com.framsticks.gui.ImageProvider;
+import com.framsticks.gui.components.Control;
+import org.apache.log4j.Logger;
+
+import javax.swing.*;
+import java.awt.*;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+
+/**
+ * Frame displaying manager logs.
+ */
+@SuppressWarnings("serial")
+public class ServerLogFrame extends JFrame {
+	public JTextArea logText;
+	private int levelReporting = -1;
+	private boolean popUp = true;
+
+	private final static String[] STR_ = {"DEBUG", "INFO", "WARNING", "ERROR",
+			"CRITICAL"};
+
+
+	public ServerLogFrame() {
+
+		super("FNC - Manager Log");
+		Dimension size = new Dimension(440, 400);
+		this.setSize(size);
+		this.setMinimumSize(size);
+		this.setIconImage(ImageProvider.loadImage(ImageProvider.LOGO).getImage());
+		JFrame.setDefaultLookAndFeelDecorated(true);
+		/*
+		try {
+			UIManager
+					.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
+		} catch (Exception ex) {
+		}
+		*/
+		this.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
+		logText = new JTextArea();
+		//logText.setFont(Control.FONT);
+		logText.setEditable(false);
+		logText.setWrapStyleWord(true);
+		logText.setLineWrap(true);
+		JComboBox levelBox = new JComboBox();
+		for (String i : STR_) {
+			levelBox.addItem(i);
+		}
+		levelBox.addActionListener(new ActionListener() {
+			public void actionPerformed(ActionEvent e) {
+				levelReporting = ((JComboBox) e.getSource()).getSelectedIndex();
+			}
+		});
+		JCheckBox logPopup = new JCheckBox();
+		logPopup.addActionListener(new ActionListener() {
+			public void actionPerformed(ActionEvent e) {
+				popUp = ((JCheckBox) e.getSource()).isSelected();
+			}
+		});
+		logPopup.setSelected(true);
+		JLabel levelLabel = new JLabel("Select reporting level ");
+		JLabel popupLabel = new JLabel("Window popup ? ");
+		JPanel panel = new JPanel();
+		panel.setLayout(new FlowLayout());
+		panel.add(levelLabel);
+		panel.add(levelBox);
+		panel.add(logPopup);
+		panel.add(popupLabel);
+		JScrollPane scrollPane = new JScrollPane(logText);
+		scrollPane.setBorder(BorderFactory.createEtchedBorder());
+		Container contentPane = this.getContentPane();
+		contentPane.setLayout(new BorderLayout());
+		contentPane.add(scrollPane, BorderLayout.CENTER);
+		contentPane.add(panel, BorderLayout.SOUTH);
+		levelReporting = 0;
+	}
+
+	public void setLevelReporting(int level) {
+		levelReporting = level;
+	}
+
+	public void log(int level, String clazz, String function,
+	                String message) {
+		if (level >= levelReporting) {
+			if (popUp && !this.isVisible())
+				this.setVisible(true);
+			Logger.getLogger(ServerLogFrame.class).error(
+					"level " + level + " class " + clazz + " function "
+							+ function + " msg " + message);
+			logText.append("[" + STR_[level] + "] " + clazz + "::"
+					+ function + " - " + message + "\n");
+		}
+	}
+
+	/**
+	 * Shows frame sets location relative to parent.
+	 *
+	 * @param parent Frame relative to which console window will be localized.
+	 */
+	public void show(final JFrame parent) {
+		if (parent != null) {
+			final Point parentLocation = parent.getLocation();
+			final Point location = new Point(parentLocation.x + 20,
+					parentLocation.y + 20);
+			this.setLocation(location);
+		}
+		this.setVisible(true);
+	}
+}
Index: java/main/src/main/java/com/framsticks/gui/windows/console/ConsoleFrame.java
===================================================================
--- java/main/src/main/java/com/framsticks/gui/windows/console/ConsoleFrame.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/gui/windows/console/ConsoleFrame.java	(revision 77)
@@ -0,0 +1,262 @@
+package com.framsticks.gui.windows.console;
+
+import com.framsticks.communication.*;
+import com.framsticks.gui.ImageProvider;
+import com.framsticks.util.Pair;
+import com.framsticks.util.Strings;
+import org.apache.log4j.Logger;
+
+import javax.swing.*;
+import java.awt.*;
+import java.awt.event.*;
+import java.util.ArrayList;
+import java.util.Collections;
+
+/**
+ * Frame with text field for sending commands and text pane for displaying manager responses.
+ */
+@SuppressWarnings("serial")
+public class ConsoleFrame extends JFrame {
+
+	private static final Logger LOGGER = Logger.getLogger(ConsoleFrame.class.getName());
+
+	/**
+     * Painter coloring manager responses before display.
+     */
+    private final ConsolePainter consolePainter;
+
+    /**
+     * Text field for typing commands.
+     */
+    private final JTextField commandLine;
+	/**
+     * Reference to connection.
+     */
+    protected final ClientConnection connection;
+
+	/**
+	 * List of sent messages.
+	 * TODO: is it used at all?
+	 */
+	private final ArrayList<String> sentMessages = new ArrayList<String>();
+
+	/**
+	 * Current visible tip list.
+	 */
+	private ArrayList<String> tipList = null;
+
+	private int msgIndex = 0;
+	private int tipIndex = 0;
+	private Boolean clearMsgIndex = false;
+
+
+	/**
+     * Default constructor creates frame with console.
+     */
+    @SuppressWarnings("unchecked")
+    public ConsoleFrame(ClientConnection connection) {
+	    this.connection = connection;
+        this.setTitle("Console");
+        this.setLayout(new BorderLayout());
+        this.setSize(new Dimension(440, 400));
+        this.setMinimumSize(new Dimension(440, 400));
+        this.setIconImage(ImageProvider.loadImage(ImageProvider.LOGO).getImage());
+        JFrame.setDefaultLookAndFeelDecorated(true);
+
+	    JTextPane text = new JTextPane();
+        consolePainter = new ConsolePainter(text);
+
+        text.setEditable(false);
+        final JScrollPane scrollText = new JScrollPane(text);
+        scrollText.setBorder(BorderFactory.createEtchedBorder());
+
+        JPanel scrollPanel = new JPanel();
+        scrollPanel.setLayout(new BorderLayout());
+        scrollPanel.add(scrollText, BorderLayout.CENTER);
+        scrollPanel.setBorder(BorderFactory.createEmptyBorder(7, 7, 7, 7));
+
+        commandLine = new JTextField();
+
+        commandLine.addKeyListener(new KeyListener() {
+	        @Override
+	        public void keyTyped(KeyEvent e) {
+
+	        }
+
+	        @Override
+	        public void keyPressed(KeyEvent e) {
+		        onKeyPressed(e.getKeyCode());
+	        }
+
+	        @Override
+	        public void keyReleased(KeyEvent e) {
+	        }
+        });
+
+        commandLine.setFocusTraversalKeys(
+		        KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS,
+		        Collections.EMPTY_SET);
+
+        this.addWindowListener(new WindowAdapter() {
+            public void windowActivated(WindowEvent e) {
+                commandLine.requestFocusInWindow();
+            }
+        });
+
+	    JButton sendButton = new JButton("Send");
+        sendButton.addActionListener(new ActionListener() {
+
+	        public void actionPerformed(final ActionEvent e) {
+		        buttonSendAction();
+	        }
+
+        });
+
+        final Box cmdBox = new Box(BoxLayout.LINE_AXIS);
+        cmdBox.add(commandLine);
+        cmdBox.add(Box.createHorizontalStrut(10));
+        cmdBox.add(sendButton);
+        cmdBox.setBorder(BorderFactory.createEmptyBorder(0, 7, 7, 7));
+
+        this.getContentPane().add(scrollPanel, BorderLayout.CENTER);
+        this.getContentPane().add(cmdBox, BorderLayout.PAGE_END);
+        this.setVisible(false);
+
+    }
+
+	public void setCommandLine(String command) {
+		commandLine.setText(command);
+	}
+
+
+    /**
+     * Shows console frame, sets location relative to parent.
+     *
+     * @param parent Frame relative to which console window will be localized.
+     */
+    public void show(JFrame parent) {
+        final Point parentLocation = parent.getLocation();
+        final Point location = new Point(parentLocation.x + 20, parentLocation.y + 20);
+        this.setLocation(location);
+        this.setVisible(true);
+    }
+
+    /**
+     * Adds query to console window.
+     *
+     * @param line Line of string query.
+     */
+    private void addQuery(String line) {
+        consolePainter.userMsg(line + "\n");
+    }
+
+
+    /**
+     * Sends message to manager and adds message to console frame.
+     */
+    public void buttonSendAction() {
+        if (!connection.isConnected()) {
+            JOptionPane.showMessageDialog(this, "missing connection to manager");
+            return;
+        }
+        String commandText = commandLine.getText();
+	    Pair<String, String> command = Strings.splitIntoPair(commandText, ' ', "\n");
+        Request request = Request.createRequestByTypeString(command.first);
+        if (request == null) {
+            LOGGER.warn("not a valid request: " + commandText);
+            return;
+        }
+        request.parseRest(command.second);
+
+	    addQuery(commandText);
+	    addSentMessage(commandText);
+	    commandLine.setText("");
+        connection.send(request, new ResponseCallback() {
+            @Override
+            public void process(Response response) {
+                for (File f : response.getFiles()) {
+                    consolePainter.paintMessage(f);
+                }
+            }
+        });
+    }
+
+	private void onKeyPressed(int keyCode) {
+		if (keyCode == KeyEvent.VK_TAB) {
+			String tmp = commandLine.getText();
+			int selStart = commandLine.getSelectionStart();
+
+			tmp = tmp.substring(0, selStart);
+
+			if (selStart > 0) {
+
+				if (tipList == null) {
+					createTipList(tmp.substring(0, selStart));
+					tipIndex = tipList.size() - 1;
+				}
+
+				if (tipList.size() > 0) {
+					String element = tipList.get(tipIndex);
+					tipIndex--;
+					if (tipIndex < 0) {
+						tipIndex = tipList.size() - 1;
+					}
+					commandLine.setText(element);
+				}
+
+			}
+		} else {
+			tipList = null;
+		}
+
+		if (keyCode == KeyEvent.VK_UP || keyCode == KeyEvent.VK_DOWN) {
+			int dir = (keyCode == KeyEvent.VK_UP ? -1 : 1);
+			if (clearMsgIndex) {
+				msgIndex = sentMessages.size();
+				clearMsgIndex = false;
+			}
+
+			msgIndex += dir;
+			if (msgIndex < 0) {
+				msgIndex = 0;
+			} else if (msgIndex >= sentMessages.size()) {
+				msgIndex = sentMessages.size() - 1;
+			}
+
+			String element = sentMessages.get(msgIndex);
+			commandLine.setText(element);
+			return;
+
+		}
+
+		if (keyCode == KeyEvent.VK_ENTER) {
+			clearMsgIndex = true;
+			buttonSendAction();
+			return;
+		}
+
+		clearMsgIndex = true;
+
+	}
+
+	/**
+	 * Creates commands tip list.
+	 * @param startText Text that user typed.
+	 */
+	private void createTipList(String startText) {
+		tipList = new ArrayList<String>();
+
+		for (String next : sentMessages) {
+			if (next.startsWith(startText)) {
+				tipList.add(next);
+			}
+		}
+	}
+
+	public void addSentMessage(String msg) {
+		if (!sentMessages.contains(msg)) {
+			sentMessages.add(msg);
+		}
+	}
+
+}
Index: java/main/src/main/java/com/framsticks/gui/windows/console/ConsolePainter.java
===================================================================
--- java/main/src/main/java/com/framsticks/gui/windows/console/ConsolePainter.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/gui/windows/console/ConsolePainter.java	(revision 77)
@@ -0,0 +1,222 @@
+package com.framsticks.gui.windows.console;
+
+import com.framsticks.communication.File;
+import com.framsticks.params.SourceInterface;
+import org.apache.log4j.Logger;
+
+import java.awt.Color;
+
+import javax.swing.JTextPane;
+import javax.swing.text.BadLocationException;
+import javax.swing.text.Document;
+import javax.swing.text.SimpleAttributeSet;
+
+/**
+ * Class paints messages.
+ */
+public class ConsolePainter {
+	private static final Logger LOGGER = Logger.getLogger(ConsolePainter.class.getName());
+
+	private Document doc;
+	private JTextPane textPane;
+	private Color c1 = new Color(192, 0, 0);
+	private Color c2 = new Color(84, 141, 212);
+	private Color c3 = new Color(118, 146, 60);
+	private Color c4 = new Color(0, 0, 128);
+	private SimpleLinePainter linePainter1;
+	private SimpleLinePainter linePainter2;
+	private final SimpleAttributeSet set = new SimpleAttributeSet();
+
+	
+	/**
+	 * Constructor sets reference to pane with text.
+	 * @param pane Pane where text is displaying.
+	 */
+	public ConsolePainter(JTextPane pane) {
+		this.textPane = pane;
+		doc = textPane.getStyledDocument();
+		linePainter1 = new SimpleLinePainter(textPane, new Color(224, 224, 255));
+		linePainter2 = new SimpleLinePainter(textPane, new Color(240, 240, 255));
+	}
+
+	/**
+	 * Paints message.
+	 */
+	public void paintMessage(File file) {
+
+
+		String line;
+		Boolean boldNextId = false;
+		Boolean doNotPaint = false;
+
+		while ((line = file.getContent().readLine()) != null) {
+			paintLine(line + "\n");
+			/*
+			if (doNotPaint) {
+				plainText(line);
+				if (line.endsWith("~\n")) {
+					doNotPaint = false;
+				}
+				continue;
+			}
+
+			int indColon = line.indexOf(':');
+
+			if (indColon == -1) {
+				String word = firstWord(line);
+				String rest = line.substring(word.length());
+				Color col = c1;
+
+				if (word.startsWith("ok")) {
+					col = Color.BLACK;
+				} else if (word.startsWith("error")) {
+					col = Color.RED;
+				}
+
+				paintLine(word, col, "b");
+				paintLine(rest, Color.BLACK, "b");
+				continue;
+			}
+
+			if (indColon == line.length() - 2) {
+				String before = line.substring(0, indColon);
+				String type = "b";
+
+				if (before.equals("class")) {
+					boldNextId = true;
+				}
+
+				paintLine(before + ":", c2, type);
+				paintLine("\n", Color.BLACK, "");
+				continue;
+			}
+			String before = line.substring(0, indColon);
+			String after = line.substring(indColon + 1);
+
+			String type;
+
+			if (before.equals("id") && boldNextId) {
+				type = "b";
+				boldNextId = false;
+			} else {
+				type = "";
+			}
+
+			paintLine(before + ":", c3, "b");
+			paintLine(after, Color.BLACK, type);
+
+			if (after.startsWith("~")) {
+				doNotPaint = true;
+			}*/
+
+		}
+
+		scrollDown();
+		
+	}
+
+	private void paintLine(String text) {
+		//TODO colouring output, maybe using parsers?
+		try {
+			doc.insertString(doc.getLength(), text, set);
+		} catch (BadLocationException e) {
+			e.printStackTrace();
+		}
+	}
+	/**
+	 * Paints line of text.
+	 * @param text Line of text to be painted.
+	 * @param color Font color.
+	 * @param type Font attributes [b|i|u] (bold | italic | underline)
+	 */
+	/*
+	private void paintLine(String text, Color color, String type) {
+		SimpleAttributeSet set = new SimpleAttributeSet();
+
+		if (type.contains("b")) {
+			StyleConstants.setBold(set, true);
+		}
+
+		if (type.contains("i")) {
+			StyleConstants.setItalic(set, true);
+		}
+
+		if (type.contains("u")) {
+			StyleConstants.setUnderline(set, true);
+		}
+
+		StyleConstants.setFontFamily(set, "Monospaced");
+		StyleConstants.setForeground(set, color);
+		textPane.setCharacterAttributes(set, true);
+
+		try {
+			doc.insertString(doc.getLength(), text, set);
+		} catch (BadLocationException e) {
+			e.printStackTrace();
+		}
+
+	}
+	*/
+
+
+
+	/**
+	 * Returns first word in text line.
+	 * @param line Line of text.
+	 * @return First word in text line (with space char).
+	 */
+	private String firstWord(String line) {
+		String result;
+		int spaceIndex = line.indexOf(' ');
+
+		if (spaceIndex == -1) {
+			result = line;
+		} else {
+			result = line.substring(0, spaceIndex + 1);
+		}
+
+		return result;
+	}
+
+	/**
+	 * Paint line as plain text.
+	 * @param msg
+	 */
+	/*
+	private void plainText(String msg) {
+		paintLine(msg, Color.BLACK, "");
+	}
+	*/
+
+	/**
+	 * Adds message typed by user.
+	 * @param msg Message typed by user.
+	 */
+	public void userMsg(String msg) {
+		paintLine("[USER]> "/*, c4, "b"*/);
+		scrollDown();
+		linePainter1.resetHighlight();
+		paintLine(msg);
+		scrollDown();
+	}
+
+	/**
+	 * Adds message that user 'clicked' in interface.
+	 * @param msg Message sent from interface.
+	 */
+	public void clickMsg(String msg) {
+		paintLine("[click]> "/*, c4, "b"*/);
+		scrollDown();
+		linePainter2.resetHighlight();
+		paintLine(msg);
+		scrollDown();
+	}
+
+	/**
+	 * Scrolling text pane.
+	 */
+	private void scrollDown() {
+		textPane.setCaretPosition(doc.getLength() - 1);
+	}
+
+}
Index: java/main/src/main/java/com/framsticks/gui/windows/console/SimpleLinePainter.java
===================================================================
--- java/main/src/main/java/com/framsticks/gui/windows/console/SimpleLinePainter.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/gui/windows/console/SimpleLinePainter.java	(revision 77)
@@ -0,0 +1,70 @@
+package com.framsticks.gui.windows.console;
+
+import javax.swing.text.*;
+import java.awt.*;
+
+/**
+ * Painter class to coloring text background.
+ */
+public class SimpleLinePainter extends
+		DefaultHighlighter.DefaultHighlightPainter {
+
+	private JTextComponent component;
+	private DefaultHighlighter highlighter;
+
+	/**
+	 * Constructor sets component reference.
+	 *
+	 * @param component Reference to painted component.
+	 * @param color     Background color.
+	 */
+	public SimpleLinePainter(JTextComponent component, Color color) {
+		super(color);
+
+		this.component = component;
+
+		highlighter = (DefaultHighlighter) component.getHighlighter();
+		highlighter.setDrawsLayeredHighlights(true);
+	}
+
+	/**
+	 * Adds highlight in line sets by offset.
+	 *
+	 * @param offset Line offset.
+	 */
+	public void addHighlight(int offset) {
+		try {
+			highlighter.addHighlight(offset, offset + 1, this);
+		} catch (BadLocationException ignored) {
+		}
+	}
+
+	/**
+	 * Resets highlight.
+	 */
+	public void resetHighlight() {
+
+		Element root = component.getDocument().getDefaultRootElement();
+		int line = root.getElementIndex(component.getCaretPosition());
+		Element lineElement = root.getElement(line);
+		int start = lineElement.getStartOffset();
+		addHighlight(start);
+	}
+
+
+	public Shape paintLayer(Graphics g, int offs0, int offs1, Shape bounds,
+	                        JTextComponent c, View view) {
+		try {
+			Rectangle r = c.modelToView(offs0);
+			r.x = 0;
+			r.width = c.getSize().width;
+
+			g.setColor(getColor());
+			g.fillRect(r.x, r.y, r.width, r.height);
+			return r;
+		} catch (BadLocationException e) {
+			return null;
+		}
+	}
+
+}
Index: java/main/src/main/java/com/framsticks/hosting/InstanceClient.java
===================================================================
--- java/main/src/main/java/com/framsticks/hosting/InstanceClient.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/hosting/InstanceClient.java	(revision 77)
@@ -0,0 +1,94 @@
+package com.framsticks.hosting;
+
+import com.framsticks.communication.*;
+import com.framsticks.communication.queries.ApplicationRequest;
+import com.framsticks.communication.queries.GetRequest;
+import com.framsticks.communication.queries.InfoRequest;
+import com.framsticks.core.Path;
+import com.framsticks.params.*;
+import com.framsticks.parsers.Savers;
+import com.framsticks.core.LocalInstance;
+import com.framsticks.util.Future;
+
+import java.net.Socket;
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * @author Piotr Sniegowski
+ */
+public class InstanceClient implements RequestHandler {
+
+    protected final LocalInstance instance;
+    protected final ServerConnection connection;
+
+    public InstanceClient(LocalInstance instance, Socket socket) {
+        this.instance = instance;
+        connection = new ServerConnection(socket, this);
+        connection.start();
+    }
+
+    @Override
+    public String toString() {
+        return instance + "|" + connection.toString();
+    }
+
+
+    @Override
+    public void handle(final ApplicationRequest request, final ResponseCallback responseCallback) {
+        instance.invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                final Path path = new Path(instance, request.getPath());
+                if (!path.isResolved(request.getPath())) {
+                    responseCallback.process(new Response(false, "\"invalid path\"", null));
+                    return;
+                }
+                if (request instanceof GetRequest) {
+                    instance.findInfo(path, new Future<FramsClass>() {
+                        @Override
+                        public void result(FramsClass result, Exception e) {
+                            if (result == null) {
+                                responseCallback.process(new Response(false, "\"failed to find info for access bind\"", null));
+                                return;
+                            }
+                            List<File> files = new LinkedList<File>();
+                            AccessInterface access = instance.bindAccess(path);
+
+                            if (access == null) {
+
+                                responseCallback.process(new Response(false, "\"failed to bind access\"", null));
+                                return;
+                            }
+                            ListSink sink = new ListSink();
+                            access.save(sink);
+                            files.add(new File(path.getTextual(), new ListSource(sink.getOut())));
+                            responseCallback.process(new Response(true, "", files));
+                        }
+                    });
+                    return;
+                }
+                if (request instanceof InfoRequest) {
+                    instance.findInfo(path, new Future<FramsClass>() {
+                        @Override
+                        public void result(FramsClass result, Exception e) {
+                            if (result == null) {
+                                responseCallback.process(new Response(false, "\"info not found\"", null));
+                                return;
+                            }
+                            ListSink sink = new ListSink();
+                            Savers.saveFramsClass(sink, result);
+                            List<File> files = new ArrayList<File>();
+                            files.add(new File(path.getTextual(), new ListSource(sink.getOut())));
+                            responseCallback.process(new Response(true, null, files));
+                        }
+                    });
+                    return;
+                }
+                responseCallback.process(new Response(false, "invalid", null));
+            }
+        });
+
+    }
+}
Index: java/main/src/main/java/com/framsticks/hosting/ServerInstance.java
===================================================================
--- java/main/src/main/java/com/framsticks/hosting/ServerInstance.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/hosting/ServerInstance.java	(revision 77)
@@ -0,0 +1,85 @@
+package com.framsticks.hosting;
+
+import com.framsticks.core.*;
+import com.framsticks.params.FramsClass;
+import com.framsticks.params.ParamBuilder;
+import com.framsticks.params.types.CompositeParam;
+import com.framsticks.core.LocalInstance;
+import com.framsticks.util.Future;
+import org.apache.log4j.Logger;
+
+/**
+ * @author Piotr Sniegowski
+ */
+public class ServerInstance extends LocalInstance {
+
+    private final static Logger LOGGER = Logger.getLogger(ServerInstance.class.getName());
+
+    Entity hosted;
+
+    public ServerInstance(Parameters parameters) {
+        super(parameters);
+    }
+
+    @Override
+    protected void run() {
+        super.run();
+        assert hosted != null;
+        hosted.start();
+    }
+
+    @Override
+    protected void configure() {
+        super.configure();
+
+        Parameters p = new Parameters(config.subset("hosted.entity"), "hosted", this);
+        hosted = Program.configureEntity(p);
+        if (hosted == null) {
+            LOGGER.fatal("failed to create hosted entity");
+            return;
+        }
+        hosted.configurePublic();
+        root = new Node((CompositeParam)new ParamBuilder().setName("root").setId("root").setType("o" + hosted.getClass().getCanonicalName()).build(), hosted);
+    }
+
+    @Override
+    public FramsClass getInfoFromCache(String id) {
+        assert isActive();
+        if (id == null) {
+            return null;
+        }
+        if (infoCache.containsKey(id)) {
+            return infoCache.get(id);
+        }
+        try {
+            Class nativeClass = Class.forName(id);
+            FramsClass framsClass = new FramsClass.Constructor(nativeClass, id).getResult();
+
+            registerReflectedClass(id, nativeClass);
+            putInfoIntoCache(framsClass);
+            return framsClass;
+        } catch (ClassNotFoundException ignored) {
+        }
+
+        return null;
+    }
+
+    @Override
+    protected void fetchInfo(Path path, Future<FramsClass> future) {
+        assert isActive();
+
+        FramsClass framsClass = getInfoFromCache(path.getTop().getObject().getClass().getCanonicalName());
+        if (framsClass == null) {
+            LOGGER.error("failed to create frams class for: " + path.getTop().getObject().getClass());
+            future.result(null, new Exception());
+            return;
+        }
+        future.result(framsClass, null);
+
+    }
+
+    @Override
+    protected void tryRegisterOnChangeEvents(Path path) {
+    }
+
+}
Index: java/main/src/main/java/com/framsticks/leftovers/FavouritesXMLFactory.java
===================================================================
--- java/main/src/main/java/com/framsticks/leftovers/FavouritesXMLFactory.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/leftovers/FavouritesXMLFactory.java	(revision 77)
@@ -0,0 +1,249 @@
+package com.framsticks.leftovers;
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileWriter;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.stream.XMLOutputFactory;
+import javax.xml.stream.XMLStreamWriter;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+public class FavouritesXMLFactory {
+
+	private final String pathMark = "path";
+	private final String nameMark = "name";
+	private final String fieldMark = "field";
+	private final String typeMark = "type";
+
+	/**
+	 * Writes favourites nodes and fields list to XML file.
+	 * 
+	 * @param path
+	 *            Path of XML file.
+	 * @param nodes
+	 *            Collection of user favourites nodes and fields.
+	 */
+	public void writeFavouritesXML(String path, Collection<UserFavourite> nodes) {
+		if (nodes.isEmpty()) {
+			return;
+		}
+		XMLOutputFactory factory = XMLOutputFactory.newInstance();
+		BufferedWriter writer = null;
+		XMLStreamWriter xmlWriter = null;
+		try {
+			File file = new File(path);
+			if (file.exists()) {
+				file.delete();
+			}
+			writer = new BufferedWriter(new FileWriter(file));
+			xmlWriter = factory.createXMLStreamWriter(writer);
+			xmlWriter.writeStartDocument("1.0");
+			xmlWriter.writeStartElement("root");
+			for (UserFavourite node : nodes) {
+				xmlWriter.writeStartElement("item");
+
+				xmlWriter.writeStartElement(pathMark);
+				xmlWriter.writeCharacters(node.getPath());
+				xmlWriter.writeEndElement();
+
+				xmlWriter.writeStartElement(nameMark);
+				xmlWriter.writeCharacters(node.getName());
+				xmlWriter.writeEndElement();
+
+				/*if(node.isFavouriteNode()){
+					xmlWriter.writeStartElement(typeMark);
+					xmlWriter.writeCharacters(Integer.toString(node.getNodeType().getId()));
+					xmlWriter.writeEndElement();
+				}else{ //isFavouriteField() */
+					xmlWriter.writeStartElement(fieldMark);
+					xmlWriter.writeCharacters(node.getField());
+					xmlWriter.writeEndElement();
+				//}
+
+				xmlWriter.writeEndElement();
+			}
+
+			xmlWriter.writeEndDocument();
+			xmlWriter.flush();
+		} catch (Exception e) {
+		} finally {
+			try {
+				xmlWriter.close();
+				writer.close();
+			} catch (Exception e) {
+			}
+		}
+	}
+
+	/**
+	 * Reads user favourites nodes and fields from XML file.
+	 * 
+	 * @param filePath
+	 *            PAth to XML file.
+	 * @return LinkedHashMap contains user favourites nodes and fields. Key is
+	 *         concatenation of path and field getName.
+	 */
+	public LinkedHashMap<String, UserFavourite> readFavouritesXML(String filePath) {
+		LinkedHashMap<String, UserFavourite> result = new LinkedHashMap<String, UserFavourite>();
+
+		File file = new File(filePath);
+		if (file.exists()) {
+			DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory
+					.newInstance();
+			try {
+				DocumentBuilder docBuilder = docBuilderFactory
+						.newDocumentBuilder();
+				Document doc = docBuilder.parse(file);
+				doc.getDocumentElement().normalize();
+				Node root = doc.getFirstChild();
+				NodeList items = root.getChildNodes();
+				UserFavourite userNode;
+				String path, name, field;
+				for (int i = 0; i < items.getLength(); i++) {
+					Node item = items.item(i);
+					NodeList itemDetails = item.getChildNodes();
+					if (itemDetails.getLength() == 3) {
+						if (itemDetails.item(0).getNodeName().equals(pathMark)
+								&& itemDetails.item(1).getNodeName().equals(nameMark)
+								&& (itemDetails.item(2).getNodeName().equals(fieldMark) 
+										|| itemDetails.item(2).getNodeName().equals(typeMark))) {
+							path = itemDetails.item(0).getTextContent();
+							name = itemDetails.item(1).getTextContent();
+							if (itemDetails.item(2).getNodeName().equals(
+									fieldMark)) {
+								field = itemDetails.item(2).getTextContent();
+								userNode = new UserFavourite(path, name, field);
+								result.put(path+field, userNode);
+							}else{
+								try {
+									int nodeTypeId = Integer.parseInt(itemDetails.item(2).getTextContent());
+									userNode = new UserFavourite(path, name, null);
+									result.put(path, userNode);
+								} catch (Exception e) {
+								}
+							}
+						}
+					}
+				}
+			} catch (Exception e) {
+			}
+
+		}
+
+		return result;
+	}
+
+	/**
+	 * Writes column configuration to XML file.
+	 * 
+	 * @param path
+	 *            Path to XML file.
+	 * @param groupColumns
+	 *            Map with column configuration. Key - path to group node. Value -
+	 *            List of columns getId.
+	 */
+	public void writeColumnConfigurationXML(String path,
+			Map<String, ArrayList<String>> groupColumns) {
+		if (groupColumns.isEmpty()) {
+			return;
+		}
+		XMLOutputFactory factory = XMLOutputFactory.newInstance();
+		BufferedWriter writer = null;
+		XMLStreamWriter xmlWriter = null;
+		try {
+			File file = new File(path);
+			if (file.exists()) {
+				file.delete();
+			}
+			writer = new BufferedWriter(new FileWriter(file));
+			xmlWriter = factory.createXMLStreamWriter(writer);
+			xmlWriter.writeStartDocument("1.0");
+			xmlWriter.writeStartElement("root");
+
+			Iterator<String> iterator = groupColumns.keySet().iterator();
+			while (iterator.hasNext()) {
+				/*
+	  Definition of read/write mark.
+	 */
+				String itemMark = "item";
+				xmlWriter.writeStartElement(itemMark);
+				String itemPath = iterator.next();
+				xmlWriter.writeAttribute(pathMark, itemPath);
+
+				for (String column : groupColumns.get(itemPath)) {
+					String columnMark = "column";
+					xmlWriter.writeStartElement(columnMark);
+					xmlWriter.writeCharacters(column);
+					xmlWriter.writeEndElement();
+				}
+
+				xmlWriter.writeEndElement();
+			}
+
+			xmlWriter.writeEndDocument();
+			xmlWriter.flush();
+		} catch (Exception e) {
+		} finally {
+			try {
+				xmlWriter.close();
+				writer.close();
+			} catch (Exception e) {
+			}
+		}
+	}
+
+	/**
+	 * Reads column configuration from XML file.
+	 * 
+	 * @param path
+	 *            Path to XML file.
+	 * @return HashMap with configuration. Key - path to group node. Value -
+	 *         List of columns getId.
+	 */
+	public HashMap<String, ArrayList<String>> readColumnConfigurationXML(
+			String path) {
+		HashMap<String, ArrayList<String>> result = new LinkedHashMap<String, ArrayList<String>>();
+
+		File file = new File(path);
+		if (file.exists()) {
+			DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory
+					.newInstance();
+			try {
+				DocumentBuilder docBuilder = docBuilderFactory
+						.newDocumentBuilder();
+				Document doc = docBuilder.parse(file);
+				doc.getDocumentElement().normalize();
+				Node root = doc.getFirstChild();
+				NodeList items = root.getChildNodes();
+				String itemPath;
+				ArrayList<String> columns;
+				for (int i = 0; i < items.getLength(); i++) {
+					Node item = items.item(i);
+					itemPath = item.getAttributes().getNamedItem(pathMark)
+							.getNodeValue();
+					columns = new ArrayList<String>();
+					NodeList itemDetails = item.getChildNodes();
+					for (int j = 0; j < itemDetails.getLength(); j++) {
+						columns.add(itemDetails.item(j).getTextContent());
+					}
+					result.put(itemPath, columns);
+				}
+			} catch (Exception e) {
+			}
+
+		}
+
+		return result;
+	}
+}
Index: java/main/src/main/java/com/framsticks/leftovers/UserFavourite.java
===================================================================
--- java/main/src/main/java/com/framsticks/leftovers/UserFavourite.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/leftovers/UserFavourite.java	(revision 77)
@@ -0,0 +1,38 @@
+package com.framsticks.leftovers;
+
+/**
+ * Class stores information about user favourite node or field.
+ */
+public class UserFavourite {
+
+	/**
+	 * Name of node/field.
+	 */
+	private String name;
+	/**
+	 * Path to node/field.
+	 */
+	private String path;
+	/**
+	 * Field name - property getId or group name if node is group;
+	 */
+	private String fieldId = null;
+
+	public UserFavourite(String path, String name, String fieldId) {
+		this.path = path;
+		this.name = name;
+		this.fieldId = fieldId;
+	}
+
+	public String getPath() {
+		return path;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public String getField() {
+		return fieldId;
+	}
+}
Index: java/main/src/main/java/com/framsticks/leftovers/f0/NeuroClass.java
===================================================================
--- java/main/src/main/java/com/framsticks/leftovers/f0/NeuroClass.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/leftovers/f0/NeuroClass.java	(revision 77)
@@ -0,0 +1,187 @@
+package com.framsticks.leftovers.f0;
+
+import java.util.Arrays;
+
+import com.framsticks.params.FramsClass;
+
+/**
+ * The Class NeuroClass.
+ */
+public class NeuroClass {
+	/*
+	public String name, longname, description, code, icon;
+	public Integer prefinputs, prefoutput, preflocation, vhints;
+	*/
+
+	/** The symbol glymph. */
+	private int[] symbolGlymph;
+	
+	/** The pref inputs. */
+	private int prefInputs;
+	
+	/** The pref output. */
+	private int prefOutput;
+	
+	/** The pref location. */
+	private int prefLocation;
+	
+	/** The param entry list. */
+	private FramsClass framsClass;
+	
+	/** The visual hints. */
+	private int visualHints;
+
+	/**
+	 * long description.
+	 *
+	 * @return the description
+	 */
+	String getDescription() {
+		return framsClass.getDescription();
+	}
+
+	/**
+	 * class getId (short getName).
+	 *
+	 * @return the getId
+	 */
+	String getId() {
+		return framsClass.getId();
+	}
+
+	/**
+	 * Instantiates a new neuro class.
+	 *
+	 * @param framsClass the param entry list
+	 * @param prefInputs the pref inputs
+	 * @param prefOutput the pref output
+	 * @param prefLocation the pref location
+	 * @param visualHints the visual hints
+	 * @param symbolGlymph the symbol glymph
+	 */
+	public NeuroClass(FramsClass framsClass, int prefInputs,
+			int prefOutput, int prefLocation, int visualHints,
+			int[] symbolGlymph) {
+		super();
+		this.framsClass = framsClass;
+		this.prefInputs = prefInputs;
+		this.prefOutput = prefOutput;
+		this.prefLocation = prefLocation;
+		this.visualHints = visualHints;
+		this.symbolGlymph = symbolGlymph;
+	}
+
+	/**
+	 * human friendly getName, eg. "Neuron","Link","Gyroscope"
+	 *
+	 * @return the getName
+	 */
+	String getName() {
+		return framsClass.getName();
+	}
+
+	/**
+	 * NeuroClass specific properties, recognized by all neurons of this class.
+	 *
+	 * @return the param entry list
+	 */
+	FramsClass getFramsClass() {
+		return framsClass;
+	}
+
+	/**
+	 * Gets the param tab.
+	 *
+	 * @return the param tab
+	 */
+	FramsClass getParamTab() {
+		return framsClass;
+	}
+
+	/**
+	 * preferred number of inputs, -1 = no preference (any number will go).
+	 * extra inputs may be ignored by the object (depends on the class).
+	 *
+	 * @return the preferred inputs
+	 */
+	int getPreferredInputs() {
+		return prefInputs;
+	}
+
+	/**
+	 * Gets the preferred location.
+	 *
+	 * @return 0 if the object doesn't need any assignment to the body element.
+	 * 1 = it likes to be attached to the Part ( @see
+	 * Neuro::attachToPart() )
+	 * 2 = the object prefers to have the Joint ( @see
+	 * Neuro::attachToJoint() )
+	 */
+	int getPreferredLocation() {
+		return prefLocation;
+	}
+
+	/**
+	 * Gets the preferred output.
+	 *
+	 * @return 0 if this object doesn't provide useful output signal.
+	 */
+	int getPreferredOutput() {
+		return prefOutput;
+	}
+
+	/**
+	 * vector drawing to be used in neuro net diagram. interpretation: { LEN =
+	 * datalength (excluding this number) NL = number_of_lines line#1 -> NS =
+	 * number_of_segments, x1,y1, x2,y2, ... xNS-1,yNS-1, ... line#NL -> NS =
+	 * number_of_segments, x1,y1, x2,y2, ... xNS-1,yNS-1, }
+	 *
+	 * @return the symbol glyph
+	 */
+	int[] getSymbolGlyph() {
+		return symbolGlymph;
+	}
+
+	/**
+	 * vector drawing to be used in neuro net diagram. interpretation: { LEN =
+	 * datalength (excluding this number) NL = number_of_lines line#1 -> NS =
+	 * number_of_segments, x1,y1, x2,y2, ... xNS-1,yNS-1, ... line#NL -> NS =
+	 * number_of_segments, x1,y1, x2,y2, ... xNS-1,yNS-1, }
+	 *
+	 * @param data the new symbol glyph
+	 */
+	void setSymbolGlyph(int[] data) {
+		symbolGlymph = data;
+	}
+
+	/**
+	 * additional information about how the neuron should be drawn used by
+	 * structure view (and maybe some other components). return value is defined
+	 * by the enum Hint
+	 *
+	 * @return the visual hints
+	 */
+	int getVisualHints() {
+		return visualHints;
+	}
+
+
+	@Override
+	public String toString() {
+		StringBuilder sb = new StringBuilder();
+		sb.append("NeuroClass [getId=" + framsClass.getId() + ", getName="
+				+ framsClass.getName() + ", description="
+				+ framsClass.getDescription() + ", groups#="
+				+ framsClass.getGroupCount() + ", prefInputs=" + prefInputs
+				+ ", prefOutput=" + prefOutput + ", prefLocation="
+				+ prefLocation + ", visualHints=" + visualHints
+				+ ", symbolGlymph=" + Arrays.toString(symbolGlymph)
+				+ ", paramList={");
+		for (int i = 0; i < framsClass.getParamCount(); i++) {
+			sb.append("\n");
+			sb.append(framsClass.getParamEntry(i).toString());
+		}
+		sb.append("\n}]");
+		return sb.toString();
+	}
+}
Index: java/main/src/main/java/com/framsticks/leftovers/f0/NeuroConnection.java
===================================================================
--- java/main/src/main/java/com/framsticks/leftovers/f0/NeuroConnection.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/leftovers/f0/NeuroConnection.java	(revision 77)
@@ -0,0 +1,23 @@
+package com.framsticks.leftovers.f0;
+
+/**
+ * The Class NeuroConnection.
+ */
+public class NeuroConnection {
+
+	/** n1 */
+	public Integer thisNeuro;
+
+	/** n2 */
+	public Integer connectedNeuro;
+
+	/** w */
+	public Double weight;
+
+	/** i */
+	public String info;
+
+	/** Vstyle */
+	public String visStyle;
+
+}
Index: java/main/src/main/java/com/framsticks/leftovers/f0/VisualHints.java
===================================================================
--- java/main/src/main/java/com/framsticks/leftovers/f0/VisualHints.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/leftovers/f0/VisualHints.java	(revision 77)
@@ -0,0 +1,28 @@
+package com.framsticks.leftovers.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/model/Creature.java
===================================================================
--- java/main/src/main/java/com/framsticks/model/Creature.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/model/Creature.java	(revision 77)
@@ -0,0 +1,169 @@
+package com.framsticks.model;
+
+import com.framsticks.model.MechPart;
+import com.framsticks.model.Joint;
+import com.framsticks.util.Point3d;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class Creature {
+	public String name;
+
+	public String genotype;
+
+	public String info;
+
+	public Object group;
+
+	public Integer generation;
+	public Integer getGnum() { return generation; }
+	public void setGnum(Integer gnum) { generation = gnum; }
+
+	public Integer buildProblems;
+	public Integer getBuildproblems() { return buildProblems; }
+	public void setBuildproblems(Integer buildproblems) { buildProblems = buildproblems; }
+
+	public Double startingEnergy;
+	public Double getEnerg0() { return startingEnergy; }
+	public void setEnerg0(Double energ0) { startingEnergy = energ0; }
+
+	public Double idlePowerConsumption;
+	public Double getIdleen() { return idlePowerConsumption; }
+	public void setIdleen(Double idleen) { idlePowerConsumption = idleen; }
+
+	public Double energy;
+
+	public Double energyIncome;
+	public Double getEnergy_p() { return energyIncome; }
+	public void setEnergy_p(Double energy_p) { energyIncome = energy_p; }
+
+	public Double energyCosts;
+	public Double getEnergy_m() { return energyCosts; }
+	public void setEnergy_m(Double energy_m) { energyCosts = energy_m; }
+
+	public Double energyBalance;
+	public Double getEnergy_b() { return energyBalance; }
+	public void setEnergy_b(Double energy_b) { energyBalance = energy_b; }
+
+	public Integer performanceCalculation;
+	public Integer getPerf() { return performanceCalculation; }
+	public void setPerf(Integer perf) { performanceCalculation = perf; }
+
+	public Boolean neuralNetworkEnabled;
+
+	public Boolean getNnenabled() { return neuralNetworkEnabled; }
+	public void setNnenabled(Boolean nnenabled) { neuralNetworkEnabled = nnenabled; }
+
+	public Boolean bodySimulation;
+	public Boolean getBodysim() { return bodySimulation; }
+	public void setBodysim(Boolean bodysim) { bodySimulation = bodysim; }
+
+	public Boolean selfCollisions;
+	public Boolean getSelfcol() { return selfCollisions; }
+	public void setSelfcol(Boolean selfcol) { selfCollisions = selfcol; }
+
+	public Integer lifeSpan;
+	public Integer getLifespan() { return lifeSpan; }
+	public void setLifespan(Integer lifespan) { lifeSpan = lifespan; }
+
+	public Double distance;
+
+	public Double currentVelocity;
+	public Double getC_velocity() { return currentVelocity; }
+	public void setC_velocity(Double c_velocity) { currentVelocity = c_velocity; }
+
+	public Double currentVerticalVelocity;
+	public Double getC_vertvelocity() { return currentVerticalVelocity; }
+	public void setC_vertvelocity(Double c_vertvelocity) { currentVerticalVelocity = c_vertvelocity; }
+
+	public Double currentVerticalPosition;
+	public Double getC_vertpos() { return currentVerticalPosition; }
+	public void setC_vertpos(Double c_vertpos) { currentVerticalPosition = c_vertpos; }
+
+	public Double averageVelocity;
+	public Double getVelocity() { return averageVelocity; }
+	public void setVelocity(Double c_velocity) { averageVelocity = c_velocity; }
+
+	public Double averageVerticalVelocity;
+	public Double getVertvel() { return averageVerticalVelocity; }
+	public void setVertvel(Double c_vertvelocity) { averageVerticalVelocity = c_vertvelocity; }
+
+	public Double averageVerticalPosition;
+	public Double getVertpos() { return averageVerticalPosition; }
+	public void setVertpos(Double c_vertpos) { averageVerticalPosition = c_vertpos; }
+
+	public Point3d position = new Point3d();
+
+	public Double getPos_x() { return position.x; }
+	public void setPos_x(Double pos_x) { position.x = pos_x; }
+
+	public Double getPos_y() { return position.y; }
+	public void setPos_y(Double pos_y) { position.y = pos_y; }
+
+	public Double getPos_z() { return position.z; }
+	public void setPos_z(Double pos_z) { position.z = pos_z; }
+
+	public Point3d boundingBox = new Point3d();
+	public Double getSize_x() { return boundingBox.x; }
+	public void setSize_x(Double size_x) { boundingBox.x = size_x; }
+
+	public Double getSize_y() { return boundingBox.y; }
+	public void setSize_y(Double size_y) { boundingBox.y = size_y; }
+
+	public Double getSize_z() { return boundingBox.z; }
+	public void setSize_z(Double size_z) { boundingBox.z = size_z; }
+
+	public Point3d center = new Point3d();
+
+	public Double getCenter_x() { return center.x; }
+	public void setCenter_x(Double center_x) { center.x = center_x; }
+
+	public Double getCenter_y() { return center.y; }
+	public void setCenter_y(Double center_y) { center.y = center_y; }
+
+	public Double getCenter_z() { return center.z; }
+	public void setCenter_z(Double center_z) { center.z = center_z; }
+
+	public Integer getNumparts() { return parts.size(); }
+	public void setNumparts(Integer numparts) { }
+
+	public Integer getNumjoints() { return joints.size(); }
+	public void setNumjoints(Integer numjoints) { }
+
+	public Integer getNumneurons() { return neurons.size(); }
+	public void setNumneurons(Integer numneurons) { }
+
+	public Object[] userFields = new Object[3];
+	public Object getUser1() { return userFields[0]; }
+	public void setUser1(Object user1) { userFields[0] = user1; }
+
+	public Object getUser2() { return userFields[1]; }
+	public void setUser2(Object user2) { userFields[1] = user2; }
+
+	public Object getUser3() { return userFields[2]; }
+	public void setUser3(Object user3) { userFields[2] = user3; }
+
+	public Integer selfCollisionMask;
+	public Integer getSelfmask() { return selfCollisionMask; }
+	public void setSelfmask(Integer selfmask) { selfCollisionMask = selfmask; }
+
+	public Integer otherCollisionMask;
+	public Integer getOthermask() { return otherCollisionMask; }
+	public void setOthermask(Integer othermask) { otherCollisionMask = othermask; }
+
+	public String uid;
+
+	public Integer index;
+
+	public final List<Part> parts = new ArrayList<Part>();
+	public final List<Joint> joints = new ArrayList<Joint>();
+	public final List<NeuroDef> neurodefs = new ArrayList<NeuroDef>();
+
+	public final List<MechPart> mechparts = new ArrayList<MechPart>();
+	public final List<MechJoint> mechjoints = new ArrayList<MechJoint>();
+	public final List<Neuro> neurons = new ArrayList<Neuro>();
+
+
+
+}
Index: java/main/src/main/java/com/framsticks/model/Genotype.java
===================================================================
--- java/main/src/main/java/com/framsticks/model/Genotype.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/model/Genotype.java	(revision 77)
@@ -0,0 +1,93 @@
+package com.framsticks.model;
+
+
+import com.framsticks.util.Containers;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class Genotype {
+	public String name;
+	public String genotype;
+	public String info;
+
+	public Double similarity;
+	public Double getSimi() { return similarity; }
+	public void setSimi(Double simi) { similarity = simi; }
+
+	public Double startingEnergy;
+	public Double getEnerg0() { return startingEnergy; }
+	public void setEnerg0(Double energ0) { startingEnergy = energ0; }
+
+	public Double brainConnections;
+	public Double getNumconnections() { return brainConnections; }
+	public void setNumconnections(Double numconnections) { brainConnections = numconnections; }
+
+    public Integer ordinalNumber;
+	public Integer getNum() { return ordinalNumber; }
+	public void setNum(Integer num) { ordinalNumber = num; }
+
+    public Integer generation;
+	public Integer getGnum() { return generation; }
+	public void setGnum(Integer gnum) { generation = gnum; }
+
+	public Integer instances;
+
+	public Integer lifeSpan;
+	public Integer getLifespan() { return lifeSpan; }
+	public void setLifespan(Integer lifespan) { lifeSpan = lifespan; }
+
+	public Double velocity;
+	public Double distance;
+
+
+	public Double verticalVelocity;
+	public Double getVertvel() { return verticalVelocity; }
+	public void setVertvel(Double vertvel) { verticalVelocity = vertvel; }
+
+	public Double verticalPosition;
+	public Double getVertpos() { return verticalPosition; }
+	public void setVertpos(Double vertpos) { verticalPosition = vertpos; }
+
+	public Double fitness;
+	public Double getFit() { return fitness; }
+	public void setFit(Double fit) { fitness = fit; }
+
+	public Double finalFitness;
+	public Double getFit2() { return finalFitness; }
+	public void setFit2(Double fit2) { finalFitness = fit2; }
+
+	public String genotypeInF0;
+	public String getF0genotype() { return genotypeInF0; }
+	public void setF0genotype(String f0genotype) { genotypeInF0 = f0genotype; }
+
+	public String conversionBacktrace;
+	public String getConvtrace1() { return conversionBacktrace; }
+	public void setConvtrace1(String convtrace1) { conversionBacktrace = convtrace1; }
+
+	public Object[] userFields = new Object[3];
+	public Object getUser1() { return userFields[0]; }
+	public void setUser1(Object user1) { userFields[0] = user1; }
+
+	public Object getUser2() { return userFields[1]; }
+	public void setUser2(Object user2) { userFields[1] = user2; }
+
+	public Object getUser3() { return userFields[2]; }
+	public void setUser3(Object user3) { userFields[2] = user3; }
+
+	public String uid;
+
+	public final List<Part> parts = new ArrayList<Part>();
+	public final List<Joint> joints = new ArrayList<Joint>();
+	public final List<NeuroDef> neurodefs = new ArrayList<NeuroDef>();
+
+
+    public Double getNumparts() { return (double)parts.size(); }
+	public Double getNumjoints() { return (double)joints.size(); }
+	public Double getNumneurons() { return (double)neurodefs.size(); }
+
+    //this is impossible to use, because numparts field is marked as readonly
+    public void setNumparts(Double numparts) { Containers.resizeList(parts, (int)(double)numparts); }
+    public void setNumjoints(Double numjoints) { Containers.resizeList(joints, (int)(double)numjoints); }
+    public void setNumneurons(Double numneurons) { Containers.resizeList(neurodefs, (int)(double)numneurons); }
+}
Index: java/main/src/main/java/com/framsticks/model/Joint.java
===================================================================
--- java/main/src/main/java/com/framsticks/model/Joint.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/model/Joint.java	(revision 77)
@@ -0,0 +1,76 @@
+package com.framsticks.model;
+
+import com.framsticks.util.Point3d;
+
+/**
+ * The Class Joint.
+ *
+ * All accessors are used by ReflectionAccess.
+ */
+public class Joint {
+
+	public void setP1(Integer p1) { part1 = p1; }
+	public Integer getP1() { return part1; }
+	public void setP2(Integer p2) { part2 = p2; }
+	public Integer getP2() { return part2; }
+
+	public void setDx(Double dx) { delta.x = dx; }
+	public void setDy(Double dy) { delta.y = dy; }
+	public void setDz(Double dz) { delta.z = dz; }
+
+	public Double getDx() { return delta.x; }
+	public Double getDy() { return delta.y; }
+	public Double getDz() { return delta.z; }
+
+	public void setRx(Double rx) { rotation.x = rx; }
+	public void setRy(Double ry) { rotation.y = ry; }
+	public void setRz(Double rz) { rotation.z = rz; }
+
+	public Double getRx() { return rotation.x; }
+	public Double getRy() { return rotation.y; }
+	public Double getRz() { return rotation.z; }	
+
+	public Double getStam() { return stamina; }
+	public void setStam(Double stam) { stamina = stam; }
+
+	public Double getStif() { return stiffness; }
+	public void setStif(Double stif) { stiffness = stif; }
+
+	public Double getRotstif() { return rotationStiffness; }
+	public void setRotstif(Double rotstif) { rotationStiffness = rotstif; }
+
+	public String getI() { return info; }
+	public void setI(String i) { info = i; }
+
+	public String getVstyle() { return visualizationStyle; }
+	public void setVstyle(String Vstyle) { visualizationStyle = Vstyle; }
+
+	/** p1 */
+	public Integer part1;
+
+	/** p2 */
+	public Integer part2;
+
+	/** dx, dy, dz*/
+	public final Point3d delta = new Point3d();
+
+	/** rx, ry, rz*/
+	public final Point3d rotation = new Point3d();
+
+	/** stam */
+	public Double stamina;
+
+	/** stif */
+	public Double stiffness;
+
+	/** rotstif */
+	public Double rotationStiffness;
+
+	/** i */
+	public String info;
+
+	/** Vstyle */
+	public String visualizationStyle;
+
+
+}
Index: java/main/src/main/java/com/framsticks/model/MechJoint.java
===================================================================
--- java/main/src/main/java/com/framsticks/model/MechJoint.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/model/MechJoint.java	(revision 77)
@@ -0,0 +1,57 @@
+package com.framsticks.model;
+
+import com.framsticks.util.Point3d;
+
+/**
+ * @author Piotr Sniegowski
+ */
+public class MechJoint {
+	/** rx, ry, rz*/
+	public final Point3d rotation = new Point3d();
+
+	/** dx, dy, dz*/
+	public final Point3d delta = new Point3d();
+
+	/** stif */
+	public Double stiffness;
+
+	/** rotstif */
+	public Double rotationStiffness;
+
+	/** stress */
+	public Double stress;
+
+	/** rotstress */
+	public Double rotationStress;
+
+	public Double getRx() { return rotation.x; }
+	public void setRx(Double rx) { rotation.x = rx; }
+
+	public Double getRy() { return rotation.y; }
+	public void setRy(Double ry) { rotation.y = ry; }
+
+	public Double getRz() { return rotation.z; }
+	public void setRz(Double rz) { rotation.z = rz; }
+
+	public Double getDx() { return delta.x; }
+	public void setDx(Double dx) { delta.x = dx; }
+
+	public Double getDy() { return delta.y; }
+	public void setDy(Double dy) { delta.y = dy; }
+
+	public Double getDz() { return delta.z; }
+	public void setDz(Double dz) { delta.z = dz; }
+
+	public Double getStif() { return stiffness; }
+	public void setStif(Double stif) { stiffness = stif; }
+
+	public Double getRotstif() { return rotationStiffness; }
+	public void setRotstif(Double rotstif) { rotationStiffness = rotstif; }
+
+	public Double getStress() { return stress; }
+	public void setStress(Double stress) { this.stress = stress; }
+
+	public Double getRotstress() { return rotationStress; }
+	public void setRotstress(Double rotstress) { rotationStress = rotstress; }
+
+}
Index: java/main/src/main/java/com/framsticks/model/MechPart.java
===================================================================
--- java/main/src/main/java/com/framsticks/model/MechPart.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/model/MechPart.java	(revision 77)
@@ -0,0 +1,88 @@
+package com.framsticks.model;
+
+import com.framsticks.util.Orientation;
+import com.framsticks.util.Point3d;
+
+/*
+ */
+public class MechPart {
+
+	/** x, y, z */
+	public final Point3d position = new Point3d();
+
+	/** m */
+	public Double mass = 0.0;
+
+	/** s */
+	public Double size = 0.0;
+
+	/** vol */
+	public Double volume = 0.0;
+
+	/** fr */
+	public Double friction = 0.0;
+
+	/** vx, vy, vz */
+	public final Point3d velocity = new Point3d();
+
+    /** oxx, oxy, oxz, oyx, oyy, oyz, ozx, ozy, ozz*/
+    public final Orientation orientation = new Orientation();
+
+	public Double getX() { return position.x; }
+	public void setX(Double x) { position.x = x; }
+
+	public Double getY() { return position.y; }
+	public void setY(Double y) { position.y = y; }
+
+	public Double getZ() { return position.z; }
+	public void setZ(Double z) { position.z = z; }
+
+	public Double getM() { return mass; }
+	public void setM(Double m) { mass = m; }
+
+	public Double getS() { return size; }
+	public void setS(Double s) { size = s; }
+
+	public Double getVol() { return volume; }
+	public void setVol(Double vol) { volume = vol; }
+
+	public Double getFr() { return friction; }
+	public void setFr(Double fr) { friction = fr; }
+
+	public Double getVx() { return velocity.x; }
+	public void setVx(Double vx) { velocity.x = vx; }
+
+	public Double getVy() { return velocity.y; }
+	public void setVy(Double vy) { velocity.y = vy; }
+
+	public Double getVz() { return velocity.z; }
+	public void setVz(Double vz) { velocity.z = vz; }
+
+	public Double getOxx() { return orientation.x.x; }
+	public void setOxx(Double oxx) { orientation.x.x = oxx; }
+
+	public Double getOxy() { return orientation.x.y; }
+	public void setOxy(Double oxy) { orientation.x.y = oxy; }
+
+	public Double getOxz() { return orientation.x.z; }
+	public void setOxz(Double oxz) { orientation.x.z = oxz; }
+
+	public Double getOyx() { return orientation.y.x; }
+	public void setOyx(Double oyx) { orientation.y.x = oyx; }
+
+	public Double getOyy() { return orientation.y.y; }
+	public void setOyy(Double oyy) { orientation.y.y = oyy; }
+
+	public Double getOyz() { return orientation.y.z; }
+	public void setOyz(Double oyz) { orientation.y.z = oyz; }
+
+	public Double getOzx() { return orientation.z.x; }
+	public void setOzx(Double ozx) { orientation.z.x = ozx; }
+
+	public Double getOzy() { return orientation.z.y; }
+	public void setOzy(Double ozy) { orientation.z.y = ozy; }
+
+	public Double getOzz() { return orientation.z.z; }
+	public void setOzz(Double ozz) { orientation.z.z = ozz; }
+
+}
Index: java/main/src/main/java/com/framsticks/model/Neuro.java
===================================================================
--- java/main/src/main/java/com/framsticks/model/Neuro.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/model/Neuro.java	(revision 77)
@@ -0,0 +1,41 @@
+package com.framsticks.model;
+
+import com.framsticks.util.Point3d;
+
+/**
+ * @author Piotr Sniegowski
+ */
+public class Neuro {
+
+	public Integer channelCount;
+
+	public Integer inputCount;
+	public Integer getGetInputCount() { return inputCount; }
+	public void setGetInputCount(Integer getInputCount) { inputCount = getInputCount; }
+
+	public Double inputSum;
+
+	public Double weightedInputSum;
+
+	public Double state;
+
+	public Double currentState;
+	public Double getCurrState() { return currentState; }
+	public void setCurrState(Double currState) { currentState = currState; }
+
+	public Boolean hold;
+
+
+	/** position_x, position_y, position_z*/
+	public final Point3d position = new Point3d();
+
+	public Double getPosition_x() { return position.x; }
+	public void setPosition_x(Double position_x) { position.x = position_x; }
+
+	public Double getPosition_y() { return position.y; }
+	public void setPosition_y(Double position_y) { position.y = position_y; }
+
+	public Double getPosition_z() { return position.z; }
+	public void setPosition_z(Double position_z) { position.z = position_z; }
+
+}
Index: java/main/src/main/java/com/framsticks/model/NeuroDef.java
===================================================================
--- java/main/src/main/java/com/framsticks/model/NeuroDef.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/model/NeuroDef.java	(revision 77)
@@ -0,0 +1,45 @@
+package com.framsticks.model;
+
+/**
+ * @author Piotr Sniegowski
+ */
+public class NeuroDef {
+
+	/** p */
+	public Integer part;
+
+	/** j */
+	public Integer joint;
+
+	/** d */
+	public String details;
+
+	/** i */
+	public String info;
+
+	/** Vstyle */
+	public String visualizationStyle;
+
+	/** getInputCount */
+	public Integer inputCount;
+
+	public Integer getP() { return part; }
+	public void setP(Integer p) { part = p; }
+
+	public Integer getJ() { return joint; }
+	public void setJ(Integer j) { joint = j; }
+
+	public String getD() { return details; }
+	public void setD(String d) { details = d; }
+
+	public String getI() { return info; }
+	public void setI(String i) { info = i; }
+
+	public String getVstyle() { return visualizationStyle; }
+	public void setVstyle(String Vstyle) { visualizationStyle = Vstyle; }
+
+	public Integer getGetInputCount() { return inputCount; }
+	public void setGetInputCount(Integer getInputCount) { inputCount = getInputCount; }
+
+
+}
Index: java/main/src/main/java/com/framsticks/model/Part.java
===================================================================
--- java/main/src/main/java/com/framsticks/model/Part.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/model/Part.java	(revision 77)
@@ -0,0 +1,83 @@
+package com.framsticks.model;
+
+
+import com.framsticks.util.Point3d;
+
+/**
+ * The Class Part.
+ */
+public class Part {
+
+	/** x, y, z*/
+	public final Point3d position = new Point3d();
+
+	/** rx, ry, rz*/
+	public final Point3d rotation = new Point3d();
+
+	/** m */
+	public Double mass;
+
+	/** s */
+	public Double size;
+
+	/** dn */
+	public Double density;
+
+	/** fr */
+	public Double friction;
+
+	/** ing */
+	public Double ingestion;
+
+	/** as */
+	public Double assimilation;
+
+	/** i */
+	public String info;
+
+	/** Vstyle */
+	public String visualizationStyle;
+
+	public Double getX() { return position.x; }
+	public void setX(Double x) { position.x = x; }
+
+	public Double getY() { return position.y; }
+	public void setY(Double y) { position.y = y; }
+
+	public Double getZ() { return position.z; }
+	public void setZ(Double z) { position.z = z; }
+
+	public Double getM() { return mass; }
+	public void setM(Double m) { mass = m; }
+
+	public Double getS() { return size; }
+	public void setS(Double s) { size = s; }
+
+	public Double getDn() { return density; }
+	public void setDn(Double dn) { density = dn; }
+
+	public Double getFr() { return friction; }
+	public void setFr(Double fr) { friction = fr; }
+
+	public Double getIng() { return ingestion; }
+	public void setIng(Double ing) { ingestion = ing; }
+
+	public Double getAs() { return assimilation; }
+	public void setAs(Double as) { assimilation = as; }
+
+	public Double getRx() { return rotation.x; }
+	public void setRx(Double rx) { rotation.x = rx; }
+
+	public Double getRy() { return rotation.y; }
+	public void setRy(Double ry) { rotation.y = ry; }
+
+	public Double getRz() { return rotation.z; }
+	public void setRz(Double rz) { rotation.z = rz; }
+
+	public String getI() { return info; }
+	public void setI(String i) { info = i; }
+
+	public String getVstyle() { return visualizationStyle; }
+	public void setVstyle(String vstyle) { visualizationStyle = vstyle; }
+
+}
Index: java/main/src/main/java/com/framsticks/model/World.java
===================================================================
--- java/main/src/main/java/com/framsticks/model/World.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/model/World.java	(revision 77)
@@ -0,0 +1,21 @@
+package com.framsticks.model;
+
+public class World {
+
+	public Integer wrldbnd;
+	public Double wrldwat;
+	public String faces;
+
+
+	/*
+	public static ReflectionAccess createReflection()
+	{
+		return ReflectionAccess.create(new World(),
+				"World, 1, 3, World",
+				"wrldbnd, 0, 0, World boundary, d, 0",
+				"wrldwat, 0, 0, World water, f, 0",
+				"faces, 0, 0, Faces, s, 0"
+			);
+	}
+	*/
+}
Index: java/main/src/main/java/com/framsticks/observers/Endpoint.java
===================================================================
--- java/main/src/main/java/com/framsticks/observers/Endpoint.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/observers/Endpoint.java	(revision 77)
@@ -0,0 +1,81 @@
+package com.framsticks.observers;
+
+import com.framsticks.core.Instance;
+import com.framsticks.core.InstanceListener;
+import com.framsticks.core.Path;
+import com.framsticks.params.FramsClass;
+import com.framsticks.portals.PortalEndpoint;
+import com.framsticks.core.ListChange;
+import com.framsticks.util.Dispatcher;
+import org.apache.log4j.Logger;
+
+/**
+ * @author Piotr Sniegowski
+ */
+public class Endpoint implements Dispatcher, InstanceListener {
+    private final static Logger LOGGER = Logger.getLogger(PortalEndpoint.class.getName());
+
+    protected Instance instance;
+    protected Observer observer;
+    protected String name;
+
+    public Endpoint() {
+    }
+
+    public final void configurePublic(Observer observer, Instance instance, String name) {
+        assert instance != null;
+        this.name = name;
+        this.observer = observer;
+        this.instance = instance;
+        instance.addListener(this);
+        configure();
+    }
+
+    protected void configure() {
+
+    }
+
+    @Override
+    public void onListChange(Path path, ListChange change) {
+        LOGGER.info("change " + change + " in " + path);
+    }
+
+    @Override
+    public void onRun(Exception e) {
+    }
+
+    @Override
+    public void onStop(Exception e) {
+    }
+
+    @Override
+    public String toString() {
+        return instance.toString();
+    }
+
+    public final Instance getInstance() {
+        return instance;
+    }
+
+    @Override
+    public final boolean isActive() {
+        return instance.isActive();
+    }
+
+    @Override
+    public final void invokeLater(Runnable runnable) {
+        instance.invokeLater(runnable);
+    }
+
+    public Observer getObserver() {
+        return observer;
+    }
+
+    public final String getName() {
+        return name;
+    }
+
+    public static void constructFramsClass(FramsClass.Constructor constructor) {
+        constructor.method("getName").method("getInstance");
+    }
+}
Index: java/main/src/main/java/com/framsticks/observers/Observer.java
===================================================================
--- java/main/src/main/java/com/framsticks/observers/Observer.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/observers/Observer.java	(revision 77)
@@ -0,0 +1,73 @@
+package com.framsticks.observers;
+
+import com.framsticks.core.Entity;
+import com.framsticks.core.Instance;
+import com.framsticks.core.Parameters;
+import com.framsticks.core.Program;
+import com.framsticks.params.FramsClass;
+import com.framsticks.util.Casting;
+import org.apache.commons.configuration.Configuration;
+import org.apache.log4j.Logger;
+
+import java.util.*;
+
+/**
+ * @author Piotr Sniegowski
+ */
+public abstract class Observer extends Entity {
+
+    private final static Logger LOGGER = Logger.getLogger(Observer.class.getName());
+
+    public Observer(Parameters parameters) {
+        super(parameters);
+    }
+
+    protected final Map<String, Endpoint> endpoints = new HashMap<String, Endpoint>();
+
+    protected Endpoint createEndpoint() {
+        return new Endpoint();
+    }
+
+    @Override
+    protected void configure() {
+        super.configure();
+        for (String name : config.getStringArray("endpoints")) {
+            if (getEndpoints().containsKey(name)) {
+                LOGGER.fatal("observer already contains endpoint named: " + name);
+                continue;
+            }
+            Configuration c = config.subset("endpoints." + name);
+            Parameters p = new Parameters(c.subset("entity"), name, null);
+            Entity e = Program.configureEntity(p);
+            Instance i = Casting.tryCast(Instance.class, e);
+            if (i == null) {
+                LOGGER.error("failed to create instance: " + p);
+                continue;
+            }
+            i.configurePublic();
+            Endpoint endpoint = createEndpoint();
+            endpoint.configurePublic(this, i, name);
+            getEndpoints().put(name, endpoint);
+            LOGGER.info("instance " + i + " was added to " + Observer.this);
+        }
+    }
+
+    @Override
+    protected void run() {
+        super.run();
+        for (Endpoint e : getEndpoints().values()) {
+            e.getInstance().start();
+        }
+    }
+
+
+    public Map<String, Endpoint> getEndpoints() {
+        return endpoints;
+    }
+
+    public static void constructFramsClass(FramsClass.Constructor constructor) {
+        constructor.method("getEndpoints");
+    }
+
+
+}
Index: java/main/src/main/java/com/framsticks/params/AccessInterface.java
===================================================================
--- java/main/src/main/java/com/framsticks/params/AccessInterface.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/params/AccessInterface.java	(revision 77)
@@ -0,0 +1,109 @@
+package com.framsticks.params;
+
+import java.util.Collection;
+import java.util.List;
+
+
+/**
+ * The Interface AccessInterface. It's the most general class for storing data in
+ * framsticks. In descriptions of methods names "property" and "parameter" are
+ * synonyms.
+ * 
+ * @author Jarek Szymczak <name.surname@gmail.com> (please replace name and
+ *         surname with my personal data)
+ */
+public interface AccessInterface {
+
+	Param getParam(int i);
+
+	Param getParam(String id);
+
+	String getId();
+
+
+    /*
+    	String getName();
+
+    * This method provides more verbose (but not strict) names of classes.
+     *
+     * e.g. for a list it will return l Type, and if name of FramsClass missing,
+     * it's id will be used
+     *
+    String getNiceName();
+    */
+
+	Param getGroupMember(int gi, int n);
+
+	int getParamCount();
+
+	// void call(int i, Object args, Object ret);
+	// TODO: as for now it's not necessary to implement this method
+
+	<T> T get(int i, Class<T> type);
+
+	<T> T get(String id, Class<T> type);
+
+	<T> T get(Param param, Class<T> type);
+
+	<T> int set(int i, T value);
+
+	<T> int set(String id, T value);
+
+	<T> int set(Param param, T value);
+
+	void setDefault(boolean numericOnly);
+
+	void setDefault(int i, boolean numericOnly);
+
+	void setMin();
+
+	void setMin(int i);
+
+	void setMax();
+
+	void setMax(int i);
+
+	void copyFrom(AccessInterface src);
+
+	void save(SinkInterface sink);
+
+	void load(SourceInterface stream) throws Exception;
+
+	/**
+	 * Return as a single line String.
+	 * 
+	 * @param omitDefaultValues
+	 *            the omit default values
+	 * @return the string
+	 */
+	String save2(boolean omitDefaultValues);
+
+	/**
+	 * Load values from single line String.
+	 * 
+	 * @param line
+	 *            the line with values
+	 * @return the list of not severe exceptions which occurred while loading
+	 * @throws Exception
+	 *             the severe exception occurred while loading
+	 */
+	List<Exception> load2(String line) throws Exception;
+
+	/**
+	 * Removes all the properties values.
+	 */
+	void clearValues();
+
+	void select(Object object);
+
+	Object getSelected();
+
+	AccessInterface cloneAccess();
+
+    Object createAccessee();
+
+    Collection<Param> getParams();
+
+    FramsClass getFramsClass();
+
+}
Index: java/main/src/main/java/com/framsticks/params/ArrayListAccess.java
===================================================================
--- java/main/src/main/java/com/framsticks/params/ArrayListAccess.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/params/ArrayListAccess.java	(revision 77)
@@ -0,0 +1,124 @@
+package com.framsticks.params;
+
+import com.framsticks.util.Numbers;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * @author Piotr Sniegowski
+ */
+public class ArrayListAccess extends ListAccess {
+
+    List list;
+
+
+    public ArrayListAccess(AccessInterface elementAccess) {
+        super(elementAccess);
+    }
+
+    @Override
+    public ArrayListAccess cloneAccess() {
+        return new ArrayListAccess(elementAccess.cloneAccess());
+    }
+
+    @Override
+    public List createAccessee() {
+        return new ArrayList();
+    }
+
+    @Override
+    public Param getParam(int i) {
+        return new ParamBuilder().setId(Integer.toString(i)).setName(elementAccess.getId()).setType("o " + elementAccess.getId()).build();
+    }
+
+    @Override
+    public Param getParam(String id) {
+        Integer i = Numbers.parse(id, Integer.class);
+        return (i == null ? null : getParam(i));
+    }
+
+    @Override
+    public String getId() {
+        return "l " + elementAccess.getId();
+    }
+
+    @Override
+    public int getParamCount() {
+        return list.size();
+    }
+
+    @Override
+    public <T> T get(int i, Class<T> type) {
+        if (i < list.size()) {
+            return type.cast(list.get(i));
+        }
+        return null;
+    }
+
+    @Override
+    public <T> T get(String id, Class<T> type) {
+        return get(Integer.parseInt(id), type);
+    }
+
+    @Override
+    public <T> T get(Param param, Class<T> type) {
+        return get(param.getId(), type);
+    }
+
+    @Override
+    public <T> int set(int i, T value) {
+        while (i >= list.size()) {
+            list.add(null);
+        }
+        list.set(i, value);
+        return 0;
+    }
+
+    @Override
+    public <T> int set(String id, T value) {
+        return set(Integer.parseInt(id), value);
+    }
+
+    @Override
+    public <T> int set(Param param, T value) {
+        return set(param.getId(), value);
+    }
+
+    @Override
+    public void clearValues() {
+        list.clear();
+    }
+
+    /** covariant */
+    @Override
+    public List getSelected() {
+        return list;
+    }
+
+    @Override
+    public void select(Object object) {
+        list = (List)object;
+    }
+
+    @Override
+    public String computeIdentifierFor(Object selected) {
+        return Integer.toString(list.size());
+    }
+
+    @Override
+    public Collection<Param> getParams() {
+        List<Param> result = new LinkedList<Param>();
+        if (list == null) {
+            return result;
+        }
+        for (int i = 0; i < list.size(); ++i) {
+            result.add(getParam(i));
+        }
+        return result;
+    }
+
+
+}
Index: java/main/src/main/java/com/framsticks/params/CastFailure.java
===================================================================
--- java/main/src/main/java/com/framsticks/params/CastFailure.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/params/CastFailure.java	(revision 77)
@@ -0,0 +1,7 @@
+package com.framsticks.params;
+
+/**
+ * @author Piotr Sniegowski
+ */
+public class CastFailure extends Exception {
+}
Index: java/main/src/main/java/com/framsticks/params/Flags.java
===================================================================
--- java/main/src/main/java/com/framsticks/params/Flags.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/params/Flags.java	(revision 77)
@@ -0,0 +1,74 @@
+package com.framsticks.params;
+
+import java.lang.reflect.Field;
+import org.apache.log4j.Logger;
+
+/**
+ * The class Flags contains constants connected with parameter features as
+ * well as feedback about set operation (when setting parameter value).
+ *
+ * Based on c++ defines located in: cpp/gdk/param.h
+ * 
+ * @author Jarek Szymczak <name.surname@gmail.com>
+ * (please replace name and surname with my personal data)
+ *
+ * @@author Piotr Sniegowski
+ */
+public final class Flags {
+
+	private final static Logger logger = Logger.getLogger(Flags.class.getName());
+
+
+	public static final int READONLY = 1;
+
+	public static final int DONTSAVE = 2;
+
+	public static final int USERREADONLY = 16;
+
+	public static final int USERHIDDEN = 32;
+
+	public static final int MUTALLOCENTRY = 64;
+
+	public static final int MUTALLOCDATA = 128;
+
+	public static final int NOSTATIC = 256;
+
+	public static final int CONST = 512;
+
+	public static final int CANOMITNAME = 1024;
+
+	public static final int DONTLOAD = 2048;
+
+	public static final int PSET_RONLY = 1;
+
+	public static final int PSET_CHANGED = 2;
+
+	public static final int PSET_HITMIN = 4;
+
+	public static final int PSET_HITMAX = 8;
+
+	public static Integer read(String flags) {
+		Integer allFlags = 0;
+		String[] flagsSplitted = flags.split("\\+");
+		for (String flag : flagsSplitted) {
+			try {
+				allFlags |= Integer.valueOf(flag);
+			} catch (NumberFormatException ex) {
+				try {
+					Field field = Flags.class.getDeclaredField(flag.toUpperCase());
+					allFlags |= Integer.parseInt(field.get(null).toString());
+				} catch (SecurityException e) {
+					logger.warn("security exception was thrown while trying to read flag ("
+							+ flag + ")");
+				} catch (NoSuchFieldException e) {
+					logger.warn("selected flag is not known (" + flag + ")");
+				} catch (IllegalArgumentException e) {
+					logger.warn("selected flag is not known (" + flag + ")");
+				} catch (IllegalAccessException e) {
+					logger.warn("selected flag is not known (" + flag + ")");
+				}
+			}
+		}
+		return allFlags;
+	}
+}
Index: java/main/src/main/java/com/framsticks/params/FramsClass.java
===================================================================
--- java/main/src/main/java/com/framsticks/params/FramsClass.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/params/FramsClass.java	(revision 77)
@@ -0,0 +1,304 @@
+package com.framsticks.params;
+
+import com.framsticks.params.types.CompositeParam;
+import com.framsticks.params.types.DecimalParam;
+import com.framsticks.params.types.FloatParam;
+import com.framsticks.params.types.StringParam;
+import com.framsticks.util.Casting;
+import org.apache.log4j.Logger;
+
+import javax.lang.model.element.TypeElement;
+import java.lang.reflect.*;
+import java.util.*;
+import java.util.List;
+
+/**
+ * The class FramsClass represents the class / schema of connected parameters
+ * (such as parameters within the class). It differs from C++ version by storing
+ * information about the class that parameters belong to.
+ *
+ * Based loosely on c++ class Param located in cpp/gdk/param.*
+ *
+ * @author Jarek Szymczak <name.surname@gmail.com>, Mateusz Jarus (please
+ *         replace name and surname with my personal data)
+ *
+ * @author Piotr Sniegowski
+ */
+public final class FramsClass {
+
+    private final static Logger LOGGER = Logger.getLogger(FramsClass.class.getName());
+
+    /**
+      * The Class which represents group.
+      */
+
+	/** The offset of the parameter (applied for newly added parameter). */
+	protected int fieldsNumber;
+
+	/** The groups. */
+	protected List<Group> groups = new ArrayList<Group>();
+
+	/**
+	 * The param entry map <parameterId, param> (for fast accessing of parameters
+	 * by their name)
+	 */
+	protected Map<String, Param> paramEntryMap = new LinkedHashMap<String, Param>();
+
+	/** The param list (for accessing parameters by offset in O(1) time. */
+	protected List<Param> paramList = new ArrayList<Param>();
+
+	/** The param getId map (for fast lookup of offset based on name */
+	protected Map<String, Integer> paramIdMap = new HashMap<String, Integer>();
+
+	protected String id;
+
+	protected String name;
+
+	protected String description;
+
+	public Collection<Param> getParamEntries() {
+		return paramEntryMap.values();
+	}
+
+	public FramsClass() {
+	}
+
+	public FramsClass(String id, String name, String description) {
+		this.setId(id);
+		this.setName(name);
+		this.setDescription(description);
+	}
+
+	/**
+	 * Adds new param entry.
+	 * 
+	 * @param param
+	 *            the new param entry
+	 */
+	public FramsClass append(Param param) {
+		paramEntryMap.put(param.getId(), param);
+		//paramEntryMap.put(param.getInternalId(), param);
+		paramList.add(param);
+		try {
+			Group group = groups.get(param.getGroup());
+			if (group != null) {
+				group.addProperty(param);
+			}
+		} catch (IndexOutOfBoundsException ignored) {
+
+		}
+
+		return this;
+	}
+
+	/**
+	 * Adds new group.
+	 */
+	public FramsClass appendGroup(Group group) {
+		groups.add(group);
+		return this;
+	}
+
+	public String getDescription() {
+		return description;
+	}
+
+	public int getGroupCount() {
+		return groups.size();
+	}
+
+	/**
+	 * Gets the group member.
+	 * 
+	 * @param gi
+	 *            the offset of group
+	 * @param pi
+	 *            the offset of member within a group
+	 * @return the pi-th member of group gi
+	 */
+	public Param getGroupMember(int gi, int pi) {
+		if (gi < 0 || pi < 0 || gi >= groups.size()) {
+			return null;
+        }
+		Group group = groups.get(gi);
+		return (group != null ? group.getProperty(pi) : null);
+	}
+
+	/**
+	 * Gets the group getName.
+	 * 
+	 * @param gi
+	 *            the offset of group
+	 * @return the group getName
+	 */
+	public String getGroupName(int gi) {
+		if (gi < 0 || gi >= groups.size())
+			return null;
+		return groups.get(gi).name;
+	}
+
+	public String getId() {
+		return id;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+    public String getNiceName() {
+        return name != null ? name : id;
+    }
+
+	/**
+	 * Gets the param entry.
+	 * 
+	 * @param i
+	 *            the offset of parameter
+	 * @return the param entry
+	 */
+	public Param getParamEntry(int i) {
+		if (i < 0 || i >= paramList.size()) {
+			return null;
+		}
+		return paramList.get(i);
+	}
+
+	/**
+	 * Gets the param entry.
+	 * 
+	 * @param id
+	 *            the getId of parameter
+	 * @return the param entry
+	 */
+	public Param getParamEntry(String id) {
+		return paramEntryMap.get(id);
+	}
+
+	public int getParamCount() {
+		return paramList.size();
+	}
+
+	@Override
+	public String toString() {
+		return id;
+	}
+
+	public static FramsClass getFramsClass() {
+		return new FramsClass("class", "class", null)
+			.append(new ParamBuilder().setId("name").setName("Name").setType(StringParam.class).build())
+			.append(new ParamBuilder().setId("id").setName("id").setType(StringParam.class).build())
+			.append(new ParamBuilder().setId("desc").setName("Description").setType(StringParam.class).build());
+	}
+
+	public void setId(String id) {
+		this.id = id;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+
+	public void setDescription(String description) {
+		this.description = description;
+	}
+
+    public static String getParamTypeForNativeType(Type type) {
+        if (type instanceof ParameterizedType) {
+            ParameterizedType p = (ParameterizedType) type;
+            Type rawType = p.getRawType();
+            if (rawType.equals(Map.class)) {
+                Type containedType = p.getActualTypeArguments()[1];
+                //TODO uid should be passed along during construction
+                if (containedType instanceof Class) {
+                    return "l " + ((Class) containedType).getCanonicalName() + " name";
+                }
+            }
+            return null;
+        }
+
+        if (type.equals(Integer.class)) {
+            return "d";
+        }
+        if (type.equals(String.class)) {
+            return "s";
+        }
+        if (type.equals(Double.class)) {
+            return "f";
+        }
+        if (type instanceof Class) {
+            return "o " + ((Class) type).getCanonicalName();
+        }
+        return null;
+    }
+
+    public static final String GENERATE_HELP_PREFIX = "automatically generated from: ";
+
+
+
+    public static class Constructor {
+        protected final FramsClass result;
+        protected Class currentClass;
+        public Constructor(Class src, String name) {
+            result = new FramsClass(name, name, GENERATE_HELP_PREFIX + src.toString());
+            currentClass = src;
+            while (currentClass != null) {
+                try {
+                    currentClass.getMethod("constructFramsClass", Constructor.class).invoke(null, this);
+                } catch (Exception ignored) {
+                }
+                currentClass = currentClass.getSuperclass();
+            }
+        }
+
+        public final FramsClass getResult() {
+            return result;
+        }
+
+        public Constructor method(String name, Class<?> ... arguments) {
+            try {
+                Method method = currentClass.getMethod(name, arguments);
+                if (!Modifier.isPublic(method.getModifiers())) {
+                    return this;
+                }
+                String returnParamClass = getParamTypeForNativeType(method.getGenericReturnType());
+                if (returnParamClass == null) {
+                    return this;
+                }
+                Class[] args = method.getParameterTypes();
+                if (args.length == 0) {
+                    if (method.getName().startsWith("get")) {
+                        String fieldName = method.getName().substring(3, 4).toLowerCase() + method.getName().substring(4);
+                        Param param = new ParamBuilder().setType(returnParamClass).setName(fieldName).setId(fieldName).setHelp(GENERATE_HELP_PREFIX + method.toString()).build();
+                        assert param != null;
+                        result.append(param);
+                        return this;
+                    }
+                    return this;
+                }
+                return this;
+            } catch (NoSuchMethodException e) {
+                LOGGER.fatal("method " + name + " was not found in " + currentClass.toString());
+            }
+            return this;
+        }
+        public Constructor field(String name) {
+            try {
+                Field field = currentClass.getField(name);
+                if (!Modifier.isPublic(field.getModifiers())) {
+                    return this;
+                }
+                String paramClass = getParamTypeForNativeType(field.getGenericType());
+                if (paramClass == null) {
+                    return this;
+                }
+                Param param = new ParamBuilder().setType(paramClass).setName(field.getName()).setId(field.getName()).setHelp(GENERATE_HELP_PREFIX + field.toString()).build();
+                assert param != null;
+                result.append(param);
+                return this;
+            } catch (NoSuchFieldException e) {
+                LOGGER.fatal("field " + name + " was not found in " + currentClass.toString());
+            }
+            return this;
+        }
+    }
+}
Index: java/main/src/main/java/com/framsticks/params/Group.java
===================================================================
--- java/main/src/main/java/com/framsticks/params/Group.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/params/Group.java	(revision 77)
@@ -0,0 +1,52 @@
+package com.framsticks.params;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author Piotr Sniegowski
+ */
+public class Group {
+	String name;
+
+	/**
+	 * Group members.
+	 */
+	List<Param> params = new ArrayList<Param>();
+
+	public Group(String name) {
+		this.name = name;
+	}
+
+	/**
+	 * Adds new group member.
+	 *
+	 * @param p the new group member
+	 */
+	void addProperty(Param p) {
+		params.add(p);
+	}
+
+	/**
+	 * Gets the property.
+	 *
+	 * @param i the i
+	 * @return the property
+	 */
+	Param getProperty(int i) {
+		if (i < 0 || i >= params.size())
+			return null;
+		return params.get(i);
+	}
+
+	/*
+			 * (non-Javadoc)
+			 *
+			 * @see java.lang.Object#toString()
+			 */
+	@Override
+	public String toString() {
+		return name;
+	}
+
+}
Index: java/main/src/main/java/com/framsticks/params/ListAccess.java
===================================================================
--- java/main/src/main/java/com/framsticks/params/ListAccess.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/params/ListAccess.java	(revision 77)
@@ -0,0 +1,91 @@
+package com.framsticks.params;
+
+import com.framsticks.core.Node;
+import com.framsticks.core.Path;
+import com.framsticks.params.types.CompositeParam;
+
+import java.util.List;
+
+/**
+ * @author Piotr Sniegowski
+ */
+public abstract class ListAccess implements AccessInterface {
+
+	final AccessInterface elementAccess;
+
+	public ListAccess(AccessInterface elementAccess) {
+		this.elementAccess = elementAccess;
+	}
+
+    @Override
+	public Param getGroupMember(int gi, int n) {
+		return null;
+	}
+
+	@Override
+	public void setDefault(boolean numericOnly) {
+	}
+
+	@Override
+	public void setDefault(int i, boolean numericOnly) {
+	}
+
+	@Override
+	public void setMin() {
+	}
+
+	@Override
+	public void setMin(int i) {
+	}
+
+	@Override
+	public void setMax() {
+	}
+
+	@Override
+	public void setMax(int i) {
+	}
+
+	@Override
+	public void copyFrom(AccessInterface src) {
+	}
+
+	@Override
+    public void save(SinkInterface sink) {
+        for (Param p : getParams()) {
+            assert p instanceof CompositeParam;
+            CompositeParam childParam = (CompositeParam)p;
+            Object child = get(childParam, Object.class);
+            //this is probably an assertion
+            assert child != null;
+            elementAccess.select(child);
+            elementAccess.save(sink);
+        }
+    }
+
+	@Override
+	public void load(SourceInterface stream) throws Exception {
+	}
+
+	@Override
+	public String save2(boolean omitDefaultValues) {
+		return null;
+	}
+
+	@Override
+	public List<Exception> load2(String line) throws Exception {
+		return null;
+	}
+
+	public AccessInterface getElementAccess() {
+		return elementAccess;
+	}
+
+    public abstract String computeIdentifierFor(Object selected);
+
+    @Override
+    public final FramsClass getFramsClass() {
+        return elementAccess.getFramsClass();
+    }
+
+}
Index: java/main/src/main/java/com/framsticks/params/ListSink.java
===================================================================
--- java/main/src/main/java/com/framsticks/params/ListSink.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/params/ListSink.java	(revision 77)
@@ -0,0 +1,47 @@
+package com.framsticks.params;
+
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * @author Piotr Sniegowski
+ */
+public class ListSink implements SinkInterface {
+    protected final List<String> out;
+    protected StringBuilder lineBuilder = new StringBuilder();
+
+    public ListSink(List<String> out) {
+        this.out = out;
+    }
+
+    public ListSink() {
+        this.out = new LinkedList<String>();
+    }
+
+    public final List<String> getOut() {
+        return out;
+    }
+
+
+    @Override
+    public SinkInterface print(String str) {
+        lineBuilder.append(str);
+        return this;
+    }
+
+    @Override
+    public SinkInterface print(Object obj) {
+        lineBuilder.append(obj);
+        return this;
+    }
+
+    @Override
+    public void breakLine() {
+        out.add(lineBuilder.toString());
+        lineBuilder = new StringBuilder();
+    }
+
+    @Override
+    public void close() {
+    }
+}
Index: java/main/src/main/java/com/framsticks/params/ListSource.java
===================================================================
--- java/main/src/main/java/com/framsticks/params/ListSource.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/params/ListSource.java	(revision 77)
@@ -0,0 +1,44 @@
+package com.framsticks.params;
+
+import java.util.Iterator;
+import java.util.List;
+
+public class ListSource implements SourceInterface {
+
+	private Iterator<String> iterator = null;
+    private final List<String> source;
+
+	public ListSource(List<String> source) {
+        this.source = source;
+        iterator = source.iterator();
+	}
+
+    @Override
+	public String getFilename() {
+		return "<net>";
+	}
+
+    @Override
+    public String readLine() {
+        assert iterator != null;
+		if (iterator.hasNext()) {
+			return iterator.next();
+		}
+		return null;
+	}
+
+    @Override
+    public String demangleInclude(String include) {
+		return null;
+	}
+
+    @Override
+    public SourceInterface openInclude(String include) {
+		return null;
+	}
+
+    @Override
+    public void close() {
+        iterator = null;
+	}
+}
Index: java/main/src/main/java/com/framsticks/params/Param.java
===================================================================
--- java/main/src/main/java/com/framsticks/params/Param.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/params/Param.java	(revision 77)
@@ -0,0 +1,205 @@
+package com.framsticks.params;
+
+import com.framsticks.params.types.DecimalParam;
+import com.framsticks.params.types.StringParam;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Based on c++ struct ParamEntry located in cpp/gdk/param.h
+ * Here  it is a root of Param hierarchy.
+ *
+ * @author Jarek Szymczak <name.surname@gmail.com>, Mateusz Jarus
+ * (please replace name and surname with my personal data)
+ *
+ * @author Piotr Śniegowski
+ */
+public abstract class Param {
+
+	/** The parameter id. */
+	protected String id;
+
+	/**
+	 * The parameter internal id. It's set by a user to use user's own getId in
+	 * code
+	 */
+	protected String internalId;
+
+	/** The parameter name. */
+	protected String name;
+
+	/** The help (description) concerning parameter. */
+	protected String help;
+
+	/** The number of group, that parameter belongs to. */
+	protected Integer group;
+
+	/** The getFlags stored as a bit sum. */
+	protected Integer flags;
+
+	/** The variable determining whether the parameter is an extra parameter. */
+	protected Integer extra;
+
+	/** The minimum allowed value of parameter. */
+	protected Object min;
+
+	/** The maximum allowed value of parameter. */
+	protected Object max;
+
+	/** The default value of parameter. */
+	protected Object def;
+
+
+
+	/**
+	 * The defaults used for Integer, Double and String classes, if the default
+	 * value of parameter is not explicitly given.
+	 */
+	@SuppressWarnings("rawtypes")
+	private Map<Class, Object> defaults = new HashMap<Class, Object>();
+	// static initialization of defaults
+	{
+		defaults.put(String.class, "");
+		defaults.put(Integer.class, 0);
+		defaults.put(Double.class, 0.0);
+	}
+
+	public Param() {
+
+	}
+
+	public String getId() {
+		return id;
+	}
+
+	public String getInternalId() {
+		return internalId;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public String getHelp() {
+		return help;
+	}
+
+	public Integer getGroup() {
+		return group;
+	}
+
+	public Integer getFlags() {
+		return flags;
+	}
+
+    public abstract String getType();
+
+
+	public String getEffectiveId() {
+		return (internalId != null) ? internalId : id;
+	}
+
+
+    private <T> T tryCastAndReturn(Object value, Class<T> type) {
+        if (value == null)
+            return null;
+        try {
+            return type.cast(value);
+        } catch (ClassCastException e) {
+            throw new ClassCastException("property \"" + name
+                    + "\" getType is \"" + value.getClass().getName()
+                    + "\", not \"" + type.getName() + "\"");
+        }
+    }
+	/**
+	 * Gets the minimum value of parameter.
+	 *
+	 * @param <T> the generic getType which must be correctly specified by user
+	 * @param type the getType of variable, can be checked by
+	 * @return the minimum allowed value of parameter
+	 * @throws ClassCastException the class cast exception, thrown when given getType is incorrect
+	 */
+	public <T> T getMin(Class<T> type) {
+		return tryCastAndReturn(min, type);
+	}
+
+	/**
+	 * Gets the maximum value of parameter.
+	 *
+	 * @param <T> the generic getType which must be correctly specified by user
+	 * @param type the getType of variable, can be checked by {@link #getStorageType()}
+	 * @return the maximum allowed value of parameter
+	 * @throws ClassCastException the class cast exception, thrown when given getType is incorrect
+	 */
+	public <T> T getMax(Class<T> type) {
+		return tryCastAndReturn(max, type);
+	}
+
+	/**
+	 * Gets the default value of parameter.
+	 *
+	 * @param <T> the generic getType which must be correctly specified by user
+	 * @param type the getType of variable, can be checked by {@link #getStorageType()}
+	 * @return the default value of parameter
+	 * @throws ClassCastException the class cast exception, thrown when given getType is incorrect
+	 */
+	public <T> T getDef(Class<T> type) throws ClassCastException {
+		return tryCastAndReturn(def, type);
+	}
+
+	public Integer getExtra() {
+		return extra;
+	}
+
+	public void setInternalId(String internalId) {
+		this.internalId = internalId;
+	}
+
+	@Override
+	public String toString() {
+		return getId() + ":" + this.getClass().getSimpleName();
+	}
+
+	public boolean isNumeric() {
+		return false;
+	}
+
+	public boolean isEmptyAvailable() {
+		return false;
+	}
+
+	public abstract Class getStorageType();
+
+	public boolean hasFlag(int flag) {
+		return flags != null && (flags & flag) != 0;
+	}
+
+	public Object reassign(Object newValue, Object oldValue) throws CastFailure {
+        if (newValue == null) {
+            if (isEmptyAvailable()) {
+                return null;
+            }
+            throw new CastFailure();
+        }
+        try {
+            return getStorageType().cast(newValue);
+        } catch (ClassCastException ignored) {
+            throw new CastFailure();
+        }
+    }
+
+	public boolean isUserHidden() {
+		return (flags & Flags.USERHIDDEN) != 0;
+	}
+
+    public static FramsClass getFramsClass() {
+        return new FramsClass("prop", "prop", null)
+                .append(new ParamBuilder().setId("name").setName("Name").setType(StringParam.class).build())
+                .append(new ParamBuilder().setId("id").setName("Id").setType(StringParam.class).build())
+                .append(new ParamBuilder().setId("type").setName("Type").setType(StringParam.class).build())
+                .append(new ParamBuilder().setId("help").setName("Help").setType(StringParam.class).build())
+                .append(new ParamBuilder().setId("flags").setName("Flags").setType(DecimalParam.class).build());
+    }
+
+}
Index: java/main/src/main/java/com/framsticks/params/ParamBuilder.java
===================================================================
--- java/main/src/main/java/com/framsticks/params/ParamBuilder.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/params/ParamBuilder.java	(revision 77)
@@ -0,0 +1,298 @@
+package com.framsticks.params;
+
+import com.framsticks.params.types.*;
+import org.apache.log4j.Logger;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+
+/**
+ * The class ParamBuilder helps building Param objects.
+ * 
+ * @author Mateusz Jarus <name.surname@gmail.com> (please replace name and
+ *         surname with my personal data)
+ *
+ * @author Piotr Śniegowski
+ */
+
+public class ParamBuilder {
+	private final static Logger LOGGER = Logger.getLogger(ParamBuilder.class.getName());
+
+	private static final String ID_FIELD = "id";
+	private static final String NAME_FIELD = "name";
+	private static final String HELP_FIELD = "help";
+	private static final String GROUP_FIELD = "group";
+	private static final String TYPE_FIELD = "type";
+	private static final String FLAGS_FIELD = "flags";
+
+	/** The parameter getId. */
+	private String id;
+
+	/**
+	 * The parameter internal getId. It's set by a user to use user's own getId in
+	 * code
+	 */
+	private String internalId;
+
+	/** The number of group, that parameter belongs to. */
+	private Integer group = 0;
+
+	/** The getFlags stored as a bit sum. */
+	private Integer flags = 0;
+
+	/** The parameter getName. */
+	private String name;
+
+	/** The getHelp (description) concerning parameter. */
+	private String help;
+
+	/** The getType of parameter. */
+	@SuppressWarnings("rawtypes")
+	private Class paramType;
+
+	private Param param;
+
+	/**
+	 * Build Param based on provided data.
+	 * 
+	 * @return Param object
+	 * @throws Exception
+	 *             when Param getType is not defined
+	 */
+	public Param build()  {
+        assert param != null;
+		param.id = id;
+		param.name = name;
+		param.help = help;
+		param.group = group;
+		param.flags = flags;
+		param.internalId = internalId;
+
+		return param;
+	}
+
+	public ParamBuilder setId(String id) {
+		this.id = id;
+		return this;
+	}
+
+	public <T extends Param> ParamBuilder setType(Class<T> type) {
+		this.paramType = type;
+		try {
+			this.param = (Param)paramType.newInstance();
+		} catch (InstantiationException e) {
+			e.printStackTrace();
+		} catch (IllegalAccessException e) {
+			e.printStackTrace();
+		}
+		return this;
+	}
+
+	public <T extends Param> ParamBuilder setType(T type) {
+		this.paramType = type.getClass();
+		this.param = type;
+		return this;
+	}
+
+
+	public ParamBuilder setInternalId(String internalId) {
+		this.internalId = internalId;
+		return this;
+	}
+
+	public ParamBuilder setGroup(Integer group) {
+		this.group = group;
+		return this;
+	}
+
+	public ParamBuilder setFlags(Integer flags) {
+		this.flags = flags;
+		return this;
+	}
+
+	public ParamBuilder setName(String name) {
+		this.name = name;
+		return this;
+	}
+
+	public ParamBuilder setType(String type) {
+
+		LOGGER.trace("parsing type: " + type);
+
+		String[] typeSplitted = type.split(" ");
+		String first = typeSplitted[0];
+		String second = typeSplitted.length > 1 ? typeSplitted[1] : null;
+		String third = typeSplitted.length > 2 ? typeSplitted[2] : null;
+
+		switch (first.charAt(0)) {
+			case 'o': {
+				setType(new ObjectParam(second != null ? second : first.substring(1)));
+				break;
+			}
+			case 'p': {
+				ProcedureParam procedureParam = new ProcedureParam();
+				String signature = type.substring(1);
+				try {
+					procedureParam.parseSignature(signature);
+				} catch (Exception e) {
+					LOGGER.error("invalid procedure signature '" + signature + "': " + e);
+				}
+				setType(procedureParam);
+				break;
+			}
+			case 'd': {
+
+				int tildeIndex = type.indexOf("~");
+				if (tildeIndex != -1) {
+					setType(new EnumParam(new ArrayList<String>(Arrays.asList(type.substring(tildeIndex + 1).split("~")))));
+				} else {
+					if (first.length() >= 2) {
+						switch (first.charAt(1)) {
+							case 'b': {
+								setType(BinaryParam.class);
+								break;
+							}
+							case 'c': {
+								setType(ColorParam.class);
+								break;
+							}
+						}
+					}
+                    if ("0".equals(second) && "1".equals(third)) {
+                        setType(BooleanParam.class);
+                    }
+					if (param == null) {
+						setType(DecimalParam.class);
+					}
+				}
+				if (this.param instanceof DecimalParam) {
+					try {
+						if (second != null) {
+							this.param.min = Integer.parseInt(second);
+						}
+
+						if (third != null) {
+							this.param.max = Integer.parseInt(third);
+						}
+					} catch (NumberFormatException e) {
+						LOGGER.warn("value of min or max attribute should be an Integer");
+					}
+				}
+				break;
+			}
+			case 'f': {
+				setType(FloatParam.class);
+				try {
+					if (second != null) {
+						this.param.min = Double.parseDouble(second);
+					}
+
+					if (third != null) {
+						this.param.max = Double.parseDouble(third);
+					}
+				} catch (NumberFormatException ex) {
+					LOGGER.warn("Value of min or max attribute should be Double");
+				}
+				break;
+			}
+			case 'x': {
+				setType(UniversalParam.class);
+				break;
+			}
+			case 's': {
+				setType(StringParam.class);
+				this.param.min = second;
+				this.param.max = third;
+				break;
+			}
+			case 'e': {
+				setType(EventParam.class);
+				break;
+			}
+			case 'l': {
+
+				setType(third != null ? new UniqueListParam(second, third) : new ArrayListParam(second));
+				break;
+			}
+
+		}
+		return this;
+	}
+
+	public ParamBuilder setHelp(String help) {
+		this.help = help;
+		return this;
+	}
+
+	public <T> ParamBuilder setMin(T min) {
+		this.param.min = min;
+		return this;
+	}
+
+	public <T> ParamBuilder setMax(T max) {
+		this.param.max = max;
+		return this;
+	}
+
+	public <T> ParamBuilder setDef(T def) {
+		this.param.def = def;
+		return this;
+	}
+
+	public Param build(String line) throws Exception {
+		String[] paramEntryValues = line.split(",");
+
+		if (paramEntryValues.length == 0) {
+			LOGGER.warn("field empty or wrong format (" + line
+					+ ") - omitting");
+			return null;
+		}
+
+		for (int i = 0; i < paramEntryValues.length; ++i) {
+			paramEntryValues[i] = paramEntryValues[i].trim();
+		}
+
+		try {
+			setId(paramEntryValues[0]);
+			setGroup(Integer.valueOf(paramEntryValues[1]));
+			setFlags(Flags.read(paramEntryValues[2]));
+			setName(paramEntryValues[3]);
+			setType(paramEntryValues[4]);
+			setHelp(paramEntryValues[6]);
+		} catch (IndexOutOfBoundsException e) {
+			/** everything is ok, parameters have just finished*/
+		} catch (NumberFormatException ex) {
+			LOGGER.warn("wrong format of entry: " + line
+					+ ", omitting");
+			return null;
+		}
+		return build();
+	}
+
+	public void setField(String key, String value) {
+		if (key.equals(ID_FIELD)) {
+			setId(value);
+		} else if (key.equals(NAME_FIELD)) {
+			setName(value);
+		} else if (key.equals(TYPE_FIELD)) {
+			setType(value);
+		} else if (key.equals(FLAGS_FIELD)) {
+			setFlags(Flags.read(value));
+		} else if (key.equals(HELP_FIELD)) {
+			setHelp(value);
+		} else if (key.equals(GROUP_FIELD)) {
+			setGroup(Integer.valueOf(value));
+		}
+	}
+
+
+	public static FramsClass getFramsClass() {
+		return new FramsClass("prop", "prop", null)
+				.append(new ParamBuilder().setId("name").setName("Name").setType(StringParam.class).build())
+				.append(new ParamBuilder().setId("id").setName("Id").setType(StringParam.class).build())
+				.append(new ParamBuilder().setId("type").setName("Type").setType(StringParam.class).build())
+				.append(new ParamBuilder().setId("help").setName("Help").setType(StringParam.class).build())
+				.append(new ParamBuilder().setId("flags").setName("Flags").setType(DecimalParam.class).build());
+	}
+
+}
Index: java/main/src/main/java/com/framsticks/params/PropertiesAccess.java
===================================================================
--- java/main/src/main/java/com/framsticks/params/PropertiesAccess.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/params/PropertiesAccess.java	(revision 77)
@@ -0,0 +1,87 @@
+package com.framsticks.params;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * The Class PropertiesAccess.
+ * 
+ * @author Jarek Szymczak <name.surname@gmail.com> (please replace name and
+ *         surname with my personal data)
+ *
+ * @author Piotr Śniegowski
+ */
+public class PropertiesAccess extends SimpleAbstractAccess {
+
+	public Map<String, Object> properties;
+
+    @Override
+	public Map<String, Object> createAccessee() {
+		return new HashMap<String, Object>();
+	}
+
+
+	public PropertiesAccess(FramsClass framsClass) {
+		setFramsClass(framsClass);
+	}
+
+	@Override
+	public void clearValues() {
+        assert properties != null;
+        properties.clear();
+	}
+
+	@Override
+	public <T> T get(Param param, Class<T> type) {
+        assert properties != null;
+        assert param != null;
+		Object object = null;
+		try {
+			object = properties.get(param.getId());
+			if (object == null) {
+				return param.getDef(type);
+			}
+			return type.cast(object);
+		} catch (ClassCastException e) {
+			throw new ClassCastException("property " + param.getId() + " type is " + object.getClass().getName() + ", not " + type.getName());
+		}
+
+	}
+
+	protected <T> void internalSet(Param param, T value) {
+		properties.put(param.getId(), value);
+	}
+
+	/**
+	 * Sets the new values to operate on. It does not check whether the values
+	 * which are set through this method are correct. If set values are not
+	 * correct exceptions might occurred while getting / setting the parameters
+	 * values
+	 * 
+	 * @param object
+	 *            the properties with parameters values
+	 */
+	@Override
+	public void select(Object object) {
+		this.properties = (Map<String, Object>)object;
+	}
+
+	/** covariant */
+	@Override
+	public Map<String, Object> getSelected() {
+		return properties;
+	}
+
+	@Override
+	public PropertiesAccess cloneAccess() {
+		return new PropertiesAccess(framsClass);
+		//properties = createProperties();
+		//return access;
+	}
+
+
+
+
+}
Index: java/main/src/main/java/com/framsticks/params/ReflectionAccess.java
===================================================================
--- java/main/src/main/java/com/framsticks/params/ReflectionAccess.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/params/ReflectionAccess.java	(revision 77)
@@ -0,0 +1,171 @@
+package com.framsticks.params;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.util.List;
+
+import com.framsticks.params.types.ListParam;
+import org.apache.log4j.Logger;
+
+
+/**
+ * The Class ReflectionAccess. Stores data in provided object using reflection.
+ * 
+ * @author Mateusz Jarus <name.surname@gmail.com> (please replace name and
+ *         surname with my personal data)
+ *
+ * @author Piotr Sniegowski
+ */
+public class ReflectionAccess extends SimpleAbstractAccess {
+	private final static Logger LOGGER = Logger.getLogger(ReflectionAccess.class
+			.getName());
+
+
+    protected final Class reflectedClass;
+	private Object object;
+
+	public ReflectionAccess(Class reflectedClass, FramsClass framsClass) {
+        this.reflectedClass = reflectedClass;
+		setFramsClass(framsClass);
+	}
+
+	private static String accessorName(boolean get, String id) {
+		return (get ? "get"  : "set") + id.substring(0, 1).toUpperCase() + id.substring(1);
+	}
+
+	@Override
+	public <T> T get(Param param, Class<T> type) {
+		if (object == null) {
+			return null;
+		}
+		try {
+			//TODO: use internal id, if present
+			String id = param.getId();
+			try {
+				return type.cast(object.getClass().getField(id).get(object));
+			} catch (NoSuchFieldException ignored) {
+			}
+			try {
+				return type.cast(object.getClass().getMethod(accessorName(true, id)).invoke(object));
+			} catch (NoSuchMethodException ex) {
+				//ex.printStackTrace();
+			} catch (InvocationTargetException e) {
+				//e.printStackTrace();
+            }
+
+		} catch (IllegalAccessException ex) {
+			LOGGER.warn("illegal access error occurred while trying to access returnedObject");
+			ex.printStackTrace();
+        } catch (ClassCastException ignored) {
+
+        }
+		return null;
+	}
+
+	@Override
+	protected <T> void internalSet(Param param, T value) {
+		setValue(param, value);
+	}
+
+	private <T> void setValue(Param param, T val) {
+		if (object == null) {
+			return;
+        }
+		try {
+			String id = param.getId();
+			try {
+				object.getClass().getField(id).set(object, val);
+				return;
+			} catch (NoSuchFieldException ignored) {
+			}
+			try {
+				object.getClass().getMethod(accessorName(false, id), new Class[]{val.getClass()}).invoke(object, val);
+			} catch (InvocationTargetException e) {
+				//e.printStackTrace();
+			} catch (NoSuchMethodException ignored) {
+			}
+		} catch (IllegalAccessException ex) {
+			LOGGER.warn("illegal access error occurred while trying to access returnedObject");
+			ex.printStackTrace();
+		}
+	}
+
+	void resetErrors() {
+		//TODO this replaces returnedObject.resetErrors();
+	}
+
+	@Override
+	public void clearValues() {
+		if (object == null) {
+			return;
+		}
+
+		resetErrors();
+
+		Field[] fields;
+		try {
+			// TODO: conceptually invalid - should clean only fields that are specified in FramsClass
+			fields = object.getClass().getFields();
+
+			for (Field field : fields) {
+				field.set(object, null);
+			}
+		} catch (IllegalAccessException ex) {
+			LOGGER.warn("IllegalAccessException thrown while trying to reset object values");
+			ex.printStackTrace();
+		}
+	}
+
+	/**
+	 * Sets the new object to operate on.
+	 * 
+	 * @param object
+	 *            new object to operate on
+	 */
+	@Override
+	public void select(Object object) {
+		this.object = object;
+	}
+
+	@Override
+	public Object getSelected() {
+		return object;
+	}
+
+	// TODO: find a better place for it
+	public static String objectToString(Object object) {
+		StringBuilder b = new StringBuilder();
+		for (Field f : object.getClass().getFields()) {
+			b.append(f.getName());
+			b.append(":");
+			try {
+				Object value = f.get(object);
+				b.append((value != null) ? value.toString() : "<null>");
+			} catch (IllegalAccessException e) {
+				e.printStackTrace();
+			}
+			b.append("\n");
+		}
+		return b.toString();
+	}
+
+
+	@Override
+	public ReflectionAccess cloneAccess() {
+		return new ReflectionAccess(reflectedClass, framsClass);
+	}
+
+    @Override
+    public Object createAccessee() {
+        try {
+            return reflectedClass.newInstance();
+        } catch (InstantiationException e) {
+            e.printStackTrace();
+        } catch (IllegalAccessException e) {
+            e.printStackTrace();
+        }
+        LOGGER.fatal("failed to create reflected object of class " + reflectedClass.getCanonicalName() + " for frams type " + framsClass.getId());
+
+        return null;
+    }
+}
Index: java/main/src/main/java/com/framsticks/params/SimpleAbstractAccess.java
===================================================================
--- java/main/src/main/java/com/framsticks/params/SimpleAbstractAccess.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/params/SimpleAbstractAccess.java	(revision 77)
@@ -0,0 +1,513 @@
+package com.framsticks.params;
+
+import java.io.IOException;
+import java.text.DecimalFormat;
+import java.text.DecimalFormatSymbols;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import com.framsticks.params.types.*;
+import org.apache.log4j.Logger;
+import java.util.Locale;
+
+/**
+ * The Class SimpleAbstractAccess implements all the methods of AccessInterface
+ * which actions can be implemented with usage of {@link AccessInterface} methods
+ * or concern schema, which is stored in {@link #framsClass}
+ *
+ * Based on c++ class SimpleAbstractParam located in: cpp/gdk/param.*
+ *
+ * @author Jarek Szymczak <name.surname@gmail.com>, Mateusz Jarus (please
+ *         replace name and surname with my personal data)
+ *
+ * @author Piotr Sniegowski
+ */
+public abstract class SimpleAbstractAccess implements AccessInterface {
+
+	private final static Logger LOGGER = Logger.getLogger(SimpleAbstractAccess.class.getName());
+
+
+
+    @Override
+	public final FramsClass getFramsClass() {
+		return framsClass;
+	}
+
+	public void setFramsClass(FramsClass framsClass) {
+		this.framsClass = framsClass;
+	}
+
+
+
+
+    /**
+	 * Simple String key, value class.
+	 */
+	private static class Entry {
+
+		String key;
+		String value;
+
+		Entry(String key, String value) {
+			this.key = key;
+			this.value = value;
+		}
+
+		@Override
+		public String toString() {
+			return key + " = " + value;
+		}
+	}
+
+	protected FramsClass framsClass;
+
+	@Override
+	public String getId() {
+		return framsClass.getId();
+	}
+
+    @Override
+	public int getParamCount() {
+		return framsClass.getParamCount();
+	}
+
+	@Override
+	public Param getParam(int i) {
+		return framsClass.getParamEntry(i);
+	}
+
+	@Override
+	public Param getParam(String id) {
+		return framsClass.getParamEntry(id);
+	}
+
+
+	@Override
+	public Param getGroupMember(int gi, int n) {
+		return framsClass.getGroupMember(gi, n);
+	}
+
+	@Override
+	public <T> T get(int i, Class<T> type) {
+		return get(getParam(i), type);
+	}
+
+	@Override
+	public <T> T get(String id, Class<T> type) {
+		return get(getParam(id), type);
+	}
+
+
+	@Override
+	public <T> int set(String id, T value) {
+		return set(getParam(id), value);
+	}
+
+	@Override
+	public <T> int set(int i, T value) {
+		return set(getParam(i), value);
+	}
+
+	@SuppressWarnings("unchecked")
+	@Override
+	public <T> int set(Param param, T value) {
+		int flags = 0;
+		//String id = param.getEffectiveId();
+		try {
+            Object oldValue = get(param, param.getStorageType());
+            Object casted = param.reassign(value, oldValue);
+            if (casted != oldValue) {
+                internalSet(param, casted);
+            }
+        } catch (CastFailure e) {
+            LOGGER.error("casting failure while set: ", e);
+
+        }
+        return flags;
+    }
+
+
+
+
+	@Override
+	public void setDefault(boolean numericOnly) {
+		for (int i = 0; i < framsClass.getParamCount(); i++)
+			setDefault(i, numericOnly);
+	}
+
+	@Override
+	public void setDefault(int i, boolean numericOnly) {
+		Param entry = framsClass.getParamEntry(i);
+		if ((entry != null)	&& (!numericOnly || entry.isNumeric())) {
+			set(i, entry.getDef(entry.getStorageType()));
+		}
+	}
+
+	@Override
+	public void setMin() {
+		for (int i = 0; i < framsClass.getParamCount(); i++) {
+			setMin(i);
+		}
+	}
+
+	@SuppressWarnings("unchecked")
+	@Override
+	public void setMin(int i) {
+		Param entry = framsClass.getParamEntry(i);
+		Object min = entry.getMin(entry.getStorageType());
+		if (min != null) {
+			set(i, min);
+		}
+	}
+
+	@Override
+	public void setMax() {
+		for (int i = 0; i < framsClass.getParamCount(); i++) {
+			setMax(i);
+		}
+	}
+
+	@SuppressWarnings("unchecked")
+	@Override
+	public void setMax(int i) {
+		Param entry = framsClass.getParamEntry(i);
+		Object max = entry.getMax(entry.getStorageType());
+		if (max != null) {
+			set(i, max);
+		}
+	}
+
+	@Override
+	public void copyFrom(AccessInterface src) {
+		clearValues();
+		//TODO: iterate over self, and pull from src
+		/*
+		for (int i = 0; i < src.getFramsClass().size(); i++) {
+			this.set(i, src.get(i, Object.class));
+		}
+		*/
+	}
+
+
+
+
+	@Override
+	public void save(SinkInterface sink) {
+        assert framsClass != null;
+        sink.print(framsClass.getId()).print(":").breakLine();
+        for (Param p : framsClass.getParamEntries()) {
+            if (p instanceof ValueParam) {
+                Object value = get(p, Object.class);
+                if (value == null) {
+                    continue;
+                }
+                sink.print(p.getId()).print(":");
+                ((ValueParam)p).save(sink, value);
+                sink.breakLine();
+
+
+                //continue;
+            }
+            /*
+            if (p instanceof CompositeParam) {
+                if (!(p instanceof ListParam)) {
+                    continue;
+                }
+                Collection c = get(p, Collection.class);
+                if (c != null) {
+                    save(stream, p, c.size());
+                }
+            }
+            */
+
+        }
+        sink.breakLine();
+	}
+
+	@Override
+	public String save2(boolean omitDefaultValues) {
+		StringBuilder stringBuilder = new StringBuilder();
+		DecimalFormat df = new DecimalFormat("#.###", new DecimalFormatSymbols(
+				Locale.ENGLISH));
+		boolean canOmitName = false;
+		int n = 0;
+		for (int i = 0; i < framsClass.getParamCount(); i++) {
+			Object value = this.get(i, Object.class);
+			Object def = framsClass.getParamEntry(i).getDef(Object.class);
+			if (value != null && (!omitDefaultValues || !value.equals(def))) {
+				if ((n != i && !canOmitName)
+						|| (getParam(i).getFlags() & Flags.CANOMITNAME) == 0) {
+					stringBuilder.append(getParam(i).getId());
+					stringBuilder.append("=");
+				}
+				n++;
+				canOmitName = true;
+				if (this.get(i, Object.class) instanceof String) {
+					String valueString = this.get(i, String.class);
+					valueString = valueString.replaceAll("\\\"", "\\\\\"");
+					valueString = valueString.contains(",") ? "\""
+							+ valueString + "\"" : valueString;
+					// if ("".equals(valueString.trim()))
+					// value = "\"\"";
+					stringBuilder.append(valueString);
+				} else if (this.get(i, Object.class) instanceof Double) {
+					stringBuilder.append(df.format(this.get(i, Double.class)));
+				} else
+					stringBuilder.append(this.get(i, Object.class));
+				stringBuilder.append(", ");
+			} else {
+				canOmitName = false;
+			}
+		}
+
+		String params = "";
+		if (stringBuilder.length() > 1)
+			params = stringBuilder.substring(0, stringBuilder.length() - 2);
+
+		return getId() + ":" + params;
+	}
+
+    /*
+    private static void appendToValue(StringBuilder value, String line) {
+
+        if (value.length() != 0) {
+            value.append(System.getProperty("line.separator"));
+        }
+        value.append(line);
+    }
+    */
+
+    private Entry readEntry(SourceInterface source)
+            throws IOException {
+
+        String line;
+        String key = null;
+        StringBuilder value = null;
+        while ((line = source.readLine()) != null)
+        {
+            if (key == null) {
+                int colonIndex = line.indexOf(':');
+                if (colonIndex == -1) {
+                    return null;
+                }
+                key = line.substring(0, colonIndex);
+                String inlineValue = line.substring(colonIndex + 1);
+
+
+                if (!inlineValue.startsWith("~")) {
+                    return new Entry(key, inlineValue);
+                }
+                value = new StringBuilder();
+                value.append(inlineValue.substring(1));
+                continue;
+            }
+            if (value.length() != 0) {
+                value.append(System.getProperty("line.separator"));
+            }
+            if (line.contains("~")) {
+                value.append(line.substring(0, line.indexOf("~")));
+                return new Entry(key, value.toString());
+            }
+            value.append(line);
+            /*
+            if (line.contains("~")) {
+                String lastLine = line.substring(0, line.indexOf("~"));
+                if (lastLine.length() > 0) {
+                    appendToValue(value, lastLine);
+                }
+                return new Entry(key, value.toString());
+            }
+            appendToValue(value, line);
+            */
+        }
+        return null;
+    }
+
+    @Override
+    public void load(SourceInterface source) throws Exception {
+        //TODO not clearing values, because get from manager gives only fields, not children
+        //this.clearValues();
+
+        Entry entry;
+
+        while ((entry = readEntry(source)) != null) {
+            Param param = getParam(entry.key);
+            if (param == null) {
+                continue;
+            }
+            if ((param.getFlags() & Flags.DONTLOAD) != 0) {
+                LOGGER.debug("DontLoad flag was set - not loading...");
+            } else {
+                int retFlags = this.set(param, entry.value);
+                if ((retFlags & (Flags.PSET_HITMIN | Flags.PSET_HITMAX)) != 0) {
+                    String which = ((retFlags & Flags.PSET_HITMIN) != 0) ? "small"
+                            : "big";
+                    LOGGER.warn("value of key '" + entry.key
+                            + "' was too " + which + ", adjusted");
+                }
+            }
+        }
+    }
+
+    @Override
+	public List<Exception> load2(String line) throws Exception {
+		this.clearValues();
+
+		// list of not terminable exceptions that occured
+		List<Exception> exceptions = new ArrayList<Exception>();
+
+		int indexOfColon = line.indexOf(':');
+		if (indexOfColon < 0)
+			indexOfColon = line.length();
+		String classId = line.substring(0, indexOfColon).trim();
+		if (!getId().equals(classId))
+			throw new Exception(
+					"Inappropriate getId of param interface (class), specified \""
+							+ classId + "\" while should be \"" + getId()
+							+ "\"");
+		String parameters;
+		if (indexOfColon == line.length())
+			parameters = "";
+		else
+			parameters = line.substring(indexOfColon + 1);
+
+		// tokenize
+		boolean doubleQuotes = false;
+		char previousChar = ',';
+		List<Entry> result = new ArrayList<Entry>();
+		StringBuilder stringBuilder = new StringBuilder();
+		String key = "";
+		if (parameters.trim().length() > 0) {
+			for (char currentChar : parameters.toCharArray()) {
+				if (!doubleQuotes && currentChar == '=' && "".equals(key)) {
+					key = stringBuilder.toString();
+					stringBuilder = new StringBuilder();
+				} else if (!doubleQuotes && currentChar == ',') {
+					if (previousChar == ',') {
+						result.add(new Entry(key.trim(), null));
+					} else {
+						result.add(new Entry(key.trim(), stringBuilder
+								.toString().trim()));
+					}
+					stringBuilder = new StringBuilder();
+					key = "";
+				} else if (currentChar == '"') {
+					if (previousChar == '\\') {
+						stringBuilder.deleteCharAt(stringBuilder.length() - 1);
+						stringBuilder.append(currentChar);
+					} else
+						doubleQuotes = !doubleQuotes;
+				} else {
+					stringBuilder.append(currentChar);
+				}
+
+				previousChar = currentChar;
+			}
+
+			String last = stringBuilder.toString().trim();
+			// if (last.length() > 0 || previousChar == '\"'
+			// || previousChar == ':')
+			result.add(new Entry(key.trim(), last));
+
+			if (doubleQuotes)
+				throw new Exception(
+						"Double quotes expected while end of line met");
+		}
+
+		// if successfully parsed set all necessary values
+
+		//TODO: name omitting
+		Param currentParam = null;
+		boolean illegallyOmittedName = false;
+		for (Entry pair : result) {
+			try {
+
+				if (pair.key != null && !"".equals(pair.key)) {
+					Param param = getParam(pair.key);
+					if (param == null) {
+						illegallyOmittedName = true;
+						throw new Exception("No parameter with such id: "
+								+ pair.key);
+					} else {
+						currentParam = param;
+						illegallyOmittedName = false;
+					}
+				} else if (illegallyOmittedName
+						|| (currentParam.getFlags() & Flags.CANOMITNAME) == 0) {
+					throw new Exception(
+							"Parameter with offset: "
+									+ currentParam
+									+ " is not set, "
+									+ "because it's definition or definition of one of the previous params "
+									+ "does not contain flag, which allow to skip the getName (flag 1024)");
+				}
+
+				if (pair.value != null) {
+					int setFlag = this.set(currentParam, pair.value);
+					if ((setFlag & Flags.PSET_HITMIN) != 0) {
+						exceptions.add(createBoundaryHitException(currentParam, pair.value, Flags.PSET_HITMIN));
+					}
+
+					if ((setFlag & Flags.PSET_HITMAX) != 0) {
+						exceptions.add(createBoundaryHitException(currentParam, pair.value, Flags.PSET_HITMAX));
+					}
+
+					if ((setFlag & Flags.PSET_RONLY) != 0) {
+						throw (new Exception(
+								"Tried to set a read-only attribute \""
+										+ currentParam.getId()
+										+ "\" in class \"" + getId() + "\""));
+					}
+				}
+
+			} catch (Exception e) {
+				exceptions.add(e);
+			//} finally {
+			//  currentProperty++;
+			}
+		}
+		return exceptions;
+	}
+
+	private Exception createBoundaryHitException(Param param, String value, int flag) {
+		boolean minimum = (flag & Flags.PSET_HITMIN) != 0;
+		String boundary = (minimum ? param.getMin(Object.class) : param.getMax(Object.class)).toString();
+		String name =  (minimum ? "minimum" : "maximum");
+		return new Exception("Tried to set attribute \""
+				+ param.getId()
+				+ "\" in class \""
+				+ getId()
+				+ "\" to value which exceeds " + name + " ("
+				+ value
+				+ "), truncated to: "
+				+ boundary);
+	}
+	
+	protected abstract <T> void internalSet(Param param, T value);
+
+    @Override
+    public Collection<Param> getParams() {
+        return framsClass.getParamEntries();
+    }
+
+    /*
+	protected <T extends Comparable<T>> int setAndCut(Param param, Object value, Class<T> type) {
+		int flags = 0;
+		T val = type.cast(value);
+		T min = param.getMin(type);
+		T max = param.getMax(type);
+		if (min != null && val.compareTo(min) < 0) {
+			val = min;
+			flags |= Flags.PSET_HITMIN;
+		}
+		if (max != null && val.compareTo(max) > 0) {
+			val = max;
+			flags |= Flags.PSET_HITMAX;
+		}
+		internalSet(param, val);
+		return flags;
+	}*/
+
+
+}
Index: java/main/src/main/java/com/framsticks/params/SimpleSource.java
===================================================================
--- java/main/src/main/java/com/framsticks/params/SimpleSource.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/params/SimpleSource.java	(revision 77)
@@ -0,0 +1,49 @@
+package com.framsticks.params;
+
+/**
+ * @author Piotr Sniegowski
+ */
+public class SimpleSource implements SourceInterface {
+
+	final String content;
+	int cursor;
+
+	public SimpleSource(String content) {
+		this.content = content;
+        cursor = 0;
+	}
+
+	@Override
+	public String getFilename() {
+		return "<String>";
+	}
+
+	@Override
+	public String readLine() {
+		if (cursor >= content.length()) {
+			return null;
+		}
+		int nextEndLine = content.indexOf('\n', cursor);
+		if (nextEndLine == -1) {
+			nextEndLine = content.length();
+		}
+		String result = content.substring(cursor, nextEndLine);
+		cursor = nextEndLine + 1;
+		return result;
+	}
+
+	@Override
+	public String demangleInclude(String include) {
+		return null;
+	}
+
+	@Override
+	public SourceInterface openInclude(String include) {
+		return null;
+	}
+
+	@Override
+	public void close() {
+
+	}
+}
Index: java/main/src/main/java/com/framsticks/params/SinkInterface.java
===================================================================
--- java/main/src/main/java/com/framsticks/params/SinkInterface.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/params/SinkInterface.java	(revision 77)
@@ -0,0 +1,11 @@
+package com.framsticks.params;
+
+/**
+ * @author Piotr Sniegowski
+ */
+public interface SinkInterface {
+    SinkInterface print(String str);
+    SinkInterface print(Object obj);
+    void breakLine();
+    void close();
+}
Index: java/main/src/main/java/com/framsticks/params/SourceInterface.java
===================================================================
--- java/main/src/main/java/com/framsticks/params/SourceInterface.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/params/SourceInterface.java	(revision 77)
@@ -0,0 +1,9 @@
+package com.framsticks.params;
+
+public interface SourceInterface {
+	String getFilename();
+	String readLine();
+	String demangleInclude(String include);
+	SourceInterface openInclude(String include);
+	void close();
+}
Index: java/main/src/main/java/com/framsticks/params/UniqueListAccess.java
===================================================================
--- java/main/src/main/java/com/framsticks/params/UniqueListAccess.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/params/UniqueListAccess.java	(revision 77)
@@ -0,0 +1,192 @@
+package com.framsticks.params;
+
+import com.framsticks.util.Casting;
+import com.framsticks.util.Numbers;
+import org.apache.log4j.Logger;
+
+import java.util.*;
+
+/**
+ * @author Piotr Sniegowski
+ */
+public class UniqueListAccess extends ListAccess {
+
+    private static final Logger LOGGER = Logger.getLogger(UniqueListAccess.class.getName());
+
+    Map<String, Object> map;
+
+    final String uidName;
+
+    public UniqueListAccess(AccessInterface elementAccess, String uidName) {
+        super(elementAccess);
+        this.uidName = uidName;
+    }
+
+    @Override
+    public Map<String, Object> createAccessee() {
+        return new HashMap<String, Object>();
+    }
+
+    @Override
+    public Param getParam(int i) {
+        LOGGER.error("accesing unique list through index");
+        assert false;
+        return null;
+        //LOGGER.error("accesing unique list through index");
+        //return null;
+        //return new ParamBuilder().setId(Integer.toString(i)).setName(elementAccess.getId()).setType("o " + elementAccess.getId()).build();
+    }
+
+    @Override
+    public Param getParam(String id) {
+        Integer i = Numbers.parse(id, Integer.class);
+        if (i != null) {
+            return getParam(i);
+        }
+        return new ParamBuilder().setId(id).setName(elementAccess.getId()).setType("o " + elementAccess.getId()).build();
+    }
+
+    @Override
+    public String getId() {
+        return "l " + elementAccess.getId() + " " + uidName;
+    }
+
+    @Override
+    public int getParamCount() {
+        return map.size();
+    }
+
+    @Override
+    public <T> T get(int i, Class<T> type) {
+        LOGGER.error("accesing unique list through index");
+        assert false;
+        return null;
+        //Object[] values = map.values().toArray();
+        //return Casting.tryCast(i < values.length ? values[i] : null, type);
+    }
+
+    @Override
+    public <T> T get(String id, Class<T> type) {
+        Integer i = Numbers.parse(id, Integer.class);
+        if (i != null) {
+            return get(i, type);
+        }
+        return Casting.tryCast(type, map.containsKey(id) ? map.get(id) : null);
+    }
+
+    @Override
+    public <T> T get(Param param, Class<T> type) {
+        return get(param.getId(), type);
+    }
+
+    public String getUidOf(Object value) {
+        Object tmp = elementAccess.getSelected();
+        elementAccess.select(value);
+        String uid = elementAccess.get(uidName, String.class);
+        elementAccess.select(tmp);
+        if (uid == null) {
+            return null;
+        }
+        return uid;
+    }
+
+    protected int setByUid(Object object, String uid) {
+        if (uid == null) {
+            uid = getUidOf(object);
+            if (uid == null) {
+                LOGGER.error("failed to set - missing uid");
+                return 0;
+            }
+        }
+        if (object == null) {
+            map.remove(uid);
+        } else {
+            map.put(uid, object);
+        }
+        return 0;
+    }
+
+    @Override
+    public <T> int set(int i, T value) {
+        LOGGER.error("accesing unique list through index");
+        //return setByUid(value, null);
+        return 0;
+    }
+
+    @Override
+    public <T> int set(String id, T value) {
+        Integer i = Numbers.parse(id, Integer.class);
+        if (i != null) {
+            return set(i, value);
+        }
+        if (value == null) {
+            return setByUid(null, id);
+        }
+        String uid = getUidOf(value);
+        if (uid != null && id != null) {
+            if (!id.equals(uid)) {
+                LOGGER.error("uid mismatch with set key");
+                return 0;
+            }
+            setByUid(value, uid);
+            return 0;
+        }
+        if (uid != null) {
+            setByUid(value, uid);
+            return 0;
+        }
+        if (id != null) {
+            setByUid(value, id);
+            return 0;
+        }
+        LOGGER.error("missing both uid and id - failed to set");
+        return 0;
+    }
+
+    @Override
+    public <T> int set(Param param, T value) {
+        return set(param.getId(), value);
+    }
+
+    @Override
+    public void clearValues() {
+        map.clear();
+    }
+
+    @Override
+    public void select(Object object) {
+        map = (Map<String, Object>)object;
+    }
+
+    @Override
+    public Object getSelected() {
+        return map;
+    }
+
+    @Override
+    public UniqueListAccess cloneAccess() {
+        return new UniqueListAccess(elementAccess.cloneAccess(), uidName);
+    }
+
+    @Override
+    public String computeIdentifierFor(Object selected) {
+        String uid = getUidOf(selected);
+        if (uid == null) {
+            LOGGER.error("missing uid field");
+            return null;
+        }
+        return uid;
+    }
+
+    @Override
+    public Collection<Param> getParams() {
+        List<Param> result = new LinkedList<Param>();
+        if (map == null) {
+            return result;
+        }
+        for (String k : map.keySet()) {
+            result.add(getParam(k));
+        }
+        return result;
+    }
+}
Index: java/main/src/main/java/com/framsticks/params/Util.java
===================================================================
--- java/main/src/main/java/com/framsticks/params/Util.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/params/Util.java	(revision 77)
@@ -0,0 +1,16 @@
+package com.framsticks.params;
+
+/**
+ * @author Piotr Sniegowski
+ */
+public abstract class Util {
+    public static String readSourceToString(SourceInterface source) {
+        StringBuilder result = new StringBuilder();
+        String line;
+        while ((line = source.readLine()) != null) {
+            result.append(line).append(" ");
+        }
+        source.close();
+        return result.toString();
+    }
+}
Index: java/main/src/main/java/com/framsticks/params/types/ArrayListParam.java
===================================================================
--- java/main/src/main/java/com/framsticks/params/types/ArrayListParam.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/params/types/ArrayListParam.java	(revision 77)
@@ -0,0 +1,68 @@
+package com.framsticks.params.types;
+
+import com.framsticks.params.AccessInterface;
+import com.framsticks.params.ArrayListAccess;
+import com.framsticks.params.CastFailure;
+import com.framsticks.util.Casting;
+import com.framsticks.util.Containers;
+import com.framsticks.util.Numbers;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author Piotr Sniegowski
+ */
+public class ArrayListParam extends ListParam {
+
+    public ArrayListParam(String containedTypeName) {
+        super(containedTypeName);
+    }
+
+
+    @Override
+    public Class getStorageType() {
+        return List.class;
+    }
+
+    @Override
+    public AccessInterface prepareAccessInterface(AccessInterface access) {
+        return new ArrayListAccess(access);
+    }
+
+    @Override
+    public String computeAccessId() {
+        return "l " + containedTypeName;
+    }
+
+    @Override
+    public Object reassign(Object newValue, Object oldValue) throws CastFailure {
+        if (newValue == null) {
+            throw new CastFailure();
+        }
+        Integer size = Numbers.cast(newValue, Integer.class);
+        if (size != null) {
+            //return oldValue;
+            List list;
+            if (oldValue == null) {
+                list = new ArrayList();
+            } else {
+                list = Casting.tryCast(List.class, oldValue);
+                if (list == null) {
+                    throw new CastFailure();
+                }
+            }
+            Containers.resizeList(list, size);
+            return list;
+        }
+        if (oldValue != null) {
+            return oldValue;
+        }
+        return newValue;
+    }
+
+    @Override
+    public String getType() {
+        return "l " + getContainedTypeName();
+    }
+}
Index: java/main/src/main/java/com/framsticks/params/types/BinaryParam.java
===================================================================
--- java/main/src/main/java/com/framsticks/params/types/BinaryParam.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/params/types/BinaryParam.java	(revision 77)
@@ -0,0 +1,32 @@
+package com.framsticks.params.types;
+
+import com.framsticks.params.CastFailure;
+import com.framsticks.util.Numbers;
+
+/**
+ * @author Piotr Sniegowski
+ */
+public class BinaryParam extends ValueParam {
+	@Override
+	public Class getStorageType() {
+		return Integer.class;
+	}
+
+    @Override
+    public String getType() {
+        return "db";
+    }
+
+    @Override
+    public Object reassign(Object newValue, Object oldValue) throws CastFailure {
+        if (newValue instanceof String) {
+            Integer v = Numbers.parse((String) newValue, Integer.class);
+            if (v != null) {
+                return v;
+            }
+            throw new CastFailure();
+        }
+        return super.reassign(newValue, oldValue);
+    }
+
+}
Index: java/main/src/main/java/com/framsticks/params/types/BooleanParam.java
===================================================================
--- java/main/src/main/java/com/framsticks/params/types/BooleanParam.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/params/types/BooleanParam.java	(revision 77)
@@ -0,0 +1,47 @@
+package com.framsticks.params.types;
+
+import com.framsticks.params.CastFailure;
+import com.framsticks.params.SinkInterface;
+
+/**
+ * @author Piotr Sniegowski
+ */
+public class BooleanParam extends DecimalParam {
+    @Override
+    public Class getStorageType() {
+        return Boolean.class;
+    }
+
+    @Override
+    public Object reassign(Object newValue, Object oldValue) throws CastFailure {
+		if (newValue instanceof Boolean) {
+			return newValue;
+		}
+        Object casted = super.reassign(newValue, oldValue);
+        if (casted instanceof Integer) {
+            Integer i = (Integer)casted;
+            if (i == 0) return false;
+            if (i == 1) return true;
+            throw new CastFailure();
+        }
+        /*
+        if (newValue instanceof String) {
+            if (newValue.equals("true")) return true;
+            if (newValue.equals("false")) return false;
+            throw new CastFailure();
+        }
+        */
+        throw new CastFailure();
+    }
+
+    @Override
+    public String getType() {
+        return "d 0 1";
+    }
+
+    @Override
+    public void save(SinkInterface sink, Object value) {
+        assert value instanceof Boolean;
+        sink.print(((Boolean)value) ? "1" : "0");
+    }
+}
Index: java/main/src/main/java/com/framsticks/params/types/ColorParam.java
===================================================================
--- java/main/src/main/java/com/framsticks/params/types/ColorParam.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/params/types/ColorParam.java	(revision 77)
@@ -0,0 +1,20 @@
+package com.framsticks.params.types;
+
+/**
+ * @author Piotr Sniegowski
+ */
+public class ColorParam extends ValueParam {
+
+	@Override
+	public Class getStorageType() {
+		return Void.class;
+	}
+
+    @Override
+    public String getType() {
+        return "dc";
+    }
+
+
+
+}
Index: java/main/src/main/java/com/framsticks/params/types/CompositeParam.java
===================================================================
--- java/main/src/main/java/com/framsticks/params/types/CompositeParam.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/params/types/CompositeParam.java	(revision 77)
@@ -0,0 +1,33 @@
+package com.framsticks.params.types;
+
+import com.framsticks.params.AccessInterface;
+import com.framsticks.params.Param;
+import com.framsticks.util.Strings;
+
+/**
+ * @author Piotr Sniegowski
+ */
+public abstract class CompositeParam extends Param {
+	protected final String containedTypeName;
+
+	public CompositeParam(String containedTypeName) {
+		this.containedTypeName = Strings.notEmpty(containedTypeName) ? containedTypeName : null;
+	}
+
+    public boolean isMatchingContainedName(String name) {
+        assert name != null;
+        if (containedTypeName == null) {
+            return true;
+        }
+        return name.equals(containedTypeName);
+    }
+
+	public String getContainedTypeName() {
+		return containedTypeName;
+	}
+
+    public abstract AccessInterface prepareAccessInterface(AccessInterface access);
+
+    public abstract String computeAccessId();
+
+}
Index: java/main/src/main/java/com/framsticks/params/types/DecimalParam.java
===================================================================
--- java/main/src/main/java/com/framsticks/params/types/DecimalParam.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/params/types/DecimalParam.java	(revision 77)
@@ -0,0 +1,41 @@
+package com.framsticks.params.types;
+
+import com.framsticks.params.CastFailure;
+import com.framsticks.util.Numbers;
+
+/**
+ * @author Piotr Sniegowski
+ */
+public class DecimalParam extends ValueParam {
+
+	@Override
+	public boolean isNumeric() {
+		return true;
+	}
+
+	@Override
+	public Class getStorageType() {
+		return Integer.class;
+	}
+
+
+
+    @Override
+    public Object reassign(Object newValue, Object oldValue) throws CastFailure {
+        if (newValue instanceof String) {
+            Integer v = Numbers.parse((String)newValue, Integer.class);
+            if (v != null) {
+                return v;
+            }
+            throw new CastFailure();
+        }
+        return super.reassign(newValue, oldValue);
+    }
+
+    @Override
+    public String getType() {
+        return "d";
+    }
+
+
+}
Index: java/main/src/main/java/com/framsticks/params/types/EnumParam.java
===================================================================
--- java/main/src/main/java/com/framsticks/params/types/EnumParam.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/params/types/EnumParam.java	(revision 77)
@@ -0,0 +1,29 @@
+package com.framsticks.params.types;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author Piotr Sniegowski
+ */
+public class EnumParam extends DecimalParam {
+
+	ArrayList<String> enums;
+
+	/**
+	 * This constructor exists because EnumParam is different package than ParamBuilder.
+	 *
+	 * @param enums
+	 */
+	public EnumParam(ArrayList<String> enums) {
+		assert(enums != null);
+		this.enums = enums;
+	}
+
+	public List<String> getElements() {
+		return enums;
+	}
+
+
+
+}
Index: java/main/src/main/java/com/framsticks/params/types/EventParam.java
===================================================================
--- java/main/src/main/java/com/framsticks/params/types/EventParam.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/params/types/EventParam.java	(revision 77)
@@ -0,0 +1,21 @@
+package com.framsticks.params.types;
+
+import com.framsticks.params.Param;
+
+/**
+ * @author Piotr Sniegowski
+ */
+public class EventParam extends Param {
+	@Override
+	public Class getStorageType() {
+		return Void.class;
+	}
+
+    @Override
+    public String getType() {
+        return "e";
+    }
+
+
+
+}
Index: java/main/src/main/java/com/framsticks/params/types/FloatParam.java
===================================================================
--- java/main/src/main/java/com/framsticks/params/types/FloatParam.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/params/types/FloatParam.java	(revision 77)
@@ -0,0 +1,37 @@
+package com.framsticks.params.types;
+
+import com.framsticks.params.CastFailure;
+import com.framsticks.util.Numbers;
+
+/**
+ * @author Piotr Sniegowski
+ */
+public class FloatParam extends ValueParam {
+	@Override
+	public boolean isNumeric() {
+		return true;
+	}
+	@Override
+	public Class getStorageType() {
+		return Double.class;
+	}
+
+	@Override
+    public Object reassign(Object newValue, Object oldValue) throws CastFailure {
+        if (newValue instanceof String) {
+		    Double v = Numbers.parse((String)newValue, Double.class);
+            if (v != null) {
+                return v;
+            }
+            throw new CastFailure();
+        }
+        return super.reassign(newValue, oldValue);
+	}
+
+    @Override
+    public String getType() {
+        return "f";
+    }
+
+
+}
Index: java/main/src/main/java/com/framsticks/params/types/ListParam.java
===================================================================
--- java/main/src/main/java/com/framsticks/params/types/ListParam.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/params/types/ListParam.java	(revision 77)
@@ -0,0 +1,24 @@
+package com.framsticks.params.types;
+
+import com.framsticks.params.CastFailure;
+import com.framsticks.util.Casting;
+import com.framsticks.util.Containers;
+import com.framsticks.util.Numbers;
+
+import java.util.List;
+
+/**
+ * @author Piotr Sniegowski
+ */
+public abstract class ListParam extends CompositeParam {
+
+	public ListParam(String containedTypeName) {
+		super(containedTypeName);
+	}
+
+
+
+
+
+
+}
Index: java/main/src/main/java/com/framsticks/params/types/ObjectParam.java
===================================================================
--- java/main/src/main/java/com/framsticks/params/types/ObjectParam.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/params/types/ObjectParam.java	(revision 77)
@@ -0,0 +1,48 @@
+package com.framsticks.params.types;
+
+import com.framsticks.params.AccessInterface;
+import com.framsticks.params.CastFailure;
+
+/**
+ * @author Piotr Sniegowski
+ */
+public class ObjectParam extends CompositeParam {
+
+	public ObjectParam(String containedTypeName) {
+		super(containedTypeName);
+	}
+
+    @Override
+    public String computeAccessId() {
+        return containedTypeName;
+    }
+
+    @Override
+	public Class getStorageType() {
+		return Object.class;
+	}
+
+	@Override
+	public boolean isEmptyAvailable() {
+		return true;
+	}
+
+	@Override
+	public Object reassign(Object newValue, Object oldValue) throws CastFailure {
+		return newValue;
+	}
+
+    @Override
+    public AccessInterface prepareAccessInterface(AccessInterface access) {
+        return access;
+    }
+
+    @Override
+    public String getType() {
+        return "o " + containedTypeName;
+    }
+
+
+
+
+}
Index: java/main/src/main/java/com/framsticks/params/types/ProcedureParam.java
===================================================================
--- java/main/src/main/java/com/framsticks/params/types/ProcedureParam.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/params/types/ProcedureParam.java	(revision 77)
@@ -0,0 +1,82 @@
+package com.framsticks.params.types;
+
+import com.framsticks.params.CastFailure;
+import com.framsticks.params.FramsClass;
+import com.framsticks.params.Param;
+import com.framsticks.params.ParamBuilder;
+import com.framsticks.util.Strings;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * @author Piotr Sniegowski
+ */
+public class ProcedureParam extends Param {
+	private Param resultType;
+	private List<Param> argumentsType = new ArrayList<Param>();
+
+	private static Pattern addressPattern = Pattern.compile("^([^\\(]+)?\\(([^\\)]*)\\)$");
+
+	protected static Param parseType(String type, String name) {
+		return new ParamBuilder().setType(type).setName(name).build();
+	}
+
+	public void parseSignature(String signature) throws Exception {
+		if (!Strings.notEmpty(signature)) {
+			return;
+		}
+		Matcher matcher = addressPattern.matcher(signature);
+		if (!matcher.matches()) {
+			throw new Exception("invalid signature");
+		}
+		String result = Strings.collapse(matcher.group(1));
+		if (result != null) {
+			resultType = parseType(result, null);
+		}
+		String arguments = matcher.group(2);
+		if (!Strings.notEmpty(arguments)) {
+			return;
+		}
+		for (String a : arguments.split(",")) {
+			int space = a.indexOf(' ');
+			String type;
+			String name;
+			if (space == -1) {
+				type = a;
+				name = null;
+			} else {
+				type = a.substring(0, space);
+				name = a.substring(space + 1);
+			}
+			argumentsType.add(parseType(type, name));
+		}
+	}
+
+
+	@Override
+	public Class getStorageType() {
+		return Void.class;
+	}
+
+	public Param getResultType() {
+		return resultType;
+	}
+
+	public List<Param> getArgumentsType() {
+		return argumentsType;
+	}
+
+    @Override
+    public Object reassign(Object newValue, Object oldValue) throws CastFailure {
+        throw new CastFailure();
+    }
+
+    @Override
+    public String getType() {
+        return "p";
+    }
+
+}
Index: java/main/src/main/java/com/framsticks/params/types/StringParam.java
===================================================================
--- java/main/src/main/java/com/framsticks/params/types/StringParam.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/params/types/StringParam.java	(revision 77)
@@ -0,0 +1,41 @@
+package com.framsticks.params.types;
+
+import com.framsticks.params.CastFailure;
+import com.framsticks.params.SinkInterface;
+
+/**
+ * @author Piotr Sniegowski
+ */
+public class StringParam extends ValueParam {
+	@Override
+	public Class getStorageType() {
+		return String.class;
+	}
+
+	@Override
+	public boolean isEmptyAvailable() {
+		return true;
+	}
+
+    @Override
+    public Object reassign(Object newValue, Object oldValue) throws CastFailure {
+        if (newValue instanceof String) {
+            return (String)newValue;
+        }
+        return super.reassign(newValue, oldValue);
+    }
+
+    @Override
+    public String getType() {
+        return "s";
+    }
+
+    private static final String SEPARATOR = System.getProperty("line.separator");
+
+    @Override
+    public void save(SinkInterface sink, Object value) {
+        assert value instanceof String;
+        String s = (String)value;
+        sink.print((s.contains(SEPARATOR) ? (s = "~" + SEPARATOR + s + "~") : s));
+    }
+}
Index: java/main/src/main/java/com/framsticks/params/types/UniqueListParam.java
===================================================================
--- java/main/src/main/java/com/framsticks/params/types/UniqueListParam.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/params/types/UniqueListParam.java	(revision 77)
@@ -0,0 +1,68 @@
+package com.framsticks.params.types;
+
+import com.framsticks.params.AccessInterface;
+import com.framsticks.params.CastFailure;
+import com.framsticks.params.UniqueListAccess;
+import com.framsticks.util.Numbers;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author Piotr Sniegowski
+ */
+public class UniqueListParam extends ListParam {
+
+    final String uidName;
+
+    public UniqueListParam(String containedTypeName, String uidName) {
+        super(containedTypeName);
+        this.uidName = uidName;
+    }
+
+    @Override
+    public String computeAccessId() {
+        return "l " + containedTypeName + " " + uidName;
+    }
+
+
+    @Override
+    public Class getStorageType() {
+        return Map.class;
+    }
+
+    @Override
+    public AccessInterface prepareAccessInterface(AccessInterface access) {
+        return new UniqueListAccess(access, uidName);
+    }
+
+
+    @Override
+    public Object reassign(Object newValue, Object oldValue) throws CastFailure {
+        if (newValue instanceof Map) {
+            return newValue;
+        }
+        Integer size = Numbers.cast(newValue, Integer.class);
+        if (size != null) {
+            //return oldValue;
+            /*
+            the integer value should be ignored, because this may cause, that object is created before
+            information about it's elements is available, which would break resolution flow
+            */
+            if (oldValue != null) {
+                return oldValue;
+            }
+            return new HashMap();
+        }
+
+        throw new CastFailure();
+    }
+
+    @Override
+    public String getType() {
+        return "l " + containedTypeName + " " + uidName;
+    }
+
+
+}
Index: java/main/src/main/java/com/framsticks/params/types/UniversalParam.java
===================================================================
--- java/main/src/main/java/com/framsticks/params/types/UniversalParam.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/params/types/UniversalParam.java	(revision 77)
@@ -0,0 +1,26 @@
+package com.framsticks.params.types;
+
+import com.framsticks.params.CastFailure;
+import com.framsticks.util.Numbers;
+
+/**
+ * @author Piotr Sniegowski
+ */
+public class UniversalParam extends ValueParam {
+	@Override
+	public Class getStorageType() {
+		return Object.class;
+	}
+
+	@Override
+	public boolean isEmptyAvailable() {
+		return true;
+	}
+
+    @Override
+    public String getType() {
+        return "x";
+    }
+
+
+}
Index: java/main/src/main/java/com/framsticks/params/types/ValueParam.java
===================================================================
--- java/main/src/main/java/com/framsticks/params/types/ValueParam.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/params/types/ValueParam.java	(revision 77)
@@ -0,0 +1,14 @@
+package com.framsticks.params.types;
+
+import com.framsticks.params.Param;
+import com.framsticks.params.SinkInterface;
+
+/**
+ * @author Piotr Sniegowski
+ */
+public abstract class ValueParam extends Param {
+
+    public void save(SinkInterface sink, Object value) {
+        sink.print(value);
+    }
+}
Index: java/main/src/main/java/com/framsticks/parsers/FileSource.java
===================================================================
--- java/main/src/main/java/com/framsticks/parsers/FileSource.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/parsers/FileSource.java	(revision 77)
@@ -0,0 +1,79 @@
+package com.framsticks.parsers;
+
+import com.framsticks.params.SourceInterface;
+
+import java.io.BufferedReader;
+import java.io.FileReader;
+import java.io.IOException;
+
+
+public class FileSource implements SourceInterface {
+
+	private BufferedReader reader;
+	private String filename;
+	
+	public FileSource(String filename) throws IOException
+	{
+		this.filename = filename;
+        reader = new BufferedReader(new FileReader(filename));
+	}
+
+
+    @Override
+    public String readLine()
+	{
+		try
+		{
+			return reader.readLine();
+		} catch (IOException ignored) {
+
+		}
+		return null;
+	}
+
+    @Override
+    public String getFilename()
+	{
+		return filename;
+	}
+
+    @Override
+    public String demangleInclude(String include)
+	{
+		if (!include.contains(java.io.File.separator)) {
+			String currentFilePath = (new java.io.File(filename)).getParent();
+			if (!String.valueOf(
+					currentFilePath.charAt(currentFilePath.length() - 1))
+					.equals(java.io.File.separator)) {
+				currentFilePath = currentFilePath + java.io.File.separator;
+			}
+			include = currentFilePath + include;
+		}	
+		return include;
+	}
+
+    @Override
+    public SourceInterface openInclude(String include)
+	{
+		try
+		{
+			return new FileSource(include);
+		}
+		catch(IOException e)
+		{
+			
+		}
+		return null;
+	}
+
+    @Override
+    public void close()
+	{
+		try {
+			reader.close();
+		} catch (IOException e) {
+			
+		}
+	}
+	
+}
Index: java/main/src/main/java/com/framsticks/parsers/GenotypeLoader.java
===================================================================
--- java/main/src/main/java/com/framsticks/parsers/GenotypeLoader.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/parsers/GenotypeLoader.java	(revision 77)
@@ -0,0 +1,70 @@
+package com.framsticks.parsers;
+
+import com.framsticks.model.Genotype;
+import com.framsticks.params.*;
+import com.framsticks.params.types.*;
+
+import org.apache.log4j.Logger;
+
+public class GenotypeLoader extends MultiParamLoader {
+	private Genotype genotypeReturnObject = new Genotype();
+	private static Logger logger = Logger.getLogger(GenotypeLoader.class);
+
+	public GenotypeLoader() throws Exception {
+
+		FramsClass entries = new FramsClass("Genotype", "org", "A Genotype with the associated performance information. All but one Genotype objects are placed in Genotype Groups. There is also a single static Genotype object not associated with a group, which is used as a temporary storage by genetic operators and some functions from GenePools.");
+		entries
+			.appendGroup(new Group("Body"))
+			.appendGroup(new Group("Performance"))
+			.appendGroup(new Group("Fitness"))
+			.appendGroup(new Group("Conversions"));
+
+		//getId, group-number, getFlags, getName, getType(getType min max), getHelp
+		entries
+			.append(new ParamBuilder().setId("name").setGroup(0).setName("Name").setType(new StringParam()).setMin(0).setMax(40).build())
+			.append(new ParamBuilder().setId("genotype").setGroup(0).setName("Genotype").setType(new StringParam()).setMin(1).build())
+			.append(new ParamBuilder().setId("info").setGroup(0).setName("Info").setType(new StringParam()).setMin(1).setHelp("Additional information or comments").build())
+			.append(new ParamBuilder().setId("simi").setGroup(1).setFlags(Flags.READONLY | Flags.DONTSAVE).setName("Similarity").setType(new FloatParam()).build())
+			.append(new ParamBuilder().setId("energ0").setGroup(1).setFlags(Flags.READONLY | Flags.DONTSAVE).setName("Starting energy").setType(new FloatParam()).build())
+			.append(new ParamBuilder().setId("strsiz").setGroup(1).setFlags(Flags.READONLY | Flags.DONTSAVE | Flags.USERHIDDEN).setName("Body parts (deprecated; use numparts)").setType(new FloatParam()).build())
+			.append(new ParamBuilder().setId("strjoints").setGroup(1).setFlags(Flags.READONLY | Flags.DONTSAVE | Flags.USERHIDDEN).setName("Body joints (deprecated; use numjoints)").setType(new FloatParam()).build())
+			.append(new ParamBuilder().setId("nnsiz").setGroup(1).setFlags(Flags.READONLY | Flags.DONTSAVE | Flags.USERHIDDEN).setName("Brain size (deprecated; use numneurons)").setType(new FloatParam()).build())
+			.append(new ParamBuilder().setId("nncon").setGroup(1).setFlags(Flags.READONLY | Flags.DONTSAVE | Flags.USERHIDDEN).setName("Brain connections (deprecated; use numconnections)").setType(new FloatParam()).build())
+			.append(new ParamBuilder().setId("numparts").setGroup(1).setFlags(Flags.READONLY | Flags.DONTSAVE).setName("Body parts").setType(new FloatParam()).build())
+			.append(new ParamBuilder().setId("numjoints").setGroup(1).setFlags(Flags.READONLY | Flags.DONTSAVE).setName("Body joints").setType(new FloatParam()).build())
+			.append(new ParamBuilder().setId("numneurons").setGroup(1).setFlags(Flags.READONLY | Flags.DONTSAVE).setName("Brain size").setType(new FloatParam()).build())
+			.append(new ParamBuilder().setId("numconnections").setGroup(1).setFlags(Flags.READONLY | Flags.DONTSAVE).setName("Brain connections").setType(new FloatParam()).build())
+			.append(new ParamBuilder().setId("num").setGroup(2).setName("Ordinal number").setType(new DecimalParam()).build())
+			.append(new ParamBuilder().setId("gnum").setGroup(2).setName("Generation").setType(new DecimalParam()).build())
+			.append(new ParamBuilder().setId("popsiz").setGroup(2).setFlags(Flags.USERHIDDEN).setName("Deprecated; use entities").setType(new DecimalParam()).build())
+			.append(new ParamBuilder().setId("entities").setGroup(2).setFlags(Flags.DONTSAVE).setName("Instances").setType(new DecimalParam()).setHelp("Copies of this genotype").build())
+			.append(new ParamBuilder().setId("lifespan").setGroup(2).setName("Life span").setType(new FloatParam()).setHelp("Average life span").build())
+			.append(new ParamBuilder().setId("velocity").setGroup(2).setName("Velocity").setType(new FloatParam()).setHelp("Average velocity").build())
+			.append(new ParamBuilder().setId("distance").setGroup(2).setName("Distance").setType(new FloatParam()).build())
+			.append(new ParamBuilder().setId("vertvel").setGroup(2).setName("Vertical velocity").setType(new FloatParam()).build())
+			.append(new ParamBuilder().setId("vertpos").setGroup(2).setName("Vertical position").setType(new FloatParam()).build())
+			.append(new ParamBuilder().setId("fit").setGroup(3).setFlags(Flags.READONLY | Flags.DONTSAVE).setName("Fitness").setType(new FloatParam()).build())
+			.append(new ParamBuilder().setId("fit2").setGroup(3).setFlags(Flags.READONLY | Flags.DONTSAVE).setName("Final fitness").setType(new FloatParam()).setHelp("Fitness shifted by (avg-n*stddev)").build())
+			.append(new ParamBuilder().setId("f0genotype").setGroup(4).setFlags(Flags.READONLY | Flags.DONTSAVE).setName("f0 genotype").setType(new StringParam()).setMin(1).setHelp("converted to f0 genotype").build())
+			.append(new ParamBuilder().setId("user1").setGroup(2).setName("User field 1").setType(new UniversalParam()).build())
+			.append(new ParamBuilder().setId("user2").setGroup(2).setName("User field 2").setType(new UniversalParam()).build())
+			.append(new ParamBuilder().setId("user3").setGroup(2).setName("User field 3").setType(new UniversalParam()).build())
+			.append(new ParamBuilder().setId("isValid").setGroup(0).setFlags(Flags.READONLY | Flags.DONTSAVE | Flags.USERHIDDEN).setName("Valid").setType(new DecimalParam()).setMin(0).setMax(1).build())
+			.append(new ParamBuilder().setId("uid").setGroup(0).setFlags(Flags.READONLY | Flags.USERHIDDEN).setName("#").setType("s").setHelp("Unique identifier").build());
+
+		ReflectionAccess reflectionParam = new ReflectionAccess(Genotype.class, entries);
+		addAccessInterface(reflectionParam);
+		addBreakCondition(Status.AfterObject);
+	}
+
+	public Genotype loadNextGenotype() throws Exception {
+		logger.info("Loading next genotype");
+		Status result = go();
+
+		if (result == Status.AfterObject) {
+			return genotypeReturnObject;
+		}
+
+		return null;
+	}
+}
Index: java/main/src/main/java/com/framsticks/parsers/Loaders.java
===================================================================
--- java/main/src/main/java/com/framsticks/parsers/Loaders.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/parsers/Loaders.java	(revision 77)
@@ -0,0 +1,50 @@
+package com.framsticks.parsers;
+
+import com.framsticks.params.*;
+import org.apache.log4j.Logger;
+
+/**
+ * @author Piotr Sniegowski
+ */
+public class Loaders {
+
+	private static final Logger LOGGER = Logger.getLogger(Loaders.class.getName());
+
+	public static FramsClass loadFramsClass(SourceInterface source) {
+		MultiParamLoader loader = new MultiParamLoader();
+		loader.setNewSource(source);
+
+        FramsClass result = new FramsClass();
+
+        AccessInterface framsClassAccess = new ReflectionAccess(FramsClass.class, FramsClass.getFramsClass());
+        AccessInterface paramBuilderAccess = new ReflectionAccess(ParamBuilder.class, ParamBuilder.getFramsClass());
+        framsClassAccess.select(result);
+		loader.addAccessInterface(framsClassAccess);
+		loader.addAccessInterface(paramBuilderAccess);
+
+		loader.addBreakCondition(MultiParamLoader.Status.AfterObject);
+
+		try {
+			MultiParamLoader.Status condition;
+			while ((condition = loader.go()) != MultiParamLoader.Status.Finished) {
+				if (condition == MultiParamLoader.Status.AfterObject) {
+
+					Object object = loader.returnObject();
+                    if (object instanceof FramsClass) {
+                        continue;
+                    }
+                    if (object instanceof ParamBuilder) {
+                        result.append(((ParamBuilder) object).build());
+					}
+				}
+			}
+			return result;
+		} catch (Exception e) {
+			LOGGER.error("an error occurred while loading class description: " + e + " before " + source.readLine());
+			e.printStackTrace();
+		}
+		return null;
+
+
+	}
+}
Index: java/main/src/main/java/com/framsticks/parsers/MultiParamLoader.java
===================================================================
--- java/main/src/main/java/com/framsticks/parsers/MultiParamLoader.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/parsers/MultiParamLoader.java	(revision 77)
@@ -0,0 +1,380 @@
+package com.framsticks.parsers;
+
+import com.framsticks.params.*;
+import org.apache.log4j.Logger;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.*;
+
+public class MultiParamLoader {
+	private final static Logger logger = Logger
+			.getLogger(MultiParamLoader.class.getName());
+
+	/**
+	 * The class which name was recently found in the file, to which execution
+	 * should be passed.
+	 */
+	public AccessInterface getLastAccessInterface() {
+		return lastAccessInterface;
+	}
+
+	/** TODO does it support multilines? */
+	/**
+	 * Specifies the condition to break execution.
+	 */
+	public enum Status {
+		None, Finished, BeforeObject, AfterObject, BeforeUnknown, OnComment, OnError, Loading
+	}
+
+	/**
+	 * Specifies the action that should be taken inside loops.
+	 */
+	private enum LoopAction {
+		Nothing, Break, Continue
+	}
+
+	protected AccessInterface lastAccessInterface;
+
+	/**
+	 * Empty Param representing unknown classes - used to omit unknown
+	 * objects in the file.
+	 */
+	protected AccessInterface emptyParam = new PropertiesAccess(new FramsClass());
+
+	/**
+	 * Last comment found in the file.
+	 */
+	protected String lastComment;
+
+	/**
+	 * Set of break conditions.
+	 */
+	private EnumSet<Status> breakConditions = EnumSet.of(Status.None);
+
+	/**
+	 * Status of current execution.
+	 */
+	private Status status;
+
+	/**
+	 * File from which data should be read.
+	 */
+	private SourceInterface currentSource;
+
+
+	/**
+	 * All the files read by the loader (there could be many of them because of
+	 * '#|include').
+	 */
+	private Stack<String> fileStack = new Stack<String>();
+
+	/**
+	 * A map that specifies connection between the getName of the file and the
+	 * actual reader.
+	 */
+	private Map<String, SourceInterface> fileMap = new HashMap<String, SourceInterface>();
+
+	/**
+	 * List of known classes.
+	 */
+	private Map<String, AccessInterface> knownParamInterfaces = new HashMap<String, AccessInterface>();
+
+	/**
+	 * Last unknown object found in the file.
+	 */
+	private String lastUnknownObjectName;
+
+	public MultiParamLoader() {
+
+	}
+
+	/**
+	 * Starts reading the file.
+	 */
+	public Status go() throws Exception {
+		logger.trace("go");
+
+		while (!isFinished()) {
+			// check if we are before some known or unknown object
+			LoopAction loopAction = tryReadObject();
+			if (loopAction == LoopAction.Break) {
+				break;
+			} else if (loopAction == LoopAction.Continue) {
+				continue;
+			}
+
+			// read data
+			String line = currentSource.readLine();
+
+			// end of file
+			if (line == null) {
+				if (!returnFromIncluded()) {
+					finish();
+					break;
+				} else {
+					continue;
+				}
+			}
+
+			// empty line
+			if (line.length() == 0) {
+				continue;
+			}
+
+			// check if some file should be included
+			if (isIncludeLine(line) == LoopAction.Continue) {
+				continue;
+			}
+
+			// check if should break on comment
+			if (isCommentLine(line) == LoopAction.Break) {
+				break;
+			}
+
+			// get class getName
+			if (changeCurrentParamInterface(line) == LoopAction.Break) {
+				break;
+			}
+		}
+
+		return status;
+	}
+
+	/**
+	 * Checks whether the reader found a known or unknown object and execution
+	 * should be passed to it.
+	 */
+	private LoopAction tryReadObject() throws Exception {
+		if (status == Status.BeforeObject
+				|| (status == Status.BeforeUnknown && lastAccessInterface != null)) {
+			// found object - let it load data
+            if (lastAccessInterface.getSelected() == null) {
+                lastAccessInterface.select(lastAccessInterface.createAccessee());
+            }
+			lastAccessInterface.load(currentSource);
+
+			if (isBreakCondition(Status.AfterObject)) {
+				// break after object creation
+				return LoopAction.Break;
+			}
+
+			return LoopAction.Continue;
+		} else if (status == Status.BeforeUnknown) {
+			logger.info("Omitting unknown object: " + lastUnknownObjectName);
+
+			// found unknown object
+			emptyParam.load(currentSource);
+			status = Status.AfterObject;
+
+			return LoopAction.Continue;
+		}
+
+		return LoopAction.Nothing;
+	}
+
+	/**
+	 * Checks whether some additional file shouldn't be included.
+	 */
+	private LoopAction isIncludeLine(String line) throws FileNotFoundException {
+		try {
+			// found comment
+			if (line.charAt(0) == '#') {
+				// maybe we should include something
+				if (line.substring(1, 8).equals("include")) {
+					int beg = line.indexOf('\"');
+					if (beg == -1) {
+						logger.info("Wanted to include some file, but the format is incorrect");
+						return LoopAction.Continue;
+					}
+
+					String includeFileName = line.substring(beg + 1);
+					int end = includeFileName.indexOf('\"');
+					if (end == -1) {
+						logger.info("Wanted to include some file, but the format is incorrect");
+						return LoopAction.Continue;
+					}
+
+					includeFileName = includeFileName.substring(0, end);
+
+					include(includeFileName);
+
+					return LoopAction.Continue;
+				}
+			}
+		} catch (IndexOutOfBoundsException ex) {
+			// value after # sign is shorter than expected 7 characters - do
+			// nothing
+		}
+
+		return LoopAction.Nothing;
+	}
+
+	/**
+	 * Checks whether execution shouldn't break on comment.
+	 */
+	private LoopAction isCommentLine(String line) {
+		if (line.charAt(0) == '#' && isBreakCondition(Status.OnComment)) {
+			// it's a simple comment - maybe we should break?
+			lastComment = line;
+			return LoopAction.Break;
+		}
+
+		return LoopAction.Nothing;
+	}
+
+	/**
+	 * Gets the getName of the class from line read from file.
+	 */
+	private LoopAction changeCurrentParamInterface(String line) {
+		// found key - value line
+		if (line.charAt(line.length() - 1) == ':') {
+			String typeName = line.substring(0, line.length() - 1);
+			lastAccessInterface = knownParamInterfaces.get(typeName);
+
+			if (lastAccessInterface != null) {
+				if (isBreakCondition(Status.BeforeObject)) {
+					logger.info("Breaking before object");
+					return LoopAction.Break;
+				}
+			} else {
+				lastUnknownObjectName = typeName;
+				if (isBreakCondition(Status.BeforeUnknown)) {
+					logger.info("Breaking before unknown");
+					return LoopAction.Break;
+				}
+			}
+		}
+		return LoopAction.Nothing;
+	}
+
+	/**
+	 * Adds another break condition.
+	 */
+	public void addBreakCondition(Status condition) {
+		breakConditions.add(condition);
+	}
+
+	/**
+	 * Removes break condition.
+	 */
+	public void removeBreakCondition(Status condition) {
+		breakConditions.remove(condition);
+	}
+
+	/**
+	 * Adds another class.
+	 */
+	public void addAccessInterface(AccessInterface accessInterface) {
+		/**TODO: by id or by name? rather by id, because from file is always lowercase*/
+		knownParamInterfaces.put(accessInterface.getId(), accessInterface);
+	}
+
+	/**
+	 * Checks whether execution is finished.
+	 */
+	private boolean isFinished() {
+		return (status == Status.Finished);
+	}
+
+	private void finish() {
+		if (currentSource != null) {
+			currentSource.close();
+		}
+
+		status = Status.Finished;
+	}
+
+	/**
+	 * Opens selected file.
+	 */
+
+	public boolean setNewSource(SourceInterface source) {
+		logger.debug("switching current source to " + source.getFilename() + "...");
+
+		currentSource = source;
+		status = Status.Loading;
+
+		return true;
+	}
+
+	/**
+	 * Includes specified file.
+	 */
+	private void include(String includeFilename) {
+
+		includeFilename = currentSource.demangleInclude(includeFilename);
+
+		if (includeFilename == null) {
+			return;
+		}
+		// check if it is already included and break if it is
+		if (isAlreadyIncluded(includeFilename)) {
+			logger.debug("circular reference ignored (" + includeFilename
+					+ ")");
+			return;
+		}
+
+		logger.info("including file " + includeFilename + "...");
+
+		SourceInterface newSource = currentSource.openInclude(includeFilename);
+		if (newSource == null) {
+			return;
+		}
+
+		fileStack.add(currentSource.getFilename());
+		fileMap.put(currentSource.getFilename(), currentSource);
+		setNewSource(newSource);
+
+	}
+
+	/**
+	 * Checks whether selected file was already included.
+	 */
+	private boolean isAlreadyIncluded(String filename) {
+		for (String file : fileStack) {
+			if (filename.equals(file)) {
+				logger.warn("file " + filename + " was already included");
+				return true;
+			}
+		}
+
+		return false;
+	}
+
+	/**
+	 * Returns from included file.
+	 */
+	private boolean returnFromIncluded() throws IOException {
+		if (fileStack.size() == 0) {
+			return false;
+		}
+
+		if (currentSource != null) {
+			currentSource.close();
+		}
+
+		String filename = fileStack.pop();
+		currentSource = fileMap.get(filename);
+		fileMap.remove(filename);
+
+		return true;
+	}
+
+	/**
+	 * Checks whether execution should break on selected condition.
+	 */
+	private boolean isBreakCondition(Status condition) {
+		status = condition;
+		return breakConditions.contains(condition);
+	}
+
+	public Object returnObject() {
+		Object result = lastAccessInterface.getSelected();
+		if (result == null) {
+			return null;
+		}
+        lastAccessInterface.select(null);
+		return result;
+	}
+}
Index: java/main/src/main/java/com/framsticks/parsers/Parser.java
===================================================================
--- java/main/src/main/java/com/framsticks/parsers/Parser.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/parsers/Parser.java	(revision 77)
@@ -0,0 +1,114 @@
+package com.framsticks.parsers;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.text.ParseException;
+import java.util.ArrayList;
+import java.util.List;
+
+import com.framsticks.params.PropertiesAccess;
+import org.apache.log4j.Logger;
+
+import com.framsticks.params.FramsClass;
+import com.framsticks.params.AccessInterface;
+
+/**
+ * The class Parser is used to parse genotype encoded in f0 representation.
+ */
+public class Parser {
+
+	private final static Logger logger = Logger.getLogger(Parser.class);
+
+	/** The schema proper for f0 representation. */
+	private Schema schema;
+
+	public Parser(Schema schema) {
+		if (schema == null)
+			throw new NullPointerException(
+					"Schema object passed to Parser object cannot be null!");
+		this.schema = schema;
+	}
+
+	/**
+	 * Parses the stream with genotype in f0 representation. The correctness of
+	 * genotype is checked. IO and syntax exceptions interrupts parsing and no
+	 * result is returned. Other exceptions, connected with schema validation
+	 * cause that certain object or it's parameter is ignored (appropriate
+	 * communicate informs user about it). Inappropriate values in numeric
+	 * fields (bigger than maximum or smaller than minimum values) are
+	 * communicated by warnings and set to minimum / maximum value.
+	 * 
+	 * @param is
+	 *            the is
+	 * @return the list
+	 * @throws IOException
+	 *             Signals that an I/O exception has occurred.
+	 * @throws ParseException
+	 *             the parse exception
+	 */
+	public List<AccessInterface> parse(InputStream is) throws IOException,
+			ParseException {
+		List<AccessInterface> result = new ArrayList<AccessInterface>();
+
+		InputStreamReader isr = null;
+		try {
+			isr = new InputStreamReader(is, "UTF-8");
+			BufferedReader br = new BufferedReader(isr);
+			int l = 0;
+			while (br.ready()) {
+				String line = br.readLine();
+				if (line == null)
+					line = "";
+				else
+					line = line.trim();
+				if (l == 0) {
+					if (!"//0".equals(line)) {
+						logger.warn("stream should begin with \"//0\" in first line");
+					} else {
+						l++;
+						continue;
+					}
+				}
+				if (line.equals("")) {
+					l++;
+					continue;
+				}
+				try {
+					int indexOfColon = line.indexOf(':');
+					if (indexOfColon < 0) {
+						indexOfColon = line.length();
+					}
+					String classId = line.substring(0, indexOfColon).trim();
+					FramsClass framsClass = schema.getMainClasses()
+							.get(classId);
+					if (framsClass == null)
+						throw new Exception("Unknown class getId: " + classId);
+					PropertiesAccess propertiesParam = new PropertiesAccess(framsClass);
+                    propertiesParam.select(propertiesParam.createAccessee());
+					List<Exception> exceptions = propertiesParam.load2(line);
+					for (Exception e : exceptions) {
+						logger.warn("In line "
+										+ Integer.valueOf(l + 1)
+										+ " the following error occured (however entry was added): "
+										+ e.getMessage());
+					}
+					result.add(propertiesParam);
+				} catch (Exception e) {
+					logger.warn("In line "
+									+ Integer.valueOf(l + 1)
+									+ " the following error occured (entry was not added): "
+									+ e.getMessage());
+				} finally {
+					l++;
+				}
+			}
+		} finally {
+			if (isr != null)
+				isr.close();
+		}
+
+		return result;
+	}
+}
Index: java/main/src/main/java/com/framsticks/parsers/Savers.java
===================================================================
--- java/main/src/main/java/com/framsticks/parsers/Savers.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/parsers/Savers.java	(revision 77)
@@ -0,0 +1,22 @@
+package com.framsticks.parsers;
+
+import com.framsticks.params.*;
+import com.framsticks.params.SinkInterface;
+
+/**
+ * @author Piotr Sniegowski
+ */
+public class Savers {
+    public static void saveFramsClass(SinkInterface sink, FramsClass framsClass) {
+
+        AccessInterface framsClassAccess = new ReflectionAccess(FramsClass.class, FramsClass.getFramsClass());
+        AccessInterface paramAccess = new ReflectionAccess(Param.class, Param.getFramsClass());
+        framsClassAccess.select(framsClass);
+        framsClassAccess.save(sink);
+        for (Param p : framsClass.getParamEntries()) {
+            paramAccess.select(p);
+            paramAccess.save(sink);
+        }
+    }
+
+}
Index: java/main/src/main/java/com/framsticks/parsers/Schema.java
===================================================================
--- java/main/src/main/java/com/framsticks/parsers/Schema.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/parsers/Schema.java	(revision 77)
@@ -0,0 +1,340 @@
+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 java.util.Map.Entry;
+
+import com.framsticks.params.FramsClass;
+import com.framsticks.params.Param;
+import com.framsticks.params.types.DecimalParam;
+import com.framsticks.params.types.StringParam;
+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 com.framsticks.params.Group;
+import com.framsticks.params.ParamBuilder;
+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)
+ */
+public class Schema {
+
+	private final static Logger logger = Logger.getLogger(Schema.class);
+
+	/** The main classes (such as part, joint, etc.) */
+	private Map<String, FramsClass> mainClasses = new HashMap<String, FramsClass>();
+
+	/** The neuro classes (classess representing different types of neurons). */
+	private Map<String, NeuroClass> neuroClasses = new HashMap<String, NeuroClass>();
+
+	// TODO: definition can be changed
+	/**
+	 * Instantiates a new schema with usage of f0def.xml file stored in
+	 * resources.
+	 * 
+	 * @throws Exception
+	 *             the exception if one occured while reading the stream
+	 */
+	public Schema() throws Exception {
+		this(Thread.currentThread().getContextClassLoader()
+				.getResourceAsStream("f0def.xml"));
+	}
+
+	/**
+	 * Instantiates a new schema.
+	 * 
+	 * @param xmlStream
+	 *            the xml stream with schema
+	 * @throws Exception
+	 *             the exception if one occured while reading the stream
+	 */
+	public Schema(InputStream xmlStream) throws Exception {
+
+		DocumentBuilderFactory factory;
+		DocumentBuilder db;
+
+		try {
+			factory = javax.xml.parsers.DocumentBuilderFactory.newInstance();
+			db = factory.newDocumentBuilder();
+
+			Document document = db.parse(xmlStream);
+			NodeList classes = document.getElementsByTagName("CLASS");
+
+			for (int i = 0; i < classes.getLength(); i++) {
+				Node classNode = classes.item(i);
+				FramsClass framsClass = processClass(classNode);
+				mainClasses.put(framsClass.getId(), 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 occured 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 e) {
+			logger.fatal("unexpected exception occured: ", e);
+			throw e;
+		} catch (ParserConfigurationException e) {
+			logger.fatal("unexpected exception occured: ", e);
+			throw e;
+		} catch (SAXException e) {
+			logger.fatal("unexpected exception occured: ", e);
+			throw 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) {
+		try {
+			return Integer.parseInt(getAttribute(attributes, name));
+		} catch (NullPointerException e) {
+			return 0;
+		} catch (NumberFormatException e) {
+			logger.fatal("attribute " + name
+					+ " should be numeric (it is not)");
+			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 FramsClass processClass(Node classNode) throws Exception {
+		String classId = null;
+		String className = "";
+		String classDescription = "";
+		try {
+			classId = classNode.getAttributes().getNamedItem("ID")
+					.getNodeValue();
+		} catch (NullPointerException e) {
+			throw new Exception("Class getId is not defined!");
+		}
+
+		className = getAttributeFromNode("NAME", classNode);
+		classDescription = getAttributeFromNode("DESCRIPTION", classNode);
+
+		FramsClass framsClass = new FramsClass(classId, className,
+				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 = attributes.getNamedItem("NAME") == null ? null
+						: attributes.getNamedItem("NAME").getNodeValue();
+				if (name == null)
+					logger.warn("Group getName in class \"" + classId + "\" ("
+							+ className + ") is undefined");
+				else
+					framsClass.appendGroup(new Group(name));
+
+			} else if ("PROP".equals(node.getNodeName())
+					|| "NEUROPROP".equals(node.getNodeName())) {
+
+				NamedNodeMap attributes = node.getAttributes();
+				Param param = processParameter(attributes, classId);
+				framsClass.append(param);
+			}
+
+		}
+
+		return framsClass;
+	}
+
+	/**
+	 * It analyses the single property within the clas
+	 * 
+	 * @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 Param processParameter(NamedNodeMap attributes, String classId)
+			throws Exception {
+
+		String id = getAttribute(attributes, "ID");
+		if (id == null)
+			throw new Exception("Property ID in class \"" + classId
+					+ "\" is undefined");
+		String type = getAttribute(attributes, "TYPE");
+		if (type == null)
+			throw new Exception("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);
+		}
+
+		Map<String, String> minMaxDef = new HashMap<String, String>();
+
+		for (String key : new String[] { "MIN", "MAX", "DEF" }) {
+			String value = getAttribute(attributes, key);
+			if (value != null && !value.trim().equals(""))
+				minMaxDef.put(key, value);
+		}
+
+		ParamBuilder builder = new ParamBuilder();
+		builder.setId(id).setName(name).setHelp(description).setGroup(group).setFlags(flags);
+
+		if ("d".equals(type)) {
+
+			Map<String, Integer> minMaxDefInt = new HashMap<String, Integer>();
+			for (Entry<String, String> entry : minMaxDef.entrySet()) {
+				try {
+					minMaxDefInt.put(entry.getKey(),
+							Integer.parseInt(entry.getValue()));
+				} catch (NumberFormatException e) {
+					logger.warn(entry.getKey() + " attribute in property \""
+							+ id + "\" getId in class \"" + classId
+							+ "\" should be an integer value");
+				}
+			}
+
+			builder.setType(DecimalParam.class);
+			builder.setMin(minMaxDefInt.get("MIN"));
+			builder.setMax(minMaxDefInt.get("MAX"));
+			builder.setDef(minMaxDefInt.get("DEF"));
+
+		} else if ("f".equals(type)) {
+
+			Map<String, Double> minMaxDefDouble = new HashMap<String, Double>();
+			for (Entry<String, String> entry : minMaxDef.entrySet()) {
+				try {
+					minMaxDefDouble.put(entry.getKey(),
+							Double.parseDouble(entry.getValue()));
+				} catch (NumberFormatException e) {
+					logger.warn(entry.getKey() + " attribute in property \""
+							+ id + "\" getId in class \"" + classId
+							+ "\" should be a double value");
+				}
+			}
+			builder.setType(DecimalParam.class);
+			builder.setMin(minMaxDefDouble.get("MIN"));
+			builder.setMax(minMaxDefDouble.get("MAX"));
+			builder.setDef(minMaxDefDouble.get("DEF"));
+
+
+		} else if ("s".equals(type)) {
+			builder.setType(StringParam.class);
+			builder.setDef(minMaxDef.get("DEF"));
+		} else {
+			builder.setType(type);
+		}
+		return builder.build();
+	}
+
+	public Map<String, FramsClass> getMainClasses() {
+		return Collections.unmodifiableMap(mainClasses);
+	}
+
+	public Map<String, NeuroClass> getNeuroClasses() {
+		return Collections.unmodifiableMap(neuroClasses);
+	}
+
+}
Index: java/main/src/main/java/com/framsticks/portals/Portal.java
===================================================================
--- java/main/src/main/java/com/framsticks/portals/Portal.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/portals/Portal.java	(revision 77)
@@ -0,0 +1,55 @@
+package com.framsticks.portals;
+
+import com.framsticks.core.Parameters;
+import com.framsticks.observers.Observer;
+import com.framsticks.params.FramsClass;
+import com.framsticks.util.PeriodicTask;
+import org.apache.log4j.Logger;
+
+
+/**
+ * @author Piotr Sniegowski
+ */
+public class Portal extends Observer {
+
+    private final static Logger LOGGER = Logger.getLogger(Portal.class.getName());
+
+    public Integer counter = 0;
+
+    public Portal(Parameters parameters) {
+        super(parameters);
+    }
+
+    @Override
+    public void run() {
+        super.run();
+        new PeriodicTask(this, 1000) {
+
+            @Override
+            public void run() {
+                ++counter;
+                LOGGER.debug("counter is now: " + counter);
+                again();
+            }
+        };
+    }
+
+    @Override
+    protected void configure() {
+        super.configure();
+    }
+
+
+    @Override
+    protected PortalEndpoint createEndpoint() {
+        return new PortalEndpoint();
+    }
+
+    public Double getCounterSquared() {
+        return (double)(counter * counter);
+    }
+
+    public static void constructFramsClass(FramsClass.Constructor constructor) {
+        constructor.method("getCounterSquared").field("counter");
+    }
+}
Index: java/main/src/main/java/com/framsticks/portals/PortalEndpoint.java
===================================================================
--- java/main/src/main/java/com/framsticks/portals/PortalEndpoint.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/portals/PortalEndpoint.java	(revision 77)
@@ -0,0 +1,68 @@
+package com.framsticks.portals;
+
+import com.framsticks.core.Path;
+import com.framsticks.observers.Endpoint;
+import com.framsticks.util.Dispatching;
+import com.framsticks.util.Future;
+import com.framsticks.util.Logging;
+import org.apache.log4j.Logger;
+
+/**
+ * @author Piotr Sniegowski
+ */
+public class PortalEndpoint extends Endpoint {
+
+	private final static Logger LOGGER = 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 Runnable() {
+            @Override
+            public void run() {
+                PortalEndpoint.this.instance.resolve(path, new Future<Path>() {
+                    @Override
+                    public void result(Path result, Exception e) {
+                        Logging.log(LOGGER, "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() {
+                LOGGER.debug("change at " + path);
+            }
+        });
+    }
+    */
+
+
+
+
+}
Index: java/main/src/main/java/com/framsticks/remote/NodeListener.java
===================================================================
--- java/main/src/main/java/com/framsticks/remote/NodeListener.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/remote/NodeListener.java	(revision 77)
@@ -0,0 +1,13 @@
+package com.framsticks.remote;
+
+import com.framsticks.core.ListChange;
+import com.framsticks.core.Path;
+
+/**
+ * @author Piotr Sniegowski
+ */
+public interface NodeListener {
+    void onUpgrade(Path path);
+    void onChange(Path path);
+    void onChildChange(Path path, ListChange.Action action);
+}
Index: java/main/src/main/java/com/framsticks/remote/RecursiveFetcher.java
===================================================================
--- java/main/src/main/java/com/framsticks/remote/RecursiveFetcher.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/remote/RecursiveFetcher.java	(revision 77)
@@ -0,0 +1,98 @@
+package com.framsticks.remote;
+
+import com.framsticks.core.Node;
+import com.framsticks.core.Path;
+import com.framsticks.params.AccessInterface;
+import com.framsticks.params.FramsClass;
+import com.framsticks.params.Param;
+import com.framsticks.params.types.CompositeParam;
+import com.framsticks.core.Instance;
+import com.framsticks.util.Future;
+import com.framsticks.util.StateFunctor;
+import com.framsticks.util.Stopwatch;
+import org.apache.log4j.Logger;
+
+/**
+ * @author Piotr Sniegowski
+ */
+public class RecursiveFetcher {
+
+    private final static Logger LOGGER = Logger.getLogger(RecursiveFetcher.class.getName());
+
+    protected final Instance instance;
+    protected final StateFunctor stateFunctor;
+    protected int dispatched;
+    protected final Stopwatch stopwatch = new Stopwatch();
+
+    public RecursiveFetcher(Instance instance, final Path path, StateFunctor stateFunctor) {
+        this.instance = instance;
+        this.stateFunctor = stateFunctor;
+        dispatched = 1;
+        process(path);
+    }
+
+    protected void finished() {
+        assert instance.isActive();
+        LOGGER.info("recursively fetched in " + stopwatch);
+        stateFunctor.call(null);
+    }
+
+    protected void process(final Path path) {
+        assert instance.isActive();
+        if (path == null || !path.isResolved()) {
+            LOGGER.warn("path " + path + " is not resolved - skipping");
+        } else {
+            AccessInterface access = instance.bindAccess(path);
+            FramsClass framsClass = access.getFramsClass();
+            assert framsClass != null;
+            for (Param p : access.getParams()) {
+                if (p instanceof CompositeParam) {
+                    CompositeParam childParam = (CompositeParam)p;
+                    Object child = access.get(childParam, Object.class);
+                    final Path childPath = path.appendNode(new Node(childParam, child));
+                    if (childPath.isResolved() && instance.getInfoFromCache(childPath) != null) {
+                        ++dispatched;
+                        instance.invokeLater(new Runnable() {
+                            @Override
+                            public void run() {
+                                fetch(childPath);
+                            }
+                        });
+                        continue;
+                    }
+                    ++dispatched;
+                    instance.resolve(childPath, new Future<Path>() {
+                        @Override
+                        public void result(Path result, Exception e) {
+                            assert instance.isActive();
+                            if (e != null) {
+                                LOGGER.error(e);
+                                return;
+                            }
+                            fetch(result);
+                        }
+                    });
+                }
+            }
+        }
+        --dispatched;
+        if (dispatched == 0) {
+            finished();
+        }
+    }
+
+    protected void fetch(final Path path) {
+        instance.fetchValues(path, new StateFunctor() {
+            @Override
+            public void call(Exception e) {
+                if (e != null) {
+                    LOGGER.error("failed to fetch values for " + path + ": " + e);
+                    process(null);
+                    return;
+                }
+                process(path);
+            }
+        });
+    }
+
+}
Index: java/main/src/main/java/com/framsticks/remote/RemoteInstance.java
===================================================================
--- java/main/src/main/java/com/framsticks/remote/RemoteInstance.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/remote/RemoteInstance.java	(revision 77)
@@ -0,0 +1,456 @@
+package com.framsticks.remote;
+
+import com.framsticks.communication.*;
+import com.framsticks.communication.queries.GetRequest;
+import com.framsticks.communication.queries.InfoRequest;
+import com.framsticks.communication.queries.SetRequest;
+import com.framsticks.communication.util.LoggingSubscriptionCallback;
+import com.framsticks.core.ListChange;
+import com.framsticks.core.Parameters;
+import com.framsticks.core.Path;
+import com.framsticks.params.*;
+import com.framsticks.params.types.CompositeParam;
+import com.framsticks.params.types.EventParam;
+import com.framsticks.parsers.MultiParamLoader;
+import com.framsticks.core.Instance;
+import com.framsticks.util.*;
+import org.apache.log4j.Logger;
+
+import java.util.*;
+
+/**
+ * @author Piotr Sniegowski
+ */
+public class RemoteInstance extends Instance {
+
+	private final static Logger LOGGER = Logger.getLogger(RemoteInstance.class.getName());
+
+    protected Path simulator;
+    protected final ClientConnection connection;
+
+    protected final Set<Pair<Path, Subscription>> subscriptions = new HashSet<Pair<Path, Subscription>>();
+
+    public Pair<Path, Subscription> getSubscription(Path path) {
+        for (Pair<Path, Subscription> s : subscriptions) {
+            if (s.first.matches(path)) {
+                return s;
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public void run() {
+        assert isActive();
+        super.run();
+        connection.connect(new StateFunctor() {
+			@Override
+			public void call(Exception e) {
+                if (e != null) {
+                    fireRun(e);
+                    return;
+                }
+				connection.negotiateProtocolVersion(new StateFunctor() {
+					@Override
+					public void call(Exception e) {
+						if (e != null) {
+							LOGGER.fatal("unsupported protocol version!\n minimal version is: "
+									+ "nmanager protocol is: "
+									+ connection.getProtocolVersion());
+							connection.close();
+                            fireRun(e);
+							return;
+						}
+
+                        invokeLater(new Runnable() {
+                            @Override
+                            public void run() {
+                                resolveAndFetch("/simulator", new Future<Path>() {
+                                    @Override
+                                    public void result(Path path, Exception e) {
+                                        if (e != null) {
+                                            LOGGER.fatal("failed to resolve simulator node");
+                                            fireRun(e);
+                                            return;
+                                        }
+                                        assert isActive();
+                                        simulator = path;
+                                        fireRun(null);
+                                        LOGGER.info("resolved simulator node");
+
+                                        EventParam param = getParam(simulator, "running_changed", EventParam.class);
+                                        assert param != null;
+                                        connection.subscribe(simulator.getTextual() + "/" + param.getId(), new LoggingSubscriptionCallback(LOGGER, "server running state change", new EventCallback() {
+                                            @Override
+                                            public void call(List<File> files) {
+                                                invokeLater(new Runnable() {
+                                                    @Override
+                                                    public void run() {
+                                                        updateSimulationRunning();
+                                                    }
+                                                });
+                                            }
+                                        }));
+                                        new PeriodicTask(RemoteInstance.this, 1000) {
+                                            @Override
+                                            public void run() {
+                                                updateSimulationRunning();
+                                                again();
+                                            }
+                                        };
+                                    }
+                                });
+                            }
+                        });
+					}
+				});
+			}
+		});
+	}
+
+	public RemoteInstance(Parameters parameters) {
+        super(parameters);
+        connection = new ClientConnection(config.getString("address"));
+    }
+
+	@Override
+	public String toString() {
+        assert Dispatching.isThreadSafe();
+		return getConnection().getAddress();
+	}
+
+	public void setRunning(final boolean running) {
+        assert isActive();
+        //simulator.call(simulator.getParam(running ? "start" : "stop", ProcedureParam.class), new LoggingStateCallback(LOGGER, (running ? "starting" : "stopping") + " server"));
+	}
+
+	protected final UnaryListenersSet<Boolean> simulationRunningListeners = new UnaryListenersSet<Boolean>();
+
+	protected void updateSimulationRunning() {
+        assert isActive();
+        /*
+        fetchValue(simulator, getParam(simulator, "running", Param.class), new StateFunctor() {
+            @Override
+            public void call(Exception e) {
+                if (e != null) {
+                    LOGGER.fatal("failed to query simulator running status: " + e);
+                    return;
+                }
+
+                invokeLater(new Runnable() {
+                    @Override
+                    public void run() {
+                        boolean value = bindAccess(simulator).get("running", Boolean.class);
+                        LOGGER.trace("server running: " + value);
+                        simulationRunningListeners.call(value);
+                    }
+                });
+
+            }
+        });
+        */
+	}
+
+	public void addRunningStateListener(UnaryFunctor<Boolean, Boolean> listener) {
+        assert isActive();
+        simulationRunningListeners.add(listener);
+	}
+
+	public void disconnect() {
+        assert isActive();
+        if (connection.isConnected()) {
+			connection.close();
+		}
+	}
+
+    public final ClientConnection getConnection() {
+        return connection;
+    }
+
+    @Override
+    public void fetchValue(final Path path, final Param param, final StateFunctor stateFunctor) {
+        assert isActive();
+        assert param != null;
+        assert path.isResolved();
+        connection.send(new GetRequest().setField(param.getId()).setPath(path.getTextual()), this, new ResponseCallback() {
+            @Override
+            public void process(Response response) {
+                assert isActive();
+                if (!response.getOk()) {
+                    stateFunctor.call(new Exception(response.getComment()));
+                    return;
+                }
+                try {
+                    processFetchedValues(path, response.getFiles());
+                    stateFunctor.call(null);
+                } catch (Exception ex) {
+                    stateFunctor.call(ex);
+                }
+            }
+        });
+    }
+
+    protected final Map<String, Set<Future<FramsClass>>> infoRequests = new HashMap<String, Set<Future<FramsClass>>>();
+
+    protected void finishInfoRequest(String id, FramsClass result, Exception e) {
+        assert isActive();
+        Set<Future<FramsClass>> futures = infoRequests.get(id);
+        infoRequests.remove(id);
+        for (Future<FramsClass> f : futures) {
+            f.result(result, e);
+        }
+    }
+
+    @Override
+    protected void fetchInfo(final Path path, final Future<FramsClass> future) {
+
+        final String name = path.getTop().getParam().getContainedTypeName();
+
+        if (infoRequests.containsKey(name)) {
+            infoRequests.get(name).add(future);
+            return;
+        }
+
+        LOGGER.debug("issuing info request for " + name);
+        Set<Future<FramsClass>> futures = new HashSet<Future<FramsClass>>();
+        futures.add(future);
+        infoRequests.put(name, futures);
+
+        //TODO: if the info is in the cache, then don't communicate
+        connection.send(new InfoRequest().setPath(path.getTextual()), this, new ResponseCallback() {
+            @Override
+            public void process(Response response) {
+                assert isActive();
+                if (!response.getOk()) {
+                    finishInfoRequest(name, null, new Exception(response.getComment()));
+                    return;
+                }
+
+                assert response.getFiles().size() == 1;
+                assert path.isTheSame(response.getFiles().get(0).getPath());
+                FramsClass framsClass = processFetchedInfo(response.getFiles().get(0));
+
+                if (framsClass == null) {
+                    LOGGER.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())) {
+                    String mismatch = "class name mismatch: param=" + thisParam.getContainedTypeName() + " differs from fetched=" + framsClass.getId();
+                    LOGGER.error(mismatch);
+                    finishInfoRequest(name, null, new Exception(mismatch));
+                    return;
+                }
+                finishInfoRequest(name, framsClass, null);
+            }
+        });
+    }
+
+    @Override
+    public void fetchValues(final Path path, final StateFunctor stateFunctor) {
+        assert isActive();
+        assert path.getTop().getObject() != null;
+
+        LOGGER.trace("fetching values for " + path);
+        connection.send(new GetRequest().setPath(path.getTextual()), this, new ResponseCallback() {
+            @Override
+            public void process(Response response) {
+                assert isActive();
+                if (!response.getOk()) {
+                    stateFunctor.call(new Exception(response.getComment()));
+                    return;
+                }
+                try {
+                    processFetchedValues(path, response.getFiles());
+                    stateFunctor.call(null);
+                } catch (Exception ex) {
+                    LOGGER.error("an exception occurred while loading: " + ex);
+                    ex.printStackTrace();
+                    stateFunctor.call(ex);
+                }
+            }
+        });
+    }
+
+    @Override
+    public void resolve(final Path path, final Future<Path> future) {
+        assert isActive();
+        if (path.getTop().getObject() != null) {
+            if (getInfoFromCache(path) != null) {
+                future.result(path, null);
+                return;
+            }
+            findInfo(path, new Future<FramsClass>() {
+                @Override
+                public void result(FramsClass result, Exception e) {
+                    if (e != null) {
+                        future.result(null, e);
+                        return;
+                    }
+                    future.result(path, null);
+                }
+            });
+            return;
+        }
+        findInfo(path, new Future<FramsClass>() {
+            @Override
+            public void result(FramsClass result, Exception e) {
+                assert isActive();
+                if (e != null) {
+                    future.result(null, e);
+                    return;
+                }
+                assert path.getTop().getParam().isMatchingContainedName(result.getId());
+                Path p = (path.getTop().getParam().getContainedTypeName() != null ? path : new Path(path.getInstance(), path.getTextual()));
+                future.result(create(p), null);
+            }
+        });
+    }
+
+    @Override
+    protected void tryRegisterOnChangeEvents(final Path path) {
+        assert isActive();
+        AccessInterface access = bindAccess(path);
+        if (!(access instanceof ListAccess)) {
+            return;
+        }
+
+
+        assert path.size() >= 2;
+        FramsClass underFramsClass = getInfoFromCache(path.getUnder().getParam().getContainedTypeName());
+
+        EventParam changedEvent = Casting.tryCast(EventParam.class, underFramsClass.getParamEntry(path.getTop().getParam().getId() + "_changed"));
+        if (changedEvent == null) {
+            return;
+        }
+
+        if (getSubscription(path) != null) {
+            return;
+        }
+
+        final Pair<Path, Subscription> temporary = new Pair<Path, Subscription>(path, null);
+        subscriptions.add(temporary);
+
+        connection.subscribe(path.getTextual() + "_changed", new SubscriptionCallback() {
+            @Override
+            public EventCallback subscribed(final Subscription subscription) {
+                if (subscription == null) {
+                    LOGGER.error("failed to subscribe for change event for " + path);
+                    return null;
+                }
+                LOGGER.debug("subscribed for change event for " + path);
+                subscription.setDispatcher(RemoteInstance.this);
+                RemoteInstance.this.invokeLater(new Runnable() {
+                    @Override
+                    public void run() {
+                        subscriptions.remove(temporary);
+                        subscriptions.add(new Pair<Path, Subscription>(path, subscription));
+                    }
+                });
+                return new EventCallback() {
+                    @Override
+                    public void call(List<File> files) {
+                        assert isActive();
+                        assert files.size() == 1;
+                        MultiParamLoader loader = new MultiParamLoader();
+                        loader.setNewSource(files.get(0).getContent());
+                        loader.addBreakCondition(MultiParamLoader.Status.AfterObject);
+                        ReflectionAccess access = new ReflectionAccess(ListChange.class, ListChange.getFramsClass());
+                        loader.addAccessInterface(access);
+                        MultiParamLoader.Status status;
+                        try {
+                            while ((status = loader.go()) != MultiParamLoader.Status.Finished) {
+                                if (status == MultiParamLoader.Status.AfterObject) {
+                                    AccessInterface accessInterface = loader.getLastAccessInterface();
+                                    reactToChange(path, (ListChange) accessInterface.getSelected());
+                                }
+                            }
+                        } catch (Exception e) {
+                            e.printStackTrace();
+                        }
+                    }
+                };
+            }
+        });
+    }
+
+
+    protected void reactToChange(final Path path, final ListChange listChange) {
+        assert isActive();
+        LOGGER.debug("reacting to change " + listChange + " in " + path);
+		AccessInterface access = bindAccess(path);
+		assert access != null;
+
+		if ((listChange.getAction() == ListChange.Action.Modify) && (listChange.getPosition() == -1)) {
+			final String p = path.getTextual();
+			resolveAndFetch(p, new Future<Path>() {
+				@Override
+				public void result(Path result, Exception e) {
+					if (e != null) {
+						LOGGER.error("failed to modify " + p + ": " + e);
+						return;
+					}
+					fireListChange(path, listChange);
+				}
+			});
+			return;
+		}
+
+
+        CompositeParam childParam = Casting.tryCast(CompositeParam.class, access.getParam(listChange.getBestIdentifier()));
+        assert childParam != null;
+        switch (listChange.getAction()) {
+            case Add: {
+                final String p = path.getTextual() + "/" + childParam.getId();
+                resolveAndFetch(p, new Future<Path>() {
+                    @Override
+                    public void result(Path result, Exception e) {
+                        if (e != null) {
+                            LOGGER.error("failed to add " + p + ": " + e);
+                            return;
+                        }
+                        LOGGER.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) {
+                            LOGGER.error("failed to modify " + p + ": " + e);
+                            return;
+                        }
+                        fireListChange(path, listChange);
+                    }
+                });
+                break;
+            }
+        }
+    }
+
+	@Override
+	public void storeValue(final Path path, final Param param, final Object value, final StateFunctor stateFunctor) {
+		assert isActive();
+
+		LOGGER.trace("storing value " + param + " for " + path);
+		connection.send(new SetRequest().value(value.toString()).setField(param.getId()).setPath(path.getTextual()), this, new StateCallback() {
+			@Override
+			public void call(Exception e) {
+				if (e == null) {
+					bindAccess(path).set(param, value);
+				}
+				stateFunctor.call(e);
+			}
+		});
+	}
+}
Index: java/main/src/main/java/com/framsticks/util/AtOnceDispatcher.java
===================================================================
--- java/main/src/main/java/com/framsticks/util/AtOnceDispatcher.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/util/AtOnceDispatcher.java	(revision 77)
@@ -0,0 +1,19 @@
+package com.framsticks.util;
+
+/**
+ * @author Piotr Sniegowski
+ */
+public class AtOnceDispatcher implements Dispatcher {
+
+    public static final AtOnceDispatcher instance = new AtOnceDispatcher();
+
+    @Override
+    public final boolean isActive() {
+        return true;
+    }
+
+    @Override
+    public final void invokeLater(Runnable runnable) {
+        runnable.run();
+    }
+}
Index: java/main/src/main/java/com/framsticks/util/Casting.java
===================================================================
--- java/main/src/main/java/com/framsticks/util/Casting.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/util/Casting.java	(revision 77)
@@ -0,0 +1,34 @@
+package com.framsticks.util;
+
+import com.framsticks.core.Entity;
+import com.framsticks.core.Instance;
+import org.apache.commons.configuration.HierarchicalConfiguration;
+
+/**
+ * @author Piotr Sniegowski
+ */
+public abstract class Casting {
+    public static <T> T tryCast(Class<T> class_, Object object) {
+        try {
+            return class_.cast(object);
+        } catch (ClassCastException ignored) {
+            return null;
+        }
+    }
+
+    public static <T> T assertCast(Class<T> class_, Object object) {
+        try {
+            return class_.cast(object);
+        } catch (ClassCastException ignored) {
+            assert false;
+            return null;
+        }
+    }
+
+    public static <T> T throwCast(Class<T> class_, Object object) {
+        if (object == null) {
+            throw new NullPointerException();
+        }
+        return class_.cast(object);
+    }
+}
Index: java/main/src/main/java/com/framsticks/util/Containers.java
===================================================================
--- java/main/src/main/java/com/framsticks/util/Containers.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/util/Containers.java	(revision 77)
@@ -0,0 +1,17 @@
+package com.framsticks.util;
+
+import java.util.List;
+
+/**
+ * @author Piotr Sniegowski
+ */
+public abstract class Containers {
+    public static void resizeList(List list, int size) {
+        while (list.size() < size) {
+            list.add(null);
+        }
+        while (list.size() > size) {
+            list.remove(list.size() - 1);
+        }
+    }
+}
Index: java/main/src/main/java/com/framsticks/util/Dispatcher.java
===================================================================
--- java/main/src/main/java/com/framsticks/util/Dispatcher.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/util/Dispatcher.java	(revision 77)
@@ -0,0 +1,9 @@
+package com.framsticks.util;
+
+/**
+ * @author Piotr Sniegowski
+ */
+public interface Dispatcher {
+    public boolean isActive();
+    public void invokeLater(Runnable runnable);
+}
Index: java/main/src/main/java/com/framsticks/util/Dispatching.java
===================================================================
--- java/main/src/main/java/com/framsticks/util/Dispatching.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/util/Dispatching.java	(revision 77)
@@ -0,0 +1,43 @@
+package com.framsticks.util;
+
+/**
+ * @author Piotr Sniegowski
+ */
+public abstract class Dispatching {
+
+    public static boolean isThreadSafe() {
+        return true;
+    }
+
+    public static void invokeLaterOrNow(Dispatcher dispatcher, Runnable runnable) {
+        if (dispatcher.isActive()) {
+            runnable.run();
+            return;
+        }
+        dispatcher.invokeLater(runnable);
+    }
+
+    public static void dispatchOk(Dispatcher dispatcher, final StateFunctor stateFunctor) {
+        dispatcher.invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                stateFunctor.call(null);
+            }
+        });
+    }
+
+    public static boolean assertInvokeLater(Dispatcher dispatcher, Runnable runnable) {
+        dispatcher.invokeLater(runnable);
+        return true;
+    }
+
+    public static void invokeDispatch(Dispatcher dispatcher, final Dispatcher finalDispatcher, final Runnable runnable) {
+        dispatcher.invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                finalDispatcher.invokeLater(runnable);
+            }
+        });
+    }
+
+}
Index: java/main/src/main/java/com/framsticks/util/Future.java
===================================================================
--- java/main/src/main/java/com/framsticks/util/Future.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/util/Future.java	(revision 77)
@@ -0,0 +1,8 @@
+package com.framsticks.util;
+
+/**
+ * @author Piotr Sniegowski
+ */
+public interface Future <T> {
+    void result(T result, Exception e);
+}
Index: java/main/src/main/java/com/framsticks/util/Iterators.java
===================================================================
--- java/main/src/main/java/com/framsticks/util/Iterators.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/util/Iterators.java	(revision 77)
@@ -0,0 +1,22 @@
+package com.framsticks.util;
+
+import java.util.Iterator;
+
+/**
+ * @author Piotr Sniegowski
+ */
+public class Iterators {
+	public static String resolve(Iterator iterator, String separator) {
+		StringBuilder b = new StringBuilder();
+		boolean following = false;
+		while (iterator.hasNext()) {
+			if (following) {
+				b.append(separator);
+			} else {
+				following = true;
+			}
+			b.append(iterator.next());
+		}
+		return b.toString();
+	}
+}
Index: java/main/src/main/java/com/framsticks/util/Layout.java
===================================================================
--- java/main/src/main/java/com/framsticks/util/Layout.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/util/Layout.java	(revision 77)
@@ -0,0 +1,23 @@
+package com.framsticks.util;
+
+
+import javax.swing.*;
+import java.awt.*;
+
+/**
+ * @author Piotr Sniegowski
+ */
+public class Layout {
+	public static void fixComponentSize(JComponent component, Dimension dimension) {
+		component.setPreferredSize(dimension);
+		component.setMaximumSize(dimension);
+		component.setMaximumSize(dimension);
+	}
+
+	public static void copyComponentDimensions(JComponent destination, JComponent source) {
+		destination.setPreferredSize(source.getPreferredSize());
+		destination.setMaximumSize(source.getMaximumSize());
+		destination.setMinimumSize(source.getMinimumSize());
+	}
+
+}
Index: java/main/src/main/java/com/framsticks/util/Logging.java
===================================================================
--- java/main/src/main/java/com/framsticks/util/Logging.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/util/Logging.java	(revision 77)
@@ -0,0 +1,19 @@
+package com.framsticks.util;
+
+import org.apache.log4j.Logger;
+
+/**
+ * @author Piotr Sniegowski
+ */
+public abstract class Logging {
+    public static boolean log(Logger logger, String action, Object subject, Exception e) {
+        if (e != null) {
+            logger.error("failed to " + action + " " + subject + ": " + e);
+            return true;
+        }
+        if (logger.isDebugEnabled()) {
+            logger.debug("done: " + action + " " + subject);
+        }
+        return false;
+    }
+}
Index: java/main/src/main/java/com/framsticks/util/Numbers.java
===================================================================
--- java/main/src/main/java/com/framsticks/util/Numbers.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/util/Numbers.java	(revision 77)
@@ -0,0 +1,44 @@
+package com.framsticks.util;
+
+import java.lang.reflect.InvocationTargetException;
+
+/**
+ * @author Piotr Sniegowski
+ */
+public abstract class Numbers {
+	public static <T extends Number> T parse(String value, Class<T> type) {
+		if (!Strings.notEmpty(value)) {
+			return null;
+		}
+		try {
+			return (T)type.getMethod("valueOf", String.class).invoke(null, value);
+		} catch (IllegalAccessException e) {
+			e.printStackTrace();
+		} catch (InvocationTargetException e) {
+            if (e.getTargetException() instanceof NumberFormatException) {
+                return null;
+            }
+			e.printStackTrace();
+		} catch (NoSuchMethodException e) {
+			e.printStackTrace();
+		} catch (NumberFormatException ignored) {
+			return null;
+		}
+		return null;
+	}
+
+
+	public static <T extends Number> T cast(Object value, Class<T> type) {
+		if (value == null) {
+			return null;
+		}
+		if (value instanceof String) {
+			return parse((String)value, type);
+		}
+		if (value.getClass() == type) {
+			return type.cast(value);
+		}
+		return null;
+	}
+
+}
Index: java/main/src/main/java/com/framsticks/util/Orientation.java
===================================================================
--- java/main/src/main/java/com/framsticks/util/Orientation.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/util/Orientation.java	(revision 77)
@@ -0,0 +1,18 @@
+package com.framsticks.util;
+
+/**
+ * @author Piotr Sniegowski
+ */
+public class Orientation {
+    public final Point3d x;
+    public final Point3d y;
+    public final Point3d z;
+
+    public Orientation() {
+        x = new Point3d();
+        y = new Point3d();
+        z = new Point3d();
+    }
+
+
+}
Index: java/main/src/main/java/com/framsticks/util/Pair.java
===================================================================
--- java/main/src/main/java/com/framsticks/util/Pair.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/util/Pair.java	(revision 77)
@@ -0,0 +1,20 @@
+package com.framsticks.util;
+
+/**
+ * @author Piotr Sniegowski
+ */
+public class Pair<T1, T2> {
+    public final T1 first;
+    public final T2 second;
+
+    public Pair(T1 first, T2 second) {
+        this.first = first;
+        this.second = second;
+    }
+
+    @Override
+    public String toString() {
+        return Strings.toStringNullProof(first) + " " + Strings.toStringNullProof(second);
+    }
+
+}
Index: java/main/src/main/java/com/framsticks/util/PeriodicTask.java
===================================================================
--- java/main/src/main/java/com/framsticks/util/PeriodicTask.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/util/PeriodicTask.java	(revision 77)
@@ -0,0 +1,27 @@
+package com.framsticks.util;
+
+/**
+ * @author Piotr Sniegowski
+ */
+public abstract class PeriodicTask implements Runnable {
+
+    protected final long period;
+    protected Dispatcher dispatcher;
+
+    public PeriodicTask(Dispatcher dispatcher, long period) {
+        this.period = period;
+        this.dispatcher = dispatcher;
+        dispatcher.invokeLater(this);
+    }
+
+
+    public void again() {
+        dispatcher.invokeLater(new Task(System.currentTimeMillis() + period) {
+            @Override
+            public void run() {
+                PeriodicTask.this.run();
+            }
+        });
+    }
+
+}
Index: java/main/src/main/java/com/framsticks/util/Point3d.java
===================================================================
--- java/main/src/main/java/com/framsticks/util/Point3d.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/util/Point3d.java	(revision 77)
@@ -0,0 +1,29 @@
+package com.framsticks.util;
+	
+/**
+ * The simple class which represent point in 3d space.
+ */
+public class Point3d
+{
+	public Double x;
+	public Double y;
+	public Double z;
+
+	public Point3d() {
+		x = 0.0;
+		y = 0.0;
+		z = 0.0;
+	}
+
+	public Point3d(Double x, Double y, Double z) {
+		this.x = x;
+		this.y = y;
+		this.z = z;
+	}
+
+	@Override
+	public String toString() {
+		//return new StringBuilder().append(x).append(" ").append(y).append(" ").append("z").toString();
+		return x + " " + y + " " + z;
+	}
+}
Index: java/main/src/main/java/com/framsticks/util/ProgramArguments.java
===================================================================
--- java/main/src/main/java/com/framsticks/util/ProgramArguments.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/util/ProgramArguments.java	(revision 77)
@@ -0,0 +1,65 @@
+package com.framsticks.util;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author Piotr Sniegowski
+ */
+public class ProgramArguments {
+
+	private final Map<String, List<String>> arguments = new HashMap<String, List<String>>();
+
+	public ProgramArguments(String[] args) {
+		int a = 0;
+		while (a < args.length) {
+			if (args[a].startsWith("--")) {
+				String argumentName = args[a].substring(2);
+
+				String argumentValue;
+				if (a + 1 < args.length && (!args[a + 1].startsWith("--"))) {
+					argumentValue = args[a + 1];
+					a += 2;
+				} else {
+					argumentValue = null;
+					a += 1;
+				}
+
+				List<String> argumentValues;
+				if (arguments.containsKey(argumentName)) {
+					argumentValues = arguments.get(argumentName);
+				} else {
+					argumentValues = new ArrayList<String>();
+					arguments.put(argumentName, argumentValues);
+				}
+				argumentValues.add(argumentValue);
+			}
+		}
+
+	}
+
+	public void forEach(String argument, UnaryFunctor<Boolean, String> functor) {
+		if (!arguments.containsKey(argument)) {
+			return;
+		}
+		for (String v : arguments.get(argument)) {
+			if (!functor.call(v)) {
+				break;
+			}
+		}
+	}
+
+	public String getSingle(String argument, String defValue) {
+		if (!arguments.containsKey(argument)) {
+			return defValue;
+		}
+		List<String> values = arguments.get(argument);
+		if (values.size() != 1) {
+			return defValue;
+		}
+		return values.get(0);
+	}
+
+}
Index: java/main/src/main/java/com/framsticks/util/StateFunctor.java
===================================================================
--- java/main/src/main/java/com/framsticks/util/StateFunctor.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/util/StateFunctor.java	(revision 77)
@@ -0,0 +1,8 @@
+package com.framsticks.util;
+
+/**
+ * @author Piotr Sniegowski
+ */
+public interface StateFunctor {
+	public void call(Exception e);
+}
Index: java/main/src/main/java/com/framsticks/util/Stopwatch.java
===================================================================
--- java/main/src/main/java/com/framsticks/util/Stopwatch.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/util/Stopwatch.java	(revision 77)
@@ -0,0 +1,17 @@
+package com.framsticks.util;
+
+/**
+ * @author Piotr Sniegowski
+ */
+public class Stopwatch {
+    final long start = System.currentTimeMillis();
+
+    public final long elapsed() {
+        return System.currentTimeMillis() - start;
+    }
+
+    @Override
+    public final String toString() {
+        return elapsed() + "ms";
+    }
+}
Index: java/main/src/main/java/com/framsticks/util/Strings.java
===================================================================
--- java/main/src/main/java/com/framsticks/util/Strings.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/util/Strings.java	(revision 77)
@@ -0,0 +1,41 @@
+package com.framsticks.util;
+
+/**
+ * @author Piotr Sniegowski
+ */
+public abstract class Strings {
+	public static String valueOf(Object o) {
+		if (o == null) {
+			return null;
+		}
+		return o.toString();
+	}
+
+	public static boolean notEmpty(String str) {
+		return str != null && !str.equals("");
+	}
+
+	public static String toStringNullProof(Object object) {
+		if (object == null) {
+			return "";
+		}
+		return object.toString();
+	}
+
+	public static String collapse(String s) {
+		if (s == null) {
+			return null;
+		}
+		s = s.trim();
+		return (s.equals("")) ? null : s;
+	}
+
+    public static Pair<String, String> splitIntoPair(String string, char separator, String second) {
+        int pos = string.indexOf(separator);
+        if (pos == -1) {
+            return new Pair<String, String>(string.substring(0, string.length() - 1), second);
+        } else {
+            return new Pair<String, String>(string.substring(0, pos), string.substring(pos + 1));
+        }
+    }
+}
Index: java/main/src/main/java/com/framsticks/util/Task.java
===================================================================
--- java/main/src/main/java/com/framsticks/util/Task.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/util/Task.java	(revision 77)
@@ -0,0 +1,22 @@
+package com.framsticks.util;
+
+/**
+ * @author Piotr Sniegowski
+ */
+public abstract class Task implements Runnable {
+
+    protected final long moment;
+
+    public Task() {
+        moment = System.currentTimeMillis();
+    }
+
+    public Task(long moment) {
+        this.moment = moment;
+    }
+
+    public final long getMoment() {
+        return moment;
+    }
+
+}
Index: java/main/src/main/java/com/framsticks/util/Thread.java
===================================================================
--- java/main/src/main/java/com/framsticks/util/Thread.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/util/Thread.java	(revision 77)
@@ -0,0 +1,137 @@
+package com.framsticks.util;
+
+import org.apache.log4j.Logger;
+
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.ListIterator;
+import java.util.Queue;
+
+/**
+ * @author Piotr Sniegowski
+ */
+public class Thread implements Dispatcher {
+
+    private static final Logger LOGGER = Logger.getLogger(Thread.class.getName());
+
+    protected final java.lang.Thread thread;
+
+    private final LinkedList<Task> queue = new LinkedList<Task>();
+
+    public Thread() {
+        thread = new java.lang.Thread(new Runnable() {
+            @Override
+            public void run() {
+                Thread.this.routine();
+            }
+        });
+    }
+    public Thread(String s) {
+        this();
+        thread.setName(s);
+        thread.start();
+    }
+
+    public Thread(String s, java.lang.Thread thread) {
+        this.thread = thread;
+        thread.setName(s);
+    }
+
+    @Override
+    public final boolean isActive() {
+        return thread.equals(java.lang.Thread.currentThread());
+    }
+
+    protected void routine() {
+        while (!java.lang.Thread.interrupted()) {
+            Task task;
+            synchronized (queue) {
+                if (queue.isEmpty()) {
+                    try {
+                        queue.wait();
+                    } catch (InterruptedException ignored) {
+                        break;
+                    }
+                    continue;
+                }
+                task = queue.peekFirst();
+                assert task != null;
+                if (task.moment > System.currentTimeMillis()) {
+                    try {
+                        queue.wait(task.moment - System.currentTimeMillis());
+                    } catch (InterruptedException ignored) {
+                        continue;
+                    }
+                    continue;
+                }
+                queue.pollFirst();
+            }
+            try {
+                task.run();
+            } catch (Exception e) {
+                LOGGER.error("error in thread: " + e);
+                e.printStackTrace();
+            }
+        }
+    }
+
+    protected void enqueueTask(Task task) {
+        synchronized (queue) {
+            ListIterator<Task> i = queue.listIterator();
+            while (i.hasNext()) {
+                Task t = i.next();
+                if (t.getMoment() > task.getMoment()) {
+                    i.previous();
+                    i.add(task);
+                    task = null;
+                    break;
+                }
+            }
+            if (task != null) {
+                queue.add(task);
+            }
+
+            /*
+            Iterator<Task> j = queue.iterator();
+            Task prev = null;
+            while (j.hasNext()) {
+                Task next = j.next();
+                assert (prev == null) || prev.getMoment() <= next.getMoment();
+                prev = next;
+            }
+            */
+            queue.notify();
+        }
+    }
+
+    @Override
+    public void invokeLater(final Runnable runnable) {
+        if (!(runnable instanceof Task)) {
+            enqueueTask(new Task() {
+                @Override
+                public void run() {
+                    runnable.run();
+                }
+            });
+            return;
+        }
+        enqueueTask((Task)runnable);
+    }
+
+    public void interrupt() {
+        thread.interrupt();
+    }
+
+    public void join() throws InterruptedException {
+        thread.join();
+    }
+
+    public void start() {
+        thread.start();
+    }
+
+    public void setName(String name) {
+        thread.setName(name);
+
+    }
+}
Index: java/main/src/main/java/com/framsticks/util/UnaryFunctor.java
===================================================================
--- java/main/src/main/java/com/framsticks/util/UnaryFunctor.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/util/UnaryFunctor.java	(revision 77)
@@ -0,0 +1,8 @@
+package com.framsticks.util;
+
+/**
+ * @author Piotr Sniegowski
+ */
+public interface UnaryFunctor <Ret, Arg> {
+		Ret call(Arg arg);
+}
Index: java/main/src/main/java/com/framsticks/util/UnaryListenersSet.java
===================================================================
--- java/main/src/main/java/com/framsticks/util/UnaryListenersSet.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/util/UnaryListenersSet.java	(revision 77)
@@ -0,0 +1,27 @@
+package com.framsticks.util;
+
+
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+/**
+ * @author Piotr Sniegowski
+ */
+public class UnaryListenersSet<T> {
+	Set<UnaryFunctor<Boolean, T>> listeners = new HashSet<UnaryFunctor<Boolean, T>>();
+
+	public void add(UnaryFunctor<Boolean, T> listener) {
+		listeners.add(listener);
+	}
+
+	public void call(T argument) {
+		Iterator<UnaryFunctor<Boolean, T>> iterator = listeners.iterator();
+		while (iterator.hasNext()) {
+			if (iterator.next().call(argument)) {
+				iterator.remove();
+			}
+		}
+	}
+
+}
Index: java/main/src/main/java/com/framsticks/util/UnsupportedOperationException.java
===================================================================
--- java/main/src/main/java/com/framsticks/util/UnsupportedOperationException.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/util/UnsupportedOperationException.java	(revision 77)
@@ -0,0 +1,8 @@
+package com.framsticks.util;
+
+/**
+ * @author Piotr Sniegowski
+ */
+public class UnsupportedOperationException extends Exception {
+
+}
Index: java/main/src/main/java/com/framsticks/visualization/Viewer.java
===================================================================
--- java/main/src/main/java/com/framsticks/visualization/Viewer.java	(revision 77)
+++ java/main/src/main/java/com/framsticks/visualization/Viewer.java	(revision 77)
@@ -0,0 +1,282 @@
+package com.framsticks.visualization;
+
+import com.framsticks.communication.Connection;
+import com.framsticks.model.World;
+import com.sun.j3d.loaders.IncorrectFormatException;
+import com.sun.j3d.loaders.ParsingErrorException;
+import com.sun.j3d.loaders.Scene;
+import com.sun.j3d.loaders.objectfile.ObjectFile;
+import com.sun.j3d.utils.behaviors.mouse.MouseRotate;
+import com.sun.j3d.utils.universe.PlatformGeometry;
+import com.sun.j3d.utils.universe.SimpleUniverse;
+import com.sun.j3d.utils.universe.ViewingPlatform;
+
+import javax.media.j3d.*;
+import javax.swing.*;
+import javax.swing.text.StyledDocument;
+import javax.vecmath.Color3f;
+import javax.vecmath.Point3d;
+import javax.vecmath.Vector3f;
+import java.awt.*;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.io.FileNotFoundException;
+import java.util.ArrayList;
+
+import org.apache.log4j.Logger;
+
+
+
+public class Viewer {
+    static final long serialVersionUID = 1;
+
+    private static Logger logger = Logger.getLogger(Viewer.class);
+
+    Canvas3D canvas3d;
+    SimpleUniverse universe;
+
+    World world;
+    private JMenuBar menuBar;
+
+	private JScrollPane scrollPane;
+    private boolean scrollLock = false;
+
+	private JCheckBoxMenuItem loggingItem;
+    private JCheckBoxMenuItem autorefreshItem;
+
+	private Connection connection;
+    ArrayList<String> args;
+
+    public Viewer(ArrayList<String> args, JMenuBar menuBar) {
+        super();
+        this.args = args;
+        this.menuBar = menuBar;
+        loggingItem = new JCheckBoxMenuItem("Logging");
+        loggingItem.setSelected(true);
+
+        init();
+
+    }
+
+	public BranchGroup createSceneGraph() {
+        // Create the root of the branch graph
+        BranchGroup objRoot = new BranchGroup();
+
+        // Create a Transform group to scale all objects so they
+        // appear in the scene.
+        TransformGroup objScale = new TransformGroup();
+        Transform3D t3d = new Transform3D();
+        t3d.setScale(0.7);
+        objScale.setTransform(t3d);
+        objRoot.addChild(objScale);
+
+        TransformGroup objTrans = new TransformGroup();
+        objTrans.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
+        objTrans.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
+        objScale.addChild(objTrans);
+
+        String filename = "/static/shared/res/obj/cylinder.obj";
+        int flags = ObjectFile.RESIZE;
+        flags |= ObjectFile.TRIANGULATE;
+        flags |= ObjectFile.STRIPIFY;
+		double creaseAngle = 60.0;
+		ObjectFile f = new ObjectFile(flags,
+                (float) (creaseAngle * Math.PI / 180.0));
+        Scene s = null;
+        try {
+            s = f.load(this.getClass().getResource(filename).getFile());
+        } catch (FileNotFoundException e) {
+            System.err.println(e);
+            System.exit(1);
+        } catch (ParsingErrorException e) {
+            System.err.println(e);
+            System.exit(1);
+        } catch (IncorrectFormatException e) {
+            System.err.println(e);
+            System.exit(1);
+        }
+
+        objTrans.addChild(s.getSceneGroup());
+
+        BoundingSphere bounds = new BoundingSphere(new Point3d(0.0, 0.0, 0.0),
+                100.0);
+
+        Color3f bgColor = new Color3f(0.05f, 0.05f, 0.5f);
+        Background bgNode = new Background(bgColor);
+        bgNode.setApplicationBounds(bounds);
+        objRoot.addChild(bgNode);
+
+        return objRoot;
+    }
+
+    private void init() {
+
+	    JTextPane textPane = new JTextPane();
+        textPane.setEditable(false);
+
+	    StyledDocument styledDocument = textPane.getStyledDocument();
+
+        scrollPane = new JScrollPane(textPane);
+        //scrollPane.
+        //scrollPane
+        //		.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
+
+        // paneScrollPane.setMinimumSize(new Dimension(400, 300));
+
+        createMenuBar();
+
+        GraphicsConfiguration config = SimpleUniverse
+                .getPreferredConfiguration();
+
+        // Create a Canvas3D using the preferred configuration
+        canvas3d = new Canvas3D(config);
+
+        // Create simple universe with view branch
+        universe = new SimpleUniverse(canvas3d);
+        BoundingSphere bounds = new BoundingSphere(new Point3d(0.0, 0.0, 0.0),
+                100.0);
+
+        // add mouse behaviours to the ViewingPlatform
+        ViewingPlatform viewingPlatform = universe.getViewingPlatform();
+
+        PlatformGeometry platformGeometry = new PlatformGeometry();
+
+        // Set up the ambient light
+        Color3f ambientColor = new Color3f(0.1f, 0.1f, 0.1f);
+        AmbientLight ambientLightNode = new AmbientLight(ambientColor);
+        ambientLightNode.setInfluencingBounds(bounds);
+        platformGeometry.addChild(ambientLightNode);
+
+        // Set up the directional lights
+        Color3f light1Color = new Color3f(1.0f, 1.0f, 0.9f);
+        Vector3f light1Direction = new Vector3f(1.0f, 1.0f, 1.0f);
+        Color3f light2Color = new Color3f(1.0f, 1.0f, 1.0f);
+        Vector3f light2Direction = new Vector3f(-1.0f, -1.0f, -1.0f);
+
+        DirectionalLight light1 = new DirectionalLight(light1Color,
+                light1Direction);
+        light1.setInfluencingBounds(bounds);
+        platformGeometry.addChild(light1);
+
+        DirectionalLight light2 = new DirectionalLight(light2Color,
+                light2Direction);
+        light2.setInfluencingBounds(bounds);
+        platformGeometry.addChild(light2);
+
+        viewingPlatform.setPlatformGeometry(platformGeometry);
+
+        viewingPlatform.setNominalViewingTransform();
+
+        // Ensure at least 5 msec per frame (i.e., < 200Hz)
+        universe.getViewer().getView().setMinimumFrameCycleTime(5);
+
+        BranchGroup scene = new BranchGroup();
+        BranchGroup content = createSceneGraph();
+
+        // canvas3d.addMouseListener(behaviour);
+        TransformGroup transformGroup = new TransformGroup(new Transform3D());
+        transformGroup.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
+        transformGroup.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
+        MouseRotate behaviour = new MouseRotate();
+        behaviour.setTransformGroup(transformGroup);
+        transformGroup.addChild(behaviour);
+        // behaviour.addListener(canvas3d);
+        // behaviour.initialize();
+        behaviour.setSchedulingBounds(new BoundingSphere(new Point3d(0.0, 0.0,
+                0.0), 100.0));
+        transformGroup.addChild(content);
+        // transformGroup.addChild(behaviour);
+        scene.addChild(transformGroup);
+
+        universe.addBranchGraph(scene);
+
+
+    }
+
+    private void createMenuBar() {
+
+        JMenu serverItem = new JMenu("Manager");
+        menuBar.add(serverItem);
+
+        JMenuItem testModeItem = new JMenuItem("Test mode");
+        serverItem.add(testModeItem);
+
+	    JMenuItem connectItem = new JMenuItem("Connect");
+        serverItem.add(connectItem);
+
+        JMenu simulationItem = new JMenu("Simulation");
+        menuBar.add(simulationItem);
+
+	    //TODO: move init to main window
+        JMenuItem initItem = new JMenuItem("Init");
+        simulationItem.add(initItem);
+        initItem.addActionListener(new ActionListener() {
+            public void actionPerformed(ActionEvent event) {
+            }
+        });
+
+        JMenuItem refreshCreaturesItem = new JMenuItem("Refresh creatures");
+        simulationItem.add(refreshCreaturesItem);
+        refreshCreaturesItem.addActionListener(new ActionListener() {
+            public void actionPerformed(ActionEvent event) {
+
+            }
+        });
+
+        JMenuItem refreshWorldItem = new JMenuItem("Refresh world");
+        simulationItem.add(refreshWorldItem);
+        refreshWorldItem.addActionListener(new ActionListener() {
+            public void actionPerformed(ActionEvent event) {
+                refreshWorld();
+            }
+        });
+
+	    JMenu styleMenu = new JMenu("Style");
+        menuBar.add(styleMenu);
+
+	    JMenu viewMenu = new JMenu("View");
+        menuBar.add(viewMenu);
+        rebuildViewMenu(null);
+
+        JMenu optionsMenu = new JMenu("Options");
+        menuBar.add(optionsMenu);
+
+        autorefreshItem = new JCheckBoxMenuItem("Autorefresh");
+        autorefreshItem.addActionListener(new ActionListener() {
+            public void actionPerformed(ActionEvent e) {
+                if (autorefreshItem.isSelected()) {
+
+                }
+            }
+        });
+        optionsMenu.add(autorefreshItem);
+
+        optionsMenu.add(loggingItem);
+
+    }
+
+    public void refreshWorld() {
+
+
+    }
+
+
+
+
+    public void setCommunication(Connection connection) {
+        this.connection = connection;
+    }
+
+    public void rebuildViewMenu(Object creatures) {
+
+    }
+
+    public Component getViewComponent() {
+        return canvas3d;
+    }
+
+    public Component getControlComponent() {
+        return scrollPane;
+    }
+
+}
Index: java/main/src/main/resources/configs/framsticks.properties
===================================================================
--- java/main/src/main/resources/configs/framsticks.properties	(revision 77)
+++ java/main/src/main/resources/configs/framsticks.properties	(revision 77)
@@ -0,0 +1,32 @@
+com.framsticks.entities.browser.class=com.framsticks.gui.Browser
+#com.framsticks.entities.browser.endpoints=localhost,dump,remote_portal
+com.framsticks.entities.browser.size.width=1500
+com.framsticks.entities.browser.size.height=800
+com.framsticks.entities.browser.endpoints=localhost,dump
+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.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.entity=browser
Index: java/main/src/main/resources/configs/log4j.properties
===================================================================
--- java/main/src/main/resources/configs/log4j.properties	(revision 77)
+++ java/main/src/main/resources/configs/log4j.properties	(revision 77)
@@ -0,0 +1,47 @@
+# -------------------------------------------------------------------
+# Global logger configuration
+# -------------------------------------------------------------------
+#log4j.rootLogger=INFO, STDOUT, FILE
+log4j.rootLogger=DEBUG, STDOUT, FILE
+
+
+# -------------------------------------------------------------------
+# Disable certain libraries from spamming the output
+# -------------------------------------------------------------------
+
+# Apache commons
+log4j.logger.org.apache.commons=WARN
+
+# HttpClient
+log4j.logger.httpclient=WARN
+
+
+# -------------------------------------------------------------------
+# Define appenders.
+# -------------------------------------------------------------------
+
+# A plain console appender
+log4j.appender.STDOUT=org.apache.log4j.ConsoleAppender
+log4j.appender.STDOUT.Target=System.out
+log4j.appender.STDOUT.layout=org.apache.log4j.PatternLayout
+log4j.appender.STDOUT.layout.ConversionPattern=%d{ABSOLUTE} [%-5p] [%t] %c -- %m%n
+
+# File appender
+log4j.appender.FILE=org.apache.log4j.FileAppender
+log4j.appender.FILE.File=${user.home}/frams_network_client.log
+log4j.appender.FILE.layout=org.apache.log4j.PatternLayout
+log4j.appender.FILE.layout.ConversionPattern=%d{ABSOLUTE} [%-5p] [%t] %c -- %m%n
+
+log4j.logger.com.framsticks=INFO
+#log4j.logger.com.framsticks.remote.RemoteInstance=DEBUG
+#log4j.logger.com.framsticks.gui.TreeNode=DEBUG
+#log4j.logger.com.framsticks.gui.components.CheckBox=DEBUG
+
+#log4j.logger.com.framsticks.core=DEBUG
+#log4j.logger.com.framsticks.gui.TreeNode=TRACE
+#log4j.logger.com.framsticks.gui.ObjectPanel=TRACE
+#log4j.logger.com.framsticks.communication=DEBUG
+#log4j.logger.com.framsticks.communication.ServerConnection=DEBUG
+#log4j.logger.com.framsticks.portals=DEBUG
+#log4j.logger.com.framsticks.gui=DEBUG
+#log4j.logger.com.framsticks.dumping.LoadStream=TRACE
