Initial contribution to Eclipse.org
diff --git a/.project b/.project
new file mode 100644
index 0000000..e0efa3a
--- /dev/null
+++ b/.project
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>org.eclipse.statet-rj</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+	</buildSpec>
+	<natures>
+	</natures>
+</projectDescription>
diff --git a/.settings/org.eclipse.core.resources.prefs b/.settings/org.eclipse.core.resources.prefs
new file mode 100644
index 0000000..c99f846
--- /dev/null
+++ b/.settings/org.eclipse.core.resources.prefs
@@ -0,0 +1,4 @@
+eclipse.preferences.version=1
+encoding//core/_build/org.eclipse.statet.rj.core/about.ini=ISO-8859-1
+encoding//eclient/org.eclipse.statet.rj.eclient.core/about.ini=ISO-8859-1
+encoding/<project>=UTF-8
diff --git a/.settings/org.eclipse.core.runtime.prefs b/.settings/org.eclipse.core.runtime.prefs
new file mode 100644
index 0000000..5a0ad22
--- /dev/null
+++ b/.settings/org.eclipse.core.runtime.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+line.separator=\n
diff --git a/core/_build/org.eclipse.statet.rj.core-feature/.project b/core/_build/org.eclipse.statet.rj.core-feature/.project
new file mode 100644
index 0000000..39a2158
--- /dev/null
+++ b/core/_build/org.eclipse.statet.rj.core-feature/.project
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>org.eclipse.statet.rj.core-feature</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.pde.FeatureBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.pde.FeatureNature</nature>
+	</natures>
+</projectDescription>
diff --git a/core/_build/org.eclipse.statet.rj.core-feature/build.properties b/core/_build/org.eclipse.statet.rj.core-feature/build.properties
new file mode 100644
index 0000000..4fc35c8
--- /dev/null
+++ b/core/_build/org.eclipse.statet.rj.core-feature/build.properties
@@ -0,0 +1,2 @@
+bin.includes= feature.xml,\
+              feature.properties
diff --git a/core/_build/org.eclipse.statet.rj.core-feature/feature.properties b/core/_build/org.eclipse.statet.rj.core-feature/feature.properties
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/core/_build/org.eclipse.statet.rj.core-feature/feature.properties
diff --git a/core/_build/org.eclipse.statet.rj.core-feature/feature.xml b/core/_build/org.eclipse.statet.rj.core-feature/feature.xml
new file mode 100644
index 0000000..3df684c
--- /dev/null
+++ b/core/_build/org.eclipse.statet.rj.core-feature/feature.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<feature
+      id="org.eclipse.statet.rj.core"
+      version="2.1.0.qualifier"
+      label="StatET RJ - Java Core"
+      provider-name="Eclipse.org"
+      license-feature="org.eclipse.license"
+      license-feature-version="1.0.1">
+
+   <description url="https://www.eclipse.org/statet">
+      Core of high-level Java-R library RJ
+   </description>
+
+   <copyright>
+      Copyright (c) 2003, 2017 Stephan Wahlbrink and others. All rights reserved.
+   </copyright>
+
+   <license url="%license_url">
+      %license_text
+   </license>
+
+   <plugin
+         id="org.eclipse.statet.rj.core"
+         download-size="0"
+         install-size="0"
+         version="0.0.0"
+         unpack="false"/>
+
+   <plugin
+         id="org.eclipse.statet.rj.data"
+         download-size="0"
+         install-size="0"
+         version="0.0.0"
+         unpack="false"/>
+
+   <plugin
+         id="org.eclipse.statet.rj.server"
+         download-size="0"
+         install-size="0"
+         version="0.0.0"
+         unpack="false"/>
+
+</feature>
diff --git a/core/_build/org.eclipse.statet.rj.core/.gitignore b/core/_build/org.eclipse.statet.rj.core/.gitignore
new file mode 100644
index 0000000..5e56e04
--- /dev/null
+++ b/core/_build/org.eclipse.statet.rj.core/.gitignore
@@ -0,0 +1 @@
+/bin
diff --git a/core/_build/org.eclipse.statet.rj.core/.project b/core/_build/org.eclipse.statet.rj.core/.project
new file mode 100644
index 0000000..89ad76e
--- /dev/null
+++ b/core/_build/org.eclipse.statet.rj.core/.project
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>org.eclipse.statet.rj.core</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.jdt.core.javabuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.pde.ManifestBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.pde.SchemaBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.jdt.core.javanature</nature>
+		<nature>org.eclipse.pde.PluginNature</nature>
+	</natures>
+</projectDescription>
diff --git a/core/_build/org.eclipse.statet.rj.core/META-INF/MANIFEST.MF b/core/_build/org.eclipse.statet.rj.core/META-INF/MANIFEST.MF
new file mode 100644
index 0000000..cf22859
--- /dev/null
+++ b/core/_build/org.eclipse.statet.rj.core/META-INF/MANIFEST.MF
@@ -0,0 +1,6 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-SymbolicName: org.eclipse.statet.rj.core;singleton:=true
+Bundle-Version: 2.1.0.qualifier
+Bundle-Vendor: Eclipse.org
+Bundle-Name: StatET RJ - Java Core
diff --git a/core/_build/org.eclipse.statet.rj.core/about.html b/core/_build/org.eclipse.statet.rj.core/about.html
new file mode 100644
index 0000000..e71ae66
--- /dev/null
+++ b/core/_build/org.eclipse.statet.rj.core/about.html
@@ -0,0 +1,37 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+		"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+<title>About</title>
+</head>
+<body lang="EN-US">
+<h2>About This Content</h2>
+
+<p>December 1, 2017</p>
+<h3>License</h3>
+
+<p>
+	The Eclipse Foundation makes available all content in this plug-in
+	(&quot;Content&quot;). Unless otherwise indicated below, the Content
+	is provided to you under the terms and conditions of the Eclipse
+	Public License Version 2.0 (&quot;EPL&quot;), or the Apache License,
+	Version 2.0 (AL). A copy of the EPL is available at <a href="https://www.eclipse.org/legal/epl-2.0">https://www.eclipse.org/legal/epl-2.0</a>.
+	For purposes of the EPL, &quot;Program&quot; will mean the Content.
+	A copy of the AL is available at <a href="https://www.apache.org/licenses/LICENSE-2.0">https://www.apache.org/licenses/LICENSE-2.0</a>.
+</p>
+
+<p>
+	If you did not receive this Content directly from the Eclipse
+	Foundation, the Content is being redistributed by another party
+	(&quot;Redistributor&quot;) and different terms and conditions may
+	apply to your use of any object code in the Content. Check the
+	Redistributor's license that was provided with the Content. If no such
+	license exists, contact the Redistributor. Unless otherwise indicated
+	below, the terms and conditions of the EPL or AL still apply to any
+	source code in the Content and such source code may be obtained at <a
+	href="https://www.eclipse.org/">https://www.eclipse.org</a>.
+</p>
+
+</body>
+</html>
diff --git a/core/_build/org.eclipse.statet.rj.core/about.ini b/core/_build/org.eclipse.statet.rj.core/about.ini
new file mode 100644
index 0000000..a14498e
--- /dev/null
+++ b/core/_build/org.eclipse.statet.rj.core/about.ini
@@ -0,0 +1,7 @@
+featureImage= rj32.png
+aboutText= \
+StatET RJ - Java Core\n\
+\n\
+Copyright (c) 2003, 2017 Stephan Wahlbrink and others. All rights reserved.\n\
+Visit https://www.eclipse.org/statet\n\
+\n\
diff --git a/core/_build/org.eclipse.statet.rj.core/build.properties b/core/_build/org.eclipse.statet.rj.core/build.properties
new file mode 100644
index 0000000..7d15c10
--- /dev/null
+++ b/core/_build/org.eclipse.statet.rj.core/build.properties
@@ -0,0 +1,4 @@
+bin.includes= META-INF/,\
+              about.html,\
+              about.ini,\
+              rj32.png
diff --git a/core/_build/org.eclipse.statet.rj.core/rj32.png b/core/_build/org.eclipse.statet.rj.core/rj32.png
new file mode 100644
index 0000000..d9450d1
--- /dev/null
+++ b/core/_build/org.eclipse.statet.rj.core/rj32.png
Binary files differ
diff --git a/core/_build/org.eclipse.statet.rj.server-consoleserver/pom.xml b/core/_build/org.eclipse.statet.rj.server-consoleserver/pom.xml
new file mode 100644
index 0000000..0bfc76c
--- /dev/null
+++ b/core/_build/org.eclipse.statet.rj.server-consoleserver/pom.xml
@@ -0,0 +1,62 @@
+<?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>
+	
+	<parent>
+		<groupId>org.eclipse.statet.rj</groupId>
+		<artifactId>rj-core</artifactId>
+		<version>2.1-SNAPSHOT</version>
+	</parent>
+	
+	<groupId>org.eclipse.statet.rj-packaging</groupId>
+	<artifactId>org.eclipse.statet.rj.core-consoleserver</artifactId>
+	<version>2.1.0-SNAPSHOT</version>
+	<packaging>pom</packaging>
+	
+	<dependencies>
+		<dependency>
+			<groupId>org.eclipse.statet.rj</groupId>
+			<artifactId>org.eclipse.statet.rj.data</artifactId>
+			<version>2.1.0-SNAPSHOT</version>
+			<type>eclipse-plugin</type>
+		</dependency>
+		<dependency>
+			<groupId>org.eclipse.statet.rj</groupId>
+			<artifactId>org.eclipse.statet.rj.server</artifactId>
+			<version>2.1.0-SNAPSHOT</version>
+			<type>eclipse-plugin</type>
+		</dependency>
+		<dependency>
+			<groupId>org.eclipse.statet.rj</groupId>
+			<artifactId>org.eclipse.statet.rj.server.remotetools</artifactId>
+			<version>2.1.0-SNAPSHOT</version>
+			<type>eclipse-plugin</type>
+		</dependency>
+	</dependencies>
+	
+	<build>
+		<plugins>
+			<plugin>
+				<artifactId>maven-assembly-plugin</artifactId>
+				<version>2.4</version>
+				<executions>
+					<execution>
+						<id>pack-server</id>
+						<phase>package</phase>
+						<goals>
+							<goal>single</goal>
+						</goals>
+						<configuration>
+							<descriptors>
+								<descriptor>server.xml</descriptor>
+							</descriptors>
+						</configuration>
+					</execution>
+				</executions>
+			</plugin>
+		</plugins>
+	</build>
+	
+</project>
diff --git a/core/_build/org.eclipse.statet.rj.server-consoleserver/server.xml b/core/_build/org.eclipse.statet.rj.server-consoleserver/server.xml
new file mode 100644
index 0000000..eecd8c6
--- /dev/null
+++ b/core/_build/org.eclipse.statet.rj.server-consoleserver/server.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2"
+		xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+		xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
+	<id>distr</id>
+	
+	<formats>
+		<format>tar.gz</format>
+	</formats>
+	
+	<includeBaseDirectory>false</includeBaseDirectory>
+	
+	<fileSets>
+		<fileSet>
+			<outputDirectory>/</outputDirectory>
+			<directory>../../org.eclipse.statet.rj.remotetools</directory>
+			<includes>
+				<include>startup.sh</include>
+			</includes>
+			<fileMode>755</fileMode>
+		</fileSet>
+	</fileSets>
+	
+	<dependencySets>
+		<dependencySet>
+			<outputDirectory>/</outputDirectory>
+			<useTransitiveDependencies>false</useTransitiveDependencies>
+			<includes>
+				<include>org.eclipse.statet.rj:org.eclipse.statet.rj.remotetools</include>
+			</includes>
+			<unpack>true</unpack>
+			<unpackOptions>
+				<excludes>
+					<exclude>startup.sh</exclude>
+					<exclude>META-INF/**</exclude>
+				</excludes>
+			</unpackOptions>
+		</dependencySet>
+		<dependencySet>
+			<outputDirectory>/</outputDirectory>
+			<useTransitiveDependencies>false</useTransitiveDependencies>
+			<includes>
+				<include>org.eclipse.statet.rj:org.eclipse.statet.rj.data</include>
+				<include>org.eclipse.statet.rj:org.eclipse.statet.rj.server</include>
+			</includes>
+			<outputFileNameMapping>${artifact.artifactId}.${artifact.extension}</outputFileNameMapping>
+		</dependencySet>
+	</dependencySets>
+	
+</assembly>
diff --git a/core/org.eclipse.statet.rj.client/.classpath b/core/org.eclipse.statet.rj.client/.classpath
new file mode 100644
index 0000000..465ce24
--- /dev/null
+++ b/core/org.eclipse.statet.rj.client/.classpath
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8">
+		<attributes>
+			<attribute name="owner.project.facets" value="java"/>
+		</attributes>
+	</classpathentry>
+	<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+	<classpathentry kind="src" path="src"/>
+	<classpathentry kind="src" path="srcRSetups"/>
+	<classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/core/org.eclipse.statet.rj.client/.gitignore b/core/org.eclipse.statet.rj.client/.gitignore
new file mode 100644
index 0000000..5e56e04
--- /dev/null
+++ b/core/org.eclipse.statet.rj.client/.gitignore
@@ -0,0 +1 @@
+/bin
diff --git a/core/org.eclipse.statet.rj.client/.project b/core/org.eclipse.statet.rj.client/.project
new file mode 100644
index 0000000..20b6194
--- /dev/null
+++ b/core/org.eclipse.statet.rj.client/.project
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>org.eclipse.statet.rj.client</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.wst.common.project.facet.core.builder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.jdt.core.javabuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.pde.ManifestBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.pde.SchemaBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.pde.api.tools.apiAnalysisBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.pde.PluginNature</nature>
+		<nature>org.eclipse.jdt.core.javanature</nature>
+		<nature>org.eclipse.pde.api.tools.apiAnalysisNature</nature>
+		<nature>org.eclipse.wst.common.modulecore.ModuleCoreNature</nature>
+		<nature>org.eclipse.wst.common.project.facet.core.nature</nature>
+	</natures>
+</projectDescription>
diff --git a/core/org.eclipse.statet.rj.client/.settings/org.eclipse.core.resources.prefs b/core/org.eclipse.statet.rj.client/.settings/org.eclipse.core.resources.prefs
new file mode 100644
index 0000000..99f26c0
--- /dev/null
+++ b/core/org.eclipse.statet.rj.client/.settings/org.eclipse.core.resources.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+encoding/<project>=UTF-8
diff --git a/core/org.eclipse.statet.rj.client/.settings/org.eclipse.core.runtime.prefs b/core/org.eclipse.statet.rj.client/.settings/org.eclipse.core.runtime.prefs
new file mode 100644
index 0000000..5a0ad22
--- /dev/null
+++ b/core/org.eclipse.statet.rj.client/.settings/org.eclipse.core.runtime.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+line.separator=\n
diff --git a/core/org.eclipse.statet.rj.client/.settings/org.eclipse.jdt.core.prefs b/core/org.eclipse.statet.rj.client/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000..ccb1eaa
--- /dev/null
+++ b/core/org.eclipse.statet.rj.client/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,325 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.codeComplete.argumentPrefixes=
+org.eclipse.jdt.core.codeComplete.argumentSuffixes=
+org.eclipse.jdt.core.codeComplete.fieldPrefixes=
+org.eclipse.jdt.core.codeComplete.fieldSuffixes=
+org.eclipse.jdt.core.codeComplete.localPrefixes=
+org.eclipse.jdt.core.codeComplete.localSuffixes=
+org.eclipse.jdt.core.codeComplete.staticFieldPrefixes=
+org.eclipse.jdt.core.codeComplete.staticFieldSuffixes=
+org.eclipse.jdt.core.codeComplete.staticFinalFieldPrefixes=
+org.eclipse.jdt.core.codeComplete.staticFinalFieldSuffixes=
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=1.8
+org.eclipse.jdt.core.compiler.debug.lineNumber=generate
+org.eclipse.jdt.core.compiler.debug.localVariable=generate
+org.eclipse.jdt.core.compiler.debug.sourceFile=generate
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.source=1.8
+org.eclipse.jdt.core.formatter.align_fields_grouping_blank_lines=2147483647
+org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_assignment=0
+org.eclipse.jdt.core.formatter.alignment_for_binary_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_compact_if=16
+org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=80
+org.eclipse.jdt.core.formatter.alignment_for_enum_constants=0
+org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16
+org.eclipse.jdt.core.formatter.alignment_for_expressions_in_for_loop_header=0
+org.eclipse.jdt.core.formatter.alignment_for_method_declaration=0
+org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16
+org.eclipse.jdt.core.formatter.alignment_for_parameterized_type_references=0
+org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_resources_in_try=85
+org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=16
+org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_type_arguments=0
+org.eclipse.jdt.core.formatter.alignment_for_type_parameters=0
+org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch=16
+org.eclipse.jdt.core.formatter.blank_lines_after_imports=2
+org.eclipse.jdt.core.formatter.blank_lines_after_package=1
+org.eclipse.jdt.core.formatter.blank_lines_before_field=0
+org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=1
+org.eclipse.jdt.core.formatter.blank_lines_before_imports=1
+org.eclipse.jdt.core.formatter.blank_lines_before_member_type=1
+org.eclipse.jdt.core.formatter.blank_lines_before_method=1
+org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=2
+org.eclipse.jdt.core.formatter.blank_lines_before_package=1
+org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=1
+org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=1
+org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_block=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_lambda_body=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=false
+org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=false
+org.eclipse.jdt.core.formatter.comment.format_block_comments=true
+org.eclipse.jdt.core.formatter.comment.format_header=false
+org.eclipse.jdt.core.formatter.comment.format_html=true
+org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=true
+org.eclipse.jdt.core.formatter.comment.format_line_comments=true
+org.eclipse.jdt.core.formatter.comment.format_source_code=true
+org.eclipse.jdt.core.formatter.comment.indent_parameter_description=false
+org.eclipse.jdt.core.formatter.comment.indent_root_tags=true
+org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert
+org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=do not insert
+org.eclipse.jdt.core.formatter.comment.line_length=100
+org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries=false
+org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries=true
+org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments=false
+org.eclipse.jdt.core.formatter.compact_else_if=true
+org.eclipse.jdt.core.formatter.continuation_indentation=2
+org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=2
+org.eclipse.jdt.core.formatter.disabling_tag=@formatter\:off
+org.eclipse.jdt.core.formatter.enabling_tag=@formatter\:on
+org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false
+org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true
+org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true
+org.eclipse.jdt.core.formatter.indent_empty_lines=true
+org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true
+org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true
+org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true
+org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=false
+org.eclipse.jdt.core.formatter.indentation.size=4
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_enum_constant=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_label=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_type_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert
+org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert
+org.eclipse.jdt.core.formatter.insert_space_after_lambda_arrow=insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources=insert
+org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert
+org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=insert
+org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert
+org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw=insert
+org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.join_lines_in_comments=true
+org.eclipse.jdt.core.formatter.join_wrapped_lines=true
+org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=false
+org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false
+org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=false
+org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false
+org.eclipse.jdt.core.formatter.lineSplit=100
+org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false
+org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=false
+org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0
+org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=1
+org.eclipse.jdt.core.formatter.parentheses_positions_in_annotation=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_catch_clause=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_enum_constant_declaration=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_for_statment=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_if_while_statement=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_lambda_declaration=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_method_delcaration=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_method_invocation=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_switch_statement=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_try_clause=common_lines
+org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=true
+org.eclipse.jdt.core.formatter.tabulation.char=tab
+org.eclipse.jdt.core.formatter.tabulation.size=4
+org.eclipse.jdt.core.formatter.use_on_off_tags=false
+org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false
+org.eclipse.jdt.core.formatter.wrap_before_assignment_operator=false
+org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true
+org.eclipse.jdt.core.formatter.wrap_before_conditional_operator=false
+org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch=true
+org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true
+org.eclipse.jdt.core.javaFormatter=org.eclipse.jdt.core.defaultJavaFormatter
diff --git a/core/org.eclipse.statet.rj.client/.settings/org.eclipse.jdt.ui.prefs b/core/org.eclipse.statet.rj.client/.settings/org.eclipse.jdt.ui.prefs
new file mode 100644
index 0000000..e62a4f5
--- /dev/null
+++ b/core/org.eclipse.statet.rj.client/.settings/org.eclipse.jdt.ui.prefs
@@ -0,0 +1,131 @@
+cleanup.add_default_serial_version_id=true
+cleanup.add_generated_serial_version_id=false
+cleanup.add_missing_annotations=true
+cleanup.add_missing_deprecated_annotations=true
+cleanup.add_missing_methods=false
+cleanup.add_missing_nls_tags=false
+cleanup.add_missing_override_annotations=true
+cleanup.add_missing_override_annotations_interface_methods=true
+cleanup.add_serial_version_id=false
+cleanup.always_use_blocks=true
+cleanup.always_use_parentheses_in_expressions=true
+cleanup.always_use_this_for_non_static_field_access=true
+cleanup.always_use_this_for_non_static_method_access=false
+cleanup.convert_functional_interfaces=false
+cleanup.convert_to_enhanced_for_loop=false
+cleanup.correct_indentation=false
+cleanup.format_source_code=false
+cleanup.format_source_code_changes_only=false
+cleanup.insert_inferred_type_arguments=false
+cleanup.make_local_variable_final=true
+cleanup.make_parameters_final=true
+cleanup.make_private_fields_final=true
+cleanup.make_type_abstract_if_missing_method=false
+cleanup.make_variable_declarations_final=true
+cleanup.never_use_blocks=false
+cleanup.never_use_parentheses_in_expressions=false
+cleanup.organize_imports=true
+cleanup.qualify_static_field_accesses_with_declaring_class=false
+cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true
+cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=false
+cleanup.qualify_static_member_accesses_with_declaring_class=true
+cleanup.qualify_static_method_accesses_with_declaring_class=false
+cleanup.remove_private_constructors=true
+cleanup.remove_redundant_type_arguments=true
+cleanup.remove_trailing_whitespaces=false
+cleanup.remove_trailing_whitespaces_all=true
+cleanup.remove_trailing_whitespaces_ignore_empty=false
+cleanup.remove_unnecessary_casts=true
+cleanup.remove_unnecessary_nls_tags=true
+cleanup.remove_unused_imports=true
+cleanup.remove_unused_local_variables=false
+cleanup.remove_unused_private_fields=true
+cleanup.remove_unused_private_members=false
+cleanup.remove_unused_private_methods=true
+cleanup.remove_unused_private_types=true
+cleanup.sort_members=false
+cleanup.sort_members_all=false
+cleanup.use_anonymous_class_creation=false
+cleanup.use_blocks=true
+cleanup.use_blocks_only_for_return_and_throw=false
+cleanup.use_lambda=true
+cleanup.use_parentheses_in_expressions=false
+cleanup.use_this_for_non_static_field_access=true
+cleanup.use_this_for_non_static_field_access_only_if_necessary=false
+cleanup.use_this_for_non_static_method_access=true
+cleanup.use_this_for_non_static_method_access_only_if_necessary=true
+cleanup.use_type_arguments=false
+cleanup_profile=_StatET
+cleanup_settings_version=2
+eclipse.preferences.version=1
+editor_save_participant_org.eclipse.jdt.ui.postsavelistener.cleanup=true
+formatter_profile=_StatET
+formatter_settings_version=12
+org.eclipse.jdt.ui.exception.name=e
+org.eclipse.jdt.ui.gettersetter.use.is=true
+org.eclipse.jdt.ui.ignorelowercasenames=true
+org.eclipse.jdt.ui.importorder=\#;java;javax;com.ibm.icu;org.osgi;org.eclipse;;org.eclipse.statet.jcommons;org.eclipse.statet.ecommons;org.eclipse.statet;
+org.eclipse.jdt.ui.javadoc=true
+org.eclipse.jdt.ui.keywordthis=true
+org.eclipse.jdt.ui.ondemandthreshold=99
+org.eclipse.jdt.ui.overrideannotation=true
+org.eclipse.jdt.ui.staticondemandthreshold=99
+org.eclipse.jdt.ui.text.custom_code_templates=<?xml version\="1.0" encoding\="UTF-8" standalone\="no"?><templates><template autoinsert\="true" context\="gettercomment_context" deleted\="false" description\="Comment for getter method" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.gettercomment" name\="gettercomment">/**\n * @return the ${bare_field_name}\n */</template><template autoinsert\="true" context\="settercomment_context" deleted\="false" description\="Comment for setter method" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.settercomment" name\="settercomment">/**\n * @param ${param} the ${bare_field_name} to set\n */</template><template autoinsert\="true" context\="constructorcomment_context" deleted\="false" description\="Comment for created constructors" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.constructorcomment" name\="constructorcomment">/**\n * ${tags}\n */</template><template autoinsert\="false" context\="filecomment_context" deleted\="false" description\="Comment for created Java files" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.filecomment" name\="filecomment">/*\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\#\n \# Copyright (c) ${year} ${user} and others.\n # \n # This program and the accompanying materials are made available under the\n # terms of the Eclipse Public License 2.0 which is available at\n # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n # which is available at https://www.apache.org/licenses/LICENSE-2.0.\n # \n # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n # \n \# Contributors\:\n \#     ${user} - initial API and implementation\n \#\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=*/</template><template autoinsert\="false" context\="typecomment_context" deleted\="false" description\="Comment for created types" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.typecomment" name\="typecomment">/**\n * \n * ${tags}\n */</template><template autoinsert\="true" context\="fieldcomment_context" deleted\="false" description\="Comment for fields" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.fieldcomment" name\="fieldcomment">/**\n * \n */</template><template autoinsert\="true" context\="methodcomment_context" deleted\="false" description\="Comment for non-overriding methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.methodcomment" name\="methodcomment">/**\n * ${tags}\n */</template><template autoinsert\="false" context\="overridecomment_context" deleted\="false" description\="Comment for overriding methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.overridecomment" name\="overridecomment"/><template autoinsert\="true" context\="delegatecomment_context" deleted\="false" description\="Comment for delegate methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.delegatecomment" name\="delegatecomment">/**\n * ${tags}\n * ${see_to_target}\n */</template><template autoinsert\="false" context\="newtype_context" deleted\="false" description\="Newly created files" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.newtype" name\="newtype">${filecomment}\n\n${package_declaration}\n\n${typecomment}\n${type_declaration}</template><template autoinsert\="true" context\="classbody_context" deleted\="false" description\="Code in new class type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.classbody" name\="classbody">\n</template><template autoinsert\="true" context\="interfacebody_context" deleted\="false" description\="Code in new interface type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.interfacebody" name\="interfacebody">\n</template><template autoinsert\="true" context\="enumbody_context" deleted\="false" description\="Code in new enum type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.enumbody" name\="enumbody">\n</template><template autoinsert\="true" context\="annotationbody_context" deleted\="false" description\="Code in new annotation type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.annotationbody" name\="annotationbody">\n</template><template autoinsert\="true" context\="catchblock_context" deleted\="false" description\="Code in new catch blocks" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.catchblock" name\="catchblock">// ${todo} Auto-generated catch block\n${exception_var}.printStackTrace();</template><template autoinsert\="true" context\="methodbody_context" deleted\="false" description\="Code in created method stubs" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.methodbody" name\="methodbody">// ${todo} Auto-generated method stub\n${body_statement}</template><template autoinsert\="true" context\="constructorbody_context" deleted\="false" description\="Code in created constructor stubs" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.constructorbody" name\="constructorbody">${body_statement}\n// ${todo} Auto-generated constructor stub</template><template autoinsert\="true" context\="getterbody_context" deleted\="false" description\="Code in created getters" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.getterbody" name\="getterbody">return ${field};</template><template autoinsert\="true" context\="setterbody_context" deleted\="false" description\="Code in created setters" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.setterbody" name\="setterbody">${field} \= ${param};</template></templates>
+sp_cleanup.add_default_serial_version_id=true
+sp_cleanup.add_generated_serial_version_id=false
+sp_cleanup.add_missing_annotations=true
+sp_cleanup.add_missing_deprecated_annotations=true
+sp_cleanup.add_missing_methods=false
+sp_cleanup.add_missing_nls_tags=false
+sp_cleanup.add_missing_override_annotations=true
+sp_cleanup.add_missing_override_annotations_interface_methods=true
+sp_cleanup.add_serial_version_id=false
+sp_cleanup.always_use_blocks=true
+sp_cleanup.always_use_parentheses_in_expressions=true
+sp_cleanup.always_use_this_for_non_static_field_access=true
+sp_cleanup.always_use_this_for_non_static_method_access=false
+sp_cleanup.convert_functional_interfaces=false
+sp_cleanup.convert_to_enhanced_for_loop=false
+sp_cleanup.correct_indentation=false
+sp_cleanup.format_source_code=false
+sp_cleanup.format_source_code_changes_only=false
+sp_cleanup.insert_inferred_type_arguments=false
+sp_cleanup.make_local_variable_final=true
+sp_cleanup.make_parameters_final=true
+sp_cleanup.make_private_fields_final=true
+sp_cleanup.make_type_abstract_if_missing_method=false
+sp_cleanup.make_variable_declarations_final=false
+sp_cleanup.never_use_blocks=false
+sp_cleanup.never_use_parentheses_in_expressions=false
+sp_cleanup.on_save_use_additional_actions=true
+sp_cleanup.organize_imports=true
+sp_cleanup.qualify_static_field_accesses_with_declaring_class=false
+sp_cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true
+sp_cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=false
+sp_cleanup.qualify_static_member_accesses_with_declaring_class=true
+sp_cleanup.qualify_static_method_accesses_with_declaring_class=false
+sp_cleanup.remove_private_constructors=true
+sp_cleanup.remove_redundant_type_arguments=true
+sp_cleanup.remove_trailing_whitespaces=false
+sp_cleanup.remove_trailing_whitespaces_all=false
+sp_cleanup.remove_trailing_whitespaces_ignore_empty=true
+sp_cleanup.remove_unnecessary_casts=true
+sp_cleanup.remove_unnecessary_nls_tags=false
+sp_cleanup.remove_unused_imports=false
+sp_cleanup.remove_unused_local_variables=false
+sp_cleanup.remove_unused_private_fields=false
+sp_cleanup.remove_unused_private_members=false
+sp_cleanup.remove_unused_private_methods=false
+sp_cleanup.remove_unused_private_types=true
+sp_cleanup.sort_members=false
+sp_cleanup.sort_members_all=false
+sp_cleanup.use_anonymous_class_creation=false
+sp_cleanup.use_blocks=true
+sp_cleanup.use_blocks_only_for_return_and_throw=false
+sp_cleanup.use_lambda=false
+sp_cleanup.use_parentheses_in_expressions=false
+sp_cleanup.use_this_for_non_static_field_access=true
+sp_cleanup.use_this_for_non_static_field_access_only_if_necessary=false
+sp_cleanup.use_this_for_non_static_method_access=true
+sp_cleanup.use_this_for_non_static_method_access_only_if_necessary=true
+sp_cleanup.use_type_arguments=false
diff --git a/core/org.eclipse.statet.rj.client/.settings/org.eclipse.wst.common.component b/core/org.eclipse.statet.rj.client/.settings/org.eclipse.wst.common.component
new file mode 100644
index 0000000..fba8ab5
--- /dev/null
+++ b/core/org.eclipse.statet.rj.client/.settings/org.eclipse.wst.common.component
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project-modules id="moduleCoreId" project-version="1.5.0">
+    <wb-module deploy-name="org.eclipse.statet.rj.client">
+        <wb-resource deploy-path="/" source-path="/src"/>
+    </wb-module>
+</project-modules>
diff --git a/core/org.eclipse.statet.rj.client/.settings/org.eclipse.wst.common.project.facet.core.xml b/core/org.eclipse.statet.rj.client/.settings/org.eclipse.wst.common.project.facet.core.xml
new file mode 100644
index 0000000..a1f5f3c
--- /dev/null
+++ b/core/org.eclipse.statet.rj.client/.settings/org.eclipse.wst.common.project.facet.core.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<faceted-project>
+  <fixed facet="java"/>
+  <fixed facet="jst.utility"/>
+  <installed facet="java" version="1.8"/>
+  <installed facet="jst.utility" version="1.0"/>
+</faceted-project>
diff --git a/core/org.eclipse.statet.rj.client/META-INF/MANIFEST.MF b/core/org.eclipse.statet.rj.client/META-INF/MANIFEST.MF
new file mode 100644
index 0000000..19dae44
--- /dev/null
+++ b/core/org.eclipse.statet.rj.client/META-INF/MANIFEST.MF
@@ -0,0 +1,14 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-SymbolicName: org.eclipse.statet.rj.client;singleton:=true
+Bundle-Version: 2.1.0.qualifier
+Bundle-Vendor: Eclipse.org
+Bundle-Name: StatET RJ - Client Implementation
+Bundle-RequiredExecutionEnvironment: JavaSE-1.8
+Require-Bundle: org.eclipse.statet.rj.data;bundle-version="[2.1.0,2.2.0)",
+ org.eclipse.statet.rj.server;bundle-version="[2.1.0,2.2.0)",
+ org.eclipse.statet.rj.services.core;bundle-version="[2.1.0,2.2.0)"
+Import-Package: org.osgi.framework;version="1.8.0",
+ org.eclipse.core.runtime
+Export-Package: org.eclipse.statet.rj.rsetups;version="3.0.0",
+ org.eclipse.statet.rj.server.client
diff --git a/core/org.eclipse.statet.rj.client/about.html b/core/org.eclipse.statet.rj.client/about.html
new file mode 100644
index 0000000..e71ae66
--- /dev/null
+++ b/core/org.eclipse.statet.rj.client/about.html
@@ -0,0 +1,37 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+		"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+<title>About</title>
+</head>
+<body lang="EN-US">
+<h2>About This Content</h2>
+
+<p>December 1, 2017</p>
+<h3>License</h3>
+
+<p>
+	The Eclipse Foundation makes available all content in this plug-in
+	(&quot;Content&quot;). Unless otherwise indicated below, the Content
+	is provided to you under the terms and conditions of the Eclipse
+	Public License Version 2.0 (&quot;EPL&quot;), or the Apache License,
+	Version 2.0 (AL). A copy of the EPL is available at <a href="https://www.eclipse.org/legal/epl-2.0">https://www.eclipse.org/legal/epl-2.0</a>.
+	For purposes of the EPL, &quot;Program&quot; will mean the Content.
+	A copy of the AL is available at <a href="https://www.apache.org/licenses/LICENSE-2.0">https://www.apache.org/licenses/LICENSE-2.0</a>.
+</p>
+
+<p>
+	If you did not receive this Content directly from the Eclipse
+	Foundation, the Content is being redistributed by another party
+	(&quot;Redistributor&quot;) and different terms and conditions may
+	apply to your use of any object code in the Content. Check the
+	Redistributor's license that was provided with the Content. If no such
+	license exists, contact the Redistributor. Unless otherwise indicated
+	below, the terms and conditions of the EPL or AL still apply to any
+	source code in the Content and such source code may be obtained at <a
+	href="https://www.eclipse.org/">https://www.eclipse.org</a>.
+</p>
+
+</body>
+</html>
diff --git a/core/org.eclipse.statet.rj.client/build.properties b/core/org.eclipse.statet.rj.client/build.properties
new file mode 100644
index 0000000..5ce0c73
--- /dev/null
+++ b/core/org.eclipse.statet.rj.client/build.properties
@@ -0,0 +1,9 @@
+source..= src/,\
+          srcRSetups/
+output..= bin/
+javacDefaultEncoding..= UTF-8
+
+bin.includes= META-INF/,\
+              .,\
+              about.html
+src.includes= .settings/org.eclipse.core.resources.prefs
diff --git a/core/org.eclipse.statet.rj.client/src/org/eclipse/statet/rj/server/client/AbstractRJComClient.java b/core/org.eclipse.statet.rj.client/src/org/eclipse/statet/rj/server/client/AbstractRJComClient.java
new file mode 100644
index 0000000..619e4a2
--- /dev/null
+++ b/core/org.eclipse.statet.rj.client/src/org/eclipse/statet/rj/server/client/AbstractRJComClient.java
@@ -0,0 +1,1798 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server.client;
+
+import static org.eclipse.statet.rj.server.util.ServerUtils.MISSING_ANSWER_STATUS;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.ObjectInput;
+import java.io.OutputStream;
+import java.rmi.ConnectException;
+import java.rmi.RemoteException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Random;
+import java.util.concurrent.Callable;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.core.runtime.Status;
+
+import org.eclipse.statet.rj.RjException;
+import org.eclipse.statet.rj.data.REnvironment;
+import org.eclipse.statet.rj.data.RJIO;
+import org.eclipse.statet.rj.data.RJIOExternalizable;
+import org.eclipse.statet.rj.data.RList;
+import org.eclipse.statet.rj.data.RObject;
+import org.eclipse.statet.rj.data.RReference;
+import org.eclipse.statet.rj.server.BinExchange;
+import org.eclipse.statet.rj.server.ComHandler;
+import org.eclipse.statet.rj.server.ConsoleReadCmdItem;
+import org.eclipse.statet.rj.server.CtrlCmdItem;
+import org.eclipse.statet.rj.server.DataCmdItem;
+import org.eclipse.statet.rj.server.DataCmdItem.Operation;
+import org.eclipse.statet.rj.server.DbgCmdItem;
+import org.eclipse.statet.rj.server.DbgCmdItem.CustomDataReader;
+import org.eclipse.statet.rj.server.ExtUICmdItem;
+import org.eclipse.statet.rj.server.GDCmdItem;
+import org.eclipse.statet.rj.server.GraOpCmdItem;
+import org.eclipse.statet.rj.server.MainCmdC2SList;
+import org.eclipse.statet.rj.server.MainCmdItem;
+import org.eclipse.statet.rj.server.MainCtrlCmdItem;
+import org.eclipse.statet.rj.server.REngine;
+import org.eclipse.statet.rj.server.RjsComConfig;
+import org.eclipse.statet.rj.server.RjsComObject;
+import org.eclipse.statet.rj.server.RjsPing;
+import org.eclipse.statet.rj.server.RjsStatus;
+import org.eclipse.statet.rj.server.Server;
+import org.eclipse.statet.rj.server.client.RClientGraphic.InitConfig;
+import org.eclipse.statet.rj.server.dbg.CtrlReport;
+import org.eclipse.statet.rj.services.RPlatform;
+import org.eclipse.statet.rj.services.RService;
+
+
+/**
+ * Generic RJ Com protocol client for servers offering a {@link REngine}.
+ * <p>
+ * It offers basic implementation for most methods of the {@link RService} API,
+ * including:</p>
+ * <ul>
+ *   <li>Expression evaluation</li>
+ *   <li>Data exchange to assign or eval/read {@link RObject}</li>
+ *   <li>File exchange to write/read file on the server (must be enabled at server side)</li>
+ *   <li>R graphics (requires an {@link RClientGraphicFactory}, set in {@link #initGraphicFactory()},
+ *       or via {@link #setGraphicFactory(RClientGraphicFactory, RClientGraphicActions)})</li>
+ *   <li>Console (REPL), if connected to server slot 0</li>
+ * </ul>
+ * <p>
+ * If offers two mechanisms allowing the usage of RService API and R thread when they are already
+ * used by a regular call. So the two modes allows to "hijack" the R thread to "inject" additional
+ * calls to the RService API:</p>
+ * <ul>
+ *   <li>Hot Mode: Enables to run code in any situation, also if R is busy. Nesting of hot modes is
+ *       not possible. It can be requested asynchronous from any thread. The hot mode is appropriate
+ *       for e.g. short task for the GUI.</li>
+ *   <li>Extra Mode: Enables to run code at the before or after of a client-server communication.
+ *       Must be requested synchronous from the R thread.</li>
+ * </ul>
+ */
+public abstract class AbstractRJComClient implements ComHandler {
+	
+	
+	public static final String RJ_CLIENT_ID= "org.eclipse.statet.rj.client";
+	
+	public static int[] version() {
+		return new int[] { 2, 1, 0 };
+	}
+	
+	public static final int EXTRA_BEFORE= 1;
+	public static final int EXTRA_NESTED= 2;
+	
+	private static final ScheduledExecutorService RJHelper_EXECUTOR =
+			Executors.newSingleThreadScheduledExecutor(new DaemonThreadFactory("RJHelper"));
+	
+	private static final Random RAND= new Random();
+	
+	
+	private static class DummyFactory implements RClientGraphicFactory {
+		
+		@Override
+		public Map<String, ? extends Object> getInitServerProperties() {
+			return null;
+		}
+		
+		@Override
+		public RClientGraphic newGraphic(final int devId, final double w, final double h,
+				final InitConfig config,
+				final boolean active, final RClientGraphicActions actions, final int options) {
+			return new RClientGraphicDummy(devId, w, h);
+		}
+		
+		@Override
+		public void closeGraphic(final RClientGraphic graphic) {
+		}
+		
+	}
+	
+	private final static class RunnableList {
+		
+		private Runnable[] array;
+		private int size;
+		
+		public RunnableList() {
+			this.array= new Runnable[4];
+			this.size= 0;
+		}
+		
+		
+		public void add(final Runnable value) {
+			if (value == null) {
+				throw new IllegalArgumentException();
+			}
+			final int oldCapacity= this.array.length;
+			if (this.size < oldCapacity) {
+				this.array[this.size++]= value;
+				return;
+			}
+			final Runnable[] newArray= new Runnable[oldCapacity + 4];
+			System.arraycopy(this.array, 0, newArray, 0, oldCapacity);
+			newArray[this.size++]= value;
+			this.array= newArray;
+		}
+		
+		public boolean isNotEmpty() {
+			return (this.size != 0);
+		}
+		
+		public Runnable[] consume() {
+			final Runnable[] oldListeners= this.array;
+			this.size= 0;
+			this.array= new Runnable[4];
+			return oldListeners;
+		}
+		
+	}
+	
+	
+	private class KeepAliveRunnable implements Runnable {
+		
+		@Override
+		public void run() {
+			runAsyncPing();
+		}
+		
+	}
+	
+	private class HotModeRequestRunnable implements Runnable {
+		
+		@Override
+		public void run() {
+			if (AbstractRJComClient.this.hotModeRequested.get()) {
+				try {
+					runAsyncCtrl(CtrlCmdItem.REQUEST_HOT_MODE);
+				}
+				catch (final CoreException e) {
+					if (e.getStatus().getSeverity() != IStatus.CANCEL) {
+						log(new Status(IStatus.ERROR, RJ_CLIENT_ID, -1, "An error occurred when requesting hot mode.", e));
+					}
+				}
+			}
+		}
+	}
+	
+	
+	private RService rService;
+	private Object rHandle;
+	
+	private IProgressMonitor progressMonitor;
+	
+	private final RJIO mainIO= new RJIO();
+	private MainCmdItem mainC2SFirst;
+	private final MainCmdC2SList mainC2SList= new MainCmdC2SList(this.mainIO);
+	private final RunnableList mainDeferredCmds= new RunnableList();
+	private boolean mainRunGC;
+	
+	private boolean consoleReadCallbackRequired;
+	private ConsoleReadCmdItem consoleReadCallback;
+	
+	private final Object platformLock= new Object();
+	private Map<String, Object> platformData;
+	private RPlatform platformObj;
+	
+	private final byte randomId= (byte) (0xff & RAND.nextInt(255));
+	
+	private int dataLevelRequest= 0;
+	private int dataLevelAnswer= 0;
+	private int dataLevelIgnore= 0;
+	private byte dataRequestCounter= (byte) (0xff & RAND.nextInt(255));
+	private final int[] dataRequestId= new int[32];
+	private final MainCmdItem[] dataAnswer= new MainCmdItem[32];
+	
+	private boolean runFinishTask;
+	
+	private boolean dbgOpRequest;
+	private DbgCmdItem dbgOpAnswer;
+	private CustomDataReader dbgOpCustomReader;
+	
+	private int hotModeState;
+	private ConsoleReadCmdItem hotModeReadCallbackBackup;
+	private MainCmdItem hotModeC2SFirstBackup;
+	private final AtomicBoolean hotModeRequested= new AtomicBoolean();
+	private final Runnable hotModeRunnable= new HotModeRequestRunnable();
+	
+	private int extraModeRequested;
+	
+	private RClientGraphicFactory graphicFactory;
+	private RClientGraphicActions graphicActions;
+	private final RClientGraphic graphicDummy= new RClientGraphicDummy(1, 0, 0);
+	private RClientGraphic[] graphics= new RClientGraphic[16];
+	private int currentGraphicOptions;
+	private RClientGraphic lastGraphic;
+	
+	private REngine rjConsoleEngine;
+	
+	private List<Runnable> defferedRunnables;
+	
+	private boolean closed;
+	private ScheduledFuture<?> keepAliveJob;
+	private String closedMessage= "Connection to R engine is closed.";
+	
+	private final Lock clientWaitLock= new ReentrantLock();
+	private final Condition clientWaitCondition= this.clientWaitLock.newCondition();
+	private final List<Callable<Boolean>> cancelHandler= new ArrayList<>();
+	
+	
+	protected AbstractRJComClient() {
+	}
+	
+	
+	public void initClient(final Object rHandle, final RService r,
+			final Map<String, Object> properties, final int id) {
+		this.rHandle= rHandle;
+		this.rService= r;
+		properties.put("rj.com.init", Boolean.TRUE); //$NON-NLS-1$
+		properties.put(RjsComConfig.RJ_COM_S2C_ID_PROPERTY_ID, id);
+		
+		try {
+			initGraphicFactory();
+		}
+		catch (final Exception e) {
+			log(new Status(IStatus.ERROR, RJ_CLIENT_ID, -1, "An error occurred when initializing R client graphic factory.", e));
+		}
+		if (this.graphicFactory != null) {
+			final Map<String, ? extends Object> additional= this.graphicFactory.getInitServerProperties();
+			if (additional != null) {
+				properties.putAll(additional);
+			}
+		}
+		else {
+			this.graphicFactory= new DummyFactory();
+			log(new Status(IStatus.WARNING, RJ_CLIENT_ID, -1, "No R client graphic factory configured.", null));
+		}
+	}
+	
+	public void setDbgCustomCmdReader(final DbgCmdItem.CustomDataReader reader) {
+		this.dbgOpCustomReader= reader;
+	}
+	
+	public final void setServer(final REngine rjServer, final int client) {
+		final List<Runnable> runnables;
+		synchronized (this) {
+			this.rjConsoleEngine= rjServer;
+			if (client == 0) {
+				long t= 45 * 1000;
+				try {
+					final String p= System.getProperty("org.eclipse.statet.rj.client.keepaliveInterval"); //$NON-NLS-1$
+					if (p != null && p.length() > 0) {
+						t= Long.parseLong(p);
+					}
+				}
+				catch (final Exception e) {}
+				this.keepAliveJob= RJHelper_EXECUTOR.scheduleWithFixedDelay(
+						new KeepAliveRunnable(), t, t, TimeUnit.MILLISECONDS );
+			}
+			runnables= this.defferedRunnables;
+			this.defferedRunnables= null;
+		}
+		if (runnables != null) {
+			for (int i= 0; i < runnables.size(); i++) {
+				RJHelper_EXECUTOR.execute(runnables.get(i));
+			}
+		}
+	}
+	
+	public Object getRHandle() {
+		return this.rHandle;
+	}
+	
+	public RService getRService() {
+		return this.rService;
+	}
+	
+	public final REngine getConsoleEngine() {
+		return this.rjConsoleEngine;
+	}
+	
+	protected void execAsync(final Runnable runnable) {
+		synchronized (this) {
+			if (this.rjConsoleEngine == null) {
+				if (this.defferedRunnables == null) {
+					this.defferedRunnables= new ArrayList<>(8);
+				}
+				this.defferedRunnables.add(runnable);
+				return;
+			}
+		}
+		RJHelper_EXECUTOR.execute(runnable);
+	}
+	
+	protected void initGraphicFactory() {
+	}
+	
+	
+	public final void setGraphicFactory(final RClientGraphicFactory factory, final RClientGraphicActions actions) {
+		if (factory == null) {
+			throw new NullPointerException();
+		}
+		this.graphicFactory= factory;
+		this.graphicActions= actions;
+	}
+	
+	public boolean isClosed() {
+		return this.closed;
+	}
+	
+	public void setClosed(final boolean closed) {
+		if (this.closed != closed) {
+			this.closed= closed;
+			if (closed) {
+				final ScheduledFuture<?> job= this.keepAliveJob;
+				if (job != null) {
+					this.keepAliveJob= null;
+					job.cancel(true);
+				}
+			}
+		}
+	}
+	
+	public void setRjsProperties(final Map<String, ? extends Object> properties) throws CoreException {
+		try {
+			this.rjConsoleEngine.setProperties(properties);
+		}
+		catch (final RemoteException e) {
+			throw new CoreException(new Status(IStatus.ERROR, RJ_CLIENT_ID, "An error occurred when setting server properties.", e));
+		}
+	}
+	
+	
+	@Override
+	public final void processMainCmd(final ObjectInput in) throws IOException {
+		boolean runGC= false;
+		updateBusy(in.readBoolean());
+		if (this.hotModeState == 4) {
+			this.hotModeState= 0;
+			this.consoleReadCallback= this.hotModeReadCallbackBackup;
+			this.hotModeReadCallbackBackup= null;
+			if (this.hotModeC2SFirstBackup != null) {
+				addC2SCmd(this.hotModeC2SFirstBackup);
+				this.hotModeC2SFirstBackup= null;
+			}
+		}
+		
+		this.mainIO.connect(in);
+		final int check= this.mainIO.readCheck1();
+		
+		while (true) {
+			final byte type= in.readByte();
+			switch (type) {
+			case MainCmdItem.T_NONE:
+				this.mainIO.readCheck2(check);
+				this.mainIO.disconnect(in);
+				this.mainRunGC= runGC;
+				return;
+			case MainCmdItem.T_CONSOLE_READ_ITEM:
+				processPrompt(new ConsoleReadCmdItem(this.mainIO));
+				continue;
+			case MainCmdItem.T_CONSOLE_WRITE_ITEM:
+				runGC= true;
+				writeConsoleOutput(this.mainIO.readByte(), this.mainIO.readString());
+				continue;
+			case MainCmdItem.T_MESSAGE_ITEM:
+				runGC= true;
+				showMessage(this.mainIO.readString());
+				continue;
+			case MainCmdItem.T_EXTENDEDUI_ITEM:
+				runGC= true;
+				processUICallback(this.mainIO);
+				continue;
+			case MainCmdItem.T_GRAPH_ITEM:
+				runGC= true;
+				processGDCmd(this.mainIO);
+				continue;
+			case MainCmdItem.T_MAIN_CTRL_ITEM:
+				runGC= true;
+				processMainCtrlCmd(this.mainIO);
+				continue;
+			case MainCmdItem.T_DATA_ITEM:
+				runGC= true;
+				processDataCmd(this.mainIO);
+				continue;
+			case MainCmdItem.T_GRAPHICS_OP_ITEM:
+				runGC= true;
+				processGraphicsOpCmd(this.mainIO);
+				continue;
+			case MainCmdItem.T_DBG_ITEM:
+				runGC= true;
+				processDbgCmd(this.mainIO);
+				continue;
+			default:
+				this.mainIO.disconnect(in);
+				throw new IOException("Unknown cmdtype id: " + type);
+			}
+		}
+	}
+	
+	private final void processCmdDeferred(final Runnable runnable) {
+		this.mainDeferredCmds.add(runnable);
+	}
+	
+	
+	public final boolean processUICallback(final RJIO io) throws IOException {
+		final ExtUICmdItem item= new ExtUICmdItem(io);
+		try {
+			final RList answer= handleUICallback(item.getDataText(), item.getDataArgs(),
+					this.progressMonitor);
+			item.setAnswer(answer);
+		}
+		catch (final IOException e) {
+			throw e;
+		}
+		catch (final Exception e) {
+			log(new Status(IStatus.ERROR, RJ_CLIENT_ID, -1, "An error occurred when exec RJ UI command '" + item.getDataText() + "'.", e)); 
+			if (item.waitForClient()) {
+				item.setAnswer(new RjsStatus(RjsStatus.ERROR, 0, "Client error processing current command."));
+			}
+		}
+		if (item.waitForClient()) {
+			addC2SCmd(item);
+			return true;
+		}
+		return false;
+	}
+	
+	protected RList handleUICallback(final String commandId, final RList args,
+			final IProgressMonitor monitor) throws Exception {
+		throw new CoreException(new Status(IStatus.WARNING, RJ_CLIENT_ID, -1, "Unhandled RJ UI command '" + commandId + "'.", null)); 
+	}
+	
+	
+	public final void processGDCmd(final RJIO io) throws IOException {
+		final int devId;
+		final int options;
+		{	final int i= io.readInt();
+			options= (i & MainCmdItem.OV_WAITFORCLIENT);
+			devId= (i & ~MainCmdItem.OV_WAITFORCLIENT);
+		}
+		byte requestId= -1;
+		try {
+			switch (io.readByte()) {
+			case GDCmdItem.C_NEW_PAGE:
+				addGraphic(devId,
+						io.readDouble(),
+						io.readDouble(),
+						io.readInt(),
+						io.readBoolean() );
+				return;
+			case GDCmdItem.C_CLOSE_DEVICE:
+				removeGraphic(devId);
+				return;
+			case GDCmdItem.C_GET_SIZE:
+				addC2SCmd(new GDCmdItem.DoubleAnswer(requestId= io.readByte(),
+						devId, getGraphic(devId).computeSize() ));
+				return;
+			case GDCmdItem.C_SET_ACTIVE_OFF:
+				getGraphic(devId).setActive(false);
+				return;
+			case GDCmdItem.C_SET_ACTIVE_ON:
+				getGraphic(devId).setActive(true);
+				return;
+			case GDCmdItem.C_SET_MODE:
+				getGraphic(devId).setMode(io.readByte());
+				return;
+			case GDCmdItem.C_GET_FONTMETRIC:
+				addC2SCmd(new GDCmdItem.DoubleAnswer(requestId= io.readByte(),
+						devId, getGraphic(devId).computeFontMetric(
+								io.readInt() )));
+				return;
+			case GDCmdItem.C_GET_STRINGWIDTH:
+				addC2SCmd(new GDCmdItem.DoubleAnswer(requestId= io.readByte(),
+						devId, getGraphic(devId).computeStringWidth(
+								io.readString() )));
+				return;
+				
+			case GDCmdItem.SET_CLIP:
+				getGraphic(devId).addSetClip(
+						io.readDouble(),
+						io.readDouble(),
+						io.readDouble(),
+						io.readDouble() );
+				return;
+			case GDCmdItem.SET_COLOR:
+				getGraphic(devId).addSetColor(
+						io.readInt() );
+				return;
+			case GDCmdItem.SET_FILL:
+				getGraphic(devId).addSetFill(
+						io.readInt() );
+				return;
+			case GDCmdItem.SET_LINE:
+				getGraphic(devId).addSetLine(
+						io.readInt(),
+						io.readFloat(),
+						io.readByte(),
+						io.readByte(),
+						io.readFloat() );
+				return;
+			case GDCmdItem.SET_FONT:
+				getGraphic(devId).addSetFont(
+						io.readString(),
+						io.readInt(),
+						io.readFloat(),
+						io.readFloat() );
+				return;
+				
+			case GDCmdItem.DRAW_LINE:
+				getGraphic(devId).addDrawLine(
+						io.readDouble(),
+						io.readDouble(),
+						io.readDouble(),
+						io.readDouble() );
+				return;
+			case GDCmdItem.DRAW_RECTANGLE:
+				getGraphic(devId).addDrawRect(
+						io.readDouble(),
+						io.readDouble(),
+						io.readDouble(),
+						io.readDouble() );
+				return;
+			case GDCmdItem.DRAW_POLYLINE:
+				getGraphic(devId).addDrawPolyline(
+						io.readDoubleArray(),
+						io.readDoubleArray2() );
+				return;
+			case GDCmdItem.DRAW_POLYGON:
+				getGraphic(devId).addDrawPolygon(
+						io.readDoubleArray(),
+						io.readDoubleArray2() );
+				return;
+			case GDCmdItem.DRAW_PATH:
+				getGraphic(devId).addDrawPath(
+						io.readIntArray(),
+						io.readDoubleArray(),
+						io.readDoubleArray2(),
+						io.readInt() );
+				return;
+			case GDCmdItem.DRAW_CIRCLE:
+				getGraphic(devId).addDrawCircle(
+						io.readDouble(),
+						io.readDouble(),
+						io.readDouble() );
+				return;
+			case GDCmdItem.DRAW_TEXT:
+				getGraphic(devId).addDrawText(
+						io.readString(),
+						io.readDouble(),
+						io.readDouble(),
+						io.readDouble(),
+						io.readDouble() );
+				return;
+			case GDCmdItem.DRAW_RASTER:
+				getGraphic(devId).addDrawRaster(
+						io.readByteArray(),
+						io.readBoolean(),
+						io.readInt(),
+						io.readInt(),
+						io.readDouble(),
+						io.readDouble(),
+						io.readDouble(),
+						io.readDouble(),
+						io.readDouble(),
+						io.readBoolean() );
+				return;
+				
+			case GDCmdItem.CAPTURE:
+				addC2SCmd(new GDCmdItem.Answer(requestId= io.readByte(),
+						devId, getGraphic(devId).capture(
+								io.readInt(),
+								io.readInt() )));
+				return;
+				
+			case GDCmdItem.U_LOCATOR: {
+				final byte fid= requestId= io.readByte();
+				processCmdDeferred(new Runnable() {
+					@Override
+					public void run() {
+						addC2SCmd(new GDCmdItem.DoubleAnswer(fid,
+								devId, getGraphic(devId).runRLocator(
+										AbstractRJComClient.this.rService,
+										AbstractRJComClient.this.progressMonitor )));
+					}
+				});
+				return; }
+				
+			default:
+				if ((options & MainCmdItem.OV_WAITFORCLIENT) != 0) {
+					requestId= io.readByte();
+				}
+				throw new UnsupportedOperationException("Unknown GD command.");
+			}
+		}
+		catch (final IOException e) {
+			throw e;
+		}
+		catch (final Throwable e) {
+			log(new Status(IStatus.ERROR, RJ_CLIENT_ID, -1, "An error occurred when processing graphic command.", e));
+			if (requestId >= 0) {
+				addC2SCmd(new GDCmdItem.Answer(requestId, devId, new RjsStatus(RjsStatus.ERROR, 0)));
+			}
+//			throw new RuntimeException(e);
+		}
+	}
+	
+	
+	private final void processMainCtrlCmd(final RJIO io) throws IOException {
+		try {
+			final MainCtrlCmdItem item= new MainCtrlCmdItem(io);
+			addDataAnswer(item);
+		}
+		catch (final IOException e) {
+			throw e;
+		}
+		catch (final Exception e) {
+			log(new Status(IStatus.ERROR, RJ_CLIENT_ID, -1, "An error occurred when processing control command answer.", e));
+		}
+	}
+	
+	private final void processDataCmd(final RJIO io) throws IOException {
+		try {
+			final DataCmdItem item= new DataCmdItem(io);
+			addDataAnswer(item);
+		}
+		catch (final IOException e) {
+			throw e;
+		}
+		catch (final Exception e) {
+			log(new Status(IStatus.ERROR, RJ_CLIENT_ID, -1, "An error occurred when processing data command answer.", e));
+		}
+	}
+	
+	private final void processGraphicsOpCmd(final RJIO io) throws IOException {
+		try {
+			final GraOpCmdItem item= new GraOpCmdItem(io);
+			addDataAnswer(item);
+		}
+		catch (final IOException e) {
+			throw e;
+		}
+		catch (final Exception e) {
+			log(new Status(IStatus.ERROR, RJ_CLIENT_ID, -1, "An error occurred when processing graphic operation answer.", e));
+		}
+	}
+	
+	private final int newDataLevel() {
+		final int level= ++this.dataLevelRequest;
+		if (level >= this.dataAnswer.length) {
+			this.dataLevelRequest--;
+			throw new UnsupportedOperationException("too much nested operations");
+		}
+		this.dataLevelAnswer= 0;
+		
+		return level;
+	}
+	
+	private final MainCmdItem createDataRequestId(final int level, final MainCmdItem item) {
+		this.dataRequestId[level]= ((((0xff) & item.getCmdType()) << 24)
+				| ((0xff & item.getOp()) << 16)
+				| ((0xff & this.randomId << 8))
+				| ((0xff & ++this.dataRequestCounter)) ); 
+		item.requestId= (((0xff & level) << 24) | (0xffffff & this.dataRequestId[level]));
+		return item;
+	}
+	
+	private final void addDataAnswer(final MainCmdItem item) throws RjException {
+		final int level= (((0xff000000) & item.requestId) >>> 24);
+		if (level > 0 && level <= this.dataLevelRequest
+				&& this.dataRequestId[level] == (((0xff & item.getCmdType()) << 24)
+						| (0xffffff & item.requestId)) ) {
+			this.dataAnswer[level]= item;
+			this.dataLevelAnswer= level;
+			return;
+		}
+		if ((item.requestId & 0xff00 >>> 8) != (this.randomId & 0xff)) {
+			// other client
+//			System.out.println("Other client: " + item);
+			return;
+		}
+		throw new RjException("Unexpected server answer: " + item);
+	}
+	
+	private final void finalizeDataLevel() {
+		final int level= this.dataLevelRequest--;
+		this.dataAnswer[level]= null;
+		this.dataLevelAnswer= (this.dataAnswer[this.dataLevelRequest] != null) ? this.dataLevelRequest : 0;
+		
+		this.runFinishTask= true;
+	}
+	
+	public final int getDataLevel() {
+		return this.dataLevelRequest;
+	}
+	
+	
+	protected final void processDbgCmd(final RJIO io) throws IOException {
+		final DbgCmdItem item= new DbgCmdItem(io, this.dbgOpCustomReader);
+		if (item.getOp() > DbgCmdItem.OP_C2S_S2C) {
+			handleDbgEvent(item.getOp(), item.getData());
+		}
+		else if (this.dbgOpRequest) {
+			this.dbgOpAnswer= item;
+		}
+	}
+	
+	protected void handleDbgEvent(final byte dbgOp, final Object event) {
+	}
+	
+	
+	protected abstract void log(IStatus status);
+	
+	protected abstract void handleServerStatus(final RjsStatus serverStatus, final IProgressMonitor monitor) throws CoreException;
+	
+	protected abstract void handleStatus(Status status, IProgressMonitor monitor);
+	
+	protected void scheduleConnectionCheck() {
+	}
+	
+	
+	public final boolean runAsyncPing() {
+		try {
+			final RjsComObject answer= this.rjConsoleEngine.runAsync(RjsPing.INSTANCE);
+			if (answer instanceof RjsStatus) {
+				final RjsStatus status= (RjsStatus) answer;
+				if (status.getSeverity() == RjsStatus.OK) {
+					return true;
+				}
+				scheduleConnectionCheck();
+			}
+		}
+		catch (final ConnectException e) {
+			scheduleConnectionCheck();
+		}
+		catch (final RemoteException e) {
+			// TODO if (rmiregistry is available) scheduleCheck();
+			// no need to log here
+		}
+		catch (final Exception e) {
+		}
+		return false;
+	}
+	
+	public final boolean runAsyncInterrupt() {
+		final Callable<Boolean>[] handlers= getCancelHandlers();
+		for (int i= handlers.length - 1; i >= 0; i--) {
+			try {
+				final Boolean done= handlers[i].call();
+				if (done != null && done.booleanValue()) {
+					return false;
+				}
+			}
+			catch (final Exception e) {
+				// handler failed
+			}
+		}
+		final IProgressMonitor monitor= this.progressMonitor;
+		if (monitor != null) {
+			monitor.setCanceled(true);
+		}
+		try {
+			runAsyncCtrl(CtrlCmdItem.REQUEST_CANCEL);
+			return true;
+		}
+		catch (final CoreException e) {
+			if (e.getStatus().getSeverity() != IStatus.CANCEL) {
+				log(new Status(IStatus.ERROR, RJ_CLIENT_ID, -1, "An error occurred when trying to interrupt R.", e));
+			}
+			return false;
+		}
+	}
+	
+	public final void runAsyncCtrl(final int id) throws CoreException {
+		final RjsStatus status= (RjsStatus) runAsync(new CtrlCmdItem(id));
+		if (status.getSeverity() != RjsStatus.OK) {
+			throw new CoreException(new Status(status.getSeverity(), RJ_CLIENT_ID, status.getCode(),
+					"Executing CTRL command failed.", null));
+		}
+	}
+	
+	public final RjsComObject runAsync(final RjsComObject com) throws CoreException {
+		if (this.closed) {
+			throw new CoreException(new Status(IStatus.ERROR, RJ_CLIENT_ID, 0, this.closedMessage, null));
+		}
+		try {
+			return this.rjConsoleEngine.runAsync(com);
+		}
+		catch (final Exception e) {
+			throw new CoreException(new Status(IStatus.ERROR, RJ_CLIENT_ID, 0, "Communication error.", e));
+		}
+	}
+	
+	public final void runMainLoopPing(final IProgressMonitor monitor) throws CoreException {
+		try {
+			this.mainRunGC= false;
+			final RjsStatus status= (RjsStatus) this.rjConsoleEngine.runMainLoop(RjsPing.INSTANCE);
+			if (status.getSeverity() == RjsStatus.OK) {
+				return;
+			}
+			handleServerStatus(status, monitor);
+		}
+		catch (final ConnectException e) {
+			handleServerStatus(new RjsStatus(RjsStatus.INFO, Server.S_DISCONNECTED), monitor);
+		}
+		catch (final Exception e) {
+			// no need to log here
+			handleServerStatus(new RjsStatus(RjsStatus.INFO, Server.S_LOST), monitor);
+		}
+	}
+	
+	public final void runMainLoop(RjsComObject sendCom, MainCmdItem sendItem, final IProgressMonitor monitor) throws CoreException {
+		if (this.closed) {
+			throw new CoreException(new Status(IStatus.ERROR, RJ_CLIENT_ID, 0, this.closedMessage, null));
+		}
+		final boolean loopReadCallbackIgnore= !this.consoleReadCallbackRequired;
+		final int loopDataLevelIgnore= this.dataLevelIgnore;
+		try {
+			if ((this.extraModeRequested & EXTRA_BEFORE) != 0 && this.hotModeState < 1) {
+				this.extraModeRequested= 0;
+				this.dataLevelIgnore= this.dataLevelRequest;
+				processExtraMode(EXTRA_BEFORE);
+			}
+			while (this.hotModeRequested.get()
+					&& this.hotModeState < 1 && !this.dbgOpRequest) {
+				this.dataLevelIgnore= this.dataLevelRequest;
+				startHotMode();
+			}
+			this.progressMonitor= monitor;
+			int ok= 0;
+			while (!this.closed) {
+				try {
+					RjsComObject receivedCom= null;
+					if (sendItem != null) {
+						if (sendItem.getCmdType() == MainCmdItem.T_CONSOLE_READ_ITEM) {
+							this.consoleReadCallback= null;
+						}
+						this.mainC2SList.setObjects(sendItem);
+						sendCom= this.mainC2SList;
+						sendItem= null;
+					}
+	//				System.out.println("client *-> server: " + sendCom);
+					this.mainRunGC= false;
+					receivedCom= this.rjConsoleEngine.runMainLoop(sendCom);
+					this.mainC2SList.clear();
+					sendCom= null;
+	//				System.out.println("client *<- server: " + receivedCom);
+					switch (receivedCom.getComType()) {
+					case RjsComObject.T_PING:
+						ok= 0;
+						sendCom= RjsStatus.OK_STATUS;
+						continue;
+					case RjsComObject.T_MAIN_LIST:
+						if (this.mainDeferredCmds.isNotEmpty()) {
+							final Runnable[] runnables= this.mainDeferredCmds.consume();
+							for (int i= 0; i < runnables.length; i++) {
+								if (runnables[i] != null) {
+									try {
+										runnables[i].run();
+									}
+									catch (final Exception e) {
+										log(new Status(IStatus.ERROR, RJ_CLIENT_ID, 0,
+												"An error occurred when running a deferred command.", e ));
+									}
+								}
+							}
+						}
+						ok= 0;
+						switch (this.hotModeState) {
+						case 1:
+							sendCom= this.mainC2SList; // repeat
+							continue;
+						case 2:
+							this.hotModeState= 3;
+							this.hotModeRequested.set(false);
+							this.dataLevelIgnore= this.dataLevelRequest;
+							try {
+								processHotMode();
+								continue;
+							}
+							finally {
+								this.progressMonitor= monitor;
+								this.hotModeState= 4;
+								this.consoleReadCallback.setAnswer(RjsStatus.OK_STATUS);
+								sendItem= this.consoleReadCallback;
+							}
+						default:
+							while ((sendItem= getC2SCmds()) == null
+									&& (loopReadCallbackIgnore || this.consoleReadCallback != null)
+									&& (this.dataLevelRequest <= loopDataLevelIgnore
+											|| this.dataLevelRequest == this.dataLevelAnswer
+											|| (this.extraModeRequested & EXTRA_NESTED) != 0 )
+									&& (this.dbgOpRequest == (this.dbgOpAnswer != null))) {
+								if (this.mainRunGC) {
+									this.mainRunGC= false;
+									this.rjConsoleEngine.runMainLoop(RjsPing.INSTANCE);
+								}
+								if ((this.extraModeRequested & EXTRA_NESTED) != 0 && this.hotModeState < 1) {
+									this.extraModeRequested= 0;
+									this.dataLevelIgnore= this.dataLevelRequest;
+									try {
+										processExtraMode(EXTRA_NESTED);
+										continue; // validate again
+									}
+									finally {
+										this.progressMonitor= monitor;
+									}
+								}
+								else {
+									return; // finished
+								}
+							}
+							continue;
+						}
+					case RjsComObject.T_STATUS:
+						ok= 0;
+						processStatus((RjsStatus) receivedCom, monitor);
+						sendCom= this.mainC2SList;
+						continue;
+					}
+				}
+				catch (final ConnectException e) {
+					handleServerStatus(new RjsStatus(RjsStatus.INFO, Server.S_DISCONNECTED), monitor);
+					return;
+				}
+				catch (final RemoteException e) {
+					log(new Status(IStatus.ERROR, RJ_CLIENT_ID, -1, "Communication error detail. Send:\n"+sendCom, e));
+					if (!this.closed && runAsyncPing()) { // async to avoid server gc
+						if (this.consoleReadCallback == null && ok == 0) {
+							ok++;
+							handleStatus(new Status(IStatus.ERROR, RJ_CLIENT_ID, "Communication error, see Eclipse log for detail."), monitor);
+							continue;
+						}
+						throw new CoreException(new Status(IStatus.ERROR, RJ_CLIENT_ID, -1, "Communication error.", e));
+					}
+					handleServerStatus(new RjsStatus(RjsStatus.INFO, Server.S_LOST), monitor);
+					return;
+				}
+			}
+			
+			handleServerStatus(new RjsStatus(RjsStatus.INFO, Server.S_DISCONNECTED), monitor);
+		}
+		finally {
+			this.dataLevelIgnore= loopDataLevelIgnore;
+		}
+	}
+	
+	
+	protected final void addC2SCmd(final MainCmdItem item) {
+		if (this.mainC2SFirst == null) {
+			this.mainC2SFirst= item;
+		}
+		else {
+			item.next= this.mainC2SFirst;
+			this.mainC2SFirst= item;
+			
+			// TODO
+			log(new Status(IStatus.INFO, RJ_CLIENT_ID, "Multiple C2S items:\\" + this.mainC2SFirst.toString() + "\n" + this.mainC2SFirst.next.toString()));
+		}
+	}
+	
+	private final MainCmdItem getC2SCmds() {
+		final MainCmdItem item= this.mainC2SFirst;
+		this.mainC2SFirst= null;
+		return item;
+	}
+	
+	private final void processStatus(final RjsStatus status, final IProgressMonitor monitor)
+			throws CoreException {
+		if ((status.getCode() & 0xffffff00) == 0) {
+			handleServerStatus(status, monitor);
+			return;
+		}
+		if (status.getSeverity() != RjsStatus.OK) {
+			// TODO
+//			System.out.println(status);
+		}
+	}
+	
+	private final void processPrompt(final ConsoleReadCmdItem item) {
+		switch (item.getCmdOption() & 0xf) {
+		case 2:
+			if (this.hotModeState < 2) {
+				this.hotModeState= 2;
+				this.hotModeReadCallbackBackup= this.consoleReadCallback;
+				this.hotModeC2SFirstBackup= this.mainC2SFirst;
+				this.mainC2SFirst= null;
+			}
+			this.consoleReadCallback= item;
+			return;
+		case RjsComObject.V_TRUE:
+			this.consoleReadCallback= item;
+			updatePrompt(item.getDataText(), true);
+			return;
+		default:
+			this.consoleReadCallback= item;
+			updatePrompt(item.getDataText(), false);
+			return;
+		}
+	}
+	
+	public void requestHotMode(final boolean async) {
+		this.hotModeRequested.set(true);
+		if (async) {
+			RJHelper_EXECUTOR.schedule(this.hotModeRunnable, 100, TimeUnit.MILLISECONDS);
+		}
+	}
+	
+	public boolean startHotMode() {
+		if (this.hotModeState == 0) {
+			this.hotModeRequested.set(false);
+			final boolean savedCallbackRequired= this.consoleReadCallbackRequired;
+			this.consoleReadCallbackRequired= false;
+			try {
+				this.hotModeState= 1;
+				runMainLoop(new CtrlCmdItem(CtrlCmdItem.REQUEST_HOT_MODE), null, new NullProgressMonitor());
+				return true;
+			}
+			catch (final Throwable e) {
+				this.hotModeState= 0;
+				log(new Status(IStatus.ERROR, RJ_CLIENT_ID, 0,
+						"An error occurred when running hot mode.", e ));
+			}
+			finally {
+				this.consoleReadCallbackRequired= savedCallbackRequired;
+			}
+		}
+		return false;
+	}
+	
+	public void requestExtraMode(final int positions) {
+		this.extraModeRequested= positions;
+	}
+	
+	
+	protected void updateBusy(final boolean isBusy) {
+	}
+	
+	protected void updatePrompt(final String text, final boolean addToHistory) {
+	}
+	
+	protected void writeConsoleOutput(final byte streamId, final String text) {
+	}
+	
+	protected void showMessage(final String text) {
+	}
+	
+	protected void processHotMode() {
+	}
+	
+	protected void processExtraMode(final int i) {
+	}
+	
+	private void addGraphic(final int devId, final double w, final double h, final int canvasColor,
+			final boolean activate) throws RjException {
+		if (devId >= 0) {
+			if (devId >= this.graphics.length) {
+				final RClientGraphic[] newArray= new RClientGraphic[devId + 10];
+				System.arraycopy(this.graphics, 0, newArray, 0, this.graphics.length);
+				this.graphics= newArray;
+			}
+			final InitConfig config= new InitConfig();
+			config.canvasColor= canvasColor;
+			if (this.graphics[devId] != null) {
+				this.graphics[devId].reset(w, h, config);
+				this.graphics[devId].setActive(activate);
+			}
+			else {
+				this.graphics[devId]= this.lastGraphic= this.graphicFactory.newGraphic(devId,
+						w, h, config,
+						activate, this.graphicActions, this.currentGraphicOptions);
+			}
+			return;
+		}
+		throw new RjException("Invalid GD devId: " + devId);
+	}
+	
+	private void removeGraphic(final int devId) {
+		if (devId >= 0 && devId < this.graphics.length) {
+			if (this.graphics[devId] != null) {
+				try {
+					this.graphicFactory.closeGraphic(this.graphics[devId]);
+				}
+				catch (final Exception e) {
+					log(new Status(IStatus.ERROR, RJ_CLIENT_ID, -1,
+							"An error occurred when closing R graphic (Device " + (devId+1) + ").", e ));
+				}
+				this.graphics[devId]= null;
+			}
+		}
+	}
+	
+	protected RClientGraphic getGraphic(final int devId) {
+		if (devId >= 0 && devId < this.graphics.length) {
+			final RClientGraphic graphic= this.graphics[devId];
+			if (graphic != null) {
+				return graphic;
+			}
+		}
+		return this.graphicDummy;
+	}
+	
+	public void disposeAllGraphics() {
+		for (int devId= 0; devId < this.graphics.length; devId++) {
+			removeGraphic(devId);
+		}
+	}
+	
+	
+	public final void activateConsole() {
+		if (this.rjConsoleEngine == null) {
+			throw new IllegalStateException("Missing REngine");
+		}
+		this.consoleReadCallbackRequired= true;
+	}
+	
+	public final void answerConsole(final String input, final IProgressMonitor monitor) throws CoreException {
+		this.consoleReadCallback.setAnswer(input);
+		runMainLoop(null, this.consoleReadCallback, monitor);
+		
+		this.runFinishTask= false;
+	}
+	
+	public final boolean isConsoleReady() {
+		return (this.consoleReadCallback != null);
+	}
+	
+	
+	private Map<String, Object> getServerData() throws RemoteException {
+		if (this.platformData != null) {
+			return this.platformData;
+		}
+		final Map<String, Object> data= this.rjConsoleEngine.getPlatformData();
+		if (data != null && data.containsKey("version.string")) { //$NON-NLS-1$
+			this.platformData= data;
+		}
+		return data;
+	}
+	
+	public final RPlatform getRPlatform() {
+		synchronized (this.platformLock) {
+			if (this.platformObj == null) {
+				try {
+					final Map<String, Object> data= getServerData();
+					if (data != null && data.containsKey("version.string")) {
+						this.platformObj= new RPlatform((String) this.platformData.get("os.type"),
+								(String) this.platformData.get("file.sep"),
+								(String) this.platformData.get("path.sep"),
+								(String) this.platformData.get("version.string"),
+								(String) this.platformData.get("os.name"),
+								(String) this.platformData.get("os.arch"),
+								(String) this.platformData.get("os.version") );
+					}
+				}
+				catch (final RemoteException e) {
+					log(new Status(IStatus.ERROR, RJ_CLIENT_ID,
+							"An error occured when loading data for RPlatform information.", e));
+				}
+			}
+			return this.platformObj;
+		}
+	}
+	
+	public final String getProperty(final String key) {
+		synchronized (this.platformLock) {
+			try {
+				final Map<String, Object> data= getServerData();
+				if (data != null) {
+					final Object value= data.get(key);
+					return (value instanceof String) ? (String) value : null;
+				}
+			}
+			catch (final RemoteException e) {
+			}
+			return null;
+		}
+	}
+	
+	
+	public final void finishTask(
+			final IProgressMonitor monitor) throws CoreException {
+		if (!this.runFinishTask) {
+			return;
+		}
+		final int level= newDataLevel();
+		try {
+			runMainLoop(null, createDataRequestId(level, new MainCtrlCmdItem(MainCtrlCmdItem.OP_FINISH_TASK,
+					0 )), monitor);
+			if (this.dataAnswer[level] == null || !this.dataAnswer[level].isOK()) {
+				final RjsStatus status= (this.dataAnswer[level] != null) ? this.dataAnswer[level].getStatus() : MISSING_ANSWER_STATUS;
+				if (status.getSeverity() == RjsStatus.CANCEL) {
+					throw new CoreException(Status.CANCEL_STATUS);
+				}
+				else {
+					throw new CoreException(new Status(status.getSeverity(), RJ_CLIENT_ID, status.getCode(),
+							"Evaluation failed: " + status.getMessage(), null));
+				}
+			}
+			return;
+		}
+		finally {
+			finalizeDataLevel();
+			this.runFinishTask= false;
+		}
+	}
+	
+	
+	public boolean isValidEnvir(final RObject envir) {
+		switch (envir.getRObjectType()) {
+		case RObject.TYPE_REFERENCE:
+			return (((RReference) envir).getReferencedRObjectType() == RObject.TYPE_ENVIRONMENT);
+		case RObject.TYPE_LANGUAGE:
+			return true;
+		default:
+			return false;
+		}
+	}
+	
+	public final void evalVoid(final String expression, final RObject envir,
+			final IProgressMonitor monitor) throws CoreException {
+		if (expression == null) {
+			throw new NullPointerException("expression");
+		}
+		if (envir != null && !isValidEnvir(envir)) {
+			throw new IllegalArgumentException("envir");
+		}
+		final int level= newDataLevel();
+		try {
+			runMainLoop(null, createDataRequestId(level, new DataCmdItem(DataCmdItem.EVAL_EXPR_VOID,
+					0, expression, null, null, envir )), monitor);
+			if (this.dataAnswer[level] == null || !this.dataAnswer[level].isOK()) {
+				final RjsStatus status= (this.dataAnswer[level] != null) ? this.dataAnswer[level].getStatus() : MISSING_ANSWER_STATUS;
+				if (status.getSeverity() == RjsStatus.CANCEL) {
+					throw new CoreException(Status.CANCEL_STATUS);
+				}
+				else {
+					throw new CoreException(new Status(status.getSeverity(), RJ_CLIENT_ID, status.getCode(),
+							"Evaluation failed: " + status.getMessage(), null));
+				}
+			}
+			return;
+		}
+		finally {
+			finalizeDataLevel();
+		}
+	}
+	
+	public final void evalVoid(final String name, final RList args, final RObject envir,
+			final IProgressMonitor monitor) throws CoreException {
+		if (name == null) {
+			throw new NullPointerException("name");
+		}
+		if (args == null) {
+			throw new NullPointerException("args");
+		}
+		if (envir != null && !isValidEnvir(envir)) {
+			throw new IllegalArgumentException("envir");
+		}
+		final int level= newDataLevel();
+		try {
+			runMainLoop(null, createDataRequestId(level, new DataCmdItem(DataCmdItem.EVAL_FCALL_VOID,
+					0, name, args, null, envir )), monitor );
+			if (this.dataAnswer[level] == null || !this.dataAnswer[level].isOK()) {
+				final RjsStatus status= (this.dataAnswer[level] != null) ? this.dataAnswer[level].getStatus() : MISSING_ANSWER_STATUS;
+				if (status.getSeverity() == RjsStatus.CANCEL) {
+					throw new CoreException(Status.CANCEL_STATUS);
+				}
+				else {
+					throw new CoreException(new Status(status.getSeverity(), RJ_CLIENT_ID, status.getCode(),
+							"Evaluation failed: " + status.getMessage(), null));
+				}
+			}
+			return;
+		}
+		finally {
+			finalizeDataLevel();
+		}
+	}
+	
+	public RObject evalData(final String expression, final RObject envir,
+			final String factoryId, final int options, final int depth,
+			final IProgressMonitor monitor) throws CoreException {
+		if (expression == null) {
+			throw new NullPointerException("expression");
+		}
+		if (envir != null && !isValidEnvir(envir)) {
+			throw new IllegalArgumentException("envir");
+		}
+		final byte checkedDepth= (depth < Byte.MAX_VALUE) ? (byte) depth : Byte.MAX_VALUE;
+		final int level= newDataLevel();
+		try {
+			runMainLoop(null, createDataRequestId(level, new DataCmdItem(DataCmdItem.EVAL_EXPR_DATA,
+					options, checkedDepth, expression, null, null, envir, factoryId )), monitor);
+			if (this.dataAnswer[level] == null || !this.dataAnswer[level].isOK()) {
+				final RjsStatus status= (this.dataAnswer[level] != null) ? this.dataAnswer[level].getStatus() : MISSING_ANSWER_STATUS;
+				if (status.getSeverity() == RjsStatus.CANCEL) {
+					throw new CoreException(Status.CANCEL_STATUS);
+				}
+				else {
+					throw new CoreException(new Status(status.getSeverity(), RJ_CLIENT_ID, status.getCode(),
+							"Evaluation failed: " + status.getMessage(), null));
+				}
+			}
+			return ((DataCmdItem) this.dataAnswer[level]).getData();
+		}
+		finally {
+			finalizeDataLevel();
+		}
+	}
+	
+	public RObject evalData(final String name, final RObject args, final RObject envir,
+			final String factoryId, final int options, final int depth,
+			final IProgressMonitor monitor) throws CoreException {
+		if (name == null) {
+			throw new NullPointerException("name");
+		}
+		if (args == null) {
+			throw new NullPointerException("args");
+		}
+		if (envir != null && !isValidEnvir(envir)) {
+			throw new IllegalArgumentException("envir");
+		}
+		final byte checkedDepth= (depth < Byte.MAX_VALUE) ? (byte) depth : Byte.MAX_VALUE;
+		final int level= newDataLevel();
+		try {
+			runMainLoop(null, createDataRequestId(level, new DataCmdItem(DataCmdItem.EVAL_FCALL_DATA,
+					options, checkedDepth, name, args, null, envir, factoryId )), monitor );
+			if (this.dataAnswer[level] == null || !this.dataAnswer[level].isOK()) {
+				final RjsStatus status= (this.dataAnswer[level] != null) ? this.dataAnswer[level].getStatus() : MISSING_ANSWER_STATUS;
+				if (status.getSeverity() == RjsStatus.CANCEL) {
+					throw new CoreException(Status.CANCEL_STATUS);
+				}
+				else {
+					throw new CoreException(new Status(status.getSeverity(), RJ_CLIENT_ID, status.getCode(),
+							"Evaluation failed: " + status.getMessage(), null));
+				}
+			}
+			return ((DataCmdItem) this.dataAnswer[level]).getData();
+		}
+		finally {
+			finalizeDataLevel();
+		}
+	}
+	
+	public final RObject evalData(final RReference reference,
+			final String factoryId, final int options, final int depth,
+			final IProgressMonitor monitor) throws CoreException {
+		final byte checkedDepth= (depth < Byte.MAX_VALUE) ? (byte) depth : Byte.MAX_VALUE;
+		final int level= newDataLevel();
+		try {
+			final long handle= reference.getHandle();
+			runMainLoop(null, createDataRequestId(level, new DataCmdItem(DataCmdItem.RESOLVE_DATA,
+					options, checkedDepth, Long.toString(handle), null, null, null, factoryId )), monitor );
+			
+			if (this.dataAnswer[level] == null || !this.dataAnswer[level].isOK()) {
+				final RjsStatus status= (this.dataAnswer[level] != null) ? this.dataAnswer[level].getStatus() : MISSING_ANSWER_STATUS;
+				if (status.getSeverity() == RjsStatus.CANCEL) {
+					throw new CoreException(Status.CANCEL_STATUS);
+				}
+				else {
+					throw new CoreException(new Status(status.getSeverity(), RJ_CLIENT_ID, status.getCode(),
+							"Evaluation failed: " + status.getMessage(), null));
+				}
+			}
+			return ((DataCmdItem) this.dataAnswer[level]).getData();
+		}
+		finally {
+			finalizeDataLevel();
+		}
+	}
+	
+	public RObject evalData(final byte envType, final String name,
+			final String factoryId, final int options, final int depth,
+			final IProgressMonitor monitor) throws CoreException {
+		if (name == null) {
+			throw new NullPointerException("name");
+		}
+		final Operation operation;
+		switch (envType) {
+		case REnvironment.ENVTYPE_NAMESPACE:
+			operation= DataCmdItem.EVAL_NAMESPACE_DATA;
+			break;
+		case REnvironment.ENVTYPE_NAMESPACE_EXPORTS:
+			operation= DataCmdItem.EVAL_NAMESPACE_EXPORTS_DATA;
+			break;
+		default:
+			throw new IllegalArgumentException("envType= " + envType);
+		}
+		
+		final byte checkedDepth= (depth < Byte.MAX_VALUE) ? (byte) depth : Byte.MAX_VALUE;
+		final int level= newDataLevel();
+		try {
+			runMainLoop(null, createDataRequestId(level, new DataCmdItem(operation,
+					options, checkedDepth,
+					name, null, null, null, factoryId )), monitor );
+			
+			if (this.dataAnswer[level] == null || !this.dataAnswer[level].isOK()) {
+				final RjsStatus status= (this.dataAnswer[level] != null) ? this.dataAnswer[level].getStatus() : MISSING_ANSWER_STATUS;
+				if (status.getSeverity() == RjsStatus.CANCEL) {
+					throw new CoreException(Status.CANCEL_STATUS);
+				}
+				else {
+					throw new CoreException(new Status(status.getSeverity(), RJ_CLIENT_ID, status.getCode(),
+							"Evaluation failed: " + status.getMessage(), null));
+				}
+			}
+			return ((DataCmdItem) this.dataAnswer[level]).getData();
+		}
+		finally {
+			finalizeDataLevel();
+		}
+	}
+	
+	public final void assignData(final String expression, final RObject data, final RObject envir,
+			final IProgressMonitor monitor) throws CoreException {
+		if (expression == null) {
+			throw new NullPointerException("expression");
+		}
+		if (data == null) {
+			throw new NullPointerException("data");
+		}
+		if (envir != null && !isValidEnvir(envir)) {
+			throw new IllegalArgumentException("envir");
+		}
+		final int level= newDataLevel();
+		try {
+			runMainLoop(null, createDataRequestId(level, new DataCmdItem(DataCmdItem.ASSIGN_DATA,
+					0, null, data, expression, envir )), monitor );
+			if (this.dataAnswer[level] == null || !this.dataAnswer[level].isOK()) {
+				final RjsStatus status= (this.dataAnswer[level] != null) ? this.dataAnswer[level].getStatus() : MISSING_ANSWER_STATUS;
+				if (status.getSeverity() == RjsStatus.CANCEL) {
+					throw new CoreException(Status.CANCEL_STATUS);
+				}
+				else {
+					throw new CoreException(new Status(status.getSeverity(), RJ_CLIENT_ID, status.getCode(),
+							"Assignment failed: " + status.getMessage(), null));
+				}
+			}
+			return;
+		}
+		finally {
+			finalizeDataLevel();
+		}
+	}
+	
+	public final void assignData(final String name, final RObject args, final String expression,
+			final RObject envir,
+			final IProgressMonitor monitor) throws CoreException {
+		if (name == null) {
+			throw new NullPointerException("name");
+		}
+		if (args == null) {
+			throw new NullPointerException("args");
+		}
+		if (expression == null) {
+			throw new NullPointerException("expression");
+		}
+		if (envir != null && !isValidEnvir(envir)) {
+			throw new IllegalArgumentException("envir");
+		}
+		final int level= newDataLevel();
+		try {
+			runMainLoop(null, createDataRequestId(level, new DataCmdItem(DataCmdItem.ASSIGN_FCALL,
+					0, name, args, expression, envir )), monitor );
+			if (this.dataAnswer[level] == null || !this.dataAnswer[level].isOK()) {
+				final RjsStatus status= (this.dataAnswer[level] != null) ? this.dataAnswer[level].getStatus() : MISSING_ANSWER_STATUS;
+				if (status.getSeverity() == RjsStatus.CANCEL) {
+					throw new CoreException(Status.CANCEL_STATUS);
+				}
+				else {
+					throw new CoreException(new Status(status.getSeverity(), RJ_CLIENT_ID, status.getCode(),
+							"Assignment failed: " + status.getMessage(), null));
+				}
+			}
+			return;
+		}
+		finally {
+			finalizeDataLevel();
+		}
+	}
+	
+	public RObject[] findData(final String symbol, final RObject envir, final boolean inherits,
+			final String factoryId, final int options, final int depth,
+			final IProgressMonitor monitor) throws CoreException {
+		if (symbol == null) {
+			throw new NullPointerException("symbol");
+		}
+		final byte checkedDepth= (depth < Byte.MAX_VALUE) ? (byte) depth : Byte.MAX_VALUE;
+		final int level= newDataLevel();
+		try {
+			runMainLoop(null, createDataRequestId(level, new DataCmdItem(DataCmdItem.FIND_DATA,
+					(inherits) ? (options | 0x1000) : options, checkedDepth,
+					symbol, null, null, envir, factoryId )), monitor );
+			if (this.dataAnswer[level] == null || !this.dataAnswer[level].isOK()) {
+				final RjsStatus status= (this.dataAnswer[level] != null) ? this.dataAnswer[level].getStatus() : MISSING_ANSWER_STATUS;
+				if (status.getSeverity() == RjsStatus.CANCEL) {
+					throw new CoreException(Status.CANCEL_STATUS);
+				}
+				else {
+					throw new CoreException(new Status(status.getSeverity(), RJ_CLIENT_ID, status.getCode(),
+							"Evaluation failed: " + status.getMessage(), null));
+				}
+			}
+			final DataCmdItem dataItem= (DataCmdItem) this.dataAnswer[level];
+			return (dataItem.getRho() != null) ?
+					new RObject[] { dataItem.getData(), dataItem.getRho() } :
+					null;
+		}
+		finally {
+			finalizeDataLevel();
+		}
+	}
+	
+	
+	public void downloadFile(final OutputStream out, final String fileName, final int options, final IProgressMonitor monitor) throws CoreException {
+		final BinExchange request= new BinExchange(out, fileName, this.rjConsoleEngine, options);
+		final BinExchange answer;
+		try {
+			answer= (BinExchange) runAsync(request);
+		}
+		finally {
+			request.clear();
+		}
+		if (answer == null || !answer.isOK()) {
+			final RjsStatus status= (answer != null) ? answer.getStatus() : MISSING_ANSWER_STATUS;
+			if (status.getSeverity() == RjsStatus.CANCEL) {
+				throw new CoreException(Status.CANCEL_STATUS);
+			}
+			else {
+				throw new CoreException(new Status(status.getSeverity(), RJ_CLIENT_ID, status.getCode(),
+						"Downloading file failed: " + status.getMessage(), null));
+			}
+		}
+	}
+	
+	public byte[] downloadFile(final String fileName, final int options, final IProgressMonitor monitor) throws CoreException {
+		final BinExchange request= new BinExchange(fileName, this.rjConsoleEngine, options);
+		final BinExchange answer;
+		try {
+			answer= (BinExchange) runAsync(request);
+		}
+		finally {
+			request.clear();
+		}
+		if (answer == null || !answer.isOK()) {
+			final RjsStatus status= (answer != null) ? answer.getStatus() : MISSING_ANSWER_STATUS;
+			if (status.getSeverity() == RjsStatus.CANCEL) {
+				throw new CoreException(Status.CANCEL_STATUS);
+			}
+			else {
+				throw new CoreException(new Status(status.getSeverity(), RJ_CLIENT_ID, status.getCode(),
+						"Downloading file failed: " + status.getMessage(), null));
+			}
+		}
+		return answer.getBytes();
+	}
+	
+	public void uploadFile(final InputStream in, final long length, final String fileName, final int options, final IProgressMonitor monitor) throws CoreException {
+		final BinExchange request= new BinExchange(in, length, fileName, this.rjConsoleEngine, options);
+		final BinExchange answer;
+		try {
+			answer= (BinExchange) runAsync(request);
+		}
+		finally {
+			request.clear();
+		}
+		if (answer == null || !answer.isOK()) {
+			final RjsStatus status= (answer != null) ? answer.getStatus() : MISSING_ANSWER_STATUS;
+			if (status.getSeverity() == RjsStatus.CANCEL) {
+				throw new CoreException(Status.CANCEL_STATUS);
+			}
+			else {
+				throw new CoreException(new Status(status.getSeverity(), RJ_CLIENT_ID, status.getCode(),
+						"Uploading file failed: " + status.getMessage(), null));
+			}
+		}
+	}
+	
+	
+	public Object execSyncDbgOp(final byte dbgOp, final RJIOExternalizable request,
+			final IProgressMonitor monitor) throws CoreException {
+		if (this.dbgOpRequest) {
+			throw new IllegalStateException();
+		}
+		this.dbgOpRequest= true;
+		try {
+			runMainLoop(null, new DbgCmdItem(dbgOp, 0, request), monitor);
+			if (this.dbgOpAnswer == null || !this.dbgOpAnswer.isOK()) {
+				final RjsStatus status= (this.dbgOpAnswer != null) ? this.dbgOpAnswer.getStatus() : MISSING_ANSWER_STATUS;
+				if (status.getSeverity() == RjsStatus.CANCEL) {
+					throw new CoreException(Status.CANCEL_STATUS);
+				}
+				else {
+					throw new CoreException(new Status(status.getSeverity(), RJ_CLIENT_ID, status.getCode(),
+							"Dbg operation failed: " + status.getMessage(), null));
+				}
+			}
+			{	final Object data= this.dbgOpAnswer.getData();
+				if (data instanceof CtrlReport) {
+					final CtrlReport report= (CtrlReport) data;
+					if (!report.isEngineSuspended()) {
+						this.consoleReadCallback= null;
+					}
+				}
+				return data;
+			}
+		}
+		finally {
+			this.dbgOpRequest= false;
+			this.dbgOpAnswer= null;
+		}
+	}
+	
+	public void execAsyncDbgOp(final byte op, final RJIOExternalizable request)
+			throws CoreException {
+		execAsync(new Runnable() {
+			@Override
+			public void run() {
+				try {
+					runAsync(new DbgCmdItem(op, 0, request));
+					// in future check returned status if required
+				}
+				catch (final CoreException e) {
+					log(new Status(IStatus.ERROR, RJ_CLIENT_ID, -1,
+							"An error occurred when executing background dbg operation.", e));
+				}
+			}
+		});
+	}
+	
+	
+	public int getGraphicOptions() {
+		return this.currentGraphicOptions;
+	}
+	
+	public void setGraphicOptions(final int options) {
+		this.currentGraphicOptions= options;
+		this.lastGraphic= null;
+	}
+	
+	public RClientGraphic getLastGraphic() {
+		return this.lastGraphic;
+	}
+	
+	public Object execSyncGraphicOp(final int devId, final byte op,
+			final IProgressMonitor monitor) throws CoreException {
+		final int level= newDataLevel();
+		try {
+			runMainLoop(null, createDataRequestId(level, new GraOpCmdItem(devId, op)),
+					monitor );
+			if (this.dataAnswer[level] == null || !this.dataAnswer[level].isOK()) {
+				final RjsStatus status= (this.dataAnswer[level] != null) ? this.dataAnswer[level].getStatus() : MISSING_ANSWER_STATUS;
+				if (status.getSeverity() == RjsStatus.CANCEL) {
+					throw new CoreException(Status.CANCEL_STATUS);
+				}
+				else {
+					throw new CoreException(new Status(status.getSeverity(), RJ_CLIENT_ID, status.getCode(),
+							"Graphics operation failed: " + status.getMessage(), null));
+				}
+			}
+			return ((GraOpCmdItem) this.dataAnswer[level]).getData();
+		}
+		finally {
+			finalizeDataLevel();
+		}
+	}
+	
+	public Object execSyncGraphicOp(final int devId, final byte op, final RJIOExternalizable data,
+			final IProgressMonitor monitor) throws CoreException {
+		final int level= newDataLevel();
+		try {
+			runMainLoop(null, createDataRequestId(level, new GraOpCmdItem(devId, op, data)),
+					monitor );
+			if (this.dataAnswer[level] == null || !this.dataAnswer[level].isOK()) {
+				final RjsStatus status= (this.dataAnswer[level] != null) ? this.dataAnswer[level].getStatus() : MISSING_ANSWER_STATUS;
+				if (status.getSeverity() == RjsStatus.CANCEL) {
+					throw new CoreException(Status.CANCEL_STATUS);
+				}
+				else {
+					throw new CoreException(new Status(status.getSeverity(), RJ_CLIENT_ID, status.getCode(),
+							"Graphics operation failed: " + status.getMessage(), null));
+				}
+			}
+			return ((GraOpCmdItem) this.dataAnswer[level]).getData();
+		}
+		finally {
+			finalizeDataLevel();
+		}
+	}
+	
+	
+	public void addCancelHandler(final Callable<Boolean> handler) {
+		synchronized (this.cancelHandler) {
+			this.cancelHandler.add(handler);
+		}
+	}
+	
+	public void removeCancelHandler(final Callable<Boolean> handler) {
+		synchronized (this.cancelHandler) {
+			final int idx= this.cancelHandler.lastIndexOf(handler);
+			if (idx >= 0) {
+				this.cancelHandler.remove(idx);
+			}
+		}
+	}
+	
+	protected Callable<Boolean>[] getCancelHandlers() {
+		synchronized (this.cancelHandler) {
+			return this.cancelHandler.toArray(new Callable[this.cancelHandler.size()]);
+		}
+	}
+	
+	public Lock getWaitLock() {
+		return this.clientWaitLock;
+	}
+	
+	public void waitingForUser() {
+		if (this.hotModeRequested.get()) {
+			this.clientWaitLock.unlock();
+			try {
+				startHotMode();
+			}
+			finally {
+				this.clientWaitLock.lock();
+			}
+			return;
+		}
+		
+		try {
+			this.clientWaitCondition.awaitNanos(1000 * 100);
+		}
+		catch (final InterruptedException e1) {
+		}
+	}
+	
+	public void resume() {
+		this.clientWaitCondition.signal();
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.client/src/org/eclipse/statet/rj/server/client/AbstractRJComClientGraphicActions.java b/core/org.eclipse.statet.rj.client/src/org/eclipse/statet/rj/server/client/AbstractRJComClientGraphicActions.java
new file mode 100644
index 0000000..729842d
--- /dev/null
+++ b/core/org.eclipse.statet.rj.client/src/org/eclipse/statet/rj/server/client/AbstractRJComClientGraphicActions.java
@@ -0,0 +1,109 @@
+/*=============================================================================#
+ # Copyright (c) 2011, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server.client;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+
+import org.eclipse.statet.rj.server.gr.Coord;
+import org.eclipse.statet.rj.server.gr.GraOp;
+
+
+public abstract class AbstractRJComClientGraphicActions implements RClientGraphicActions {
+	
+	
+	public static interface Factory {
+		
+		
+		AbstractRJComClientGraphicActions create(AbstractRJComClient rjs, Object rHandle);
+		
+	}
+	
+	
+	protected final AbstractRJComClient rjs;
+	
+	
+	protected AbstractRJComClientGraphicActions(final AbstractRJComClient rjs) {
+		if (rjs == null) {
+			throw new NullPointerException("rjs");
+		}
+		this.rjs= rjs;
+	}
+	
+	
+	public void doResizeGraphic(final int devId,
+			final IProgressMonitor monitor) throws CoreException {
+		this.rjs.execSyncGraphicOp(devId, GraOp.OP_REQUEST_RESIZE, monitor);
+	}
+	
+	public void doCloseGraphic(final int devId,
+			final IProgressMonitor monitor) throws CoreException {
+		this.rjs.execSyncGraphicOp(devId, GraOp.OP_CLOSE, monitor);
+	}
+	
+	
+	@Override
+	public void copy(final int devId, final String toDev, final String toDevFile, final String toDevArgs,
+			final IProgressMonitor monitor) throws CoreException {
+		final StringBuilder sb= new StringBuilder(64);
+		sb.append("rj.gd::.rj.copyGD(");
+		sb.append("devNr=").append((devId + 1)).append("L,");
+		sb.append("device=").append(toDev).append(",");
+		if (toDevFile != null) {
+			sb.append("file=\"").append(toDevFile).append("\",");
+		}
+		if (toDevArgs != null && toDevArgs.length() > 0) {
+			sb.append(toDevArgs);
+			sb.append(",");
+		}
+		sb.replace(sb.length()-1, sb.length(), ")");
+		this.rjs.evalVoid(sb.toString(), null, monitor);
+	}
+	
+	@Override
+	public double[] convertGraphic2User(final int devId, final double[] xy,
+			final IProgressMonitor monitor) throws CoreException {
+		if (xy == null) {
+			throw new NullPointerException("xy");
+		}
+		if (xy.length != 2) {
+			throw new IllegalArgumentException("length of xy");
+		}
+		final Coord coord= (Coord) this.rjs.execSyncGraphicOp(devId, GraOp.OP_CONVERT_DEV2USER,
+				new Coord(xy[0], xy[1]), monitor );
+		if (coord != null && !Double.isNaN(coord.getX()) && !Double.isNaN(coord.getY())) {
+			return new double[] { coord.getX(), coord.getY() };
+		}
+		return null;
+	}
+	
+	@Override
+	public double[] convertUser2Graphic(final int devId, final double[] xy,
+			final IProgressMonitor monitor) throws CoreException {
+		if (xy == null) {
+			throw new NullPointerException("xy");
+		}
+		if (xy.length != 2) {
+			throw new IllegalArgumentException("length of xy");
+		}
+		final Coord coord= (Coord) this.rjs.execSyncGraphicOp(devId, GraOp.OP_CONVERT_USER2DEV,
+				new Coord(xy[0], xy[1]), monitor );
+		if (coord != null && !Double.isNaN(coord.getX()) && !Double.isNaN(coord.getY())) {
+			return new double[] { coord.getX(), coord.getY() };
+		}
+		return null;
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.client/src/org/eclipse/statet/rj/server/client/DaemonThreadFactory.java b/core/org.eclipse.statet.rj.client/src/org/eclipse/statet/rj/server/client/DaemonThreadFactory.java
new file mode 100644
index 0000000..fd28741
--- /dev/null
+++ b/core/org.eclipse.statet.rj.client/src/org/eclipse/statet/rj/server/client/DaemonThreadFactory.java
@@ -0,0 +1,44 @@
+/*=============================================================================#
+ # Copyright (c) 2010, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server.client;
+
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.atomic.AtomicInteger;
+
+
+class DaemonThreadFactory implements ThreadFactory {
+	
+	
+	final AtomicInteger threadNumber= new AtomicInteger(1);
+	final String namePrefix;
+	final String nameSuffix= "]";
+	
+	
+	public DaemonThreadFactory(final String name) {
+		this.namePrefix= name + " [Thread-";
+	}
+	
+	
+	@Override
+	public Thread newThread(final Runnable r) {
+		final Thread t= new Thread(r,
+				this.namePrefix + this.threadNumber.getAndIncrement() + this.nameSuffix);
+		
+		t.setDaemon(true);
+		t.setPriority(Thread.NORM_PRIORITY);
+		return t;
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.client/src/org/eclipse/statet/rj/server/client/FunctionCallImpl.java b/core/org.eclipse.statet.rj.client/src/org/eclipse/statet/rj/server/client/FunctionCallImpl.java
new file mode 100644
index 0000000..3ca3cbb
--- /dev/null
+++ b/core/org.eclipse.statet.rj.client/src/org/eclipse/statet/rj/server/client/FunctionCallImpl.java
@@ -0,0 +1,242 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server.client;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+
+import org.eclipse.statet.rj.data.RList;
+import org.eclipse.statet.rj.data.RObject;
+import org.eclipse.statet.rj.data.RObjectFactory;
+import org.eclipse.statet.rj.data.impl.RLanguageImpl;
+import org.eclipse.statet.rj.data.impl.RNullImpl;
+import org.eclipse.statet.rj.services.FunctionCall;
+import org.eclipse.statet.rj.services.RService;
+
+
+public class FunctionCallImpl implements FunctionCall {
+	
+	
+	private final String name;
+	
+	private final List<String> argNames= new ArrayList<>();
+	private final List<RObject> argValues= new ArrayList<>();
+	
+	private final AbstractRJComClient rjs;
+	private final RObjectFactory rObjectFactory;
+	
+	
+	public FunctionCallImpl(final AbstractRJComClient client, final String name,
+			final RObjectFactory rObjectFactory) {
+		this.rjs= client;
+		this.rObjectFactory= rObjectFactory;
+		this.name= name;
+	}
+	
+	
+	@Override
+	public FunctionCall add(final String arg, final String expression) {
+		if (expression == null) {
+			throw new NullPointerException();
+		}
+		this.argNames.add(arg);
+		final RObject data= new RLanguageImpl((byte) 0, expression, null);
+		this.argValues.add(data);
+		return this;
+	}
+	
+	@Override
+	public FunctionCall add(final String expression) {
+		return this.add(null, expression);
+	}
+	
+	@Override
+	public FunctionCall add(final String arg, final RObject data) {
+		if (data == null) {
+			throw new NullPointerException();
+		}
+		this.argNames.add(arg);
+		this.argValues.add(data);
+		return this;
+	}
+	
+	@Override
+	public FunctionCall add(final RObject data) {
+		return this.add(null, data);
+	}
+	
+	@Override
+	public FunctionCall addLogi(final String arg, final boolean logical) {
+		final RObject data= this.rObjectFactory.createVector(
+				this.rObjectFactory.createLogiData(new boolean[] { logical }) );
+		this.argNames.add(arg);
+		this.argValues.add(data);
+		return this;
+	}
+	
+	@Override
+	public FunctionCall addLogi(final boolean logical) {
+		return addLogi(null, logical);
+	}
+	
+	@Override
+	public FunctionCall addInt(final String arg, final int integer) {
+		final RObject data= this.rObjectFactory.createVector(
+				this.rObjectFactory.createIntData(new int[] { integer }) );
+		this.argNames.add(arg);
+		this.argValues.add(data);
+		return this;
+	}
+	
+	@Override
+	public FunctionCall addInt(final int integer) {
+		return addInt(null, integer);
+	}
+	
+	@Override
+	public FunctionCall addNum(final String arg, final double numeric) {
+		final RObject data= this.rObjectFactory.createVector(
+				this.rObjectFactory.createNumData(new double[] { numeric }) );
+		this.argNames.add(arg);
+		this.argValues.add(data);
+		return this;
+	}
+	
+	@Override
+	public FunctionCall addNum(final double numeric) {
+		return this.addNum(null, numeric);
+	}
+	
+	@Override
+	public FunctionCall addChar(final String arg, final String character) {
+		final RObject data= this.rObjectFactory.createVector(
+				this.rObjectFactory.createCharData(new String[] { character }));
+		this.argNames.add(arg);
+		this.argValues.add(data);
+		return this;
+	}
+	
+	@Override
+	public FunctionCall addChar(final String character) {
+		return this.addChar(null, character);
+	}
+	
+	@Override
+	public FunctionCall addCplx(final String arg, final double real, final double imaginary) {
+		final RObject data= this.rObjectFactory.createVector(
+				this.rObjectFactory.createCplxData(new double[] { real }, new double[] {imaginary }) );
+		this.argNames.add(arg);
+		this.argValues.add(data);
+		return this;
+	}
+	
+	@Override
+	public FunctionCall addCplx(final double real, final double imaginary) {
+		return addCplx(null, real, imaginary);
+	}
+	
+	@Override
+	public FunctionCall addNull(final String arg) {
+		this.argNames.add(arg);
+		this.argValues.add(RNullImpl.INSTANCE);
+		return this;
+	}
+	
+	@Override
+	public FunctionCall addNull() {
+		return this.addNull(null);
+	}
+	
+	
+	private RList prepareArgs(final IProgressMonitor monitor) throws CoreException {
+		// TODO step by step upload for large objects
+		final String[] names= this.argNames.toArray(new String[this.argNames.size()]);
+		final RObject[] values= this.argValues.toArray(new RObject[this.argValues.size()]);
+		assert (names.length == values.length);
+		return this.rObjectFactory.createList(values, names);
+	}
+	
+	@Override
+	public void evalVoid(final IProgressMonitor monitor) throws CoreException {
+		final RList args= prepareArgs(monitor);
+		this.rjs.evalVoid(this.name, args, null, monitor);
+	}
+	
+	@Override
+	public void evalVoid(final RObject envir, final IProgressMonitor monitor) throws CoreException {
+		final RList args= prepareArgs(monitor);
+		this.rjs.evalVoid(this.name, args, envir, monitor);
+	}
+	
+	@Override
+	public RObject evalData(final IProgressMonitor monitor) throws CoreException {
+		final RList args= prepareArgs(monitor);
+		return this.rjs.evalData(this.name, args, null, null, 0, RService.DEPTH_INFINITE, monitor);
+	}
+	
+	@Override
+	public RObject evalData(final String factoryId, final int options, final int depth,
+			final IProgressMonitor monitor) throws CoreException {
+		final RList args= prepareArgs(monitor);
+		return this.rjs.evalData(this.name, args, null, factoryId, options, depth, monitor);
+	}
+	
+	@Override
+	public RObject evalData(final RObject envir,
+			final String factoryId, final int options, final int depth,
+			final IProgressMonitor monitor) throws CoreException {
+		final RList args= prepareArgs(monitor);
+		return this.rjs.evalData(this.name, args, envir, factoryId, options, depth, monitor);
+	}
+	
+	@Override
+	public void evalAssign(final String target, final IProgressMonitor monitor) throws CoreException {
+		final RList args= prepareArgs(monitor);
+		this.rjs.assignData(this.name, args, target, null, monitor);
+	}
+	
+	@Override
+	public String toString() {
+		final StringBuilder call= new StringBuilder();
+		call.append(this.name);
+		call.append('(');
+		if (this.argNames.size() > 0) {
+			for (int i= 0; i < this.argNames.size(); i++) {
+				final String argName= this.argNames.get(i);
+				if (argName != null) {
+					call.append('\n');
+					call.append(argName);
+					call.append("= "); //$NON-NLS-1$
+				}
+				final Object value= this.argValues.get(i);
+				if (value instanceof String) {
+					call.append((String) value);
+				}
+				else if (value instanceof RObject) {
+					call.append("\n<DATA>\n"); //$NON-NLS-1$
+					call.append(value.toString());
+					call.append("\n</DATA>"); //$NON-NLS-1$
+				}
+			}
+			call.append("\n"); //$NON-NLS-1$
+		}
+		call.append(')');
+		return call.toString();
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.client/src/org/eclipse/statet/rj/server/client/RClientGraphic.java b/core/org.eclipse.statet.rj.client/src/org/eclipse/statet/rj/server/client/RClientGraphic.java
new file mode 100644
index 0000000..18beaab
--- /dev/null
+++ b/core/org.eclipse.statet.rj.client/src/org/eclipse/statet/rj/server/client/RClientGraphic.java
@@ -0,0 +1,182 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server.client;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+
+import org.eclipse.statet.rj.graphic.core.RCircle;
+import org.eclipse.statet.rj.graphic.core.RClipSetting;
+import org.eclipse.statet.rj.graphic.core.RColorSetting;
+import org.eclipse.statet.rj.graphic.core.RFillSetting;
+import org.eclipse.statet.rj.graphic.core.RFontSetting;
+import org.eclipse.statet.rj.graphic.core.RLine;
+import org.eclipse.statet.rj.graphic.core.RLineSetting;
+import org.eclipse.statet.rj.graphic.core.RPath;
+import org.eclipse.statet.rj.graphic.core.RPolygon;
+import org.eclipse.statet.rj.graphic.core.RPolyline;
+import org.eclipse.statet.rj.graphic.core.RRaster;
+import org.eclipse.statet.rj.graphic.core.RRect;
+import org.eclipse.statet.rj.graphic.core.RText;
+import org.eclipse.statet.rj.services.RService;
+
+
+/**
+ * Interface for the R side of (RJ) graphics at client layer.
+ * 
+ * The methods are called by the client protocol handler
+ * (e.g. {@link AbstractRJComClient}) and must not be called at
+ * another place.
+ */
+public interface RClientGraphic {
+	
+	
+	class InitConfig {
+		
+		public int canvasColor;
+		
+	}
+	
+	
+	/**
+	 * Mask for fill rule
+	 * <ul>
+	 *   <li>{@link #FILL_WIND_EVEN_ODD}</li>
+	 *   <li>{@link #FILL_WIND_NON_ZERO}</li>
+	 * </ul>
+	 * 
+	 * @since 2.0
+	 */
+	int MASK_FILL_RULE= 0x3;
+	
+	/**
+	 * Constant for "even-odd" winding rule for filling elements
+	 * 
+	 * @since 2.0
+	 */
+	int FILL_WIND_EVEN_ODD= 0x0;
+	
+	/**
+	 * Constant for "non-zero" winding rule for filling elements
+	 * 
+	 * @since 2.0
+	 */
+	int FILL_WIND_NON_ZERO= 0x1;
+	
+	
+	/**
+	 * Returns the device id of R
+	 * 
+	 * @return the id
+	 */
+	int getDevId();
+	
+	/**
+	 * 
+	 * @param w the width of the graphic
+	 * @param h the height of the graphic
+	 * @param config initialization configuration
+	 */
+	void reset(double w, double h, InitConfig config);
+	
+	/**
+	 * Sets if the graphic is the active device in R.
+	 * 
+	 * @param active <code>true</code> if active, otherwise <code>false</code>
+	 */
+	void setActive(boolean active);
+	
+	/**
+	 * Returns if the graphic is the active device in R.
+	 * 
+	 * @return <code>true</code> if active, otherwise <code>false</code>
+	 */
+	boolean isActive();
+	
+	/**
+	 * Sets the current mode signaled by R.
+	 * <p>
+	 * Values:
+	 *     0= R stopped drawing
+	 *     1= R started drawing
+	 *     2= graphical input exists
+	 * 
+	 * @param mode the value constant
+	 */
+	void setMode(int mode);
+	
+	double[] computeSize();
+	double[] computeFontMetric(int ch);
+	double[] computeStringWidth(String txt);
+	
+	/**
+	 * @see RClipSetting#RClipSetting(double, double, double, double)
+	 */
+	void addSetClip(double x0, double y0, double x1, double y1);
+	/**
+	 * @see RColorSetting#RColorSetting(int)
+	 */
+	void addSetColor(int color);
+	/**
+	 * @see RFillSetting#RFillSetting(int)
+	 */
+	void addSetFill(int color);
+	/**
+	 * @see RLineSetting#RLineSetting(int, double, byte, byte, float)
+	 */
+	void addSetLine(int type, float width, byte cap, byte join, float joinMiterLimit);
+	/**
+	 * @see RFontSetting#RFontSetting(String, int, double, double, double)
+	 */
+	void addSetFont(String family, int face, float pointSize, float lineHeight);
+	/**
+	 * @see RLine#RLine(double, double, double, double)
+	 */
+	void addDrawLine(double x0, double y0, double x1, double y1);
+	/**
+	 * @see RRect#RRect(double, double, double, double)
+	 */
+	void addDrawRect(double x0, double y0, double x1, double y1);
+	/**
+	 * @see RPolyline
+	 */
+	void addDrawPolyline(double[] x, double[] y);
+	/**
+	 * @see RPolygon
+	 */
+	void addDrawPolygon(double[] x, double[] y);
+	/**
+	 * @see RPath
+	 */
+	void addDrawPath(int[] n, double[] x, double[] y, int winding);
+	/**
+	 * @see RCircle#RCircle(double, double, double)
+	 */
+	void addDrawCircle(double x, double y, double r);
+	/**
+	 * @see RText
+	 */
+	void addDrawText(String txt, double x, double y, double rDeg, double hAdj);
+	/**
+	 * @see RRaster
+	 */
+	void addDrawRaster(byte[] imgData, boolean imgAlpha, int imgWidth, int imgHeight,
+			double x, double y, double w, double h, double rDeg, boolean interpolate);
+	
+	byte[] capture(int width, int height);
+	
+	
+	double[] runRLocator(RService r, IProgressMonitor monitor);
+	
+}
diff --git a/core/org.eclipse.statet.rj.client/src/org/eclipse/statet/rj/server/client/RClientGraphicActions.java b/core/org.eclipse.statet.rj.client/src/org/eclipse/statet/rj/server/client/RClientGraphicActions.java
new file mode 100644
index 0000000..f01d860
--- /dev/null
+++ b/core/org.eclipse.statet.rj.client/src/org/eclipse/statet/rj/server/client/RClientGraphicActions.java
@@ -0,0 +1,45 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server.client;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+
+
+/**
+ * Interface for (RJ) graphics offering actions which can be used
+ * in graphic views/windows.
+ */
+public interface RClientGraphicActions {
+	
+	
+	Object getRHandle();
+	
+	String getRLabel();
+	
+	IStatus resizeGraphic(int devId, Runnable beforeResize);
+	
+	IStatus closeGraphic(int devId);
+	
+	
+	void copy(int devId, String toDev, String toDevFile, String toDevArgs,
+			IProgressMonitor monitor) throws CoreException;
+	double[] convertGraphic2User(int devId, double[] xy,
+			IProgressMonitor monitor) throws CoreException;
+	double[] convertUser2Graphic(int devId, double[] xy,
+			IProgressMonitor monitor) throws CoreException;
+	
+}
diff --git a/core/org.eclipse.statet.rj.client/src/org/eclipse/statet/rj/server/client/RClientGraphicDummy.java b/core/org.eclipse.statet.rj.client/src/org/eclipse/statet/rj/server/client/RClientGraphicDummy.java
new file mode 100644
index 0000000..67eb6ab
--- /dev/null
+++ b/core/org.eclipse.statet.rj.client/src/org/eclipse/statet/rj/server/client/RClientGraphicDummy.java
@@ -0,0 +1,147 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server.client;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+
+import org.eclipse.statet.rj.services.RService;
+
+
+/**
+ * A minimal {@link RClientGraphic} implementation.
+ */
+public class RClientGraphicDummy implements RClientGraphic {
+	
+	
+	private final int devId;
+	
+	private boolean isActive;
+	
+	private double[] size;
+	
+	
+	public RClientGraphicDummy(final int devId, final double w, final double h) {
+		this.devId= devId;
+		this.size= new double[] { w, h };
+	}
+	
+	
+	@Override
+	public int getDevId() {
+		return this.devId;
+	}
+	
+	@Override
+	public void reset(final double w, final double h, final InitConfig config) {
+		this.size= new double[] { w, h };
+	}
+	
+	@Override
+	public void setMode(final int mode) {
+	}
+	
+	@Override
+	public void setActive(final boolean active) {
+		this.isActive= active;
+	}
+	
+	@Override
+	public boolean isActive() {
+		return this.isActive;
+	}
+	
+	@Override
+	public double[] computeSize() {
+		return this.size;
+	}
+	
+	@Override
+	public double[] computeFontMetric(final int ch) {
+		return null;
+	}
+	
+	@Override
+	public double[] computeStringWidth(final String txt) {
+		return null;
+	}
+	
+	@Override
+	public void addSetClip(final double x0, final double y0, final double x1, final double y1) {
+	}
+	
+	@Override
+	public void addSetColor(final int color) {
+	}
+	
+	@Override
+	public void addSetFill(final int color) {
+	}
+	
+	@Override
+	public void addSetLine(final int type, final float width,
+			final byte cap, final byte join, final float joinMiterLimit) {
+	}
+	
+	@Override
+	public void addSetFont(final String family, final int face, final float pointSize, final float lineHeight) {
+	}
+	
+	@Override
+	public void addDrawLine(final double x0, final double y0, final double x1, final double y1) {
+	}
+	
+	@Override
+	public void addDrawRect(final double x0, final double y0, final double x1, final double y1) {
+	}
+	
+	@Override
+	public void addDrawPolyline(final double[] x, final double[] y) {
+	}
+	
+	@Override
+	public void addDrawPolygon(final double[] x, final double[] y) {
+	}
+	
+	@Override
+	public void addDrawPath(final int[] n, final double[] x, final double[] y, final int winding) {
+	}
+	
+	@Override
+	public void addDrawCircle(final double x, final double y, final double r) {
+	}
+	
+	@Override
+	public void addDrawText(final String text,
+			final double x, final double y, final double rDeg, final double hAdj) {
+	}
+	
+	@Override
+	public void addDrawRaster(final byte[] imgData, final boolean imgAlpha, final int imgWidth, final int imgHeight,
+			final double x, final double y, final double w, final double h,
+			final double rDeg, final boolean interpolate) {
+	}
+	
+	@Override
+	public byte[] capture(final int width, final int height) {
+		return null;
+	}
+	
+	
+	@Override
+	public double[] runRLocator(final RService r, final IProgressMonitor monitor) {
+		return null;
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.client/src/org/eclipse/statet/rj/server/client/RClientGraphicFactory.java b/core/org.eclipse.statet.rj.client/src/org/eclipse/statet/rj/server/client/RClientGraphicFactory.java
new file mode 100644
index 0000000..0009097
--- /dev/null
+++ b/core/org.eclipse.statet.rj.client/src/org/eclipse/statet/rj/server/client/RClientGraphicFactory.java
@@ -0,0 +1,87 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server.client;
+
+import java.util.Map;
+
+import org.eclipse.statet.rj.server.client.RClientGraphic.InitConfig;
+
+
+/**
+ * Factory interface used to create (and close) {@link RClientGraphic} objects.
+ * 
+ * The methods are called by the client protocol handler
+ * ({@link AbstractRJComClient}) and must not be called at
+ * another place.
+ */
+public interface RClientGraphicFactory {
+	
+	
+	/**
+	 * Indicates explicitly that the graphic will be added to a global graphic
+	 * collection.
+	 * 
+	 * Typically that means, the graphic is shown in the default graphic view/window.
+	 */
+	int MANAGED_ON= 1 << 1;
+	
+	/**
+	 * Indicates that the graphic will not be added to a global graphic collection.
+	 * 
+	 * Typically that means, the graphic isn't shown in the default graphic view/window.
+	 */
+	int MANAGED_OFF= 1 << 2;
+	
+	/**
+	 * Indicates that the graphic will be disposed if closed in R.
+	 */
+	int R_CLOSE_ON= 1 << 3;
+	
+	/**
+	 * Indicates that the graphic will not be disposed if closed in R.
+	 */
+	int R_CLOSE_OFF= 1 << 4;
+	
+	/**
+	 * Returns a map with properties configuring the server
+	 * The values must be serializable.
+	 * 
+	 * @return a map with keys and values of the properties
+	 */
+	Map<String, ? extends Object> getInitServerProperties();
+	
+	/**
+	 * Called if a new graphic is created in R (<code>dev.new()</code>).
+	 * 
+	 * @param devId
+	 * @param w
+	 * @param h
+	 * @param config initialization configuration
+	 * @param active
+	 * @param actions
+	 * @return a new graphic object
+	 */
+	RClientGraphic newGraphic(int devId, double w, double h, InitConfig config,
+			boolean active, RClientGraphicActions actions, int options);
+	
+	/**
+	 * Called if the graphic is closed by the R (<code>dev.off()</code>
+	 * or R closed).
+	 * 
+	 * @param graphic the closed graphic
+	 */
+	void closeGraphic(RClientGraphic graphic);
+	
+}
diff --git a/core/org.eclipse.statet.rj.client/src/org/eclipse/statet/rj/server/client/RGraphicCreatorImpl.java b/core/org.eclipse.statet.rj.client/src/org/eclipse/statet/rj/server/client/RGraphicCreatorImpl.java
new file mode 100644
index 0000000..747f64e
--- /dev/null
+++ b/core/org.eclipse.statet.rj.client/src/org/eclipse/statet/rj/server/client/RGraphicCreatorImpl.java
@@ -0,0 +1,107 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server.client;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+
+import org.eclipse.statet.rj.graphic.core.RGraphic;
+import org.eclipse.statet.rj.services.FunctionCall;
+import org.eclipse.statet.rj.services.RGraphicCreator;
+import org.eclipse.statet.rj.services.RService;
+
+
+/**
+ * Default implementation for {@link RGraphicCreator}.
+ * <p>
+ * Requires R package <code>rj</code>.</p>
+ */
+public class RGraphicCreatorImpl implements RGraphicCreator {
+	
+	
+	private final RService service;
+	private final AbstractRJComClient rjs;
+	
+	private int options;
+	
+	private double width= -1;
+	private double height= -1;
+	
+	
+	public RGraphicCreatorImpl(final RService service, final AbstractRJComClient rjs, final int options) {
+		this.service= service;
+		this.rjs= rjs;
+	}
+	
+	
+	@Override
+	public void setSize(final double width, final double height) {
+		if (width == -1 && height == -1) {
+			this.width= -1;
+			this.height= -1;
+			return;
+		}
+		if (width <= 0 || height <= 0) {
+			throw new IllegalArgumentException();
+		}
+		this.width= width;
+		this.height= height;
+	}
+	
+	@Override
+	public RGraphic create(final String expression, final IProgressMonitor monitor) throws CoreException {
+		return create(expression, null, monitor);
+	}
+	
+	@Override
+	public RGraphic create(final FunctionCall fcall, final IProgressMonitor monitor) throws CoreException {
+		return create(null, fcall, monitor);
+	}
+	
+	private RGraphic create(final String expression, final FunctionCall fcall, final IProgressMonitor monitor) throws CoreException {
+		final int savedOptions= this.rjs.getGraphicOptions();
+		int graphicOptions= this.options;
+		if ((this.options & RClientGraphicFactory.MANAGED_ON) == 0) {
+			graphicOptions |= RClientGraphicFactory.MANAGED_OFF;
+		}
+		if ((this.options & RClientGraphicFactory.R_CLOSE_ON) == 0) {
+			graphicOptions |= RClientGraphicFactory.R_CLOSE_OFF;
+		}
+		this.rjs.setGraphicOptions(graphicOptions);
+		final RClientGraphic graphic;
+		try {
+			if (this.width < 0) {
+				this.service.evalVoid("rj.gd::rj.GD()", monitor);
+			}
+			else {
+				this.service.evalVoid("rj.gd::rj.GD(" +
+						"width= " + this.width + ", height= "+this.height+", size.unit= \"px\"" +
+						")", monitor );
+			}
+			if (expression != null) {
+				this.service.evalData(expression, monitor);
+			}
+			else {
+				fcall.evalVoid(monitor);
+			}
+			graphic= this.rjs.getLastGraphic();
+		}
+		finally {
+			this.rjs.setGraphicOptions(savedOptions);
+		}
+		return ((graphic instanceof RGraphic) ? ((RGraphic) graphic) : null);
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.client/srcRSetups/org/eclipse/statet/rj/rsetups/RSetup.java b/core/org.eclipse.statet.rj.client/srcRSetups/org/eclipse/statet/rj/rsetups/RSetup.java
new file mode 100644
index 0000000..e709f55
--- /dev/null
+++ b/core/org.eclipse.statet.rj.client/srcRSetups/org/eclipse/statet/rj/rsetups/RSetup.java
@@ -0,0 +1,168 @@
+/*=============================================================================#
+ # Copyright (c) 2010, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.rsetups;
+
+import java.util.ArrayList;
+import java.util.List;
+
+
+/**
+ * A single R setup loaded or created for a given OS/architecture.
+ */
+public class RSetup {
+	
+	
+	private final String id;
+	
+	private String name;
+	private String version;
+	
+	private String os;
+	private String arch;
+	
+	private String rHome;
+	
+	private final List<String> rLibsSite= new ArrayList<>(2);
+	private final List<String> rLibs= new ArrayList<>(2);
+	private final List<String> rLibsUser= new ArrayList<>(2);
+	
+	
+	public RSetup(final String id) {
+		this.id= id;
+	}
+	
+	
+	/**
+	 * Returns the unique id of the setup.
+	 * 
+	 * @return the id
+	 */
+	public String getId() {
+		return this.id;
+	}
+	
+	/**
+	 * Sets the name of the setup.
+	 * 
+	 * @param the new name
+	 */
+	public void setName(final String name) {
+		this.name= name;
+	}
+	
+	/**
+	 * Returns the name of the setup.
+	 * 
+	 * @return the name
+	 */
+	public String getName() {
+		return this.name;
+	}
+	
+	/**
+	 * Sets the R version.
+	 * 
+	 * @param the new name
+	 */
+	public void setRVersion(final String version) {
+		this.version= version;
+	}
+	
+	/**
+	 * Returns the R version of the setup.
+	 * 
+	 * @return the name
+	 */
+	public String getRVersion() {
+		return this.version;
+	}
+	
+	/**
+	 * Sets the operation system and its architecture the setup is loaded or created for.
+	 * 
+	 * @param os the os constant
+	 * @param arch the arch constant
+	 */
+	public void setOS(final String os, final String arch) {
+		this.os= os;
+		this.arch= arch;
+	}
+	
+	/**
+	 * Returns the operation system the setup is loaded for.
+	 * 
+	 * @return the os constant
+	 */
+	public String getOS() {
+		return this.os;
+	}
+	
+	/**
+	 * Returns the system architecture the setup is loaded for.
+	 * 
+	 * @return the arch constant
+	 */
+	public String getOSArch() {
+		return this.arch;
+	}
+	
+	
+	/**
+	 * Sets the R home directory (R_HOME) for the setup.
+	 * 
+	 * @param the R home directory
+	 */
+	public void setRHome(final String directory) {
+		this.rHome= directory;
+	}
+	
+	/**
+	 * Returns the R home directory (R_HOME) for the loaded setup.
+	 * 
+	 * @return the R home directory
+	 */
+	public String getRHome() {
+		return this.rHome;
+	}
+	
+	
+	/**
+	 * Returns the library directories for the R_LIBS_SITE group.
+	 * 
+	 * @return the directories of the libraries
+	 */
+	public List<String> getRLibsSite() {
+		return this.rLibsSite;
+	}
+	
+	/**
+	 * Returns the library directories for the R_LIBS group.
+	 * 
+	 * @return the directories of the libraries
+	 */
+	public List<String> getRLibs() {
+		return this.rLibs;
+	}
+	
+	/**
+	 * Returns the library directories for the R_LIBS_USER group.
+	 * 
+	 * @return the directories of the libraries
+	 */
+	public List<String> getRLibsUser() {
+		return this.rLibsUser;
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.client/srcRSetups/org/eclipse/statet/rj/rsetups/RSetupUtil.java b/core/org.eclipse.statet.rj.client/srcRSetups/org/eclipse/statet/rj/rsetups/RSetupUtil.java
new file mode 100644
index 0000000..0457e7e
--- /dev/null
+++ b/core/org.eclipse.statet.rj.client/srcRSetups/org/eclipse/statet/rj/rsetups/RSetupUtil.java
@@ -0,0 +1,220 @@
+/*=============================================================================#
+ # Copyright (c) 2010, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.rsetups;
+
+import java.io.File;
+import java.net.URI;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.osgi.framework.Bundle;
+
+import org.eclipse.core.runtime.FileLocator;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.ILog;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.URIUtil;
+
+
+public class RSetupUtil {
+	
+	
+	public static final String EXTENSION_POINT_ID= "org.eclipse.statet.rj.RSetups"; //$NON-NLS-1$
+	
+	private static final String BUNDLE_ID= "org.eclipse.statet.rj.server"; //$NON-NLS-1$
+	
+	
+	private static final ILog LOGGER= Platform.getLog(Platform.getBundle(BUNDLE_ID));
+	
+	
+	private static final String SETUP_ELEMENT_NAME= "setup"; //$NON-NLS-1$
+	private static final String BASE_ELEMENT_NAME= "base"; //$NON-NLS-1$
+	private static final String LIBRARY_ELEMENT_NAME= "library"; //$NON-NLS-1$
+	
+	private static final String ID_ATTRIBUTE_NAME= "id"; //$NON-NLS-1$
+	private static final String SETUP_ID_ATTRIBUTE_NAME= "setupId"; //$NON-NLS-1$
+	private static final String NAME_ATTRIBUTE_NAME= "name"; //$NON-NLS-1$
+	private static final String INHERIT_BASE_ATTRIBUTE_NAME= "inheritBase"; //$NON-NLS-1$
+	private static final String LOCATION_ATTRIBUTE_NAME= "location"; //$NON-NLS-1$
+	private static final String GROUP_ATTRIBUTE_NAME= "group"; //$NON-NLS-1$
+	
+	
+	/**
+	 * Loads all available R setups for the current or the specified platform.
+	 * 
+	 * A filter map specifying a platform contains the arguments like <code>$os$</code> and 
+	 * <code>$arch$</code> as keys; its values must be set to the known constant of the desired.
+	 * platform.
+	 * 
+	 * @param filter a platform filter or <code>null</code> for the current platform
+	 * @return a list with available R setups
+	 */
+	public static List<RSetup> loadAvailableSetups(final Map<String, String> filter) {
+		final Set<String> ids= new HashSet<>();
+		final List<RSetup> setups= new ArrayList<>();
+		final IConfigurationElement[] configurationElements= Platform.getExtensionRegistry().getConfigurationElementsFor(EXTENSION_POINT_ID);
+		for (int i= 0; i < configurationElements.length; i++) {
+			if (configurationElements[i].getName().equals(SETUP_ELEMENT_NAME)) {
+				final String id= configurationElements[i].getAttribute(ID_ATTRIBUTE_NAME);
+				if (id != null && id.length() > 0 && !ids.contains(id)) {
+					ids.add(id);
+					final RSetup setup= loadSetup(id, filter, configurationElements);
+					if (setup != null) {
+						setups.add(setup);
+					}
+				}
+			}
+		}
+		return setups;
+	}
+	
+	/**
+	 * Loads the R setup with the specified id for the current or the specified platform.
+	 * 
+	 * A filter map specifying a platform contains the arguments like <code>$os$</code> and 
+	 * <code>$arch$</code> as keys; its values must be set to the known constant of the desired.
+	 * platform.
+	 * 
+	 * @param id the id of the R setup
+	 * @param filter a platform filter or <code>null</code> for the current platform
+	 * @return the R setup or <code>null</code> if loading failed
+	 */
+	public static RSetup loadSetup(final String id, final Map<String, String> filter) {
+		final IConfigurationElement[] configurationElements= Platform.getExtensionRegistry().getConfigurationElementsFor(EXTENSION_POINT_ID);
+		return loadSetup(id, filter, configurationElements);
+	}
+	
+	private static RSetup loadSetup(final String id, final Map<String, String> filter,
+			final IConfigurationElement[] configurationElements) {
+		try {
+			for (int i= 0; i < configurationElements.length; i++) {
+				final IConfigurationElement element= configurationElements[i];
+				if (element.getName().equals(SETUP_ELEMENT_NAME)
+						&& id.equals(element.getAttribute(ID_ATTRIBUTE_NAME)) ) {
+					final RSetup setup= new RSetup(id);
+					if (filter != null && filter.containsKey("$os$")) { //$NON-NLS-1$
+						setup.setOS(filter.get("$os$"), filter.get("$arch$")); //$NON-NLS-1$ //$NON-NLS-2$
+					}
+					else {
+						setup.setOS(Platform.getOS(), Platform.getOSArch());
+					}
+					setup.setName(element.getAttribute(NAME_ATTRIBUTE_NAME));
+					loadSetupBase(id, filter, configurationElements, setup);
+					if (setup.getRHome() == null) {
+						log(IStatus.WARNING, "Incomplete R setup: Missing R home for setup '" + id + "', the setup is ignored.", element);
+						return null;
+					}
+					loadSetupLibraries(id, filter, configurationElements, setup);
+					return setup;
+				}
+			}
+		}
+		catch (final Exception e) {
+			LOGGER.log(new Status(IStatus.ERROR, BUNDLE_ID, "Error in R setup: Failed to load setup.", e));
+		}
+		return null;
+	}
+	
+	private static void loadSetupBase(final String id, final Map<String, String> filter,
+			final IConfigurationElement[] configurationElements, final RSetup setup)
+			throws Exception {
+		for (int i= 0; i < configurationElements.length; i++) {
+			final IConfigurationElement element= configurationElements[i];
+			if (element.getName().equals(BASE_ELEMENT_NAME)
+					&& id.equals(element.getAttribute(SETUP_ID_ATTRIBUTE_NAME)) ) {
+				final String path= getLocation(element, filter);
+				setup.setRHome(path);
+				return;
+			}
+		}
+		for (int i= 0; i < configurationElements.length; i++) {
+			final IConfigurationElement element= configurationElements[i];
+			if (element.equals(SETUP_ELEMENT_NAME)
+					&& id.equals(element.getAttribute(SETUP_ID_ATTRIBUTE_NAME)) ) {
+				final String inheritId= element.getAttribute(INHERIT_BASE_ATTRIBUTE_NAME);
+				if (inheritId != null) {
+					loadSetupBase(inheritId, filter, configurationElements, setup);
+				}
+				return;
+			}
+		}
+	}
+	
+	private static void loadSetupLibraries(final String id, final Map<String, String> filter,
+			final IConfigurationElement[] configurationElements, final RSetup setup)
+			throws Exception {
+		for (int i= 0; i < configurationElements.length; i++) {
+			final IConfigurationElement element= configurationElements[i];
+			if (element.getName().equals(LIBRARY_ELEMENT_NAME)
+					&& id.equals(element.getAttribute(SETUP_ID_ATTRIBUTE_NAME)) ) {
+				final String path= getLocation(element, filter);
+				if (path == null) {
+					continue;
+				}
+				final String groupId= element.getAttribute(GROUP_ATTRIBUTE_NAME);
+				if (groupId == null || groupId.length() == 0 || groupId.equals("R_LIBS")) { //$NON-NLS-1$
+					setup.getRLibs().add(path);
+				}
+				else if (groupId.equals("R_LIBS_SITE")) { //$NON-NLS-1$
+					setup.getRLibsSite().add(path);
+				}
+				else if (groupId.equals("R_LIBS_USER")) { //$NON-NLS-1$
+					setup.getRLibsUser().add(path);
+				}
+				else {
+					log(IStatus.WARNING, "Invalid R setup element: " +
+							"Unknown library group '" + groupId + "', the library is ignored", element);
+				}
+			}
+		}
+	}
+	
+	private static String getLocation(final IConfigurationElement element, final Map<String, String> filter) throws Exception {
+		final Bundle bundle= Platform.getBundle(element.getContributor().getName());
+		final String path= element.getAttribute(LOCATION_ATTRIBUTE_NAME);
+		if (bundle != null && path != null && path.length() > 0) {
+			final URL[] bundleURLs= FileLocator.findEntries(bundle, new Path(path), filter);
+			for (int i= 0; i < bundleURLs.length; i++) {
+				final URI fileURI= URIUtil.toURI(FileLocator.toFileURL(bundleURLs[i]));
+				if (fileURI.getScheme().equals("file")) { //$NON-NLS-1$
+					final File file= new File(fileURI);
+					if (file.exists() && file.isDirectory() && file.list().length > 0) {
+						return file.getAbsolutePath();
+					}
+				}
+			}
+		}
+		
+		return null;
+	}
+	
+	private static void log(final int severity, final String message, final IConfigurationElement element) {
+		final StringBuilder info= new StringBuilder(message);
+		if (element != null) {
+			info.append(" (contributed by '");
+			info.append(element.getContributor().getName());
+			info.append("').");
+		}
+		LOGGER.log(new Status(IStatus.WARNING, BUNDLE_ID, info.toString()));
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.data/.classpath b/core/org.eclipse.statet.rj.data/.classpath
new file mode 100644
index 0000000..f4b5bd5
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/.classpath
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8">
+		<attributes>
+			<attribute name="owner.project.facets" value="java"/>
+		</attributes>
+	</classpathentry>
+	<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+	<classpathentry kind="src" path="src"/>
+	<classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/core/org.eclipse.statet.rj.data/.gitignore b/core/org.eclipse.statet.rj.data/.gitignore
new file mode 100644
index 0000000..934e0e0
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/.gitignore
@@ -0,0 +1,2 @@
+/bin
+/target
diff --git a/core/org.eclipse.statet.rj.data/.project b/core/org.eclipse.statet.rj.data/.project
new file mode 100644
index 0000000..d104406
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/.project
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>org.eclipse.statet.rj.data</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.wst.common.project.facet.core.builder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.jdt.core.javabuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.pde.ManifestBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.pde.SchemaBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.jdt.core.javanature</nature>
+		<nature>org.eclipse.pde.PluginNature</nature>
+		<nature>org.eclipse.wst.common.modulecore.ModuleCoreNature</nature>
+		<nature>org.eclipse.wst.common.project.facet.core.nature</nature>
+	</natures>
+</projectDescription>
diff --git a/core/org.eclipse.statet.rj.data/.settings/org.eclipse.core.resources.prefs b/core/org.eclipse.statet.rj.data/.settings/org.eclipse.core.resources.prefs
new file mode 100644
index 0000000..99f26c0
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/.settings/org.eclipse.core.resources.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+encoding/<project>=UTF-8
diff --git a/core/org.eclipse.statet.rj.data/.settings/org.eclipse.core.runtime.prefs b/core/org.eclipse.statet.rj.data/.settings/org.eclipse.core.runtime.prefs
new file mode 100644
index 0000000..5a0ad22
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/.settings/org.eclipse.core.runtime.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+line.separator=\n
diff --git a/core/org.eclipse.statet.rj.data/.settings/org.eclipse.jdt.core.prefs b/core/org.eclipse.statet.rj.data/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000..ccb1eaa
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,325 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.codeComplete.argumentPrefixes=
+org.eclipse.jdt.core.codeComplete.argumentSuffixes=
+org.eclipse.jdt.core.codeComplete.fieldPrefixes=
+org.eclipse.jdt.core.codeComplete.fieldSuffixes=
+org.eclipse.jdt.core.codeComplete.localPrefixes=
+org.eclipse.jdt.core.codeComplete.localSuffixes=
+org.eclipse.jdt.core.codeComplete.staticFieldPrefixes=
+org.eclipse.jdt.core.codeComplete.staticFieldSuffixes=
+org.eclipse.jdt.core.codeComplete.staticFinalFieldPrefixes=
+org.eclipse.jdt.core.codeComplete.staticFinalFieldSuffixes=
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=1.8
+org.eclipse.jdt.core.compiler.debug.lineNumber=generate
+org.eclipse.jdt.core.compiler.debug.localVariable=generate
+org.eclipse.jdt.core.compiler.debug.sourceFile=generate
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.source=1.8
+org.eclipse.jdt.core.formatter.align_fields_grouping_blank_lines=2147483647
+org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_assignment=0
+org.eclipse.jdt.core.formatter.alignment_for_binary_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_compact_if=16
+org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=80
+org.eclipse.jdt.core.formatter.alignment_for_enum_constants=0
+org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16
+org.eclipse.jdt.core.formatter.alignment_for_expressions_in_for_loop_header=0
+org.eclipse.jdt.core.formatter.alignment_for_method_declaration=0
+org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16
+org.eclipse.jdt.core.formatter.alignment_for_parameterized_type_references=0
+org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_resources_in_try=85
+org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=16
+org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_type_arguments=0
+org.eclipse.jdt.core.formatter.alignment_for_type_parameters=0
+org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch=16
+org.eclipse.jdt.core.formatter.blank_lines_after_imports=2
+org.eclipse.jdt.core.formatter.blank_lines_after_package=1
+org.eclipse.jdt.core.formatter.blank_lines_before_field=0
+org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=1
+org.eclipse.jdt.core.formatter.blank_lines_before_imports=1
+org.eclipse.jdt.core.formatter.blank_lines_before_member_type=1
+org.eclipse.jdt.core.formatter.blank_lines_before_method=1
+org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=2
+org.eclipse.jdt.core.formatter.blank_lines_before_package=1
+org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=1
+org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=1
+org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_block=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_lambda_body=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=false
+org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=false
+org.eclipse.jdt.core.formatter.comment.format_block_comments=true
+org.eclipse.jdt.core.formatter.comment.format_header=false
+org.eclipse.jdt.core.formatter.comment.format_html=true
+org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=true
+org.eclipse.jdt.core.formatter.comment.format_line_comments=true
+org.eclipse.jdt.core.formatter.comment.format_source_code=true
+org.eclipse.jdt.core.formatter.comment.indent_parameter_description=false
+org.eclipse.jdt.core.formatter.comment.indent_root_tags=true
+org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert
+org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=do not insert
+org.eclipse.jdt.core.formatter.comment.line_length=100
+org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries=false
+org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries=true
+org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments=false
+org.eclipse.jdt.core.formatter.compact_else_if=true
+org.eclipse.jdt.core.formatter.continuation_indentation=2
+org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=2
+org.eclipse.jdt.core.formatter.disabling_tag=@formatter\:off
+org.eclipse.jdt.core.formatter.enabling_tag=@formatter\:on
+org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false
+org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true
+org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true
+org.eclipse.jdt.core.formatter.indent_empty_lines=true
+org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true
+org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true
+org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true
+org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=false
+org.eclipse.jdt.core.formatter.indentation.size=4
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_enum_constant=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_label=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_type_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert
+org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert
+org.eclipse.jdt.core.formatter.insert_space_after_lambda_arrow=insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources=insert
+org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert
+org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=insert
+org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert
+org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw=insert
+org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.join_lines_in_comments=true
+org.eclipse.jdt.core.formatter.join_wrapped_lines=true
+org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=false
+org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false
+org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=false
+org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false
+org.eclipse.jdt.core.formatter.lineSplit=100
+org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false
+org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=false
+org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0
+org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=1
+org.eclipse.jdt.core.formatter.parentheses_positions_in_annotation=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_catch_clause=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_enum_constant_declaration=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_for_statment=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_if_while_statement=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_lambda_declaration=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_method_delcaration=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_method_invocation=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_switch_statement=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_try_clause=common_lines
+org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=true
+org.eclipse.jdt.core.formatter.tabulation.char=tab
+org.eclipse.jdt.core.formatter.tabulation.size=4
+org.eclipse.jdt.core.formatter.use_on_off_tags=false
+org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false
+org.eclipse.jdt.core.formatter.wrap_before_assignment_operator=false
+org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true
+org.eclipse.jdt.core.formatter.wrap_before_conditional_operator=false
+org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch=true
+org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true
+org.eclipse.jdt.core.javaFormatter=org.eclipse.jdt.core.defaultJavaFormatter
diff --git a/core/org.eclipse.statet.rj.data/.settings/org.eclipse.jdt.ui.prefs b/core/org.eclipse.statet.rj.data/.settings/org.eclipse.jdt.ui.prefs
new file mode 100644
index 0000000..e62a4f5
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/.settings/org.eclipse.jdt.ui.prefs
@@ -0,0 +1,131 @@
+cleanup.add_default_serial_version_id=true
+cleanup.add_generated_serial_version_id=false
+cleanup.add_missing_annotations=true
+cleanup.add_missing_deprecated_annotations=true
+cleanup.add_missing_methods=false
+cleanup.add_missing_nls_tags=false
+cleanup.add_missing_override_annotations=true
+cleanup.add_missing_override_annotations_interface_methods=true
+cleanup.add_serial_version_id=false
+cleanup.always_use_blocks=true
+cleanup.always_use_parentheses_in_expressions=true
+cleanup.always_use_this_for_non_static_field_access=true
+cleanup.always_use_this_for_non_static_method_access=false
+cleanup.convert_functional_interfaces=false
+cleanup.convert_to_enhanced_for_loop=false
+cleanup.correct_indentation=false
+cleanup.format_source_code=false
+cleanup.format_source_code_changes_only=false
+cleanup.insert_inferred_type_arguments=false
+cleanup.make_local_variable_final=true
+cleanup.make_parameters_final=true
+cleanup.make_private_fields_final=true
+cleanup.make_type_abstract_if_missing_method=false
+cleanup.make_variable_declarations_final=true
+cleanup.never_use_blocks=false
+cleanup.never_use_parentheses_in_expressions=false
+cleanup.organize_imports=true
+cleanup.qualify_static_field_accesses_with_declaring_class=false
+cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true
+cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=false
+cleanup.qualify_static_member_accesses_with_declaring_class=true
+cleanup.qualify_static_method_accesses_with_declaring_class=false
+cleanup.remove_private_constructors=true
+cleanup.remove_redundant_type_arguments=true
+cleanup.remove_trailing_whitespaces=false
+cleanup.remove_trailing_whitespaces_all=true
+cleanup.remove_trailing_whitespaces_ignore_empty=false
+cleanup.remove_unnecessary_casts=true
+cleanup.remove_unnecessary_nls_tags=true
+cleanup.remove_unused_imports=true
+cleanup.remove_unused_local_variables=false
+cleanup.remove_unused_private_fields=true
+cleanup.remove_unused_private_members=false
+cleanup.remove_unused_private_methods=true
+cleanup.remove_unused_private_types=true
+cleanup.sort_members=false
+cleanup.sort_members_all=false
+cleanup.use_anonymous_class_creation=false
+cleanup.use_blocks=true
+cleanup.use_blocks_only_for_return_and_throw=false
+cleanup.use_lambda=true
+cleanup.use_parentheses_in_expressions=false
+cleanup.use_this_for_non_static_field_access=true
+cleanup.use_this_for_non_static_field_access_only_if_necessary=false
+cleanup.use_this_for_non_static_method_access=true
+cleanup.use_this_for_non_static_method_access_only_if_necessary=true
+cleanup.use_type_arguments=false
+cleanup_profile=_StatET
+cleanup_settings_version=2
+eclipse.preferences.version=1
+editor_save_participant_org.eclipse.jdt.ui.postsavelistener.cleanup=true
+formatter_profile=_StatET
+formatter_settings_version=12
+org.eclipse.jdt.ui.exception.name=e
+org.eclipse.jdt.ui.gettersetter.use.is=true
+org.eclipse.jdt.ui.ignorelowercasenames=true
+org.eclipse.jdt.ui.importorder=\#;java;javax;com.ibm.icu;org.osgi;org.eclipse;;org.eclipse.statet.jcommons;org.eclipse.statet.ecommons;org.eclipse.statet;
+org.eclipse.jdt.ui.javadoc=true
+org.eclipse.jdt.ui.keywordthis=true
+org.eclipse.jdt.ui.ondemandthreshold=99
+org.eclipse.jdt.ui.overrideannotation=true
+org.eclipse.jdt.ui.staticondemandthreshold=99
+org.eclipse.jdt.ui.text.custom_code_templates=<?xml version\="1.0" encoding\="UTF-8" standalone\="no"?><templates><template autoinsert\="true" context\="gettercomment_context" deleted\="false" description\="Comment for getter method" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.gettercomment" name\="gettercomment">/**\n * @return the ${bare_field_name}\n */</template><template autoinsert\="true" context\="settercomment_context" deleted\="false" description\="Comment for setter method" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.settercomment" name\="settercomment">/**\n * @param ${param} the ${bare_field_name} to set\n */</template><template autoinsert\="true" context\="constructorcomment_context" deleted\="false" description\="Comment for created constructors" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.constructorcomment" name\="constructorcomment">/**\n * ${tags}\n */</template><template autoinsert\="false" context\="filecomment_context" deleted\="false" description\="Comment for created Java files" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.filecomment" name\="filecomment">/*\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\#\n \# Copyright (c) ${year} ${user} and others.\n # \n # This program and the accompanying materials are made available under the\n # terms of the Eclipse Public License 2.0 which is available at\n # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n # which is available at https://www.apache.org/licenses/LICENSE-2.0.\n # \n # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n # \n \# Contributors\:\n \#     ${user} - initial API and implementation\n \#\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=*/</template><template autoinsert\="false" context\="typecomment_context" deleted\="false" description\="Comment for created types" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.typecomment" name\="typecomment">/**\n * \n * ${tags}\n */</template><template autoinsert\="true" context\="fieldcomment_context" deleted\="false" description\="Comment for fields" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.fieldcomment" name\="fieldcomment">/**\n * \n */</template><template autoinsert\="true" context\="methodcomment_context" deleted\="false" description\="Comment for non-overriding methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.methodcomment" name\="methodcomment">/**\n * ${tags}\n */</template><template autoinsert\="false" context\="overridecomment_context" deleted\="false" description\="Comment for overriding methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.overridecomment" name\="overridecomment"/><template autoinsert\="true" context\="delegatecomment_context" deleted\="false" description\="Comment for delegate methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.delegatecomment" name\="delegatecomment">/**\n * ${tags}\n * ${see_to_target}\n */</template><template autoinsert\="false" context\="newtype_context" deleted\="false" description\="Newly created files" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.newtype" name\="newtype">${filecomment}\n\n${package_declaration}\n\n${typecomment}\n${type_declaration}</template><template autoinsert\="true" context\="classbody_context" deleted\="false" description\="Code in new class type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.classbody" name\="classbody">\n</template><template autoinsert\="true" context\="interfacebody_context" deleted\="false" description\="Code in new interface type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.interfacebody" name\="interfacebody">\n</template><template autoinsert\="true" context\="enumbody_context" deleted\="false" description\="Code in new enum type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.enumbody" name\="enumbody">\n</template><template autoinsert\="true" context\="annotationbody_context" deleted\="false" description\="Code in new annotation type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.annotationbody" name\="annotationbody">\n</template><template autoinsert\="true" context\="catchblock_context" deleted\="false" description\="Code in new catch blocks" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.catchblock" name\="catchblock">// ${todo} Auto-generated catch block\n${exception_var}.printStackTrace();</template><template autoinsert\="true" context\="methodbody_context" deleted\="false" description\="Code in created method stubs" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.methodbody" name\="methodbody">// ${todo} Auto-generated method stub\n${body_statement}</template><template autoinsert\="true" context\="constructorbody_context" deleted\="false" description\="Code in created constructor stubs" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.constructorbody" name\="constructorbody">${body_statement}\n// ${todo} Auto-generated constructor stub</template><template autoinsert\="true" context\="getterbody_context" deleted\="false" description\="Code in created getters" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.getterbody" name\="getterbody">return ${field};</template><template autoinsert\="true" context\="setterbody_context" deleted\="false" description\="Code in created setters" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.setterbody" name\="setterbody">${field} \= ${param};</template></templates>
+sp_cleanup.add_default_serial_version_id=true
+sp_cleanup.add_generated_serial_version_id=false
+sp_cleanup.add_missing_annotations=true
+sp_cleanup.add_missing_deprecated_annotations=true
+sp_cleanup.add_missing_methods=false
+sp_cleanup.add_missing_nls_tags=false
+sp_cleanup.add_missing_override_annotations=true
+sp_cleanup.add_missing_override_annotations_interface_methods=true
+sp_cleanup.add_serial_version_id=false
+sp_cleanup.always_use_blocks=true
+sp_cleanup.always_use_parentheses_in_expressions=true
+sp_cleanup.always_use_this_for_non_static_field_access=true
+sp_cleanup.always_use_this_for_non_static_method_access=false
+sp_cleanup.convert_functional_interfaces=false
+sp_cleanup.convert_to_enhanced_for_loop=false
+sp_cleanup.correct_indentation=false
+sp_cleanup.format_source_code=false
+sp_cleanup.format_source_code_changes_only=false
+sp_cleanup.insert_inferred_type_arguments=false
+sp_cleanup.make_local_variable_final=true
+sp_cleanup.make_parameters_final=true
+sp_cleanup.make_private_fields_final=true
+sp_cleanup.make_type_abstract_if_missing_method=false
+sp_cleanup.make_variable_declarations_final=false
+sp_cleanup.never_use_blocks=false
+sp_cleanup.never_use_parentheses_in_expressions=false
+sp_cleanup.on_save_use_additional_actions=true
+sp_cleanup.organize_imports=true
+sp_cleanup.qualify_static_field_accesses_with_declaring_class=false
+sp_cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true
+sp_cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=false
+sp_cleanup.qualify_static_member_accesses_with_declaring_class=true
+sp_cleanup.qualify_static_method_accesses_with_declaring_class=false
+sp_cleanup.remove_private_constructors=true
+sp_cleanup.remove_redundant_type_arguments=true
+sp_cleanup.remove_trailing_whitespaces=false
+sp_cleanup.remove_trailing_whitespaces_all=false
+sp_cleanup.remove_trailing_whitespaces_ignore_empty=true
+sp_cleanup.remove_unnecessary_casts=true
+sp_cleanup.remove_unnecessary_nls_tags=false
+sp_cleanup.remove_unused_imports=false
+sp_cleanup.remove_unused_local_variables=false
+sp_cleanup.remove_unused_private_fields=false
+sp_cleanup.remove_unused_private_members=false
+sp_cleanup.remove_unused_private_methods=false
+sp_cleanup.remove_unused_private_types=true
+sp_cleanup.sort_members=false
+sp_cleanup.sort_members_all=false
+sp_cleanup.use_anonymous_class_creation=false
+sp_cleanup.use_blocks=true
+sp_cleanup.use_blocks_only_for_return_and_throw=false
+sp_cleanup.use_lambda=false
+sp_cleanup.use_parentheses_in_expressions=false
+sp_cleanup.use_this_for_non_static_field_access=true
+sp_cleanup.use_this_for_non_static_field_access_only_if_necessary=false
+sp_cleanup.use_this_for_non_static_method_access=true
+sp_cleanup.use_this_for_non_static_method_access_only_if_necessary=true
+sp_cleanup.use_type_arguments=false
diff --git a/core/org.eclipse.statet.rj.data/.settings/org.eclipse.wst.common.component b/core/org.eclipse.statet.rj.data/.settings/org.eclipse.wst.common.component
new file mode 100644
index 0000000..e4dc2c0
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/.settings/org.eclipse.wst.common.component
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project-modules id="moduleCoreId" project-version="1.5.0">
+    <wb-module deploy-name="org.eclipse.statet.rj.data">
+        <wb-resource deploy-path="/" source-path="/src"/>
+    </wb-module>
+</project-modules>
diff --git a/core/org.eclipse.statet.rj.data/.settings/org.eclipse.wst.common.project.facet.core.xml b/core/org.eclipse.statet.rj.data/.settings/org.eclipse.wst.common.project.facet.core.xml
new file mode 100644
index 0000000..f4ef8aa
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/.settings/org.eclipse.wst.common.project.facet.core.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<faceted-project>
+  <installed facet="java" version="1.8"/>
+</faceted-project>
diff --git a/core/org.eclipse.statet.rj.data/META-INF/MANIFEST.MF b/core/org.eclipse.statet.rj.data/META-INF/MANIFEST.MF
new file mode 100644
index 0000000..20033d3
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/META-INF/MANIFEST.MF
@@ -0,0 +1,9 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-SymbolicName: org.eclipse.statet.rj.data
+Bundle-Version: 2.1.0.qualifier
+Bundle-Vendor: Eclipse.org
+Bundle-Name: StatET RJ - Data
+Bundle-RequiredExecutionEnvironment: JavaSE-1.8
+Export-Package: org.eclipse.statet.rj.data,
+ org.eclipse.statet.rj.data.impl
diff --git a/core/org.eclipse.statet.rj.data/about.html b/core/org.eclipse.statet.rj.data/about.html
new file mode 100644
index 0000000..e71ae66
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/about.html
@@ -0,0 +1,37 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+		"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+<title>About</title>
+</head>
+<body lang="EN-US">
+<h2>About This Content</h2>
+
+<p>December 1, 2017</p>
+<h3>License</h3>
+
+<p>
+	The Eclipse Foundation makes available all content in this plug-in
+	(&quot;Content&quot;). Unless otherwise indicated below, the Content
+	is provided to you under the terms and conditions of the Eclipse
+	Public License Version 2.0 (&quot;EPL&quot;), or the Apache License,
+	Version 2.0 (AL). A copy of the EPL is available at <a href="https://www.eclipse.org/legal/epl-2.0">https://www.eclipse.org/legal/epl-2.0</a>.
+	For purposes of the EPL, &quot;Program&quot; will mean the Content.
+	A copy of the AL is available at <a href="https://www.apache.org/licenses/LICENSE-2.0">https://www.apache.org/licenses/LICENSE-2.0</a>.
+</p>
+
+<p>
+	If you did not receive this Content directly from the Eclipse
+	Foundation, the Content is being redistributed by another party
+	(&quot;Redistributor&quot;) and different terms and conditions may
+	apply to your use of any object code in the Content. Check the
+	Redistributor's license that was provided with the Content. If no such
+	license exists, contact the Redistributor. Unless otherwise indicated
+	below, the terms and conditions of the EPL or AL still apply to any
+	source code in the Content and such source code may be obtained at <a
+	href="https://www.eclipse.org/">https://www.eclipse.org</a>.
+</p>
+
+</body>
+</html>
diff --git a/core/org.eclipse.statet.rj.data/about_files/LICENSE.txt b/core/org.eclipse.statet.rj.data/about_files/LICENSE.txt
new file mode 100644
index 0000000..d645695
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/about_files/LICENSE.txt
@@ -0,0 +1,202 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
diff --git a/core/org.eclipse.statet.rj.data/build.properties b/core/org.eclipse.statet.rj.data/build.properties
new file mode 100644
index 0000000..9f02c9f
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/build.properties
@@ -0,0 +1,8 @@
+source..= src/
+output..= bin/
+javacDefaultEncoding..= UTF-8
+
+bin.includes= META-INF/,\
+              .,\
+              about.html
+src.includes= .settings/org.eclipse.core.resources.prefs
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/RArray.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/RArray.java
new file mode 100644
index 0000000..cbbe52e
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/RArray.java
@@ -0,0 +1,100 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data;
+
+
+/**
+ * An R object is of the type {@link RObject#TYPE_ARRAY array}, if it is an R
+ * data object of an "atomic" mode with a dimension attribute (<code>dim</code>).
+ * Such an R array object is represented by an instance of this interface.
+ * <p>
+ * The real data is stored in a {@link RStore} accessible by {@link #getData()}.
+ * An index for the one-dimensional data store can be computed from an
+ * index tuple relative to the dimension of the object using the methods
+ * {@link RDataUtils#getDataIdx(int[], int[])}.</p>
+ * <p>
+ * Also an S3 object based on a such a data object is of the type {@link RObject#TYPE_ARRAY array}.
+ * Whereas a S4 object is never directly of this type even the object simulates an
+ * array in R. Such an object is of the type {@link RObject#TYPE_S4OBJECT S4 object},
+ * and implements {@link RS4Object} with an object of the type {@link RObject#TYPE_ARRAY array}
+ * as data slot.</p>
+ * <p>
+ * The complementary type for objects without dimension attribute is the type
+ * {@link RObject#TYPE_VECTOR vector} and the interface {@link RVector}.</p>
+ * 
+ * @see RDataUtils#getDataIdx(int[], int[])
+ * @see RDataUtils#getDataIdxs(int[], int, int)
+ * @param <TData> the type of the data store
+ */
+public interface RArray<TData extends RStore<?>> extends RObject {
+	
+	/**
+	 * Returns the length of the object. The length of an {@link RObject#TYPE_ARRAY array}
+	 * is the count of all data values, the product of its dimensions.
+	 * 
+	 * @return the length
+	 */
+	@Override
+	long getLength();
+	
+	/**
+	 * Returns the dimension of this array. This corresponds to the R dimension
+	 * attribute (<code>dim</dim>) respectively the R <code>dim</code> function.
+	 * 
+	 * @return the dimension of this array
+	 */
+	RIntegerStore getDim();
+	
+	/**
+	 * Returns the names for the dimensions of the array. This corresponds to 
+	 * the names of the R attribute <code>dimnames</code> respectively of the R function 
+	 * <code>dimnames(object)</code>. That means it is equivalent to the R command
+	 * <code>names(dimnames(object))</code>. The names for the indexes in each dimension,
+	 * the values of the R attribute <code>dimnames</code>, are accessible by {@link #getNames(int)}.
+	 * 
+	 * The returned character data has the same length as the dimension data {@link #getDim()}. 
+	 * If the R element does not have names, the names are invalid, or names are disabled, the 
+	 * method returns <code>null</code>.
+	 * 
+	 * @return a charater data store with the names of the dimensions or <code>null</code>
+	 * 
+	 * @since de.walware.rj.data 0.5
+	 */
+	RCharacterStore getDimNames();
+	
+	/**
+	 * Returns the names for the indexes in the given dimension of the array. This corresponds to 
+	 * the values of the R attribute <code>dimnames</code> respectively of the R function 
+	 * <code>dimnames(object)</code>. The names for the dimensions itself are accessible by
+	 * {@link #getDimNames()}.
+	 * 
+	 * @param dim the dimension index
+	 * @return a data store with the names of the indexes in the given dimensions or <code>null</code>
+	 * @throws IndexOutOfBoundsException if dim &lt; 0 or dim &ge; getDim().getLength()
+	 * 
+	 * @since de.walware.rj.data 0.5
+	 */
+	RStore<?> getNames(int dim);
+	
+	
+	@Override
+	TData getData();
+	
+//	void setDim(int[] dim);
+//	void setDimNames(RList list);
+//	void insert(int dim, int idx);
+//	void remove(int dim, int idx);
+	
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/RCharacterStore.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/RCharacterStore.java
new file mode 100644
index 0000000..d65fc7f
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/RCharacterStore.java
@@ -0,0 +1,35 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data;
+
+
+/**
+ * Interface for R data stores of type {@link RStore#CHARACTER}.
+ * <p>
+ * An R data store implements this interface if the R function
+ * <code>typeof(object)</code> returns 'character'.</p>
+ */
+public interface RCharacterStore extends RStore<String> {
+	
+	
+	@Override
+	String get(int idx);
+	@Override
+	String get(long idx);
+	
+	@Override
+	String[] toArray();
+	
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/RComplexStore.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/RComplexStore.java
new file mode 100644
index 0000000..3b16a4c
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/RComplexStore.java
@@ -0,0 +1,93 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data;
+
+import org.eclipse.statet.rj.data.RComplexStore.Complex;
+
+
+/**
+ * Interface for R data stores of type {@link RStore#COMPLEX}.
+ * <p>
+ * An R data store implements this interface if the R function
+ * <code>typeof(object)</code> returns 'complex'.</p>
+ */
+public interface RComplexStore extends RStore<Complex> {
+	
+	
+	final class Complex {
+		
+		
+		private final double realValue;
+		private final double imaginaryValue;
+		
+		
+		public Complex(final double real, final double imaginary) {
+			this.realValue= real;
+			this.imaginaryValue= imaginary;
+		}
+		
+		
+		public double getRe() {
+			return this.realValue;
+		}
+		
+		public double getIm() {
+			return this.imaginaryValue;
+		}
+		
+		
+		@Override
+		public int hashCode() {
+			final long realBits= Double.doubleToLongBits(this.realValue);
+			final long imaginaryBits= Double.doubleToLongBits(this.imaginaryValue) + 1;
+			return (int) ((realBits ^ (realBits >>> 32)) | (imaginaryBits ^ (imaginaryBits >>> 32)));
+		}
+		
+		@Override
+		public boolean equals(final Object obj) {
+			if (!(obj instanceof Complex)) {
+				return false;
+			}
+			final Complex other= (Complex) obj;
+			return (this.realValue == other.realValue && this.imaginaryValue == other.imaginaryValue);
+		}
+		
+		@Override
+		public String toString() {
+			final StringBuilder sb= new StringBuilder(32);
+			sb.append(Double.toString(this.realValue));
+			if (this.imaginaryValue >= 0.0) {
+				sb.append('+');
+			}
+			sb.append(Double.toString(this.imaginaryValue));
+			sb.append('i');
+			return sb.toString();
+		}
+		
+	}
+	
+	
+	boolean isNaN(int idx);
+	boolean isNaN(long idx);
+	
+	@Override
+	Complex get(int idx);
+	@Override
+	Complex get(long idx);
+	
+	@Override
+	Complex[] toArray();
+	
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/RDataFrame.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/RDataFrame.java
new file mode 100644
index 0000000..836dca6
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/RDataFrame.java
@@ -0,0 +1,178 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data;
+
+
+/**
+ * An R object is of the type {@link RObject#TYPE_DATAFRAME vector}, if it is an R list object 
+ * inheriting the R class {@link #CLASSNAME_DATAFRAME data.frame} and compiling with the R rules for 
+ * a data frame, especially its children are {@link RVector}s of the same length.
+ * <p>
+ * The methods {@link #getLength()}, {@link #getName(int)}, {@link #get(int)} and
+ * {@link #get(String)}, inherited by the RList interface, provides access to the columns using the
+ * uniform RList API. The methods {@link #getColumnCount()}, {@link #getColumnNames()},
+ * {@link #getColumn(int)} and {@link #getColumn(String)} are data frame specific methods with
+ * similar functionality with direct access to the data stores of the columns, bypassing the RVector
+ * objects.</p>
+ * <p>
+ * The row information of the data frame are accessible by {@link #getRowCount()} and 
+ * {@link #getRowNames()}.</p>
+ */
+public interface RDataFrame extends RList, RObject {
+	
+	/**
+	 * Returns the number of columns of the data frame.
+	 * <p>
+	 * This method is synonymous to {@link #getColumnCount()}.</p>
+	 * 
+	 * @return the number of columns
+	 */
+	@Override
+	long getLength();
+	
+	/**
+	 * Returns the names of the columns of the data frame.
+	 * <p>
+	 * This method is synonymous to {@link #getColumnNames()}.</p>
+	 * 
+	 * @return the column names
+	 */
+	@Override
+	RCharacterStore getNames();
+	
+	/**
+	 * Returns the name of the specified column of the data frame.
+	 * 
+	 * @param idx the index (zero-based) of the column
+	 * @return the column name
+	 * @throws IndexOutOfBoundsException if <code>idx</code> &lt; 0 or <code>idx</code> &ge; column count
+	 */
+	@Override
+	String getName(long idx);
+	
+	/**
+	 * Returns the RVector object of the specified column of the data frame.
+	 * 
+	 * @param idx the index (zero-based) of the column
+	 * @return the column vector
+	 * @throws IndexOutOfBoundsException if <code>idx</code> &lt; 0 or <code>idx</code> &ge; column count
+	 */
+	@Override
+	RObject get(long idx);
+	
+	/**
+	 * Returns the RVector object of the column with the specified name of the data frame.
+	 * 
+	 * @param name the name of the column
+	 * @return the column vector or <code>null</code> (if no column with the specified name exists)
+	 */
+	@Override
+	RObject get(String name);
+	
+	/**
+	 * For a data frame this method always returns <code>null</code>.
+	 * 
+	 * @return <code>null</code>
+	 */
+	@Override
+	RStore<?> getData();
+	
+	
+	/**
+	 * Returns the number of columns of the data frame.
+	 * <p>
+	 * This method is synonymous to {@link #getLength()}.</p>
+	 * 
+	 * @return the number of columns
+	 */
+	long getColumnCount();
+	
+	/**
+	 * Returns the names of the columns of the data frame.
+	 * <p>
+	 * This method is synonymous to {@link #getNames()}.</p>
+	 * 
+	 * @return the column names
+	 */
+	public RCharacterStore getColumnNames();
+	
+//	String getColumnName(int idx);
+	
+	/**
+	 * Returns the data store for the specified column of the data frame.
+	 * <p>
+	 * This method is equivalent to <code>get(idx).getData()</code>.</p>
+	 * <p>
+	 * Each column data store has the length of {@link #getRowCount()}.</p>
+	 * 
+	 * @param idx the index (zero-based) of the column
+	 * @return the data store of the column
+	 * @throws IndexOutOfBoundsException if <code>idx</code> &lt; 0 or <code>idx</code> &ge; column count
+	 */
+	public RStore<?> getColumn(int idx);
+	
+	/**
+	 * Returns the data store for the specified column of the data frame.
+	 * <p>
+	 * This method is equivalent to <code>get(idx).getData()</code>.</p>
+	 * <p>
+	 * Each column data store has the length of {@link #getRowCount()}.</p>
+	 * 
+	 * @param idx the index (zero-based) of the column
+	 * @return the data store of the column
+	 * @throws IndexOutOfBoundsException if <code>idx</code> &lt; 0 or <code>idx</code> &ge; column count
+	 */
+	public RStore<?> getColumn(long idx);
+	
+	/**
+	 * Returns the data store for the column with the specified name of the data frame.
+	 * <p>
+	 * This method is equivalent to <code>get(name).getData()</code> (with additional <code>null</code>
+	 * check, if no column with that name exists).</p>
+	 * <p>
+	 * Each column data store has the length of {@link #getRowCount()}.</p>
+	 * 
+	 * @param name the name of the column
+	 * @return the data store of the column or <code>null</code> (if no column with the specified name exists)
+	 */
+	public RStore<?> getColumn(String name);
+	
+	/**
+	 * Returns the number of rows of the data frame.
+	 * <p>
+	 * Each data store of a column ({@link #getColumn(int)} has this length.
+	 * 
+	 * @return the number of rows
+	 */
+	long getRowCount();
+	
+	/**
+	 * Returns the names of the rows of the data frame.
+	 * <p>
+	 * This method is equivalent to the R command <code>row.names(obj)</code>.</p>
+	 * 
+	 * @return the row names
+	 */
+	RStore<?> getRowNames();
+	
+	
+//	void setColumn(int idx, RStore<?> column);
+//	void insertColumn(int idx, RStore<?> column);
+//	void removeColumn(int idx);
+	
+//	void insertRow(int idx);
+//	void removeRow(int idx);
+	
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/RDataJConverter.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/RDataJConverter.java
new file mode 100644
index 0000000..7e7bdcd
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/RDataJConverter.java
@@ -0,0 +1,94 @@
+/*=============================================================================#
+ # Copyright (c) 2011, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data;
+
+import java.util.Map;
+import java.util.Map.Entry;
+
+
+
+/**
+ * Converts R data objects to classic Java objects and the other way around.
+ */
+public class RDataJConverter {
+	
+	
+	private boolean keepArray1;
+	
+	private RObjectFactory rObjectFactory;
+	
+	
+	public void setKeepArray1(final boolean enable) {
+		this.keepArray1= enable;
+	}
+	
+	public void setRObjectFactory(final RObjectFactory factory) {
+		this.rObjectFactory= factory;
+	}
+	
+	public RObjectFactory getRObjectFactory() {
+		return this.rObjectFactory;
+	}
+	
+	
+	public Object toJava(final RObject rObject) {
+		switch (rObject.getRObjectType()) {
+		case RObject.TYPE_VECTOR:
+			return toJava(rObject.getData());
+		}
+		return null;
+	}
+	
+	public Object toJava(final RStore<?> rData) {
+		final Object[] array= rData.toArray();
+		if (!this.keepArray1 && array != null && array.length == 1) {
+			return array[0];
+		}
+		return array;
+	}
+	
+	
+	
+	public RObject toRJ(final Object javaObj) {
+		if (javaObj instanceof Boolean) {
+			return this.rObjectFactory.createVector(
+					this.rObjectFactory.createLogiData(new boolean[] {
+							((Boolean) javaObj).booleanValue() }));
+		}
+		if (javaObj instanceof String) {
+			return this.rObjectFactory.createVector(
+					this.rObjectFactory.createCharData(new String[] {
+							(String) javaObj }));
+		}
+		if (javaObj instanceof String[]) {
+			return this.rObjectFactory.createVector(
+					this.rObjectFactory.createCharData((String[]) javaObj) );
+		}
+		if (javaObj instanceof Map) {
+			final Map<?, ?> map= (Map<?, ?>) javaObj;
+			final String[] names= new String[map.size()];
+			final RObject[] components= new RObject[map.size()];
+			int i= 0;
+			for (final Entry<?, ?> entry : map.entrySet()) {
+				names[i]= (String) entry.getKey();
+				components[i]= toRJ(entry.getValue());
+				i++;
+			}
+			return this.rObjectFactory.createList(components, names);
+		}
+		return null;
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/RDataUtils.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/RDataUtils.java
new file mode 100644
index 0000000..2015200
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/RDataUtils.java
@@ -0,0 +1,995 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data;
+
+
+public class RDataUtils {
+	
+	/**
+	 * Returns the common abbreviation for the type of the given data store.
+	 * These are the abbreviations used by the R function <code>str(x)</code>.
+	 * If there is no abbreviation for the given type, it return the class name 
+	 * of an R vector with data of this type.
+	 * 
+	 * @param store the data store
+	 * @return an abbreviation
+	 */
+	public static final String getStoreAbbr(final RStore<?> store) {
+		switch (store.getStoreType()) {
+		case RStore.LOGICAL:
+			return "logi";
+		case RStore.INTEGER:
+			return "int";
+		case RStore.NUMERIC:
+			return "num";
+		case RStore.CHARACTER:
+			return "chr";
+		case RStore.COMPLEX:
+			return "cplx";
+		case RStore.RAW:
+			return "raw";
+		case RStore.FACTOR:
+			return ((RFactorStore) store).isOrdered() ? RObject.CLASSNAME_ORDERED : RObject.CLASSNAME_FACTOR;
+		default:
+			return "";
+		}
+	}
+	
+	/**
+	 * Returns the class name of an R vector with data of the type of the given data store.
+	 * 
+	 * @param store the data store
+	 * @return an class name
+	 */
+	public static final String getStoreClass(final RStore<?> store) {
+		switch (store.getStoreType()) {
+		case RStore.LOGICAL:
+			return RObject.CLASSNAME_LOGICAL;
+		case RStore.INTEGER:
+			return RObject.CLASSNAME_INTEGER;
+		case RStore.NUMERIC:
+			return RObject.CLASSNAME_NUMERIC;
+		case RStore.CHARACTER:
+			return RObject.CLASSNAME_CHARACTER;
+		case RStore.COMPLEX:
+			return RObject.CLASSNAME_COMPLEX;
+		case RStore.RAW:
+			return RObject.CLASSNAME_RAW;
+		case RStore.FACTOR:
+			return ((RFactorStore) store).isOrdered() ? RObject.CLASSNAME_ORDERED : RObject.CLASSNAME_FACTOR;
+		default:
+			return "";
+		}
+	}
+	
+	public static final String getStoreMode(final int storeType) {
+		switch (storeType) {
+		case RStore.LOGICAL:
+			return "logical";
+		case RStore.INTEGER:
+		case RStore.FACTOR:
+			return "integer";
+		case RStore.NUMERIC:
+			return "numeric";
+		case RStore.CHARACTER:
+			return "character";
+		case RStore.COMPLEX:
+			return "complex";
+		case RStore.RAW:
+			return "raw";
+		default:
+			return "";
+		}
+	}
+	
+	public static final String getObjectTypeName(final byte type) {
+		switch (type) {
+		case RObject.TYPE_NULL:
+			return "RNullImpl";
+		case RObject.TYPE_VECTOR:
+			return "RVector";
+		case RObject.TYPE_ARRAY:
+			return "RArray";
+		case RObject.TYPE_LIST:
+			return "RList";
+		case RObject.TYPE_DATAFRAME:
+			return "RDataFrame";
+		case RObject.TYPE_S4OBJECT:
+			return "RS4Object";
+		case RObject.TYPE_ENVIRONMENT:
+			return "REnvironment";
+		case RObject.TYPE_LANGUAGE:
+			return "RLanguage";
+		case RObject.TYPE_FUNCTION:
+			return "RFunction";
+		case RObject.TYPE_REFERENCE:
+			return "RReference";
+		case RObject.TYPE_OTHER:
+			return "<other>";
+		case RObject.TYPE_MISSING:
+			return "RMissingImpl";
+		case RObject.TYPE_PROMISE:
+			return "RPromiseImpl";
+		default:
+			return "<unkown>";
+		}
+	}
+	
+	public static final long computeLengthFromDim(final int[] dims) {
+		if (dims.length == 0) {
+			return 0;
+		}
+		long length= 1;
+		for (int i= 0; i < dims.length; i++) {
+			length *= dims[i];
+		}
+		return length;
+	}
+	
+	public static final long getDataIdx(final int[] dims, final int... idxs) {
+		assert (dims.length > 0);
+		assert (dims.length == idxs.length);
+		
+		long dataIdx= idxs[0];
+		long step= dims[0];
+		// alt: idx=0; step=1; i=0;
+		for (int i= 1; i < dims.length; i++) {
+			dataIdx+= step*idxs[i];
+			step *= dims[i];
+		}
+		return dataIdx;
+	}
+	
+	public static final long getDataIdx(final RStore<?> dims, final int... idxs) {
+		assert (dims.getLength() > 0);
+		assert (dims.getLength() == idxs.length);
+		
+		long dataIdx= idxs[0];
+		long step= dims.getInt(0);
+		// alt: idx=0; step=1; i=0;
+		for (int i= 1; i < dims.getLength(); i++) {
+			dataIdx+= step * idxs[i];
+			step *= dims.getInt(i);
+		}
+		return dataIdx;
+	}
+	
+	/**
+	 * Computes the index of a data value in a store of a matrix / 2 dimensional arrays
+	 * specified by its column and row indexes.
+	 * 
+	 * @param rowCount count of rows of the matrix
+	 * @param rowIdx row index (zero-based) of the matrix
+	 * @param columnIdx column index (zero-based) of the matrix
+	 * @return the index in the data store
+	 * 
+	 * @see #getDataIdx(int[], int...)
+	 */
+	public static final long getDataIdx(final long rowCount, final long rowIdx, final long columnIdx) {
+		return rowIdx + rowCount * columnIdx;
+	}
+	
+	public static final int[] getDataIdxs(final int[] dims, final int dim, final int idx) {
+		assert (dims.length > 0);
+		assert (0 <= dim && dim < dims.length);
+		assert (0 <= idx && idx < dims[dim]);
+		
+		final int size;
+		final int dimsCount= dims.length;
+		if (dimsCount == 1) {
+			size= 1;
+		}
+		else if (dimsCount == 2) {
+			size= dims[(dim == 0) ? 1 : 0];
+		}
+		else {
+			int counter= 1;
+			for (int dimIdx= 0; dimIdx < dimsCount; dimIdx++) {
+				if (dimIdx != dim) {
+					counter *= dims[dimIdx];
+				}
+			}
+			size= counter;
+		}
+		
+		final int[] dataIdxs= new int[size];
+		int step= 1;
+		int stepCount= 1;
+		for (int dimIdx= 0; dimIdx < dimsCount; dimIdx++) {
+			final int dimSize= dims[dimIdx];
+			if (dimIdx == dim) {
+				final int add= step*idx;
+				for (int i= 0; i < size; i++) {
+					dataIdxs[i]+= add;
+				}
+			}
+			else {
+				for (int i= 0, idxInDim= 0; i < size; idxInDim++) {
+					if (idxInDim == dimSize) {
+						idxInDim= 0;
+					}
+					final int add= step*idxInDim;
+					for (int j= 0; j < stepCount && i < size; i++,j++) {
+						dataIdxs[i]+= add;
+					}
+				}
+				stepCount *= dimSize;
+			}
+			step *= dimSize;
+		}
+		return dataIdxs;
+	}
+	
+	
+	public static final boolean isSingleString(final RObject obj) {
+		final RStore<?> data;
+		return (obj != null && (data= obj.getData()) != null
+				&& data.getStoreType() == RStore.CHARACTER
+				&& data.getLength() == 1 );
+	}
+	
+	
+	public static final RVector<?> checkRVector(final RObject obj) throws UnexpectedRDataException {
+		if (obj == null) {
+			throw new UnexpectedRDataException("Missing R object.");
+		}
+		if (obj.getRObjectType() != RObject.TYPE_VECTOR) {
+			throw new UnexpectedRDataException("Unexpected R object type: " + getObjectTypeName(obj.getRObjectType()));
+		}
+		return (RVector<?>) obj;
+	}
+	
+	@SuppressWarnings("unchecked")
+	public static final RVector<RLogicalStore> checkRLogiVector(final RObject obj) throws UnexpectedRDataException {
+		if (obj == null) {
+			throw new UnexpectedRDataException("Missing R object.");
+		}
+		if (obj.getRObjectType() != RObject.TYPE_VECTOR) {
+			throw new UnexpectedRDataException("Unexpected R object type: " + getObjectTypeName(obj.getRObjectType()));
+		}
+		if (obj.getData().getStoreType() != RStore.LOGICAL) {
+			throw new UnexpectedRDataException("Unexpected R object type: " + getStoreAbbr(obj.getData()));
+		}
+		return (RVector<RLogicalStore>) obj;
+	}
+	
+	@SuppressWarnings("unchecked")
+	public static final RVector<RIntegerStore> checkRIntVector(final RObject obj) throws UnexpectedRDataException {
+		if (obj == null) {
+			throw new UnexpectedRDataException("Missing R object.");
+		}
+		if (obj.getRObjectType() != RObject.TYPE_VECTOR) {
+			throw new UnexpectedRDataException("Unexpected R object type: " + getObjectTypeName(obj.getRObjectType()));
+		}
+		if (obj.getData().getStoreType() != RStore.INTEGER) {
+			throw new UnexpectedRDataException("Unexpected R object type: " + getStoreAbbr(obj.getData()));
+		}
+		return (RVector<RIntegerStore>) obj;
+	}
+	
+	@SuppressWarnings("unchecked")
+	public static final RVector<RNumericStore> checkRNumVector(final RObject obj) throws UnexpectedRDataException {
+		if (obj == null) {
+			throw new UnexpectedRDataException("Missing R object.");
+		}
+		if (obj.getRObjectType() != RObject.TYPE_VECTOR) {
+			throw new UnexpectedRDataException("Unexpected R object type: " + getObjectTypeName(obj.getRObjectType()));
+		}
+		if (obj.getData().getStoreType() != RStore.NUMERIC) {
+			throw new UnexpectedRDataException("Unexpected R object type: " + getStoreAbbr(obj.getData()));
+		}
+		return (RVector<RNumericStore>) obj;
+	}
+	
+	@SuppressWarnings("unchecked")
+	public static final RVector<RCharacterStore> checkRCharVector(final RObject obj) throws UnexpectedRDataException {
+		if (obj == null) {
+			throw new UnexpectedRDataException("Missing R object.");
+		}
+		if (obj.getRObjectType() != RObject.TYPE_VECTOR) {
+			throw new UnexpectedRDataException("Unexpected R object type: " + getObjectTypeName(obj.getRObjectType()));
+		}
+		if (obj.getData().getStoreType() != RStore.CHARACTER) {
+			throw new UnexpectedRDataException("Unexpected R object type: " + getStoreAbbr(obj.getData()));
+		}
+		return (RVector<RCharacterStore>) obj;
+	}
+	
+	public static final RArray<?> checkRArray(final RObject obj) throws UnexpectedRDataException {
+		if (obj == null) {
+			throw new UnexpectedRDataException("Missing R object.");
+		}
+		if (obj.getRObjectType() != RObject.TYPE_ARRAY) {
+			throw new UnexpectedRDataException("Unexpected R object type: " + getObjectTypeName(obj.getRObjectType()));
+		}
+		return (RArray<?>) obj;
+	}
+	
+	public static final RArray<?> checkRArray(final RObject obj, final int dim) throws UnexpectedRDataException {
+		if (obj == null) {
+			throw new UnexpectedRDataException("Missing R object.");
+		}
+		if (obj.getRObjectType() != RObject.TYPE_ARRAY) {
+			throw new UnexpectedRDataException("Unexpected R object type: " + getObjectTypeName(obj.getRObjectType()));
+		}
+		final RArray<?> array= (RArray<?>) obj;
+		if (dim > 0) {
+			if (dim != array.getDim().getLength()) {
+				throw new UnexpectedRDataException("Unexpected R array dimension: " + array.getDim().getLength());
+			}
+		}
+		return array;
+	}
+	
+	public static final RArray<?> checkRArray(final RObject obj, final long dim) throws UnexpectedRDataException {
+		if (obj == null) {
+			throw new UnexpectedRDataException("Missing R object.");
+		}
+		if (obj.getRObjectType() != RObject.TYPE_ARRAY) {
+			throw new UnexpectedRDataException("Unexpected R object type: " + getObjectTypeName(obj.getRObjectType()));
+		}
+		final RArray<?> array= (RArray<?>) obj;
+		if (dim > 0) {
+			if (dim != array.getDim().getLength()) {
+				throw new UnexpectedRDataException("Unexpected R array dimension: " + array.getDim().getLength());
+			}
+		}
+		return array;
+	}
+	
+	@SuppressWarnings("unchecked")
+	public static final RArray<RCharacterStore> checkRCharArray(final RObject obj, final int dim) throws UnexpectedRDataException {
+		if (obj == null) {
+			throw new UnexpectedRDataException("Missing R object.");
+		}
+		if (obj.getRObjectType() != RObject.TYPE_ARRAY) {
+			throw new UnexpectedRDataException("Unexpected R object type: " + getObjectTypeName(obj.getRObjectType()));
+		}
+		if (obj.getData().getStoreType() != RStore.CHARACTER) {
+			throw new UnexpectedRDataException("Unexpected R data type: " + getStoreAbbr(obj.getData()));
+		}
+		final RArray<RCharacterStore> array= (RArray<RCharacterStore>) obj;
+		if (dim > 0) {
+			if (dim != array.getDim().getLength()) {
+				throw new UnexpectedRDataException("Unexpected R array dimension: " + array.getDim().getLength());
+			}
+		}
+		return array;
+	}
+	
+	public static final RList checkRList(final RObject obj) throws UnexpectedRDataException {
+		if (obj == null) {
+			throw new UnexpectedRDataException("Missing R object.");
+		}
+		if (obj.getRObjectType() != RObject.TYPE_LIST) {
+			throw new UnexpectedRDataException("Unexpected R object type: " + getObjectTypeName(obj.getRObjectType()));
+		}
+		return (RList) obj;
+	}
+	
+	public static final RDataFrame checkRDataFrame(final RObject obj) throws UnexpectedRDataException {
+		if (obj == null) {
+			throw new UnexpectedRDataException("Missing R object.");
+		}
+		if (obj.getRObjectType() != RObject.TYPE_DATAFRAME) {
+			throw new UnexpectedRDataException("Unexpected R object type: " + getObjectTypeName(obj.getRObjectType()));
+		}
+		return (RDataFrame) obj;
+	}
+	
+	public static final RDataFrame checkRDataFrame(final RObject obj, final long length) throws UnexpectedRDataException {
+		if (obj == null) {
+			throw new UnexpectedRDataException("Missing R object.");
+		}
+		if (obj.getRObjectType() != RObject.TYPE_DATAFRAME) {
+			throw new UnexpectedRDataException("Unexpected R object type: " + getObjectTypeName(obj.getRObjectType()));
+		}
+		if (obj.getLength() != length) {
+			throw new UnexpectedRDataException("Unexpected R dataframe column count: " + obj.getLength());
+		}
+		return (RDataFrame) obj;
+	}
+	
+	public static final RReference checkRReference(final RObject obj) throws UnexpectedRDataException {
+		if (obj == null) {
+			throw new UnexpectedRDataException("Missing R object.");
+		}
+		if (obj.getRObjectType() != RObject.TYPE_REFERENCE) {
+			throw new UnexpectedRDataException(
+					"Unexpected R object type: " + getObjectTypeName(obj.getRObjectType()) );
+		}
+		return (RReference) obj;
+	}
+	
+	public static final RReference checkRReference(final RObject obj, final byte referencedObjectType)
+			throws UnexpectedRDataException {
+		if (obj == null) {
+			throw new UnexpectedRDataException("Missing R object.");
+		}
+		if (obj.getRObjectType() != RObject.TYPE_REFERENCE) {
+			throw new UnexpectedRDataException(
+					"Unexpected R object type: " + getObjectTypeName(obj.getRObjectType()) );
+		}
+		final RReference reference= (RReference) obj;
+		if (reference.getReferencedRObjectType() != referencedObjectType) {
+			throw new UnexpectedRDataException(
+					"Unexpected referenced R object type: " + getObjectTypeName(obj.getRObjectType()) +
+					", but " + getObjectTypeName(referencedObjectType) + " expected." );
+		}
+		return (RReference) obj;
+	}
+	
+	public static final RLanguage checkRLanguage(final RObject obj) throws UnexpectedRDataException {
+		if (obj == null) {
+			throw new UnexpectedRDataException("Missing R object.");
+		}
+		if (obj.getRObjectType() != RObject.TYPE_LANGUAGE) {
+			throw new UnexpectedRDataException("Unexpected R object type: " + getObjectTypeName(obj.getRObjectType()));
+		}
+		return (RLanguage) obj;
+	}
+	
+	public static final Boolean checkSingleLogi(final RObject obj) throws UnexpectedRDataException {
+		if (obj == null) {
+			throw new UnexpectedRDataException("Missing R object.");
+		}
+		final RStore<?> data= obj.getData();
+		if (data == null) {
+			throw new UnexpectedRDataException("Unexpected R object type: " + getObjectTypeName(obj.getRObjectType()) + " (without R data)");
+		}
+		if (data.getStoreType() != RStore.LOGICAL) {
+			throw new UnexpectedRDataException("Unexpected R data type: " + getStoreAbbr(data));
+		}
+		if (data.getLength() != 1) {
+			throw new UnexpectedRDataException("Unexpected R data length: " + data.getLength() + ", but == 1 expected.");
+		}
+		if (data.isNA(0)) {
+			return null;
+		}
+		return Boolean.valueOf(data.getLogi(0));
+	}
+	
+	public static final boolean checkSingleLogiValue(final RObject obj) throws UnexpectedRDataException {
+		if (obj == null) {
+			throw new UnexpectedRDataException("Missing R object.");
+		}
+		final RStore<?> data= obj.getData();
+		if (data == null) {
+			throw new UnexpectedRDataException("Unexpected R object type: " + getObjectTypeName(obj.getRObjectType()) + " (without R data)");
+		}
+		if (data.getStoreType() != RStore.LOGICAL) {
+			throw new UnexpectedRDataException("Unexpected R data type: " + getStoreAbbr(data));
+		}
+		if (data.getLength() != 1) {
+			throw new UnexpectedRDataException("Unexpected R data length: " + data.getLength() + ", but == 1 expected.");
+		}
+		if (data.isNA(0)) {
+			throw new UnexpectedRDataException("Unexpected R data value: NA");
+		}
+		return data.getLogi(0);
+	}
+	
+	public static final Integer checkSingleInt(final RObject obj) throws UnexpectedRDataException {
+		if (obj == null) {
+			throw new UnexpectedRDataException("Missing R object.");
+		}
+		final RStore<?> data= obj.getData();
+		if (data == null) {
+			throw new UnexpectedRDataException("Unexpected R object type: " + getObjectTypeName(obj.getRObjectType()) + " (without R data)");
+		}
+		if (data.getStoreType() != RStore.INTEGER) {
+			throw new UnexpectedRDataException("Unexpected R data type: " + getStoreAbbr(data));
+		}
+		if (data.getLength() != 1) {
+			throw new UnexpectedRDataException("Unexpected R data length: " + data.getLength() + ", but == 1 expected.");
+		}
+		if (data.isNA(0)) {
+			return null;
+		}
+		return Integer.valueOf(data.getInt(0));
+	}
+	
+	public static final int checkSingleIntValue(final RObject obj) throws UnexpectedRDataException {
+		if (obj == null) {
+			throw new UnexpectedRDataException("Missing R object.");
+		}
+		final RStore<?> data= obj.getData();
+		if (data == null) {
+			throw new UnexpectedRDataException("Unexpected R object type: " + getObjectTypeName(obj.getRObjectType()) + " (without R data)");
+		}
+		if (data.getStoreType() != RStore.INTEGER) {
+			throw new UnexpectedRDataException("Unexpected R data type: " + getStoreAbbr(data));
+		}
+		if (data.getLength() != 1) {
+			throw new UnexpectedRDataException("Unexpected R data length: " + data.getLength() + ", but == 1 expected.");
+		}
+		if (data.isNA(0)) {
+			throw new UnexpectedRDataException("Unexpected R data value: NA");
+		}
+		return data.getInt(0);
+	}
+	
+	public static final Double checkSingleNum(final RObject obj) throws UnexpectedRDataException {
+		if (obj == null) {
+			throw new UnexpectedRDataException("Missing R object.");
+		}
+		final RStore<?> data= obj.getData();
+		if (data == null) {
+			throw new UnexpectedRDataException("Unexpected R object type: " + getObjectTypeName(obj.getRObjectType()) + " (without R data)");
+		}
+		if (data.getStoreType() != RStore.NUMERIC) {
+			throw new UnexpectedRDataException("Unexpected R data type: " + getStoreAbbr(data));
+		}
+		if (data.getLength() != 1) {
+			throw new UnexpectedRDataException("Unexpected R data length: " + data.getLength() + ", but == 1 expected.");
+		}
+		if (data.isNA(0)) {
+			return null;
+		}
+		return Double.valueOf(data.getNum(0));
+	}
+	
+	public static final double checkSingleNumValue(final RObject obj) throws UnexpectedRDataException {
+		if (obj == null) {
+			throw new UnexpectedRDataException("Missing R object.");
+		}
+		final RStore<?> data= obj.getData();
+		if (data == null) {
+			throw new UnexpectedRDataException("Unexpected R object type: " + getObjectTypeName(obj.getRObjectType()) + " (without R data)");
+		}
+		if (data.getStoreType() != RStore.NUMERIC) {
+			throw new UnexpectedRDataException("Unexpected R data type: " + getStoreAbbr(data));
+		}
+		if (data.getLength() != 1) {
+			throw new UnexpectedRDataException("Unexpected R data length: " + data.getLength() + ", but == 1 expected.");
+		}
+		if (data.isNA(0)) {
+			throw new UnexpectedRDataException("Unexpected R data value: NA");
+		}
+		return data.getNum(0);
+	}
+	
+	public static final String checkSingleChar(final RObject obj) throws UnexpectedRDataException {
+		if (obj == null) {
+			throw new UnexpectedRDataException("Missing R object.");
+		}
+		final RStore<?> data= obj.getData();
+		if (data == null) {
+			throw new UnexpectedRDataException("Unexpected R object type: " + getObjectTypeName(obj.getRObjectType()) + " (without R data)");
+		}
+		if (data.getStoreType() != RStore.CHARACTER) {
+			throw new UnexpectedRDataException("Unexpected R data type: " + getStoreAbbr(data));
+		}
+		if (data.getLength() != 1) {
+			throw new UnexpectedRDataException("Unexpected R data length: " + data.getLength() + ", but == 1 expected.");
+		}
+		return data.getChar(0);
+	}
+	
+	public static final String checkSingleCharValue(final RObject obj) throws UnexpectedRDataException {
+		if (obj == null) {
+			throw new UnexpectedRDataException("Missing R object.");
+		}
+		final RStore<?> data= obj.getData();
+		if (data == null) {
+			throw new UnexpectedRDataException("Unexpected R object type: " + getObjectTypeName(obj.getRObjectType()) + " (without R data)");
+		}
+		if (data.getStoreType() != RStore.CHARACTER) {
+			throw new UnexpectedRDataException("Unexpected R data type: " + getStoreAbbr(data));
+		}
+		if (data.getLength() != 1) {
+			throw new UnexpectedRDataException("Unexpected R data length: " + data.getLength() + ", but == 1 expected.");
+		}
+		if (data.isNA(0)) {
+			throw new UnexpectedRDataException("Unexpected R data value: NA");
+		}
+		return data.getChar(0);
+	}
+	
+	public static final RObject checkType(final RObject obj, final byte objectType) throws UnexpectedRDataException {
+		if (obj == null) {
+			throw new UnexpectedRDataException("Missing R object.");
+		}
+		if (obj.getRObjectType() != objectType) {
+			throw new UnexpectedRDataException(
+					"Unexpected R object type: " + getObjectTypeName(obj.getRObjectType()) +
+					", but " + getObjectTypeName(objectType) + " expected." );
+		}
+		return obj;
+	}
+	
+	public static final RStore<?> checkData(final RStore<?> data, final byte storeType) throws UnexpectedRDataException {
+		if (data.getStoreType() != storeType) {
+			throw new UnexpectedRDataException("Unexpected R data type: " + getStoreAbbr(data) + ", but " + storeType + " expected.");
+		}
+		return data;
+	}
+	
+	
+	public static final int checkIntLength(final RObject obj) throws UnexpectedRDataException {
+		return checkIntLength(obj.getLength());
+	}
+	
+	public static final int checkIntLength(final RStore<?> data) throws UnexpectedRDataException {
+		return checkIntLength(data.getLength());
+	}
+	
+	public static final int checkIntLength(final long length) throws UnexpectedRDataException {
+		if (length < 0 || length > Integer.MAX_VALUE) {
+			throw new UnexpectedRDataException("Unexpected R data length: " + length + ", but <= 2^31-1 expected.");
+		}
+		return (int) length;
+	}
+	
+	public static final int checkIntIdx(final long idx) throws UnexpectedRDataException {
+		if (idx < 0 || idx >= Integer.MAX_VALUE) {
+			throw new UnexpectedRDataException("Unexpected R data index: " + idx + ", but < 2^31-1 expected.");
+		}
+		return (int) idx;
+	}
+	
+	public static final <T extends RObject> T checkLengthEqual(final T obj, final long length) throws UnexpectedRDataException {
+		if (obj.getLength() != length) {
+			throw new UnexpectedRDataException("Unexpected R object length: " + obj.getLength() + ", but == " + length + " expected.");
+		}
+		return obj;
+	}
+	
+	public static final <TData extends RStore<?>> TData checkLengthEqual(final TData data,
+			final long length)
+			throws UnexpectedRDataException {
+		if (data.getLength() != length) {
+			throw new UnexpectedRDataException("Unexpected R data length: " + data.getLength() + ", but == " + length + " expected.");
+		}
+		return data;
+	}
+	
+	public static final <TData extends RStore<?>> TData checkLengthGreaterOrEqual(final TData data,
+			final long length)
+			throws UnexpectedRDataException {
+		if (data.getLength() < length) {
+			throw new UnexpectedRDataException("Unexpected R data length: " + data.getLength() + ", but >= " + length + " expected.");
+		}
+		return data;
+	}
+	
+	public static final <P> P checkValue(final RStore<P> data, final int idx) throws UnexpectedRDataException {
+		final P value= data.get(idx);
+		if (value == null) {
+			throw new UnexpectedRDataException("Unexpected R data value: NA");
+		}
+		return value;
+	}
+	
+	public static final <P> P checkValue(final RStore<P> data, final long idx) throws UnexpectedRDataException {
+		final P value= data.get(idx);
+		if (value == null) {
+			throw new UnexpectedRDataException("Unexpected R data value: NA");
+		}
+		return value;
+	}
+	
+	public static final <P> P getValue(final RStore<P> data, final int idx, final P na) {
+		final P value= data.get(idx);
+		return (value != null) ? value : na;
+	}
+	
+	public static final <P> P getValue(final RStore<P> data, final long idx, final P na) {
+		final P value= data.get(idx);
+		return (value != null) ? value : na;
+	}
+	
+	
+	/*-- 2d --*/
+	
+	public static final int getRowCount(final RArray<?> array) throws UnexpectedRDataException {
+		return array.getDim().getInt(0);
+	}
+	
+	public static final void checkRowCountEqual(final RArray<?> array, final int count) throws UnexpectedRDataException {
+		if (array.getDim().getInt(0) != count) {
+			throw new UnexpectedRDataException("Unexpected R matrix row count: " + array.getDim().getInt(0) + ", but == " + count + " expected.");
+		}
+	}
+	
+	public static final void checkRowCountEqual(final RDataFrame dataframe, final long count) throws UnexpectedRDataException {
+		if (dataframe.getRowCount() != count) {
+			throw new UnexpectedRDataException("Unexpected R dataframe row count: " + dataframe.getRowCount() + ", but == " + count + " expected.");
+		}
+	}
+	
+	public static final int getColumnCount(final RArray<?> array) throws UnexpectedRDataException {
+		return array.getDim().getInt(1);
+	}
+	
+	public static final void checkColumnCountEqual(final RArray<?> array, final int count) throws UnexpectedRDataException {
+		if (array.getDim().getInt(1) != count) {
+			throw new UnexpectedRDataException("Unexpected R matrix column count: " + array.getDim().getInt(1) + ", but == " + count + " expected.");
+		}
+	}
+	
+	public static final long checkColumnName(final RArray<?> array, final String name) throws UnexpectedRDataException {
+		final long idx= array.getNames(1).indexOf(name);
+		if (idx < 0) {
+			throw new UnexpectedRDataException("Missing R matrix column: " + name);
+		}
+		return idx;
+	}
+	
+	public static final void checkColumnCountEqual(final RDataFrame dataframe, final long count) throws UnexpectedRDataException {
+		if (dataframe.getColumnCount() != count) {
+			throw new UnexpectedRDataException("Unexpected R dataframe column count: " + dataframe.getColumnCount() + ", but == " + count + " expected.");
+		}
+	}
+	
+	
+	/*-- int --*/
+	
+	public static final long binarySearch(final RVector<?> vector, final int value) {
+		final RStore<?> data= vector.getData();
+		return binarySearch(data, 0, data.getLength(), value);
+	}
+	
+	public static final long binarySearch(final RStore<?> data, final int value) {
+		return binarySearch(data, 0, data.getLength(), value);
+	}
+	
+	public static final int binarySearch(final RStore<?> data, final int fromIdx, final int toIdx, final int value) {
+		if (fromIdx < 0 || fromIdx > data.getLength()
+				|| toIdx < 0 || toIdx > data.getLength()) {
+			throw new IndexOutOfBoundsException(Long.toString(fromIdx));
+		}
+		if (fromIdx > toIdx) {
+			throw new IllegalArgumentException();
+		}
+		
+		return doBinarySearch(data, fromIdx, toIdx - 1, value);
+	}
+	
+	private static int doBinarySearch(final RStore<?> data, int low, int high, final int value) {
+		while (low <= high) {
+			final int mid= (low + high) >>> 1;
+			final int midValue= data.getInt(mid);
+			if (midValue < value) {
+				low= mid + 1;
+			}
+			else if (midValue > value) {
+				high= mid - 1;
+			}
+			else {
+				return mid; // key found
+			}
+		}
+		return -(low + 1);  // key not found.
+	}
+	
+	public static final long binarySearch(final RStore<?> data, final long fromIdx, final long toIdx, final int value) {
+		if (fromIdx < 0 || fromIdx > data.getLength()
+				|| toIdx < 0 || toIdx > data.getLength()) {
+			throw new IndexOutOfBoundsException(Long.toString(fromIdx));
+		}
+		if (fromIdx > toIdx) {
+			throw new IllegalArgumentException();
+		}
+		if (toIdx <= Integer.MAX_VALUE) {
+			return doBinarySearch(data, (int) fromIdx, (int) toIdx - 1, value);
+		}
+		
+		return doBinarySearch(data, fromIdx, toIdx - 1, value);
+	}
+	
+	private static long doBinarySearch(final RStore<?> data, long low, long high, final int value) {
+		while (low <= high) {
+			final long mid= (low + high) >>> 1;
+			final int midValue= data.getInt(mid);
+			if (midValue < value) {
+				low= mid + 1;
+			}
+			else if (midValue > value) {
+				high= mid - 1;
+			}
+			else {
+				return mid; // key found
+			}
+		}
+		return -(low + 1);  // key not found.
+	}
+	
+	public static final int binarySearch(final RStore<?> data,
+			final long[] fromIdxs, final int length, final int[] values) {
+		if (fromIdxs.length > values.length) {
+			throw new IllegalArgumentException();
+		}
+		if (length < 0 || length > data.getLength()) {
+			throw new IllegalArgumentException();
+		}
+		for (int i= 0; i < fromIdxs.length; i++) {
+			if (fromIdxs[i] < 0 || fromIdxs[i] + length > data.getLength()) {
+				throw new IndexOutOfBoundsException(Long.toString(fromIdxs[i]));
+			}
+		}
+		
+		int low= 0;
+		int high= length - 1;
+		ITER_IDX: while (low <= high) {
+			final int mid= (low + high) >>> 1;
+			for (int i= 0; i < fromIdxs.length; i++) {
+				final int midValue= data.getInt(fromIdxs[i] + mid);
+				if (midValue < values[i]) {
+					low= mid + 1;
+					continue ITER_IDX;
+				}
+				if (midValue > values[i]) {
+					high= mid - 1;
+					continue ITER_IDX;
+				}
+			}
+			return mid; // key found
+		}
+		return -(low + 1);  // key not found.
+	}
+	
+	public static final int compare(final int[] values1, final int[] values2) {
+		for (int i= 0; i < values1.length; i++) {
+			if (values1[i] < values2[i]) {
+				return -1;
+			}
+			if (values1[i] > values2[i]) {
+				return +1;
+			}
+		}
+		return 0; // equal
+	}
+	
+	
+	/*-- long ~ num -- */
+	
+	public static final long binarySearch(final RStore<?> data, final long value) {
+		return binarySearch(data, 0, data.getLength(), value);
+	}
+	
+	public static final int binarySearch(final RStore<?> data, final int fromIdx, final int toIdx, final long value) {
+		if (fromIdx < 0 || fromIdx > data.getLength()
+				|| toIdx < 0 || toIdx > data.getLength()) {
+			throw new IndexOutOfBoundsException(Long.toString(fromIdx));
+		}
+		if (fromIdx > toIdx) {
+			throw new IllegalArgumentException();
+		}
+		
+		return doBinarySearch(data, fromIdx, toIdx - 1, value);
+	}
+	
+	private static int doBinarySearch(final RStore<?> data, int low, int high, final long value) {
+		while (low <= high) {
+			final int mid= (low + high) >>> 1;
+			final double midValue= data.getNum(mid);
+			if (midValue < value) {
+				low= mid + 1;
+			}
+			else if (midValue > value) {
+				high= mid - 1;
+			}
+			else {
+				return mid; // key found
+			}
+		}
+		return -(low + 1);  // key not found.
+	}
+	
+	public static final long binarySearch(final RStore<?> data, final long fromIdx, final long toIdx, final long value) {
+		if (fromIdx < 0 || fromIdx > data.getLength()
+				|| toIdx < 0 || toIdx > data.getLength()) {
+			throw new IndexOutOfBoundsException(Long.toString(fromIdx));
+		}
+		if (fromIdx > toIdx) {
+			throw new IllegalArgumentException();
+		}
+		if (toIdx <= Integer.MAX_VALUE) {
+			return doBinarySearch(data, (int) fromIdx, (int) toIdx - 1, value);
+		}
+		
+		return doBinarySearch(data, fromIdx, toIdx - 1, value);
+	}
+	
+	private static long doBinarySearch(final RStore<?> data, long low, long high, final long value) {
+		while (low <= high) {
+			final long mid= (low + high) >>> 1;
+		final double midValue= data.getNum(mid);
+		if (midValue < value) {
+			low= mid + 1;
+		}
+		else if (midValue > value) {
+			high= mid - 1;
+		}
+		else {
+			return mid; // key found
+		}
+		}
+		return -(low + 1);  // key not found.
+	}
+	
+	public static final int binarySearch(final RStore<?> data,
+			final long[] fromIdxs, final int length, final long[] values) {
+		if (fromIdxs.length > values.length) {
+			throw new IllegalArgumentException();
+		}
+		if (length < 0 || length > data.getLength()) {
+			throw new IllegalArgumentException();
+		}
+		for (int i= 0; i < fromIdxs.length; i++) {
+			if (fromIdxs[i] < 0 || fromIdxs[i] + length > data.getLength()) {
+				throw new IndexOutOfBoundsException(Long.toString(fromIdxs[i]));
+			}
+		}
+		
+		int low= 0;
+		int high= length - 1;
+		ITER_IDX: while (low <= high) {
+			final int mid= (low + high) >>> 1;
+			for (int i= 0; i < fromIdxs.length; i++) {
+				final double midValue= data.getNum(fromIdxs[i] + mid);
+				if (midValue < values[i]) {
+					low= mid + 1;
+					continue ITER_IDX;
+				}
+				if (midValue > values[i]) {
+					high= mid - 1;
+					continue ITER_IDX;
+				}
+			}
+			return mid; // key found
+		}
+		return -(low + 1);  // key not found.
+	}
+	
+	public static final int compare(final long[] values1, final long[] values2) {
+		for (int i= 0; i < values1.length; i++) {
+			if (values1[i] < values2[i]) {
+				return -1;
+			}
+			if (values1[i] > values2[i]) {
+				return +1;
+			}
+		}
+		return 0; // equal
+	}
+	
+	
+	public static final byte[] encodeLongToRaw(final long id) {
+		final byte[] raw= new byte[8];
+		raw[0]= (byte) (id >>> 56);
+		raw[1]= (byte) (id >>> 48);
+		raw[2]= (byte) (id >>> 40);
+		raw[3]= (byte) (id >>> 32);
+		raw[4]= (byte) (id >>> 24);
+		raw[5]= (byte) (id >>> 16);
+		raw[6]= (byte) (id >>> 8);
+		raw[7]= (byte) (id);
+		return raw;
+	}
+	
+	public static final long decodeLongFromRaw(final byte[] raw) {
+		return(	((long) (raw[0] & 0xff) << 56) |
+				((long) (raw[1] & 0xff) << 48) |
+				((long) (raw[2] & 0xff) << 40) |
+				((long) (raw[3] & 0xff) << 32) |
+				((long) (raw[4] & 0xff) << 24) |
+				((raw[5] & 0xff) << 16) |
+				((raw[6] & 0xff) << 8) |
+				((raw[7] & 0xff)) );
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/REnvironment.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/REnvironment.java
new file mode 100644
index 0000000..a0d0d2e
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/REnvironment.java
@@ -0,0 +1,111 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data;
+
+
+/**
+ * An R object is of the type {@link RObject#TYPE_ENVIRONMENT environment}, if the
+ * object is an R environment.  Such an R environment object is represented
+ * by an instance of this interface.
+ * <p>
+ * The R function <code>typeof(object)</code> returns 'environment' for objects
+ * of this type.</p>
+ * <p>
+ * Even the interface extends {@link RList}, the objects are not a list in R!
+ * The inheritance is only for a uniform API.</p>
+ */
+public interface REnvironment extends RList {
+	
+	/**
+	 * Environment name of the global environment
+	 * (<code>.GlobalEnv</code>)
+	 * 
+	 * Name: {@value}
+	 **/
+	String ENVNAME_GLOBAL= "R_GlobalEnv";
+	
+	/**
+	 * Environment name of the empty environment
+	 * (<code>emptyenv()</code>)
+	 * 
+	 * Name: {@value}
+	 **/
+	String ENVNAME_EMPTY= "R_EmptyEnv";
+	
+	/**
+	 * Environment name of the base environment
+	 * (<code>baseenv()</code>)
+	 * 
+	 * Name: {@value}
+	 **/
+	String ENVNAME_BASE= "base";
+	
+	/**
+	 * Environment name of the Autoloads environment
+	 * (<code>.AutoloadEnv</code>)
+	 * 
+	 * Name: {@value}
+	 **/
+	String ENVNAME_AUTOLOADS= "Autoloads";
+	
+	
+	byte ENVTYPE_BASE=                                      0x01;
+	byte ENVTYPE_AUTOLOADS=                                 0x02;
+	byte ENVTYPE_PACKAGE=                                   0x05;
+	byte ENVTYPE_GLOBAL=                                    0x07;
+	
+	byte ENVTYPE_EMTPY=                                     0x09;
+	
+	/**
+	 * @since de.walware.rj.data 2.1
+	 */
+	byte ENVTYPE_NAMESPACE=                                 0x0B;
+	/**
+	 * @since de.walware.rj.data 2.1
+	 */
+	byte ENVTYPE_NAMESPACE_EXPORTS=                         0x0C;
+	
+	
+	/**
+	 * Returns the length of the object. The length of an {@link RObject#TYPE_ENVIRONMENT environment}
+	 * is the count the objects in the environment.
+	 * 
+	 * At moment, the length of an {@link RObject#TYPE_ENVIRONMENT environment} is always &le; 2<sup>31</sup>-1
+	 * (representable by Java int).
+	 * 
+	 * @return the length
+	 */
+	@Override
+	long getLength();
+	
+	/**
+	 * Indicates a special environment type (> 0)
+	 * see <code>ENVTYPE_</code> constants defined in {@link REnvironment}.
+	 * 
+	 * @return the type constant or &lt;= 0
+	 */
+	int getSpecialType();
+	
+	/**
+	 * Returns the environment name of the environment.  This is the return value
+	 * of the R command <code>environmentName(object)</code>.
+	 * 
+	 * @return the environment name
+	 */
+	String getEnvironmentName();
+	
+	long getHandle();
+	
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/RFactorStore.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/RFactorStore.java
new file mode 100644
index 0000000..dade50e
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/RFactorStore.java
@@ -0,0 +1,41 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data;
+
+
+/**
+ * Interface for R data stores of type {@link RStore#FACTOR}.
+ * <p>
+ * An R data store implements this interface if the R function
+ * <code>class(object)</code> returns 'factor'.</p>
+ */
+public interface RFactorStore extends RIntegerStore {
+	
+	// TODO Docu && Constructors (-> 1-based codes)
+	// TODO getFactorName(code) for 1-based code
+	
+	boolean isOrdered();
+	
+	RCharacterStore getLevels();
+	int getLevelCount();
+	
+//	void addLevel(final String label);
+//	void renameLevel(final String oldLabel, final String newLabel);
+//	void insertLevel(final int position, final String label);
+//	void removeLevel(final String label);
+	
+	RCharacterStore toCharacterData();
+	
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/RFunction.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/RFunction.java
new file mode 100644
index 0000000..e42df51
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/RFunction.java
@@ -0,0 +1,29 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data;
+
+
+public interface RFunction extends RObject {
+	
+//	RArgument getArgument(final int idx);
+//	RArgument getArgument(final String name);
+//	int getArgumentIdx(final String name);
+//	Iterator<RArgument> getArgumentIterator();
+	
+	// source based
+	String getHeaderSource();
+	String getBodySource();
+	
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/RIntegerStore.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/RIntegerStore.java
new file mode 100644
index 0000000..1a0174c
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/RIntegerStore.java
@@ -0,0 +1,35 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data;
+
+
+/**
+ * Interface for R data stores of type {@link RStore#INTEGER}.
+ * <p>
+ * An R data store implements this interface if the R function
+ * <code>typeof(object)</code> returns 'integer'.</p>
+ */
+public interface RIntegerStore extends RStore<Integer> {
+	
+	
+	@Override
+	Integer get(int idx);
+	@Override
+	Integer get(long idx);
+	
+	@Override
+	Integer[] toArray();
+	
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/RJIO.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/RJIO.java
new file mode 100644
index 0000000..4a13d96
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/RJIO.java
@@ -0,0 +1,1061 @@
+/*=============================================================================#
+ # Copyright (c) 2010, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data;
+
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.DoubleBuffer;
+import java.nio.IntBuffer;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+
+
+/**
+ * IO implementation for RJ data serialization.
+ */
+public final class RJIO {
+	
+	
+	private static final ThreadLocal<RJIO> INSTANCES= new ThreadLocal<RJIO>() {
+		
+		@Override
+		protected RJIO initialValue() {
+			return new RJIO();
+		}
+		
+	};
+	
+	public static RJIO get(final ObjectOutput out) {
+		final RJIO io= INSTANCES.get();
+		io.connect(out);
+		return io;
+	}
+	
+	public static RJIO get(final ObjectInput in) {
+		final RJIO io= INSTANCES.get();
+		io.connect(in);
+		return io;
+	}
+	
+	
+	private static final int BB_LENGTH= 16384;
+	private static final int BA_LENGTH= BB_LENGTH;
+	private static final int BB_PART= BB_LENGTH / 4;
+	private static final int CB_LENGTH= BB_LENGTH / 2;
+	private static final int CA_LENGTH= BB_LENGTH * 4;
+	private static final int IB_LENGTH= BB_LENGTH / 4;
+	private static final int DB_LENGTH= BB_LENGTH / 8;
+	
+	private static final int[] EMPTY_INT_ARRAY= new int[0];
+	
+	private static final byte MODE_BBARRAY= 0;
+	private static final byte MODE_IPARRAY= 1;
+	
+	
+	private final ByteBuffer bb;
+	private final byte[] ba;
+	private final CharBuffer cb;
+	private final char[] ca;
+	private final IntBuffer ib;
+	private final DoubleBuffer db;
+	private final byte mode;
+	
+	private ObjectInput in;
+	
+	private ObjectOutput out;
+	
+	private int temp;
+	
+	public int flags;
+	
+	private int serialKey;
+	
+	
+	public RJIO() {
+		this.bb= ByteBuffer.allocateDirect(BB_LENGTH);
+		if (this.bb.hasArray()) {
+			this.mode= MODE_BBARRAY;
+			this.ba= this.bb.array();
+		}
+		else {
+			this.mode= MODE_IPARRAY;
+			this.ba= new byte[BB_LENGTH];
+		}
+		this.cb= this.bb.asCharBuffer();
+		this.ca= new char[CA_LENGTH];
+		this.ib= this.bb.asIntBuffer();
+		this.db= this.bb.asDoubleBuffer();
+		
+		this.serialKey= (int) System.currentTimeMillis();
+	}
+	
+	
+	public void connect(final ObjectOutput out) {
+		this.out= out;
+	}
+	
+	public void connect(final ObjectInput in) {
+		this.in= in;
+	}
+	
+	public void disconnect(final ObjectOutput out) throws IOException {
+		this.out.flush();
+		this.out= null;
+	}
+	
+	public void disconnect(final ObjectInput in) throws IOException {
+		this.in= null;
+	}
+	
+	
+	private void writeFullyBB(final int bn) throws IOException {
+		switch (this.mode) {
+		case MODE_BBARRAY:
+			this.out.write(this.ba, 0, bn);
+			return;
+//		case MODE_IPARRAY:
+		default:
+			this.bb.clear();
+			this.bb.get(this.ba, 0, bn);
+			this.out.write(this.ba, 0, bn);
+			return;
+		}
+	}
+	
+	private void readFullyBB(final int bn)  throws IOException {
+		switch (this.mode) {
+		case MODE_BBARRAY:
+			this.in.readFully(this.ba, 0, bn);
+			return;
+//		case MODE_IPARRAY:
+		default:
+			this.in.readFully(this.ba, 0, bn);
+			this.bb.clear();
+			this.bb.put(this.ba, 0, bn);
+			return;
+		}
+	}
+	
+	private void readFullyBB(final int pos, final int bn) throws IOException {
+		switch (this.mode) {
+		case MODE_BBARRAY:
+			this.in.readFully(this.ba, pos, bn);
+			return;
+//		case MODE_IPARRAY:
+		default:
+			this.in.readFully(this.ba, pos, bn);
+			this.bb.clear();
+			this.bb.put(this.ba, 0, pos+bn);
+//			this.bb.position(pos);
+//			this.bb.put(this.ba, pos, bn);
+			return;
+		}
+	}
+	
+	
+	public void writeDirectly(final byte[] bytes, final int off, final int n) throws IOException {
+		this.out.write(bytes, off, n);
+	}
+	
+	
+	public void writeByte(final byte value) throws IOException {
+		this.out.writeByte(value);
+	}
+	
+	public void writeByte(final int value) throws IOException {
+		this.out.writeByte(value);
+	}
+	
+	public void writeBoolean(final boolean value) throws IOException {
+		this.out.writeByte(value ? 0x1 : 0x0);
+	}
+	
+	public void writeInt(final int value) throws IOException {
+		this.out.writeInt(value);
+	}
+	
+	public void writeIntArray(final int[] array, final int length) throws IOException {
+		final ObjectOutput out= this.out;
+		out.writeInt(length);
+		if (length <= 32) {
+			for (int i= 0; i < length; i++) {
+				out.writeInt(array[i]);
+			}
+		}
+		else if (length <= IB_LENGTH) {
+			this.ib.clear();
+			this.ib.put(array, 0, length);
+			writeFullyBB((length << 2));
+		}
+		else {
+			int iw= 0;
+			while (iw < length) {
+				final int icount= Math.min(length - iw, IB_LENGTH);
+				this.ib.clear();
+				this.ib.put(array, iw, icount);
+				writeFullyBB((icount << 2));
+				iw+= icount;
+			}
+		}
+	}
+	
+	public void writeIntData(final int[] array, final int length) throws IOException {
+		final ObjectOutput out= this.out;
+		if (length <= 32) {
+			for (int i= 0; i < length; i++) {
+				out.writeInt(array[i]);
+			}
+		}
+		else if (length <= IB_LENGTH) {
+			this.ib.clear();
+			this.ib.put(array, 0, length);
+			writeFullyBB((length << 2));
+		}
+		else {
+			int iw= 0;
+			while (iw < length) {
+				final int icount= Math.min(length - iw, IB_LENGTH);
+				this.ib.clear();
+				this.ib.put(array, iw, icount);
+				writeFullyBB((icount << 2));
+				iw+= icount;
+			}
+		}
+	}
+	
+	public void writeLong(final long value) throws IOException {
+		this.out.writeLong(value);
+	}
+	
+	public byte getVULongGrade(final long value) {
+		if ((value & 0xffffffffffffff00L) == 0) {
+			return (byte) 0;
+		}
+		if ((value & 0xffffffffffff0000L) == 0) {
+			return (byte) 1;
+		}
+		if ((value & 0xffffffffff000000L) == 0) {
+			return (byte) 2;
+		}
+		if ((value & 0xffffffff00000000L) == 0) {
+			return (byte) 3;
+		}
+		if ((value & 0xffffff0000000000L) == 0) {
+			return (byte) 4;
+		}
+		if ((value & 0xffff000000000000L) == 0) {
+			return (byte) 5;
+		}
+		if ((value & 0xff00000000000000L) == 0) {
+			return (byte) 6;
+		}
+		return 7;
+	}
+	
+	public void writeVULong(final byte grade, final long value) throws IOException {
+		if (grade == 0) {
+			this.out.writeByte((int) value);
+			return;
+		}
+		final byte[] ba= this.ba;
+		switch (grade) {
+//		case 0:
+//			ba[0]= (byte) (value);
+//			this.out.write(ba, 0, 1);
+//			return;
+		case 1:
+			ba[0]= (byte) (value >>> 8);
+			ba[1]= (byte) (value);
+			this.out.write(ba, 0, 2);
+			return;
+		case 2:
+			ba[0]= (byte) (value >>> 16);
+			ba[1]= (byte) (value >>> 8);
+			ba[2]= (byte) (value);
+			this.out.write(ba, 0, 3);
+			return;
+		case 3:
+			ba[0]= (byte) (value >>> 24);
+			ba[1]= (byte) (value >>> 16);
+			ba[2]= (byte) (value >>> 8);
+			ba[3]= (byte) (value);
+			this.out.write(ba, 0, 4);
+			return;
+		case 4:
+			ba[0]= (byte) (value >>> 32);
+			ba[1]= (byte) (value >>> 24);
+			ba[2]= (byte) (value >>> 16);
+			ba[3]= (byte) (value >>> 8);
+			ba[4]= (byte) (value);
+			this.out.write(ba, 0, 5);
+			return;
+		case 5:
+			ba[0]= (byte) (value >>> 40);
+			ba[1]= (byte) (value >>> 32);
+			ba[2]= (byte) (value >>> 24);
+			ba[3]= (byte) (value >>> 16);
+			ba[4]= (byte) (value >>> 8);
+			ba[5]= (byte) (value);
+			this.out.write(ba, 0, 6);
+			return;
+		case 6:
+			ba[0]= (byte) (value >>> 48);
+			ba[1]= (byte) (value >>> 40);
+			ba[2]= (byte) (value >>> 32);
+			ba[3]= (byte) (value >>> 24);
+			ba[4]= (byte) (value >>> 16);
+			ba[5]= (byte) (value >>> 8);
+			ba[6]= (byte) (value);
+			this.out.write(ba, 0, 7);
+			return;
+		case 7:
+			ba[0]= (byte) (value >>> 56);
+			ba[1]= (byte) (value >>> 48);
+			ba[2]= (byte) (value >>> 40);
+			ba[3]= (byte) (value >>> 32);
+			ba[4]= (byte) (value >>> 24);
+			ba[5]= (byte) (value >>> 16);
+			ba[6]= (byte) (value >>> 8);
+			ba[7]= (byte) (value);
+			this.out.write(ba, 0, 8);
+			return;
+		default:
+			throw new IOException("Unsupported data format (c= " + grade + ").");
+		}
+	}
+	
+	public void writeDouble(final double value) throws IOException {
+		this.out.writeDouble(value);
+	}
+	
+	public void writeDoubleData(final double[] array, final int length) throws IOException {
+		final ObjectOutput out= this.out;
+		if (length <= 16) {
+			for (int i= 0; i < length; i++) {
+				out.writeLong(Double.doubleToRawLongBits(array[i]));
+			}
+		}
+		else if (length <= DB_LENGTH) {
+			this.db.clear();
+			this.db.put(array, 0, length);
+			writeFullyBB((length << 3));
+		}
+		else {
+			int dw= 0;
+			while (dw < length) {
+				final int dcount= Math.min(length - dw, DB_LENGTH);
+				this.db.clear();
+				this.db.put(array, dw, dcount);
+				writeFullyBB((dcount << 3));
+				dw+= dcount;
+			}
+		}
+	}
+	
+	public void writeFloat(final float value) throws IOException {
+		this.out.writeFloat(value);
+	}
+	
+	
+	public void writeByteData(final byte[] array, final int length) throws IOException {
+		final ObjectOutput out= this.out;
+		out.write(array, 0, length);
+	}
+	
+	@SuppressWarnings("deprecation")
+	public void writeString(final String s) throws IOException {
+		final ObjectOutput out= this.out;
+		if (s != null) {
+			final int cn= s.length();
+			ASCII: if (cn <= BA_LENGTH) {
+				for (int ci= 0; ci < cn; ) {
+					if ((s.charAt(ci++) & 0xffffff00) != 0) {
+						break ASCII;
+					}
+				}
+				if (cn <= 8) {
+					out.writeInt(-cn);
+					out.writeBytes(s);
+					return;
+				}
+				else {
+					out.writeInt(-cn);
+					s.getBytes(0, cn, this.ba, 0);
+					out.write(this.ba, 0, cn);
+					return;
+				}
+			}
+			out.writeInt(cn);
+			out.writeChars(s);
+			return;
+		}
+		else {
+			out.writeInt(Integer.MIN_VALUE);
+			return;
+		}
+	}
+	
+	@SuppressWarnings("deprecation")
+	public void writeStringData(final String[] sa, final int length) throws IOException {
+		final ObjectOutput out= this.out;
+		ARRAY: for (int i= 0; i < length; i++) {
+			final String s= sa[i];
+			if (s != null) {
+				final int cn= s.length();
+				ASCII: if (cn <= BA_LENGTH) {
+					for (int ci= 0; ci < cn; ) {
+						if ((s.charAt(ci++) & 0xffffff00) != 0) {
+							break ASCII;
+						}
+					}
+					if (cn <= 8) {
+						out.writeInt(-cn);
+						out.writeBytes(s);
+						continue ARRAY;
+					}
+					else {
+						out.writeInt(-cn);
+						s.getBytes(0, cn, this.ba, 0);
+						out.write(this.ba, 0, cn);
+						continue ARRAY;
+					}
+				}
+				out.writeInt(cn);
+				out.writeChars(s);
+				continue ARRAY;
+			}
+			else {
+				out.writeInt(Integer.MIN_VALUE);
+				continue ARRAY;
+			}
+		}
+	}
+	
+	public void writeStringKeyMap(final Map<String, Object> map) throws IOException {
+		final ObjectOutput out= this.out;
+		if (map == null) {
+			out.writeInt(-1);
+			return;
+		}
+		out.writeInt(map.size());
+		for (final Entry<String, Object> entry : map.entrySet()) {
+			writeString(entry.getKey());
+			out.writeObject(entry.getValue());
+		}
+	}
+	
+	
+	public byte readByte() throws IOException {
+		return this.in.readByte();
+	}
+	
+	public boolean readBoolean() throws IOException {
+		return (this.in.readByte() == 0x1);
+	}
+	
+	public int readInt() throws IOException {
+		return this.in.readInt();
+	}
+	
+	public int[] readIntData(final int[] array, final int length) throws IOException {
+		final ObjectInput in= this.in;
+		if (length <= 256) {
+			switch (length) {
+			case 0:
+				return array;
+			case 1:
+				array[0]= in.readInt();
+				return array;
+			case 2:
+				array[0]= in.readInt();
+				array[1]= in.readInt();
+				return array;
+			case 3:
+				array[0]= in.readInt();
+				array[1]= in.readInt();
+				array[2]= in.readInt();
+				return array;
+			case 4:
+				array[0]= in.readInt();
+				array[1]= in.readInt();
+				array[2]= in.readInt();
+				array[3]= in.readInt();
+				return array;
+			default:
+				final int bn= length << 2;
+				in.readFully(this.ba, 0, bn);
+				for (int ib= 0; ib < bn; ib+= 4) {
+					array[ib >>> 2]= (
+							((this.ba[ib] & 0xff) << 24) |
+							((this.ba[ib+1] & 0xff) << 16) |
+							((this.ba[ib+2] & 0xff) << 8) |
+							((this.ba[ib+3] & 0xff)) );
+				}
+				return array;
+			}
+		}
+		else if (length <= IB_LENGTH) {
+			readFullyBB((length << 2));
+			this.ib.clear();
+			this.ib.get(array, 0, length);
+			return array;
+		}
+		else {
+			int ir= 0;
+			int position= 0;
+			final int bToComplete;
+			while (true) {
+				position+= in.read(this.ba, position, BA_LENGTH-position);
+				if (position >= BB_PART) {
+					final int icount= (position >>> 2);
+					final int bcount= (icount << 2);
+					if (this.mode != MODE_BBARRAY) {
+						this.bb.clear();
+						this.bb.put(this.ba, 0, bcount);
+					}
+					this.ib.clear();
+					this.ib.get(array, ir, icount);
+					ir+= icount;
+					switch (position - bcount) {
+					case 0:
+						position= 0;
+						break;
+					case 1:
+						this.ba[0]= this.ba[bcount];
+						position= 1;
+						break;
+					case 2:
+						this.ba[0]= this.ba[bcount];
+						this.ba[1]= this.ba[bcount+1];
+						position= 2;
+						break;
+					case 3:
+						array[ir++]= (
+								((this.ba[bcount] & 0xff) << 24) |
+								((this.ba[bcount+1] & 0xff) << 16) |
+								((this.ba[bcount+2] & 0xff) << 8) |
+								((in.read() & 0xff)) );
+						position= 0;
+						break;
+					}
+					if (length - ir <= IB_LENGTH) {
+						bToComplete= ((length - ir) << 2);
+						break;
+					}
+				}
+			}
+			if (bToComplete > 0) {
+				readFullyBB(position, bToComplete-position);
+				this.ib.clear();
+				this.ib.get(array, ir, bToComplete >>> 2);
+			}
+			return array;
+		}
+	}
+	
+	public int[] readIntArray() throws IOException {
+		final ObjectInput in= this.in;
+		final int length= in.readInt();
+		if (length <= 256) {
+			switch (length) {
+			case -1:
+				return null;
+			case 0:
+				return EMPTY_INT_ARRAY;
+			case 1:
+				return new int[] { in.readInt() };
+			case 2:
+				return new int[] { in.readInt(), in.readInt() };
+			case 3:
+				return new int[] { in.readInt(), in.readInt(), in.readInt() };
+			case 4:
+				return new int[] { in.readInt(), in.readInt(), in.readInt(), in.readInt() };
+			default:
+				final int bn= length << 2;
+				in.readFully(this.ba, 0, bn);
+				final int[] array= new int[length];
+				for (int ib= 0; ib < bn; ib+= 4) {
+					array[ib >>> 2]= (
+							((this.ba[ib] & 0xff) << 24) |
+							((this.ba[ib+1] & 0xff) << 16) |
+							((this.ba[ib+2] & 0xff) << 8) |
+							((this.ba[ib+3] & 0xff)) );
+				}
+				return array;
+			}
+		}
+		else if (length <= IB_LENGTH) {
+			readFullyBB((length << 2));
+			final int[] array= new int[length];
+			this.ib.clear();
+			this.ib.get(array, 0, length);
+			return array;
+		}
+		else {
+			final int[] array= new int[length];
+			int ir= 0;
+			int position= 0;
+			final int bToComplete;
+			while (true) {
+				position+= in.read(this.ba, position, BA_LENGTH-position);
+				if (position >= BB_PART) {
+					final int icount= (position >>> 2);
+					final int bcount= (icount << 2);
+					if (this.mode != MODE_BBARRAY) {
+						this.bb.clear();
+						this.bb.put(this.ba, 0, bcount);
+					}
+					this.ib.clear();
+					this.ib.get(array, ir, icount);
+					ir+= icount;
+					switch (position - bcount) {
+					case 0:
+						position= 0;
+						break;
+					case 1:
+						this.ba[0]= this.ba[bcount];
+						position= 1;
+						break;
+					case 2:
+						this.ba[0]= this.ba[bcount];
+						this.ba[1]= this.ba[bcount+1];
+						position= 2;
+						break;
+					case 3:
+						array[ir++]= (
+								((this.ba[bcount] & 0xff) << 24) |
+								((this.ba[bcount+1] & 0xff) << 16) |
+								((this.ba[bcount+2] & 0xff) << 8) |
+								((in.read() & 0xff)) );
+						position= 0;
+						break;
+					}
+					if (length - ir <= IB_LENGTH) {
+						bToComplete= ((length - ir) << 2);
+						break;
+					}
+				}
+			}
+			if (bToComplete > 0) {
+				readFullyBB(position, bToComplete-position);
+				this.ib.clear();
+				this.ib.get(array, ir, bToComplete >>> 2);
+			}
+			return array;
+		}
+	}
+	
+	public long readLong() throws IOException {
+		return this.in.readLong();
+	}
+	
+	public long readVULong(final byte grade) throws IOException {
+		if (grade == 0) {
+			return this.in.readUnsignedByte();
+		}
+		final byte[] ba= this.ba;
+		switch (grade) {
+//		case 0:
+//			this.in.read(ba, 0, 1);
+//			return (ba[0] & 0xff);
+		case 1:
+			this.in.read(ba, 0, 2);
+			return (((ba[0] & 0xff) << 8) |
+					(ba[1] & 0xff) );
+		case 2:
+			this.in.read(ba, 0, 3);
+			return (((ba[0] & 0xff) << 16) |
+					((ba[1] & 0xff) << 8) |
+					(ba[2] & 0xff) );
+		case 3:
+			this.in.read(ba, 0, 4);
+			return (((long) (ba[0] & 0xff) << 24) |
+					((ba[1] & 0xff) << 16) |
+					((ba[2] & 0xff) << 8) |
+					(ba[3] & 0xff) );
+		case 4:
+			this.in.read(ba, 0, 5);
+			return (((long) (ba[0] & 0xff) << 32) |
+					((long) (ba[1] & 0xff) << 24) |
+					((ba[2] & 0xff) << 16) |
+					((ba[3] & 0xff) << 8) |
+					(ba[4] & 0xff) );
+		case 5:
+			this.in.read(ba, 0, 6);
+			return (((long) (ba[0] & 0xff) << 40) |
+					((long) (ba[1] & 0xff) << 32) |
+					((long) (ba[2] & 0xff) << 24) |
+					((ba[3] & 0xff) << 16) |
+					((ba[4] & 0xff) << 8) |
+					(ba[5] & 0xff) );
+		case 6:
+			this.in.read(ba, 0, 7);
+			return (((long) (ba[0] & 0xff) << 48) |
+					((long) (ba[1] & 0xff) << 40) |
+					((long) (ba[2] & 0xff) << 32) |
+					((long) (ba[3] & 0xff) << 24) |
+					((ba[4] & 0xff) << 16) |
+					((ba[5] & 0xff) << 8) |
+					(ba[6] & 0xff) );
+		case 7:
+			this.in.read(ba, 0, 8);
+			return (((long) (ba[0] & 0xff) << 56) |
+					((long) (ba[1] & 0xff) << 48) |
+					((long) (ba[2] & 0xff) << 40) |
+					((long) (ba[3] & 0xff) << 32) |
+					((long) (ba[4] & 0xff) << 24) |
+					((ba[5] & 0xff) << 16) |
+					((ba[6] & 0xff) << 8) |
+					(ba[7] & 0xff) );
+		default:
+			throw new IOException("Unsupported data format (c= " + grade + ").");
+		}
+	}
+	
+	public double readDouble() throws IOException {
+		return this.in.readDouble();
+	}
+	
+	public double[] readDoubleData(final double[] array, final int length) throws IOException {
+		final ObjectInput in= this.in;
+		if (length <= 32) {
+			switch (length) {
+			case 0:
+				return array;
+			case 1:
+				array[0]= Double.longBitsToDouble(in.readLong());
+				return array;
+			case 2:
+				array[0]= Double.longBitsToDouble(in.readLong());
+				array[1]= Double.longBitsToDouble(in.readLong());
+				return array;
+			default:
+				final int bn= length << 3;
+				in.readFully(this.ba, 0, bn);
+				for (int db= 0; db < bn; db+= 8) {
+					array[db >>> 3]= Double.longBitsToDouble(
+							((long) (this.ba[db] & 0xff) << 56) |
+							((long) (this.ba[db+1] & 0xff) << 48) |
+							((long) (this.ba[db+2] & 0xff) << 40) |
+							((long) (this.ba[db+3] & 0xff) << 32) |
+							((long) (this.ba[db+4] & 0xff) << 24) |
+							((this.ba[db+5] & 0xff) << 16) |
+							((this.ba[db+6] & 0xff) << 8) |
+							((this.ba[db+7] & 0xff)) );
+				}
+				return array;
+			}
+		}
+		else if (length <= DB_LENGTH) {
+			readFullyBB((length << 3));
+			this.db.clear();
+			this.db.get(array, 0, length);
+			return array;
+		}
+		else {
+			int dr= 0;
+			int position= 0;
+			final int bToComplete;
+			while (true) {
+				position+= in.read(this.ba, position, BA_LENGTH-position);
+				if (position >= BB_PART) {
+					final int dcount= (position >>> 3);
+					final int bcount= (dcount << 3);
+					if (this.mode != MODE_BBARRAY) {
+						this.bb.clear();
+						this.bb.put(this.ba, 0, bcount);
+					}
+					this.db.clear();
+					this.db.get(array, dr, dcount);
+					dr+= dcount;
+					switch (position - bcount) {
+					case 0:
+						position= 0;
+						break;
+					case 1:
+						this.ba[0]= this.ba[bcount];
+						position= 1;
+						break;
+					case 2:
+						this.ba[0]= this.ba[bcount];
+						this.ba[1]= this.ba[bcount+1];
+						position= 2;
+						break;
+					case 3:
+						this.ba[0]= this.ba[bcount];
+						this.ba[1]= this.ba[bcount+1];
+						this.ba[2]= this.ba[bcount+2];
+						position= 3;
+						break;
+					case 4:
+						this.ba[0]= this.ba[bcount];
+						this.ba[1]= this.ba[bcount+1];
+						this.ba[2]= this.ba[bcount+2];
+						this.ba[3]= this.ba[bcount+3];
+						position= 4;
+						break;
+					case 5:
+						this.ba[0]= this.ba[bcount];
+						this.ba[1]= this.ba[bcount+1];
+						this.ba[2]= this.ba[bcount+2];
+						this.ba[3]= this.ba[bcount+3];
+						this.ba[4]= this.ba[bcount+4];
+						position= 5;
+						break;
+					case 6:
+						array[dr++]= Double.longBitsToDouble(
+								((long) (this.ba[bcount] & 0xff) << 56) |
+								((long) (this.ba[bcount+1] & 0xff) << 48) |
+								((long) (this.ba[bcount+2] & 0xff) << 40) |
+								((long) (this.ba[bcount+3] & 0xff) << 32) |
+								((long) (this.ba[bcount+4] & 0xff) << 24) |
+								((this.ba[bcount+5] & 0xff) << 16) |
+								((in.read() & 0xff) << 8) |
+								((in.read() & 0xff)) );
+						position= 0;
+						break;
+					case 7:
+						array[dr++]= Double.longBitsToDouble(
+								((long) (this.ba[bcount] & 0xff) << 56) |
+								((long) (this.ba[bcount+1] & 0xff) << 48) |
+								((long) (this.ba[bcount+2] & 0xff) << 40) |
+								((long) (this.ba[bcount+3] & 0xff) << 32) |
+								((long) (this.ba[bcount+4] & 0xff) << 24) |
+								((this.ba[bcount+5] & 0xff) << 16) |
+								((this.ba[bcount+6] & 0xff) << 8) |
+								((in.read() & 0xff)) );
+						position= 0;
+						break;
+					}
+					if (length - dr <= DB_LENGTH) {
+						bToComplete= ((length - dr) << 3);
+						break;
+					}
+				}
+			}
+			if (bToComplete > 0) {
+				readFullyBB(position, bToComplete-position);
+				this.db.clear();
+				this.db.get(array, dr, bToComplete >>> 3);
+			}
+			return array;
+		}
+	}
+	
+	public double[] readDoubleArray() throws IOException {
+		final int l= this.temp= this.in.readInt();
+		return readDoubleData(new double[l], l);
+	}
+	
+	public double[] readDoubleArray2() throws IOException {
+		final int l= this.temp;
+		return readDoubleData(new double[l], l);
+	}
+	
+	public float readFloat() throws IOException {
+		return this.in.readFloat();
+	}
+	
+	public byte[] readByteData(final byte[] array, final int length) throws IOException {
+		this.in.readFully(array, 0, length);
+		return array;
+	}
+	
+	public byte[] readByteArray() throws IOException {
+		final int l= this.temp= this.in.readInt();
+		return readByteData(new byte[l], l);
+	}
+	
+	public byte[] readByteArray2() throws IOException {
+		final int l= this.temp;
+		return readByteData(new byte[l], l);
+	}
+	
+	private String readString(final int cn, final char[] ca, final ObjectInput in) throws IOException {
+		int cr= 0;
+		int position= 0;
+		final int bToComplete;
+		while (true) {
+			position+= in.read(this.ba, position, BA_LENGTH-position);
+			if (position >= BB_PART) {
+				final int icount= (position >>> 1);
+				final int bcount= (icount << 1);
+				if (this.mode != MODE_BBARRAY) {
+					this.bb.clear();
+					this.bb.put(this.ba, 0, bcount);
+				}
+				this.cb.clear();
+				this.cb.get(ca, cr, icount);
+				cr+= icount;
+				if (position - bcount != 0) {
+					ca[cr++]= (char) (
+							((this.ba[bcount] & 0xff) << 8) |
+							((in.read() & 0xff)) );
+				}
+				position= 0;
+				if (cn - cr <= CB_LENGTH) {
+					bToComplete= (cn - cr) << 1;
+					break;
+				}
+			}
+		}
+		if (bToComplete > 0) {
+			readFullyBB(position, bToComplete-position);
+			this.cb.clear();
+			this.cb.get(ca, cr, bToComplete >>> 1);
+		}
+		return new String(ca, 0, cn);
+	}
+	
+	@SuppressWarnings("deprecation")
+	public String readString() throws IOException {
+		final ObjectInput in= this.in;
+		final int cn= in.readInt();
+		if (cn >= 0) {
+			if (cn == 0) {
+				return "";
+			}
+			else if (cn <= 64) {
+				for (int ci= 0; ci < cn; ci++) {
+					this.ca[ci]= in.readChar();
+				}
+				return new String(this.ca, 0, cn);
+			}
+			else if (cn <= CB_LENGTH) {
+				readFullyBB((cn << 1));
+				this.cb.clear();
+				this.cb.get(this.ca, 0, cn);
+				return new String(this.ca, 0, cn);
+			}
+			else if (cn <= CA_LENGTH) {
+				return readString(cn, this.ca, in);
+			}
+			else {
+				return readString(cn, new char[cn], in);
+			}
+		}
+		else {
+			if (cn >= -BA_LENGTH) {
+				in.readFully(this.ba, 0, -cn);
+				return new String(this.ba, 0, 0, -cn);
+			}
+			else if (cn != Integer.MIN_VALUE) {
+				final byte[] bt= new byte[-cn];
+				in.readFully(bt, 0, -cn);
+				return new String(bt, 0, 0, -cn);
+			}
+			else { // cn == Integer.MIN_VALUE
+				return null;
+			}
+		}
+	}
+	
+	@SuppressWarnings("deprecation")
+	public void readStringData(final String[] array, final int length) throws IOException {
+		final ObjectInput in= this.in;
+		ARRAY: for (int i= 0; i < length; i++) {
+			final int cn= in.readInt();
+			if (cn >= 0) {
+				if (cn == 0) {
+					array[i]= "";
+					continue ARRAY;
+				}
+				else if (cn <= 64) {
+					for (int ci= 0; ci < cn; ci++) {
+						this.ca[ci]= in.readChar();
+					}
+					array[i]= new String(this.ca, 0, cn);
+					continue ARRAY;
+				}
+				else if (cn <= CB_LENGTH) {
+					readFullyBB((cn << 1));
+					this.cb.clear();
+					this.cb.get(this.ca, 0, cn);
+					array[i]= new String(this.ca, 0, cn);
+					continue ARRAY;
+				}
+				else if (cn <= CA_LENGTH) {
+					array[i]= readString(cn, this.ca, in);
+					continue ARRAY;
+				}
+				else {
+					array[i]= readString(cn, new char[cn], in);
+					continue ARRAY;
+				}
+			}
+			else {
+				if (cn >= -BA_LENGTH) {
+					in.readFully(this.ba, 0, -cn);
+					array[i]= new String(this.ba, 0, 0, -cn);
+					continue ARRAY;
+				}
+				else if (cn != Integer.MIN_VALUE) {
+					final byte[] bt= new byte[-cn];
+					in.readFully(bt, 0, -cn);
+					array[i]= new String(bt, 0, 0, -cn);
+					continue ARRAY;
+				}
+				else { // cn == Integer.MIN_VALUE
+//					array[i]= null;
+					continue ARRAY;
+				}
+			}
+		}
+		return;
+	}
+	
+	public HashMap<String, Object> readStringKeyHashMap() throws IOException {
+		final ObjectInput in= this.in;
+		final int length= in.readInt();
+		if (length < 0) {
+			return null;
+		}
+		try {
+			final HashMap<String, Object> map= new HashMap<>(length);
+			for (int i= 0; i < length; i++) {
+				map.put(readString(), in.readObject());
+			}
+			return map;
+		}
+		catch (final ClassNotFoundException e) {
+			throw new IOException(e.getMessage());
+		}
+	}
+	
+	
+	public int writeCheck1() throws IOException {
+		this.out.writeInt(++this.serialKey);
+		return this.serialKey;
+	}
+	
+	public void writeCheck2(final int check) throws IOException {
+		this.out.writeInt(check);
+	}
+	
+	public int readCheck1() throws IOException {
+		return this.in.readInt();
+	}
+	
+	public void readCheck2(final int check) throws IOException {
+		if (check != this.in.readInt()) {
+			throw new IOException("Corrupted stream detected.");
+		}
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/RJIOExternalizable.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/RJIOExternalizable.java
new file mode 100644
index 0000000..bd8a7a9
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/RJIOExternalizable.java
@@ -0,0 +1,25 @@
+/*=============================================================================#
+ # Copyright (c) 2011, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data;
+
+import java.io.IOException;
+
+
+public interface RJIOExternalizable {
+	
+	
+	void writeExternal(RJIO out) throws IOException;
+	
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/RLanguage.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/RLanguage.java
new file mode 100644
index 0000000..5531cbd
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/RLanguage.java
@@ -0,0 +1,36 @@
+/*=============================================================================#
+ # Copyright (c) 2010, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data;
+
+
+/**
+ * R object of type call
+ */
+public interface RLanguage extends RObject {
+	
+	
+	byte NAME=                                             0x01;
+	
+	byte EXPRESSION=                                       0x02;
+	
+	byte CALL=                                             0x03;
+	
+	
+	byte getLanguageType();
+	
+	String getSource();
+	
+	
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/RList.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/RList.java
new file mode 100644
index 0000000..2369efe
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/RList.java
@@ -0,0 +1,118 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data;
+
+
+/**
+ * An R object is of the type {@link RObject#TYPE_LIST list}, if the object is
+ * an R list but not an R data frame (see {@link #TYPE_DATAFRAME}).  Such an R
+ * list object is represented by an instance of this interface.
+ * <p>
+ * The R function <code>typeof(object)</code> returns 'list' or 'pairlist' for
+ * objects of this type.</p>
+ * <p>
+ * The interfaces for R objects of the type {@value RObject#TYPE_DATAFRAME} -
+ * {@link RDataFrame}, {@link RObject#TYPE_S4OBJECT} - {@link RS4Object} and 
+ * {@link RObject#TYPE_ENVIRONMENT} - {@link REnvironment} extends this interface for the
+ * purpose of a uniform API.
+ * Objects of this type does not necessary provide the full functionality and the
+ * methods can have special meaning and conditions; see the documentation of these
+ * interfaces.</p>
+ * <p>
+ * Indexes are zero-based (as usual in Java) and not one-base like in R.</p>
+ */
+public interface RList extends RObject {
+	
+	/**
+	 * Returns the length of the object. The length of a {@link RObject#TYPE_LIST list}
+	 * is the count of list items.
+	 * 
+	 * @return the length
+	 */
+	@Override
+	long getLength();
+	
+	/**
+	 * Returns the names of the list items.
+	 * 
+	 * @return the item names
+	 */
+	RCharacterStore getNames();
+	
+	/**
+	 * Returns the name of the item at the specified index.
+	 * <p>
+	 * This is equivalent to <code>getNames().getChar(idx)</code>.</p>
+	 * 
+	 * @param idx the index (zero-based) of the item
+	 * @return the slot names
+	 * @throws IndexOutOfBoundsException if <code>idx</code> &lt; 0 or <code>idx</code> &ge; length
+	 */
+	String getName(int idx);
+	
+	/**
+	 * Returns the name of the item at the specified index.
+	 * <p>
+	 * This is equivalent to <code>getNames().getChar(idx)</code>.</p>
+	 * 
+	 * @param idx the index (zero-based) of the item
+	 * @return the slot names
+	 * @throws IndexOutOfBoundsException if <code>idx</code> &lt; 0 or <code>idx</code> &ge; length
+	 */
+	String getName(long idx);
+	
+	/**
+	 * Returns the item at the specified index.
+	 * 
+	 * @param idx the index (zero-based) of the item
+	 * @return the item
+	 * @throws IndexOutOfBoundsException if <code>idx</code> &lt; 0 or <code>idx</code> &ge; length
+	 */
+	RObject get(int idx);
+	
+	/**
+	 * Returns the item at the specified index.
+	 * 
+	 * @param idx the index (zero-based) of the item
+	 * @return the item
+	 * @throws IndexOutOfBoundsException if <code>idx</code> &lt; 0 or <code>idx</code> &ge; length
+	 */
+	RObject get(long idx);
+	
+	/**
+	 * Returns the item with the specified name. If multiple items have that name,
+	 * the first item with the given name is picked.
+	 * 
+	 * @param name the name of the item
+	 * @return the item or <code>null</code> (if no item with the specified name exists)
+	 */
+	RObject get(String name);
+	
+//	/**
+//	 * Returns an array with the R object items of the list.
+//	 * <p>
+//	 * The array is newly created for each call of this method.</p>
+//	 * 
+//	 * @return an array with the items of the list
+//	 */
+//	RObject[] toArray();
+	
+//	void insert(int idx, String name, RObject item);
+//	void add(String name, RObject item);
+//	boolean set(int idx, RObject item);
+//	boolean set(String name, RObject item);
+//	void remove(int idx);
+	
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/RLogicalStore.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/RLogicalStore.java
new file mode 100644
index 0000000..ba30af7
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/RLogicalStore.java
@@ -0,0 +1,35 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data;
+
+
+/**
+ * Interface for R data stores of type {@link RStore#LOGICAL}.
+ * <p>
+ * An R data store implements this interface if the R function
+ * <code>typeof(object)</code> returns 'logical'.</p>
+ */
+public interface RLogicalStore extends RStore<Boolean> {
+	
+	
+	@Override
+	Boolean get(int idx);
+	@Override
+	Boolean get(long idx);
+	
+	@Override
+	Boolean[] toArray();
+	
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/RNumericStore.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/RNumericStore.java
new file mode 100644
index 0000000..10abf70
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/RNumericStore.java
@@ -0,0 +1,38 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data;
+
+
+/**
+ * Interface for R data stores of type {@link RStore#NUMERIC}.
+ * <p>
+ * An R data store implements this interface if the R function
+ * <code>typeof(object)</code> returns 'double'.</p>
+ */
+public interface RNumericStore extends RStore<Double> {
+	
+	
+	boolean isNaN(int idx);
+	boolean isNaN(long idx);
+	
+	@Override
+	Double get(int idx);
+	@Override
+	Double get(long idx);
+	
+	@Override
+	Double[] toArray();
+	
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/RObject.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/RObject.java
new file mode 100644
index 0000000..d21bb2a
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/RObject.java
@@ -0,0 +1,205 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data;
+
+import org.eclipse.statet.rj.data.impl.RNullImpl;
+
+
+/**
+ * Basic interface of all R object.
+ * <p>
+ * To detect the type of an RObject instance, the method {@link #getRObjectType()} 
+ * should be used, not the java class type (e.g. instanceof) of the object.</p>
+ */
+public interface RObject {
+	
+	/**
+	 * Constant indicating the RNullImpl object respectively the R NULL value.
+	 * <p>
+	 * The object is an instance of {@link RNullImpl}.</p>
+	 */
+	byte TYPE_NULL=                     0x01;
+	
+	/**
+	 * Constant indicating an {@link RVector} object. An R object is of this type
+	 * if it is a R data object of an "atomic" mode without a dimension attribute
+	 * (<code>dim</dim>).
+	 * <p>
+	 * The object is an instance of {@link RVector}.</p>
+	 */
+	byte TYPE_VECTOR=                   0x02;
+	
+	/**
+	 * Constant indicating an {@link RArray} object. An R object is of this type
+	 * if it is a R data object of an "atomic" mode with a dimension attribute
+	 * (<code>dim</dim>).
+	 * <p>
+	 * The object is an instance of {@link RArray}.</p>
+	 */
+	byte TYPE_ARRAY=                    0x03;
+	
+	/**
+	 * Constant indicating an RDataFrame object. An R object is of this type
+	 * if it is an R list object inheriting the R class {@link #CLASSNAME_DATAFRAME data.frame}
+	 * and compiling with the R rules for a data frame, especially its children 
+	 * are {@link RVector}s of the same length.
+	 * <p>
+	 * The object is an instance of {@link RDataFrame}.</p>
+	 */
+	byte TYPE_DATAFRAME=                0x06;
+	
+	/**
+	 * Constant indicating an RList object. An R object is of this type if it is 
+	 * a list but not a data frame (see {@link #TYPE_DATAFRAME}).
+	 * <p>
+	 * The object is an instance of {@link RList}.</p>
+	 */
+	byte TYPE_LIST=                     0x07;
+	
+	/**
+	 * Constant indicating an R environment object.
+	 * <p>
+	 * The object is an instance of {@link REnvironment}.</p>
+	 */
+	byte TYPE_ENVIRONMENT=              0x08;
+	
+	/**
+	 * Constant indicating an S4 object. An R object is of this type if the R
+	 * command <code>isS4</code> returns true. This is criterion has priority
+	 * above the criteria for the other data types. If an S4 object represents 
+	 * also a simple data type, this data is accessible by its data slot.
+	 * <p>
+	 * The object is an instance of {@link RS4Object}.</p>
+	 */
+	byte TYPE_S4OBJECT=                 0x0a;
+	
+	
+	/**
+	 * Constant indicating an R language object.
+	 * <p>
+	 * The object is an instance of {@link RLanguage}.</p>
+	 */
+	byte TYPE_LANGUAGE=                 0x0c;
+	
+	/**
+	 * Constant indicating an R function object.
+	 * <p>
+	 * The object is an instance of {@link RFunction}.</p>
+	 */
+	byte TYPE_FUNCTION=                 0x0d;
+	
+	/**
+	 * Constant indicating a reference to a R object.
+	 * <p>
+	 * The object is an instance of {@link RReference}.</p>
+	 */
+	byte TYPE_REFERENCE=                0x0e;
+	
+	/**
+	 * Constant indicating an R object not matching one of the other types.
+	 */
+	byte TYPE_OTHER=                    0x0f;
+	
+	/**
+	 * Constant indicating an R object is missing (e.g. missing argument, missing slot value).
+	 * 
+	 * @since de.walware.rj.data 0.5
+	 */
+	byte TYPE_MISSING=                  0x11;
+	
+	/**
+	 * Constant indicating an R object is not yet evaluated.
+	 * 
+	 * @since de.walware.rj.data 0.6
+	 */
+	byte TYPE_PROMISE=                  0x12;
+	
+	
+	//-- Common class names --//
+	String CLASSNAME_LOGICAL= "logical";
+	String CLASSNAME_INTEGER= "integer";
+	String CLASSNAME_NUMERIC= "numeric";
+	String CLASSNAME_CHARACTER= "character";
+	String CLASSNAME_COMPLEX= "complex";
+	String CLASSNAME_RAW= "raw";
+	String CLASSNAME_FACTOR= "factor";
+	String CLASSNAME_ORDERED= "ordered";
+	
+	String CLASSNAME_ARRAY= "array";
+	String CLASSNAME_MATRIX= "matrix";
+	String CLASSNAME_DATAFRAME= "data.frame";
+	String CLASSNAME_LIST= "list";
+	String CLASSNAME_PAIRLIST= "pairlist";
+	String CLASSNAME_ENVIRONMENT= "environment";
+	String CLASSNAME_NAME= "name";
+	String CLASSNAME_EXPRESSION= "expression";
+	String CLASSNAME_CALL= "call";
+	
+	String CLASSNAME_NULL= "NULL";
+	
+	//-- Common attribute names --//
+	String ATTR_ROW_NAMES= "row.names";
+	String ATTR_NAMES= "names";
+	
+	
+	/**
+	 * Returns the object type constant of this object
+	 * <p>
+	 * See the object type constants <code>TYPE_</code> defined in {@link RObject}.</p>
+	 * 
+	 * @return the object type constant
+	 */
+	byte getRObjectType();
+	
+	/**
+	 * Returns the class name of this object in R.
+	 * <p>
+	 * If the object has multiple S3 class names in R, it returns the first one.
+	 * The analog R command is <code>class(x)[1]</code>.</p>
+	 * 
+	 * @return the R class name
+	 */
+	String getRClassName();
+	
+	/**
+	 * Returns the length of the object.
+	 * <p>
+	 * Its meaning depends on the R object type and is undefined for unknown types.</p>
+	 * 
+	 * @return the length
+	 */
+	long getLength();
+	
+	/**
+	 * Returns the data store containing object data in a one-dimensional structure.
+	 * <p>
+	 * This is supported by objects of {@link #TYPE_VECTOR}, {@link #TYPE_ARRAY} and
+	 * of {@link #TYPE_S4OBJECT} with a data slot of a one of these types providing a data
+	 * store.</p>
+	 * 
+	 * @return the data store or <code>null</code>, if not supported by the object
+	 */
+	RStore<?> getData();
+	
+	/**
+	 * Returns the attribute list of the object
+	 * <p>
+	 * Note that by default the attributes are not loaded.</p>
+	 * 
+	 * @return the attribute list or <code>null</code>, if not available
+	 */
+	RList getAttributes();
+	
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/RObjectFactory.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/RObjectFactory.java
new file mode 100644
index 0000000..0789edb
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/RObjectFactory.java
@@ -0,0 +1,79 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data;
+
+import java.io.IOException;
+
+
+
+public interface RObjectFactory {
+	
+	/** Flag to fetch only the structure but not the data (store) of the objects */
+	int F_ONLY_STRUCT= 0x1;
+	
+	/** XXX: Not yet implemented */
+	int F_WITH_ATTR= 0x2;
+	
+	/** Flag to load environments directly instead of the reference only */
+	int F_LOAD_ENVIR= 0x10;
+	
+	/** Flag to eval all promises directly */
+	int F_LOAD_PROMISE= 0x20;
+	
+	
+	int O_LENGTHGRADE_MASK= 7; // 3 bits
+	
+	int O_WITH_ATTR= 1 << 3;
+	
+	int O_CLASS_NAME= 1 << 4;
+	
+	int O_NO_CHILDREN= 1 << 5;
+	
+	int O_WITH_NAMES= 1 << 6;
+	
+	
+//	RArgument createArgument(String name, String defaultSource);
+//	RFunction createFunction(RArgument[] argument);
+//	
+	<TData extends RStore<?>> RVector<TData> createVector(TData data);
+	<TData extends RStore<?>> RArray<TData> createArray(TData data, int[] dim);
+	<TData extends RStore<?>> RArray<TData> createMatrix(TData data, int dim1, int dim2);
+	RList createList(RObject[] components, String[] names);
+//	RDataFrame createDataFrame(RData[] columns, String[] columnNames, String[] rowNames);
+	
+	RLanguage createName(String name);
+	RLanguage createExpression(String expr);
+	
+	RLogicalStore createLogiData(boolean[] logiValues);
+	RIntegerStore createIntData(int[] intValues);
+	RNumericStore createNumData(double[] numValues);
+	RComplexStore createCplxData(double[] reValues, double[] imValues);
+	RCharacterStore createCharData(String[] charValues);
+	RRawStore createRawData(byte[] values);
+	RFactorStore createFactorData(int[] codes, String[] levels);
+	
+	void writeObject(RObject object, RJIO io) throws IOException;
+	RObject readObject(RJIO io) throws IOException;
+	
+	void writeStore(RStore<?> data, RJIO io) throws IOException;
+	RStore<?> readStore(RJIO io, long length) throws IOException;
+	
+	void writeAttributeList(RList list, RJIO io) throws IOException;
+	RList readAttributeList(RJIO io) throws IOException;
+	
+	void writeNames(RStore<?> names, RJIO io) throws IOException;
+	RStore<?> readNames(RJIO io, long length) throws IOException;
+	
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/RRawStore.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/RRawStore.java
new file mode 100644
index 0000000..fa474b5
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/RRawStore.java
@@ -0,0 +1,35 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data;
+
+
+/**
+ * Interface for R data stores of type {@link RStore#RAW}.
+ * <p>
+ * An R data store implements this interface if the R function
+ * <code>typeof(object)</code> returns 'raw'.</p>
+ */
+public interface RRawStore extends RStore<Byte> {
+	
+	
+	@Override
+	Byte get(int idx);
+	@Override
+	Byte get(long idx);
+	
+	@Override
+	Byte[] toArray();
+	
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/RReference.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/RReference.java
new file mode 100644
index 0000000..8871d9a
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/RReference.java
@@ -0,0 +1,33 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data;
+
+
+/**
+ * A reference to an R object
+ */
+public interface RReference extends RObject {
+	
+	
+	/**
+	 * Only for use of the object creator
+	 */
+	long getHandle();
+	
+	byte getReferencedRObjectType();
+	
+	RObject getResolvedRObject();
+	
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/RS4Object.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/RS4Object.java
new file mode 100644
index 0000000..ae081c9
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/RS4Object.java
@@ -0,0 +1,126 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data;
+
+
+/**
+ * An R object is of the type {@link RObject#TYPE_S4OBJECT S4 object}, if the R 
+ * command <code>isS4(object)</code> returns true.  Such an R S4 object is
+ * represented by an instance of this interface.
+ * <p>
+ * Even the interface extends {@link RList}, the objects are not a list in R!
+ * The inheritance is only for a uniform API.</p>
+ * <p>
+ * If an S4 object in R simulates also a simple data type, this data is accessible
+ * by its data slot (<code>.Data</code>).  For easier work with the data slot the
+ * class provides the methods {@link #hasDataSlot()} to test if there is such a
+ * slot, {@link #getDataSlot()} to get the R object in that slot and {@link #getData()}
+ * returns directly the data store by the data slot.</p>
+ * <p>
+ * The count of all slots, its names and value objects are accessible by the inherited
+ * methods {@link #getLength()}, {@link #getName(int)}, {@link #get(int)} and
+ * {@link #get(String)}.</p>
+ */
+public interface RS4Object extends RList {
+	
+	
+	/**
+	 * Returns the S4 class name of this object in R.
+	 * 
+	 * @return the R class name
+	 */
+	@Override
+	String getRClassName();
+	
+	/**
+	 * Returns the length of the object. The length of an {@link RObject#TYPE_S4OBJECT S4 object}
+	 * is the count of slots.
+	 * <p>
+	 * An equivalent command in R is for example <code>length(slotNames(obj))</code>, but
+	 * not <code>length(obj)</code>.</p>
+	 * 
+	 * At moment, the length of an {@link RObject#TYPE_S4OBJECT S4 object} is always &le; 2<sup>31</sup>-1
+	 * (representable by Java int).
+	 * 
+	 * @return the slot count
+	 */
+	@Override
+	long getLength();
+	
+	/**
+	 * Tests if the object respectively its class provides a data slot.
+	 * <p>
+	 * The data slot is the slot with the name <code>.Data</code>.</p>
+	 * 
+	 * @return <code>true</code> if there is a data slot, otherwise <code>false</code>
+	 */
+	boolean hasDataSlot();
+	
+	/**
+	 * Returns the data slot, if it exists.
+	 * 
+	 * @return the object in the data slot
+	 */
+	RObject getDataSlot();
+	
+	/**
+	 * Returns the data store of the data slot, if it exists.
+	 * 
+	 * @return the data of the data slot
+	 */
+	@Override
+	RStore<?> getData();
+	
+	/**
+	 * Returns the names of the slots.
+	 * 
+	 * @return the slot names
+	 */
+	@Override
+	RCharacterStore getNames();
+	
+	/**
+	 * Returns the name of the slot at the given index.
+	 * <p>
+	 * This is equivalent to <code>getNames().getChar(idx)</code>.</p>
+	 * 
+	 * @param idx the index of the slot
+	 * @return the slot names
+	 * @throws IndexOutOfBoundsException if <code>idx</code> &lt; 0 or <code>idx</code> &ge; slot count
+	 */
+	@Override
+	String getName(int idx);
+	
+	/**
+	 * Returns the value of the slot at the given index.
+	 * 
+	 * @param idx the index of the slot
+	 * @return the value object of the slot
+	 * @throws IndexOutOfBoundsException if <code>idx</code> &lt; 0 or <code>idx</code> &ge; slot count
+	 */
+	@Override
+	RObject get(int idx);
+	
+	/**
+	 * Returns the value of the slot with the given name.
+	 * 
+	 * @param name the name of the slot
+	 * @return the value of the slot with the given name
+	 * @throws IllegalArgumentException if the S4 type doesn't have a slot with the given name
+	 */
+	@Override
+	RObject get(String name);
+	
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/RStore.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/RStore.java
new file mode 100644
index 0000000..c8d6285
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/RStore.java
@@ -0,0 +1,744 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data;
+
+import javax.naming.OperationNotSupportedException;
+
+
+/**
+ * This is the abstract one-dimensional data store for an R data type.
+ * <p>
+ * Data stores are not directly R objects but are used in the data objects
+ * {@link RVector} and {@link RArray}.</p>
+ * <p>
+ * There are store types for each atomic type of R (namely the types/modes
+ * numeric, complex, logical, character and raw) and a special
+ * type for factors.  To get the type of a RStore the method {@link #getStoreType()}
+ * should be used.  The available data types are:</p>
+ * <ul>
+ *   <li>{@link #LOGICAL}</li>
+ *   <li>{@link #INTEGER}</li>
+ *   <li>{@link #NUMERIC}</li>
+ *   <li>{@link #COMPLEX}</li>
+ *   <li>{@link #CHARACTER}</li>
+ *   <li>{@link #RAW}</li>
+ *   <li>{@link #FACTOR}</li>
+ * </ul>
+ * <p>
+ * The Java value can be accessed by the getter methods for the different
+ * data types.  The indexes are zero-based like in Java and not one-base like in R.
+ * Because Java doesn't provide NA for primitive data types directly,
+ * the data store provides the methods {@link #isNA(int)} and {@link #setNA(int)}
+ * to detect and set such values.
+ * If the value at an index of the store is NA, the return value of the other getter
+ * methods is undefined.</p>
+ * <p>
+ * Indexes are zero-based (as usual in Java) and not one-base like in R.</p>
+ */
+public interface RStore<P> {
+	
+	/**
+	 * Constant indicating a store for R data type <code>logical<code>.
+	 * 
+	 * <p>The story object is an instance of {@link RLogicalStore}.
+	 * The {@link #getBaseVectorRClassName() class name} is
+	 * <code>{@link RObject#CLASSNAME_LOGICAL logical}</code>.</p>
+	 * 
+	 * @see #getLogi(int)
+	 * @see #setLogi(int, boolean)
+	 */
+	byte LOGICAL=         0x00000001;
+	
+	/**
+	 * Constant indicating a store for R data type <code>integer<code>.
+	 * 
+	 * <p>The story object is an instance of {@link RIntegerStore}.
+	 * The {@link #getBaseVectorRClassName() class name} is
+	 * <code>{@link RObject#CLASSNAME_INTEGER integer}</code>.</p>
+	 * 
+	 * @see #getInt(int)
+	 * @see #setInt(int, int)
+	 */
+	byte INTEGER=         0x00000002;
+	
+	/**
+	 * Constant indicating a store for R data type <code>logical<code>.
+	 * 
+	 * <p>The story object is an instance of {@link RNumericStore}.
+	 * The {@link #getBaseVectorRClassName() class name} is
+	 * <code>{@link RObject#CLASSNAME_NUMERIC numeric}</code>.</p>
+	 * 
+	 * @see #getNum(int)
+	 * @see #setNum(int, double)
+	 */
+	byte NUMERIC=         0x00000003;
+	
+	/**
+	 * Constant indicating a store for R data type <code>complex<code>.
+	 * 
+	 * <p>The story object is an instance of {@link RComplexStore}.
+	 * The {@link #getBaseVectorRClassName() class name} is
+	 * <code>{@link RObject#CLASSNAME_COMPLEX complex}</code>.</p>
+	 * 
+	 * @see #getCplxRe(int)
+	 * @see #getCplxIm(int)
+	 * @see #setCplx(int, double, double)
+	 */
+	byte COMPLEX=         0x00000004;
+	
+	/**
+	 * Constant indicating a store for R data type <code>character<code>.
+	 * 
+	 * <p>The story object is an instance of {@link RCharacterStore}.  
+	 * The {@link #getBaseVectorRClassName() class name} is
+	 * <code>{@link RObject#CLASSNAME_CHARACTER character}</code>.</p>
+	 * 
+	 * @see #getChar(int)
+	 * @see #setChar(int, String)
+	 */
+	byte CHARACTER=       0x00000005;
+	
+	/**
+	 * Constant indicating a store for R data type <code>raw<code>.
+	 * 
+	 * <p>Note that raw data doesn't support NAs.</p>
+	 * 
+	 * <p>The story object is an instance of {@link RRawStore}.  
+	 * The {@link #getBaseVectorRClassName() class name} is
+	 * <code>{@link RObject#CLASSNAME_RAW raw}</code>.</p>
+	 * 
+	 * @see #getRaw(int)
+	 * @see #setRaw(int, byte)
+	 */
+	byte RAW=             0x00000006;
+	
+	/**
+	 * Constant indicating a special store extending the integer
+	 * data type for R objects extending the R class <code>factor<code>.
+	 * 
+	 * <p>The story object is an instance of {@link RFactorStore}.
+	 * The {@link #getBaseVectorRClassName() class name} is 
+	 * <code>{@link RObject#CLASSNAME_FACTOR factor}</code> or 
+	 * <code>{@link RObject#CLASSNAME_ORDERED ordered}</code>.
+	 * 
+	 * @see RFactorStore#getInt(int)
+	 * @see RFactorStore#getChar(int)
+	 * @see RFactorStore#setInt(int, int)
+	 * @see RFactorStore#setChar(int, String)
+	 **/
+	byte FACTOR=          0x0000000a;
+	
+	
+	/**
+	 * Returns the constant indicating the type of this RStore.
+	 * 
+	 * @return one of the constant defined in the {@link RStore} interface
+	 */
+	byte getStoreType();
+	
+	/**
+	 * Returns the R class name a vector with this data store and no other
+	 * class definitions will have.
+	 * 
+	 * @return the class name
+	 */
+	String getBaseVectorRClassName();
+	
+	/**
+	 * Returns the length of this data store.
+	 * 
+	 * <p>If this is a data store dummy for structure only R objects in Java
+	 * ({@link RObjectFactory#F_ONLY_STRUCT}), the value is <code>-1</code>.
+	 * 
+	 * @return the length or <code>-1</code>
+	 */
+	long getLength();
+	
+	/**
+	 * Tests if the value at the specified index is NA.
+	 * <p>
+	 * Note that the analogous method to the R function <code>is.na(x)</code>
+	 * is {@link #isMissing(int)}; this method returns <code>false</code> for NaN values.</p>
+	 * 
+	 * @param idx the index (zero-based) of the value
+	 * @return <code>true</code>, if the value at the specified index is NA, otherwise <code>false</code>
+	 * @throws IndexOutOfBoundsException if the index is out of range
+	 *     (idx &lt; 0 || idx &gt;= length()).
+	 */
+	boolean isNA(int idx);
+	
+	/**
+	 * Tests if the value at the specified index is NA.
+	 * <p>
+	 * Note that the analogous method to the R function <code>is.na(x)</code>
+	 * is {@link #isMissing(int)}; this method returns <code>false</code> for NaN values.</p>
+	 * 
+	 * @param idx the index (zero-based) of the value
+	 * @return <code>true</code>, if the value at the specified index is NA, otherwise <code>false</code>
+	 * @throws IndexOutOfBoundsException if the index is out of range
+	 *     (idx &lt; 0 || idx &gt;= length()).
+	 */
+	boolean isNA(long idx);
+	
+	/**
+	 * Tests if the value at the specified index is NA <b>or</b> NaN (if supported by data type).
+	 * It works by analogy with the R function <code>is.na(x)</code>.
+	 * 
+	 * @param idx the index (zero-based) of the value
+	 * @return <code>true</code>, if the value at the specified index is NA or NaN, otherwise <code>false</code>
+	 * @throws IndexOutOfBoundsException if the index is out of range
+	 *     (idx &lt; 0 || idx &gt;= length()).
+	 */
+	boolean isMissing(int idx);
+	
+	/**
+	 * Tests if the value at the specified index is NA <b>or</b> NaN (if supported by data type).
+	 * It works by analogy with the R function <code>is.na(x)</code>.
+	 * 
+	 * @param idx the index (zero-based) of the value
+	 * @return <code>true</code>, if the value at the specified index is NA or NaN, otherwise <code>false</code>
+	 * @throws IndexOutOfBoundsException if the index is out of range
+	 *     (idx &lt; 0 || idx &gt;= length()).
+	 */
+	boolean isMissing(long idx);
+	
+	/**
+	 * Sets the value at the specified index to NA.
+	 * <p>
+	 * Note that raw doesn't support NAs.</p>.
+	 * 
+	 * @param idx the index (zero-based) of the value
+	 * @param idx the index of the value to set
+	 * @throws OperationNotSupportedException if the store is not modifiable
+	 * @throws IndexOutOfBoundsException if the index is out of range
+	 *     (idx &lt; 0 || idx &gt;= length()).
+	 */
+	void setNA(int idx);
+	
+	/**
+	 * Sets the value at the specified index to NA.
+	 * <p>
+	 * Note that raw doesn't support NAs.</p>.
+	 * 
+	 * @param idx the index (zero-based) of the value
+	 * @param idx the index of the value to set
+	 * @throws OperationNotSupportedException if the store is not modifiable
+	 * @throws IndexOutOfBoundsException if the index is out of range
+	 *     (idx &lt; 0 || idx &gt;= length()).
+	 */
+	void setNA(long idx);
+	
+	/**
+	 * Return the logical/boolean value at the specified index.
+	 * <p>
+	 * Logical values in R matches exactly the Java boolean values.</p>
+	 * 
+	 * @param idx the index (zero-based) of the value
+	 * @return the current logical value
+	 * @throws IndexOutOfBoundsException if the index is out of range
+	 *     (idx &lt; 0 || idx &gt;= length()).
+	 */
+	boolean getLogi(int idx);
+	
+	/**
+	 * Return the logical/boolean value at the specified index.
+	 * <p>
+	 * Logical values in R matches exactly the Java boolean values.</p>
+	 * 
+	 * @param idx the index (zero-based) of the value
+	 * @return the current logical value
+	 * @throws IndexOutOfBoundsException if the index is out of range
+	 *     (idx &lt; 0 || idx &gt;= length()).
+	 */
+	boolean getLogi(long idx);
+	
+	/**
+	 * Sets the logical/boolean value at the specified index.
+	 * <p>
+	 * Logical values in R matches exactly the Java boolean values.</p>
+	 * 
+	 * @param idx the index (zero-based) of the value
+	 * @param logical the logical value to set
+	 * @throws OperationNotSupportedException if the store is not modifiable
+	 * @throws IndexOutOfBoundsException if the index is out of range
+	 *     (idx &lt; 0 || idx &gt;= length()).
+	 */
+	void setLogi(int idx, boolean logical);
+	
+	/**
+	 * Sets the logical/boolean value at the specified index.
+	 * <p>
+	 * Logical values in R matches exactly the Java boolean values.</p>
+	 * 
+	 * @param idx the index (zero-based) of the value
+	 * @param logical the logical value to set
+	 * @throws OperationNotSupportedException if the store is not modifiable
+	 * @throws IndexOutOfBoundsException if the index is out of range
+	 *     (idx &lt; 0 || idx &gt;= length()).
+	 */
+	void setLogi(long idx, boolean logical);
+	
+	/**
+	 * Return the integer/int value at the specified index.
+	 * <p>
+	 * Integer values in R matches exactly the Java int values, except
+	 * {@link Integer#MIN_VALUE} which doesn't exists in R and is mapped to NA.</p>
+	 * 
+	 * @param idx the index (zero-based) of the value
+	 * @return the current integer value
+	 * @throws IndexOutOfBoundsException if the index is out of range
+	 *     (idx &lt; 0 || idx &gt;= length()).
+	 */
+	int getInt(int idx);
+	
+	/**
+	 * Return the integer/int value at the specified index.
+	 * <p>
+	 * Integer values in R matches exactly the Java int values, except
+	 * {@link Integer#MIN_VALUE} which doesn't exists in R and is mapped to NA.</p>
+	 * 
+	 * @param idx the index (zero-based) of the value
+	 * @return the current integer value
+	 * @throws IndexOutOfBoundsException if the index is out of range
+	 *     (idx &lt; 0 || idx &gt;= length()).
+	 */
+	int getInt(long idx);
+	
+	/**
+	 * Sets the integer/int value at the specified index.
+	 * <p>
+	 * Integer values in R matches exactly the Java int values, except
+	 * {@link Integer#MIN_VALUE} which doesn't exists in R and is mapped to NA.</p>
+	 * 
+	 * @param idx the index (zero-based) of the value
+	 * @param integer the integer value to set
+	 * @throws OperationNotSupportedException if the store is not modifiable
+	 * @throws IndexOutOfBoundsException if the index is out of range
+	 *     (idx &lt; 0 || idx &gt;= length()).
+	 */
+	void setInt(int idx, int integer);
+	
+	/**
+	 * Sets the integer/int value at the specified index.
+	 * <p>
+	 * Integer values in R matches exactly the Java int values, except
+	 * {@link Integer#MIN_VALUE} which doesn't exists in R and is mapped to NA.</p>
+	 * 
+	 * @param idx the index (zero-based) of the value
+	 * @param integer the integer value to set
+	 * @throws OperationNotSupportedException if the store is not modifiable
+	 * @throws IndexOutOfBoundsException if the index is out of range
+	 *     (idx &lt; 0 || idx &gt;= length()).
+	 */
+	void setInt(long idx, int integer);
+	
+	/**
+	 * Return the numeric/real/double value at the specified index.
+	 * <p>
+	 * Numeric values in R matches exactly the Java double values.
+	 * Also NaN, Inf and -Inf respectively {@link Double#isNaN(double)}, 
+	 * {@link Double#POSITIVE_INFINITY} and {@link Double#NEGATIVE_INFINITY} are 
+	 * supported.</p>
+	 * 
+	 * @param idx the index (zero-based) of the value
+	 * @return the current real value
+	 * @throws IndexOutOfBoundsException if the index is out of range
+	 *     (idx &lt; 0 || idx &gt;= length()).
+	 */
+	double getNum(int idx);
+	
+	/**
+	 * Return the numeric/real/double value at the specified index.
+	 * <p>
+	 * Numeric values in R matches exactly the Java double values.
+	 * Also NaN, Inf and -Inf respectively {@link Double#isNaN(double)}, 
+	 * {@link Double#POSITIVE_INFINITY} and {@link Double#NEGATIVE_INFINITY} are 
+	 * supported.</p>
+	 * 
+	 * @param idx the index (zero-based) of the value
+	 * @return the current real value
+	 * @throws IndexOutOfBoundsException if the index is out of range
+	 *     (idx &lt; 0 || idx &gt;= length()).
+	 */
+	double getNum(long idx);
+	
+	/**
+	 * Sets the numeric/real/double value at the specified index.
+	 * <p>
+	 * Numeric values in R matches exactly the Java double values.
+	 * Also NaN, Inf and -Inf respectively {@link Double#NaN}, 
+	 * {@link Double#POSITIVE_INFINITY} and {@link Double#NEGATIVE_INFINITY} are 
+	 * supported.</p>
+	 * 
+	 * @param idx the index (zero-based) of the value
+	 * @param numeric the real value to set
+	 * @throws OperationNotSupportedException if the store is not modifiable
+	 * @throws IndexOutOfBoundsException if the index is out of range
+	 *     (idx &lt; 0 || idx &gt;= length()).
+	 */
+	void setNum(int idx, double numeric);
+	
+	/**
+	 * Sets the numeric/real/double value at the specified index.
+	 * <p>
+	 * Numeric values in R matches exactly the Java double values.
+	 * Also NaN, Inf and -Inf respectively {@link Double#NaN}, 
+	 * {@link Double#POSITIVE_INFINITY} and {@link Double#NEGATIVE_INFINITY} are 
+	 * supported.</p>
+	 * 
+	 * @param idx the index (zero-based) of the value
+	 * @param numeric the real value to set
+	 * @throws OperationNotSupportedException if the store is not modifiable
+	 * @throws IndexOutOfBoundsException if the index is out of range
+	 *     (idx &lt; 0 || idx &gt;= length()).
+	 */
+	void setNum(long idx, double numeric);
+	
+	/**
+	 * Returns the real part the complex number value at the specified index.
+	 * <p>
+	 * The numeric values of the parts of the complex number in R matches 
+	 * exactly the Java double values.
+	 * Also NaN, Inf and -Inf respectively {Double#isNaN(double)}, 
+	 * {@link Double#POSITIVE_INFINITY} and {@link Double#NEGATIVE_INFINITY} are 
+	 * supported.</p>
+	 * 
+	 * @param idx the index (zero-based) of the value
+	 * @return the current real part of the complex number value
+	 * @throws IndexOutOfBoundsException if the index is out of range
+	 *     (idx &lt; 0 || idx &gt;= length()).
+	 */
+	double getCplxRe(int idx);
+	
+	/**
+	 * Returns the real part the complex number value at the specified index.
+	 * <p>
+	 * The numeric values of the parts of the complex number in R matches 
+	 * exactly the Java double values.
+	 * Also NaN, Inf and -Inf respectively {Double#isNaN(double)}, 
+	 * {@link Double#POSITIVE_INFINITY} and {@link Double#NEGATIVE_INFINITY} are 
+	 * supported.</p>
+	 * 
+	 * @param idx the index (zero-based) of the value
+	 * @return the current real part of the complex number value
+	 * @throws IndexOutOfBoundsException if the index is out of range
+	 *     (idx &lt; 0 || idx &gt;= length()).
+	 */
+	double getCplxRe(long idx);
+	
+	/**
+	 * Returns the imaginary part the complex number value at the specified index.
+	 * <p>
+	 * The numeric values of the parts of the complex number in R matches 
+	 * exactly the Java double values.
+	 * Also NaN, Inf and -Inf respectively {Double#isNaN(double)}, 
+	 * {@link Double#POSITIVE_INFINITY} and {@link Double#NEGATIVE_INFINITY} are 
+	 * supported.</p>
+	 * 
+	 * @param idx the index (zero-based) of the value
+	 * @return the current imaginary part of the complex number value
+	 * @throws IndexOutOfBoundsException if the index is out of range
+	 *     (idx &lt; 0 || idx &gt;= length()).
+	 */
+	double getCplxIm(int idx);
+	
+	/**
+	 * Returns the imaginary part the complex number value at the specified index.
+	 * <p>
+	 * The numeric values of the parts of the complex number in R matches 
+	 * exactly the Java double values.
+	 * Also NaN, Inf and -Inf respectively {Double#isNaN(double)}, 
+	 * {@link Double#POSITIVE_INFINITY} and {@link Double#NEGATIVE_INFINITY} are 
+	 * supported.</p>
+	 * 
+	 * @param idx the index (zero-based) of the value
+	 * @return the current imaginary part of the complex number value
+	 * @throws IndexOutOfBoundsException if the index is out of range
+	 *     (idx &lt; 0 || idx &gt;= length()).
+	 */
+	double getCplxIm(long idx);
+	
+	/**
+	 * Sets the complex number value at the specified index.
+	 * <p>
+	 * The numeric values of the parts of the complex number in R matches 
+	 * exactly the Java double values.
+	 * Also NaN, Inf and -Inf respectively {@link Double#NaN}, 
+	 * {@link Double#POSITIVE_INFINITY} and {@link Double#NEGATIVE_INFINITY} are 
+	 * supported.</p>
+	 * 
+	 * @param idx the index (zero-based) of the value
+	 * @param real the real part of the complex number value
+	 * @param imaginary the imaginary part of the complex number value
+	 * @throws OperationNotSupportedException if the store is not modifiable
+	 * @throws IndexOutOfBoundsException if the index is out of range
+	 *     (idx &lt; 0 || idx &gt;= length()).
+	 */
+	void setCplx(int idx, double real, double imaginary);
+	
+	/**
+	 * Sets the complex number value at the specified index.
+	 * <p>
+	 * The numeric values of the parts of the complex number in R matches 
+	 * exactly the Java double values.
+	 * Also NaN, Inf and -Inf respectively {@link Double#NaN}, 
+	 * {@link Double#POSITIVE_INFINITY} and {@link Double#NEGATIVE_INFINITY} are 
+	 * supported.</p>
+	 * 
+	 * @param idx the index (zero-based) of the value
+	 * @param real the real part of the complex number value
+	 * @param imaginary the imaginary part of the complex number value
+	 * @throws OperationNotSupportedException if the store is not modifiable
+	 * @throws IndexOutOfBoundsException if the index is out of range
+	 *     (idx &lt; 0 || idx &gt;= length()).
+	 */
+	void setCplx(long idx, double real, double imaginary);
+	
+	/**
+	 * Returns the character value at the specified index.
+	 * <p>
+	 * R character values matches exactly Java string values, if R supports
+	 * UTF encoding.</p>
+	 * 
+	 * @param idx the index (zero-based) of the value
+	 * @return the current character value
+	 * @throws IndexOutOfBoundsException if the index is out of range
+	 *     (idx &lt; 0 || idx &gt;= length()).
+	 */
+	String getChar(int idx);
+	
+	/**
+	 * Returns the character value at the specified index.
+	 * <p>
+	 * R character values matches exactly Java string values, if R supports
+	 * UTF encoding.</p>
+	 * 
+	 * @param idx the index (zero-based) of the value
+	 * @return the current character value
+	 * @throws IndexOutOfBoundsException if the index is out of range
+	 *     (idx &lt; 0 || idx &gt;= length()).
+	 */
+	String getChar(long idx);
+	
+	/**
+	 * Sets the character/String value at the specified index.
+	 * <p>
+	 * R character values matches exactly Java string values, if R supports
+	 * UTF encoding.</p>
+	 * <p>
+	 * No quoting or escaping is required. Quoting or escaping the value
+	 * would change the real value.</p>
+	 * 
+	 * @param idx the index (zero-based) of the value
+	 * @param character the character value to set
+	 * @throws OperationNotSupportedException if the store is not modifiable
+	 * @throws IndexOutOfBoundsException if the index is out of range
+	 *     (idx &lt; 0 || idx &gt;= length()).
+	 */
+	void setChar(int idx, String character);
+	
+	/**
+	 * Sets the character/String value at the specified index.
+	 * <p>
+	 * R character values matches exactly Java string values, if R supports
+	 * UTF encoding.</p>
+	 * <p>
+	 * No quoting or escaping is required. Quoting or escaping the value
+	 * would change the real value.</p>
+	 * 
+	 * @param idx the index (zero-based) of the value
+	 * @param character the character value to set
+	 * @throws OperationNotSupportedException if the store is not modifiable
+	 * @throws IndexOutOfBoundsException if the index is out of range
+	 *     (idx &lt; 0 || idx &gt;= length()).
+	 */
+	void setChar(long idx, String character);
+	
+	/**
+	 * Returns the raw/byte value at the specified index.
+	 * <p>
+	 * R raw values matches exactly Java byte values.</p>
+	 * 
+	 * @param idx the index (zero-based) of the value
+	 * @return the current raw value
+	 * @throws IndexOutOfBoundsException if the index is out of range
+	 *     (idx &lt; 0 || idx &gt;= length()).
+	 */
+	byte getRaw(int idx);
+	
+	/**
+	 * Returns the raw/byte value at the specified index.
+	 * <p>
+	 * R raw values matches exactly Java byte values.</p>
+	 * 
+	 * @param idx the index (zero-based) of the value
+	 * @return the current raw value
+	 * @throws IndexOutOfBoundsException if the index is out of range
+	 *     (idx &lt; 0 || idx &gt;= length()).
+	 */
+	byte getRaw(long idx);
+	
+	/**
+	 * Sets the raw/byte value at the specified index.
+	 * <p>
+	 * R raw values matches exactly Java byte values.</p>
+	 * 
+	 * @param idx the index (zero-based) of the value
+	 * @param raw the raw value to set
+	 * @throws OperationNotSupportedException if the store is not modifiable
+	 * @throws IndexOutOfBoundsException if the index is out of range
+	 *     (idx &lt; 0 || idx &gt;= length()).
+	 */
+	void setRaw(int idx, byte raw);
+	
+	/**
+	 * Sets the raw/byte value at the specified index.
+	 * <p>
+	 * R raw values matches exactly Java byte values.</p>
+	 * 
+	 * @param idx the index (zero-based) of the value
+	 * @param raw the raw value to set
+	 * @throws OperationNotSupportedException if the store is not modifiable
+	 * @throws IndexOutOfBoundsException if the index is out of range
+	 *     (idx &lt; 0 || idx &gt;= length()).
+	 */
+	void setRaw(long idx, byte raw);
+	
+	/**
+	 * Returns the value at the specified index as Java object. The subtypes of 
+	 * RStore defines more specific array types.
+	 * <p>
+	 * R NA values are represented as <code>null</code>. Java primitives are converted
+	 * into its wrapper classes.</p>
+	 * 
+	 * @param idx the index (zero-based) of the value
+	 * @return an object for the current value
+	 * @throws IndexOutOfBoundsException if the index is out of range
+	 *     (idx &lt; 0 || idx &gt;= length()).
+	 */
+	P get(int idx);
+	
+	/**
+	 * Returns the value at the specified index as Java object. The subtypes of 
+	 * RStore defines more specific array types.
+	 * <p>
+	 * R NA values are represented as <code>null</code>. Java primitives are converted
+	 * into its wrapper classes.</p>
+	 * 
+	 * @param idx the index (zero-based) of the value
+	 * @return an object for the current value
+	 * @throws IndexOutOfBoundsException if the index is out of range
+	 *     (idx &lt; 0 || idx &gt;= length()).
+	 */
+	P get(long idx);
+	
+	/**
+	 * Returns the values of the store as Java object array. The subtypes of 
+	 * RStore defines more specific array types.
+	 * <p>
+	 * The array is newly created for each call of this method. It has the
+	 * length {@link #getLength()}. R NA values are represented as <code>null</code>
+	 * in the array. Java primitives are converted into its wrapper classes.</p>
+	 * 
+	 * @return a object array with the values of the store
+	 */
+	P[] toArray();
+	
+	boolean allEqual(RStore<?> other);
+	
+	
+	/**
+	 * Returns if the store contains the a NA value.
+	 * 
+	 * @return <code>true</code> if the store contains a NA value, otherwise false
+	 * 
+	 * @since de.walware.rj.data 3.0
+	 */
+	boolean containsNA();
+	
+	/**
+	 * Returns the index of the first NA value in the store.
+	 * 
+	 * @return index (zero-base) of first equal value, otherwise <code>-1</code>
+	 * 
+	 * @since de.walware.rj.data 3.0
+	 */
+	long indexOfNA();
+	
+	/**
+	 * Returns the index of the first NA value in the store, starting from the specified index.
+	 * 
+	 * @param fromIdx index (zero-based) from which to start the search
+	 * @return index (zero-based) of first equal value, otherwise <code>-1</code>
+	 * 
+	 * @since de.walware.rj.data 3.0
+	 */
+	long indexOfNA(long fromIdx);
+	
+	/**
+	 * Returns if the store contains the specified integer value.
+	 * 
+	 * @param value the value to search for
+	 * @return <code>true</code> if the store contains the value, otherwise false
+	 */
+	boolean contains(final int integer);
+	
+	/**
+	 * Returns the index of the first value in the store equal to the of the specified integer
+	 * value.
+	 * 
+	 * @param integer the value to search for
+	 * @return index (zero-based) of first equal value, otherwise <code>-1</code>
+	 */
+	long indexOf(int integer);
+	
+	/**
+	 * Returns the index of the first value in the store equal to the of the specified integer
+	 * value, starting from the specified index.
+	 * 
+	 * @param integer the value to search for
+	 * @param fromIdx index (zero-based) from which to start the search
+	 * @return index (zero-based) of first equal value, otherwise <code>-1</code>
+	 */
+	long indexOf(int integer, long fromIdx);
+	
+	/**
+	 * Returns if the store contains the specified character value.
+	 * 
+	 * @param value the value to search for
+	 * @return <code>true</code> if the store contains the value, otherwise false
+	 */
+	boolean contains(final String value);
+	
+	/**
+	 * Returns the index of the first value in the store equal to the of the specified character
+	 * value.
+	 * 
+	 * @param character the value to search for
+	 * @return index (zero-base) of first equal value, otherwise <code>-1</code>
+	 */
+	long indexOf(String character);
+	
+	/**
+	 * Returns the index of the first value in the store equal to the of the specified character
+	 * value, starting from the specified index.
+	 * 
+	 * @param character the value to search for
+	 * @param fromIdx index (zero-based) from which to start the search
+	 * @return index (zero-based) of first equal value, otherwise <code>-1</code>
+	 */
+	long indexOf(String character, long fromIdx);
+	
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/RVector.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/RVector.java
new file mode 100644
index 0000000..7626963
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/RVector.java
@@ -0,0 +1,74 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data;
+
+
+/**
+ * An R object is of the type {@link RObject#TYPE_VECTOR vector}, if it is an R
+ * data object of an "atomic" mode without a dimension attribute (<code>dim</code>).
+ * Such an R vector object is represented by an instance of this interface.
+ * <p>
+ * The real data is stored in a {@link RStore} accessible by {@link #getData()}.</p>
+ * <p>
+ * The type {@link RObject#TYPE_VECTOR vector} equates not the R command 
+ * <code>is.vector(object)</code>, mainly because all attributes except the dimension 
+ * are allowed (in the R function only the names attribute is allowed).  Especially
+ * an R factor object is of the type {@link RObject#TYPE_VECTOR vector}, implements
+ * RVector and has a data store of the type {@link RStore#FACTOR}.  Also another S3 
+ * object based on a such a data object is of the type {@link RObject#TYPE_VECTOR vector}.
+ * Whereas a S4 object is never directly of this type even the object simulates such
+ * a data object in R. Such an object is of the type {@link RObject#TYPE_S4OBJECT S4 object},
+ * and implements {@link RS4Object} with an object of the type {@link RObject#TYPE_VECTOR vector}
+ * as data slot.</p>
+ * <p>
+ * The complementary type for objects with dimension attribute is the type
+ * {@link RObject#TYPE_ARRAY array} and the interface {@link RArray}.
+ * The data structure for multiple R objects is represented by the type 
+ * {@link RObject#TYPE_LIST list} respectively the interface {@link RList}.</p>
+ * 
+ * @param <TData> the type of the data store
+ */
+public interface RVector<TData extends RStore<?>> extends RObject {
+	
+	/**
+	 * Returns the length of the object. The length of an {@link RObject#TYPE_VECTOR vector}
+	 * is the count of all data values.
+	 * 
+	 * @return the length
+	 */
+	@Override
+	long getLength();
+	
+	/**
+	 * Returns the names for the indexes of the vector. This corresponds to the values of the
+	 * R attribute (<code>names</code>) respectively the R function <code>names(object)</code>.
+	 * 
+	 * The returned character data has the same length the vector. If the R element does not have 
+	 * names, the names are invalid, or names are disabled, the method returns <code>null</code>.
+	 * 
+	 * @return a data store with the names of the indexes or <code>null</code>
+	 * 
+	 * @since de.walware.rj.data 0.5
+	 */
+	RStore<?> getNames();
+	
+	
+	@Override
+	TData getData();
+	
+//	void insert(int idx);
+//	void remove(int idx);
+	
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/UnexpectedRDataException.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/UnexpectedRDataException.java
new file mode 100644
index 0000000..3a795e7
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/UnexpectedRDataException.java
@@ -0,0 +1,30 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data;
+
+
+/**
+ * Exception indicating that the R data (object or store) is missing or not of the expected type.
+ */
+public class UnexpectedRDataException extends Exception {
+	
+	private static final long serialVersionUID= 1L;
+	
+	
+	public UnexpectedRDataException(final String message) {
+		super(message);
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/AbstractCharacterStore.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/AbstractCharacterStore.java
new file mode 100644
index 0000000..ef64b11
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/AbstractCharacterStore.java
@@ -0,0 +1,155 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data.impl;
+
+import org.eclipse.statet.rj.data.RCharacterStore;
+import org.eclipse.statet.rj.data.RObject;
+import org.eclipse.statet.rj.data.RStore;
+
+
+public abstract class AbstractCharacterStore extends AbstractRStore<String>
+		implements RCharacterStore {
+	
+	
+	protected static final boolean toLogi(final String character) {
+		switch (character.length()) {
+		case 1:
+			switch (character.charAt(0)) {
+			case 'F':
+				return false;
+			case 'T':
+				return true;
+			default:
+				break;
+			}
+			break;
+		case 4:
+			if ("true".regionMatches(0, character, 0, 4)) {
+				return true;
+			}
+			break;
+		case 5:
+			if ("false".regionMatches(0, character, 0, 5)) {
+				return false;
+			}
+			break;
+		default:
+			break;
+		}
+		throw new NumberFormatException(character);
+	}
+	
+	
+	@Override
+	public final byte getStoreType() {
+		return RStore.CHARACTER;
+	}
+	
+	@Override
+	public final String getBaseVectorRClassName() {
+		return RObject.CLASSNAME_CHARACTER;
+	}
+	
+	
+	@Override
+	public void setLogi(final int idx, final boolean logi) {
+		setChar(idx, AbstractLogicalStore.toChar(logi));
+	}
+	
+	@Override
+	public void setLogi(final long idx, final boolean logi) {
+		setChar(idx, AbstractLogicalStore.toChar(logi));
+	}
+	
+	@Override
+	public boolean getLogi(final int idx) {
+		return toLogi(getChar(idx));
+	}
+	
+	@Override
+	public boolean getLogi(final long idx) {
+		return toLogi(getChar(idx));
+	}
+	
+	@Override
+	public final void setInt(final int idx, final int integer) {
+		setChar(idx, Integer.toString(integer));
+	}
+	
+	@Override
+	public final void setInt(final long idx, final int integer) {
+		setChar(idx, Integer.toString(integer));
+	}
+	
+	@Override
+	public void setCplx(final int idx, final double real, final double imaginary) {
+		setChar(idx, AbstractComplexStore.toChar(real, imaginary));
+	}
+	
+	@Override
+	public void setCplx(final long idx, final double real, final double imaginary) {
+		setChar(idx, AbstractComplexStore.toChar(real, imaginary));
+	}
+	
+	@Override
+	public final void setRaw(final int idx, final byte raw) {
+		setChar(idx, AbstractRawStore.toChar(raw));
+	}
+	
+	@Override
+	public final void setRaw(final long idx, final byte raw) {
+		setChar(idx, AbstractRawStore.toChar(raw));
+	}
+	
+	@Override
+	public long indexOf(final int integer, final long fromIdx) {
+		return indexOf(Integer.toString(integer), fromIdx);
+	}
+	
+	
+	@Override
+	public abstract String[] toArray();
+	
+	
+	@Override
+	public boolean allEqual(final RStore<?> other) {
+		final long length= getLength();
+		if (CHARACTER != other.getStoreType() || length != other.getLength()) {
+			return false;
+		}
+		if (length < 0) {
+			return true;
+		}
+		else if (length <= Integer.MAX_VALUE) {
+			final int ilength= (int) length;
+			for (int idx= 0; idx < ilength; idx++) {
+				if (!(isNA(idx) ? other.isNA(idx) :
+						getChar(idx).equals(other.getChar(idx)) )) {
+					return false;
+				}
+			}
+		}
+		else {
+			for (long idx= 0; idx < length; idx++) {
+				if (!(isNA(idx) ? other.isNA(idx) :
+						getChar(idx).equals(other.getChar(idx)) )) {
+					return false;
+				}
+			}
+		}
+		return true;
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/AbstractComplexStore.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/AbstractComplexStore.java
new file mode 100644
index 0000000..3137a75
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/AbstractComplexStore.java
@@ -0,0 +1,71 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data.impl;
+
+import org.eclipse.statet.rj.data.RComplexStore;
+import org.eclipse.statet.rj.data.RObject;
+import org.eclipse.statet.rj.data.RStore;
+
+
+public abstract class AbstractComplexStore extends AbstractRStore<RComplexStore.Complex>
+		implements RComplexStore {
+	
+	
+	protected static final String toChar(final double real, final double imaginary) {
+		final StringBuilder sb= new StringBuilder();
+		sb.append(AbstractNumericStore.toChar(real));
+		{	final String imStr= AbstractNumericStore.toChar(imaginary);
+			if (imStr.charAt(0) != '-') {
+				sb.append('+');
+			}
+			sb.append(imStr);
+		}
+		sb.append('i');
+		return sb.toString();
+	}
+	
+	
+	@Override
+	public final byte getStoreType() {
+		return RStore.COMPLEX;
+	}
+	
+	@Override
+	public final String getBaseVectorRClassName() {
+		return RObject.CLASSNAME_COMPLEX;
+	}
+	
+	
+	@Override
+	public final String getChar(final int idx) {
+		return toChar(getCplxRe(idx), getCplxIm(idx));
+	}
+	
+	@Override
+	public final String getChar(final long idx) {
+		return toChar(getCplxRe(idx), getCplxIm(idx));
+	}
+	
+	
+	@Override
+	public long indexOf(final int integer, final long fromIdx) {
+		throw new UnsupportedOperationException();
+	}
+	
+	
+	@Override
+	public abstract Complex[] toArray();
+	
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/AbstractFactorStore.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/AbstractFactorStore.java
new file mode 100644
index 0000000..c888196
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/AbstractFactorStore.java
@@ -0,0 +1,90 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data.impl;
+
+import org.eclipse.statet.rj.data.RFactorStore;
+import org.eclipse.statet.rj.data.RObject;
+import org.eclipse.statet.rj.data.RStore;
+
+
+public abstract class AbstractFactorStore extends AbstractRStore<Integer>
+		implements RFactorStore {
+	
+	
+	protected boolean isOrdered;
+	
+	
+	@Override
+	public final byte getStoreType() {
+		return RStore.FACTOR;
+	}
+	
+	@Override
+	public final String getBaseVectorRClassName() {
+		return (this.isOrdered) ? RObject.CLASSNAME_ORDERED : RObject.CLASSNAME_FACTOR;
+	}
+	
+	@Override
+	public final boolean isOrdered() {
+		return this.isOrdered;
+	}
+	
+	
+	@Override
+	public final boolean getLogi(final int idx) {
+		return (getInt(idx) != 0);
+	}
+	
+	@Override
+	public final boolean getLogi(final long idx) {
+		return (getInt(idx) != 0);
+	}
+	
+	@Override
+	public final void setLogi(final int idx, final boolean logi) {
+		setInt(idx, logi ? 1 : 0);
+	}
+	
+	@Override
+	public final void setLogi(final long idx, final boolean logi) {
+		setInt(idx, logi ? 1 : 0);
+	}
+	
+	@Override
+	public final double getNum(final int idx) {
+		return getInt(idx);
+	}
+	
+	@Override
+	public final double getNum(final long idx) {
+		return getInt(idx);
+	}
+	
+	@Override
+	public final void setNum(final int idx, final double real) {
+		setInt(idx, (int) real);
+	}
+	
+	@Override
+	public final void setNum(final long idx, final double real) {
+		setInt(idx, (int) real);
+	}
+	
+	
+	@Override
+	public abstract Integer[] toArray();
+	
+	
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/AbstractIntegerStore.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/AbstractIntegerStore.java
new file mode 100644
index 0000000..d2f339d
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/AbstractIntegerStore.java
@@ -0,0 +1,150 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data.impl;
+
+import org.eclipse.statet.rj.data.RIntegerStore;
+import org.eclipse.statet.rj.data.RObject;
+import org.eclipse.statet.rj.data.RStore;
+
+
+public abstract class AbstractIntegerStore extends AbstractRStore<Integer>
+		implements RIntegerStore {
+	
+	
+	protected static final byte toRaw(final int integer) {
+		if ((integer & 0xffffff00) == 0) {
+			return (byte) (integer & 0xff);
+		}
+		throw new NumberFormatException(Integer.toString(integer));
+	}
+	
+	
+	@Override
+	public final byte getStoreType() {
+		return RStore.INTEGER;
+	}
+	
+	@Override
+	public final String getBaseVectorRClassName() {
+		return RObject.CLASSNAME_INTEGER;
+	}
+	
+	
+	@Override
+	public final boolean getLogi(final int idx) {
+		return (getInt(idx) != 0);
+	}
+	
+	@Override
+	public final boolean getLogi(final long idx) {
+		return (getInt(idx) != 0);
+	}
+	
+	@Override
+	public final void setLogi(final int idx, final boolean logi) {
+		setInt(idx, logi ? 1 : 0);
+	}
+	
+	@Override
+	public final void setLogi(final long idx, final boolean logi) {
+		setInt(idx, logi ? 1 : 0);
+	}
+	
+	@Override
+	public final double getNum(final int idx) {
+		return getInt(idx);
+	}
+	
+	@Override
+	public final double getNum(final long idx) {
+		return getInt(idx);
+	}
+	
+	@Override
+	public final void setNum(final int idx, final double real) {
+		setInt(idx, (int) real);
+	}
+	
+	@Override
+	public final void setNum(final long idx, final double real) {
+		setInt(idx, (int) real);
+	}
+	
+	@Override
+	public final String getChar(final int idx) {
+		return Integer.toString(getInt(idx));
+	}
+	
+	@Override
+	public final String getChar(final long idx) {
+		return Integer.toString(getInt(idx));
+	}
+	
+	@Override
+	public byte getRaw(final int idx) {
+		return toRaw(getInt(idx));
+	}
+	
+	@Override
+	public byte getRaw(final long idx) {
+		return toRaw(getInt(idx));
+	}
+	
+	
+	@Override
+	public abstract Integer[] toArray();
+	
+	
+	@Override
+	public long indexOf(final String character, final long fromIdx) {
+		try {
+			return indexOf(Integer.parseInt(character), fromIdx);
+		}
+		catch (final NumberFormatException e) {
+			return -1;
+		}
+	}
+	
+	
+	@Override
+	public boolean allEqual(final RStore<?> other) {
+		final long length= getLength();
+		if (INTEGER != other.getStoreType() || length != other.getLength()) {
+			return false;
+		}
+		if (length < 0) {
+			return true;
+		}
+		else if (length <= Integer.MAX_VALUE) {
+			final int ilength= (int) length;
+			for (int idx= 0; idx < ilength; idx++) {
+				if (!(isNA(idx) ? other.isNA(idx) :
+						getInt(idx) == other.getInt(idx) )) {
+					return false;
+				}
+			}
+		}
+		else {
+			for (long idx= 0; idx < length; idx++) {
+				if (!(isNA(idx) ? other.isNA(idx) :
+						getInt(idx) == other.getInt(idx) )) {
+					return false;
+				}
+			}
+		}
+		return true;
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/AbstractLogicalStore.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/AbstractLogicalStore.java
new file mode 100644
index 0000000..c1f6151
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/AbstractLogicalStore.java
@@ -0,0 +1,149 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data.impl;
+
+import org.eclipse.statet.rj.data.RLogicalStore;
+import org.eclipse.statet.rj.data.RObject;
+import org.eclipse.statet.rj.data.RStore;
+
+
+public abstract class AbstractLogicalStore extends AbstractRStore<Boolean>
+		implements RLogicalStore {
+	
+	
+	protected static final String toChar(final boolean logi) {
+		return (logi) ? "TRUE" : "FALSE";
+	}
+	
+	
+	@Override
+	public final byte getStoreType() {
+		return RStore.LOGICAL;
+	} 
+	
+	@Override
+	public final String getBaseVectorRClassName() {
+		return RObject.CLASSNAME_LOGICAL;
+	}
+	
+	
+	@Override
+	public final int getInt(final int idx) {
+		return getLogi(idx) ? 1 : 0;
+	}
+	
+	@Override
+	public final int getInt(final long idx) {
+		return getLogi(idx) ? 1 : 0;
+	}
+	
+	@Override
+	public final void setInt(final int idx, final int integer) {
+		setLogi(idx, integer != 0);
+	}
+	
+	@Override
+	public final void setInt(final long idx, final int integer) {
+		setLogi(idx, integer != 0);
+	}
+	
+	@Override
+	public final String getChar(final int idx) {
+		return toChar(getLogi(idx));
+	}
+	
+	@Override
+	public final String getChar(final long idx) {
+		return toChar(getLogi(idx));
+	}
+	
+	@Override
+	public void setChar(final int idx, final String character) {
+		setLogi(idx, AbstractCharacterStore.toLogi(character));
+	}
+	
+	@Override
+	public void setChar(final long idx, final String character) {
+		setLogi(idx, AbstractCharacterStore.toLogi(character));
+	}
+	
+	@Override
+	public long indexOf(final String character, final long fromIdx) {
+		if (character == null) {
+			throw new NullPointerException();
+		}
+		try {
+			return indexOf(AbstractCharacterStore.toLogi(character) ? 1 : 0, fromIdx);
+		}
+		catch (final NumberFormatException e) {
+			return -1;
+		}
+	}
+	
+	@Override
+	public byte getRaw(final int idx) {
+		return getLogi(idx) ? (byte) 1 : (byte) 0;
+	}
+	
+	@Override
+	public byte getRaw(final long idx) {
+		return getLogi(idx) ? (byte) 1 : (byte) 0;
+	}
+	
+	@Override
+	public void setRaw(final int idx, final byte raw) {
+		setLogi(idx, raw != 0);
+	}
+	
+	@Override
+	public void setRaw(final long idx, final byte raw) {
+		setLogi(idx, raw != 0);
+	}
+	
+	
+	@Override
+	public abstract Boolean[] toArray();
+	
+	
+	@Override
+	public boolean allEqual(final RStore<?> other) {
+		final long length= getLength();
+		if (LOGICAL != other.getStoreType() || length != other.getLength()) {
+			return false;
+		}
+		if (length < 0) {
+			return true;
+		}
+		else if (length <= Integer.MAX_VALUE) {
+			final int ilength= (int) length;
+			for (int idx= 0; idx < ilength; idx++) {
+				if (!(isNA(idx) ? other.isNA(idx) :
+						getLogi(idx) == other.getLogi(idx) )) {
+					return false;
+				}
+			}
+		}
+		else {
+			for (long idx= 0; idx < length; idx++) {
+				if (!(isNA(idx) ? other.isNA(idx) :
+						getLogi(idx) == other.getLogi(idx) )) {
+					return false;
+				}
+			}
+		}
+		return true;
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/AbstractNumericStore.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/AbstractNumericStore.java
new file mode 100644
index 0000000..0ff0a97
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/AbstractNumericStore.java
@@ -0,0 +1,154 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data.impl;
+
+import org.eclipse.statet.rj.data.RNumericStore;
+import org.eclipse.statet.rj.data.RObject;
+import org.eclipse.statet.rj.data.RStore;
+
+
+public abstract class AbstractNumericStore extends AbstractRStore<Double>
+		implements RNumericStore {
+	
+	
+	protected static final String toChar(final double num) {
+		if (num == Double.POSITIVE_INFINITY) {
+			return "Inf"; //$NON-NLS-1$
+		}
+		else if (num == Double.NEGATIVE_INFINITY) {
+			return "-Inf"; //$NON-NLS-1$
+		}
+		return Double.toString(num);
+	}
+	
+	
+	@Override
+	public final byte getStoreType() {
+		return RStore.NUMERIC;
+	}
+	
+	@Override
+	public final String getBaseVectorRClassName() {
+		return RObject.CLASSNAME_NUMERIC;
+	}
+	
+	
+	@Override
+	public boolean getLogi(final int idx) {
+		return getNum(idx) != 0.0;
+	}
+	
+	@Override
+	public final boolean getLogi(final long idx) {
+		return getNum(idx) != 0.0;
+	}
+	
+	@Override
+	public final void setLogi(final int idx, final boolean logi) {
+		setNum(idx, (logi) ? 1.0 : 0.0);
+	}
+	
+	@Override
+	public final void setLogi(final long idx, final boolean logi) {
+		setNum(idx, (logi) ? 1.0 : 0.0);
+	}
+	
+	@Override
+	public final int getInt(final int idx) {
+		return (int) getNum(idx);
+	}
+	
+	@Override
+	public final int getInt(final long idx) {
+		return (int) getNum(idx);
+	}
+	
+	@Override
+	public final void setInt(final int idx, final int integer) {
+		setNum(idx, integer);
+	}
+	
+	@Override
+	public final void setInt(final long idx, final int integer) {
+		setNum(idx, integer);
+	}
+	
+	@Override
+	public final double getCplxRe(final int idx) {
+		return getNum(idx);
+	}
+	
+	@Override
+	public final double getCplxRe(final long idx) {
+		return getNum(idx);
+	}
+	
+	@Override
+	public final double getCplxIm(final int idx) {
+		return 0.0;
+	}
+	
+	@Override
+	public final double getCplxIm(final long idx) {
+		return 0.0;
+	}
+	
+	@Override
+	public final String getChar(final int idx) {
+		return toChar(getNum(idx));
+	}
+	
+	@Override
+	public String getChar(final long idx) {
+		return toChar(getNum(idx));
+	}
+	
+	
+	@Override
+	public abstract Double[] toArray();
+	
+	
+	@Override
+	public boolean allEqual(final RStore<?> other) {
+		final long length= getLength();
+		if (NUMERIC != other.getStoreType() || length != other.getLength()) {
+			return false;
+		}
+		if (length < 0) {
+			return true;
+		}
+		else if (length <= Integer.MAX_VALUE) {
+			final int ilength= (int) length;
+			for (int idx= 0; idx < ilength; idx++) {
+				if (!(isMissing(idx) ?
+						(isNA(idx) ? other.isNA(idx) : other.isMissing(idx)) :
+						(Math.abs(getNum(idx) - other.getNum(idx)) < 2.220446e-16 )) ) {
+					return false;
+				}
+			}
+		}
+		else {
+			for (long idx= 0; idx < length; idx++) {
+				if (!(isMissing(idx) ?
+						(isNA(idx) ? other.isNA(idx) : other.isMissing(idx)) :
+						(Math.abs(getNum(idx) - other.getNum(idx)) < 2.220446e-16 )) ) {
+					return false;
+				}
+			}
+		}
+		return true;
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/AbstractRObject.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/AbstractRObject.java
new file mode 100644
index 0000000..3970287
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/AbstractRObject.java
@@ -0,0 +1,159 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data.impl;
+
+import java.io.IOException;
+
+import org.eclipse.statet.rj.data.RList;
+import org.eclipse.statet.rj.data.RObject;
+import org.eclipse.statet.rj.data.RStore;
+
+
+public abstract class AbstractRObject implements RObject {
+	
+	
+	protected static final RObject[] EMPTY_ROBJECT_ARRAY= new RObject[0];
+	protected static final RObject[][] EMPTY_ROBJECT_2dARRAY= new RObject[0][];
+	
+	
+	protected static final long check2dArrayLength(final RObject[][] array, final int segmentLength) {
+		long length= 0;
+		if (array.length > 0) {
+			final int last= array.length - 1;
+			for (int i= 0; i < last; i++) {
+				if (array[i].length != segmentLength) {
+					throw new IllegalArgumentException("Unexpected list segment length (" + array[i].length + ", but " + segmentLength + " expected)");
+				}
+			}
+			length= last * (long) segmentLength;
+			if (array[last].length > segmentLength) {
+				throw new IllegalArgumentException("Unexpected list segment length (" + array[last].length + ", but max " + segmentLength + " expected)");
+			}
+			length+= array[last].length;
+		}
+		return length;
+	}
+	
+	protected static final RObject[][] new2dRObjectArray(final long length, final int segmentLength) {
+		if (length == 0) {
+			return EMPTY_ROBJECT_2dARRAY;
+		}
+		final RObject[][] array= new RObject[1 + (int) ((length - 1) / segmentLength)][];
+		final int last= array.length - 1;
+		for (int i= 0; i < last; i++) {
+			array[i]= new RObject[segmentLength];
+		}
+		{	final int restLength= (int) (length % segmentLength);
+			array[last]= new RObject[(restLength == 0) ? segmentLength : restLength];
+		}
+		return array;
+	}
+	
+	
+	protected static final int checkShortLength(final long length) throws IOException {
+		if (length >= Integer.MAX_VALUE) {
+			throw new IOException("Long length (" + length + ") not supported by this implementation.");
+		}
+		return (int) length;
+	}
+	
+	
+	protected static final int getNewArraySize(final int length) {
+		if (length >= 0xfffffff) {
+			return Integer.MAX_VALUE;
+		}
+		return ((length+0x7) | 0xf) + 1;
+	}
+	
+	protected static final RObject[] ensureCapacity(final RObject[] currentValues, final int length) {
+		if (currentValues.length >= length) {
+			return currentValues;
+		}
+		return new RObject[getNewArraySize(length)];
+	}
+	
+	protected static final RStore<?>[] ensureCapacity(final RStore<?>[] currentValues, final int length) {
+		if (currentValues.length >= length) {
+			return currentValues;
+		}
+		return new RStore[getNewArraySize(length)];
+	}
+	
+	protected static final RObject[] prepareInsert(final RObject[] currentValues, final int currentLength, final int[] idxs) {
+		final RObject[] newValues= ensureCapacity(currentValues, currentLength+idxs.length);
+		int i= idxs.length-1;
+		System.arraycopy(currentValues, idxs[i], newValues, idxs[i]+i+1, currentLength-idxs[i]);
+		for (i--; i >= 0; i--) {
+			System.arraycopy(currentValues, idxs[i], newValues, idxs[i]+i+1, idxs[i+1]-idxs[i]);
+		}
+		if (currentValues != newValues) {
+			System.arraycopy(currentValues, 0, newValues, 0, idxs[0]);
+		}
+		return newValues;
+	}
+	
+	protected static final RStore<?>[] prepareInsert(final RStore<?>[] currentValues, final int currentLength, final int[] idxs) {
+		final RStore<?>[] newValues= ensureCapacity(currentValues, currentLength+idxs.length);
+		int i= idxs.length-1;
+		System.arraycopy(currentValues, idxs[i], newValues, idxs[i]+i+1, currentLength-idxs[i]);
+		for (i--; i >= 0; i--) {
+			System.arraycopy(currentValues, idxs[i], newValues, idxs[i]+i+1, idxs[i+1]-idxs[i]);
+		}
+		if (currentValues != newValues) {
+			System.arraycopy(currentValues, 0, newValues, 0, idxs[0]);
+		}
+		return newValues;
+	}
+	
+	protected static final RObject[] remove(final RObject[] currentValues, final int currentLength, final int[] idxs) {
+		final RObject[] newValues= ensureCapacity(currentValues, currentLength-idxs.length);
+		if (currentValues != newValues) {
+			System.arraycopy(currentValues, 0, newValues, 0, idxs[0]);
+		}
+		int i= 0;
+		for (; i < idxs.length-1; i++) {
+			System.arraycopy(currentValues, idxs[i]+1, newValues, idxs[i]-i, idxs[i+1]-idxs[i]);
+		}
+		System.arraycopy(currentValues, idxs[i]+1, newValues, idxs[i]-i, currentLength-idxs[i]-1);
+		return newValues;
+	}
+	
+	protected static final RStore<?>[] remove(final RStore<?>[] currentValues, final int currentLength, final int[] idxs) {
+		final RStore<?>[] newValues= ensureCapacity(currentValues, currentLength-idxs.length);
+		if (currentValues != newValues) {
+			System.arraycopy(currentValues, 0, newValues, 0, idxs[0]);
+		}
+		int i= 0;
+		for (; i < idxs.length-1; i++) {
+			System.arraycopy(currentValues, idxs[i]+1, newValues, idxs[i]-i, idxs[i+1]-idxs[i]);
+		}
+		System.arraycopy(currentValues, idxs[i]+1, newValues, idxs[i]-i, currentLength-idxs[i]-1);
+		return newValues;
+	}
+	
+	
+	private RList attributes;
+	
+	
+	protected void setAttributes(final RList attributes) {
+		this.attributes= attributes;
+	}
+	
+	@Override
+	public final RList getAttributes() {
+		return this.attributes;
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/AbstractRStore.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/AbstractRStore.java
new file mode 100644
index 0000000..fbec4af
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/AbstractRStore.java
@@ -0,0 +1,760 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data.impl;
+
+import java.util.Arrays;
+
+import org.eclipse.statet.rj.data.RDataUtils;
+import org.eclipse.statet.rj.data.RStore;
+
+
+public abstract class AbstractRStore<P> implements RStore<P> {
+	
+	
+	protected static final long NA_numeric_LONG= 0x7ff80000000007a2L;
+	protected static final long NA_numeric_LONG_MASK= 0x7ff00000ffffffffL;
+	protected static final long NA_numeric_LONG_MATCH= 0x7ff00000000007a2L;
+	protected static final int NA_numeric_INT_MATCH= 0x000007a2;
+	protected static final double NA_numeric_DOUBLE= Double.longBitsToDouble(NA_numeric_LONG);
+	protected static final long NaN_numeric_LONG= Double.doubleToLongBits(Double.NaN);
+	protected static final double NaN_numeric_DOUBLE= Double.NaN;
+	
+	protected static final int NA_integer_INT= Integer.MIN_VALUE;
+	
+	protected static final byte NA_byte_BYTE= 0x0; // no real NA, used e.g. for new values
+	
+	protected static final byte FALSE_BYTE= 0;
+	protected static final byte TRUE_BYTE= 1;
+	protected static final byte NA_logical_BYTE= 2;
+	
+	protected static final int FALSE_INT= 0;
+	protected static final int TRUE_INT= 1;
+	protected static final int NA_logical_INT= Integer.MIN_VALUE;
+	
+	protected static final int WITH_NAMES= 0x1;
+	
+	protected static final byte[] EMPTY_BYTE_ARRAY= new byte[0];
+	protected static final byte[][] EMPTY_BYTE_2dARRAY= new byte[0][];
+	protected static final int[] EMPTY_INT_ARRAY= new int[0];
+	protected static final int[][] EMPTY_INT_2dARRAY= new int[0][];
+	protected static final double[] EMPTY_DOUBLE_ARRAY= new double[0];
+	protected static final double[][] EMPTY_DOUBLE_2dARRAY= new double[0][];
+	protected static final String[] EMPTY_STRING_ARRAY= new String[0];
+	protected static final String[][] EMPTY_STRING_2dARRAY= new String[0][];
+	
+	protected static final int DEFAULT_LONG_DATA_SEGMENT_LENGTH= 1 << 28;
+	
+	
+	private final static boolean gIsBSupported;
+	static {
+		gIsBSupported= checkIsBSupported();
+	}
+	
+	public static boolean isBforNASupported() {
+		return gIsBSupported;
+	}
+	
+	private static boolean checkIsBSupported() {
+		double d= 0;
+		long l= 0;
+		
+		d= NA_numeric_DOUBLE;
+		l= Double.doubleToRawLongBits(d);
+		if (l != NA_numeric_LONG) {
+			return false;
+		}
+		
+		d= Double.longBitsToDouble(l);
+		l= Double.doubleToRawLongBits(d);
+		if (l != NA_numeric_LONG) {
+			return false;
+		}
+		return true;
+	}
+	
+	
+	protected static final long check2dArrayLength(final int[][] array, final int segmentLength) {
+		long length= 0;
+		if (array.length > 0) {
+			final int last= array.length - 1;
+			for (int i= 0; i < last; i++) {
+				if (array[i].length != segmentLength) {
+					throw new IllegalArgumentException("Unexpected data segment length (" + array[i].length + ", but " + segmentLength + " expected)");
+				}
+			}
+			length= last * (long) segmentLength;
+			if (array[last].length > segmentLength) {
+				throw new IllegalArgumentException("Unexpected data segment length (" + array[last].length + ", but max " + segmentLength + " expected)");
+			}
+			length+= array[last].length;
+		}
+		return length;
+	}
+	
+	protected static final long check2dArrayLength(final double[][] array, final int segmentLength) {
+		long length= 0;
+		if (array.length > 0) {
+			final int last= array.length - 1;
+			for (int i= 0; i < last; i++) {
+				if (array[i].length != segmentLength) {
+					throw new IllegalArgumentException("Unexpected data segment length (" + array[i].length + ", but " + segmentLength + " expected)");
+				}
+			}
+			length= last * (long) segmentLength;
+			if (array[last].length > segmentLength) {
+				throw new IllegalArgumentException("Unexpected data segment length (" + array[last].length + ", but max " + segmentLength + " expected)");
+			}
+			length+= array[last].length;
+		}
+		return length;
+	}
+	
+	protected static final long check2dArrayLength(final byte[][] array, final int segmentLength) {
+		long length= 0;
+		if (array.length > 0) {
+			final int last= array.length - 1;
+			for (int i= 0; i < last; i++) {
+				if (array[i].length != segmentLength) {
+					throw new IllegalArgumentException("Unexpected data segment length (" + array[i].length + ", but " + segmentLength + " expected)");
+				}
+			}
+			length= last * (long) segmentLength;
+			if (array[last].length > segmentLength) {
+				throw new IllegalArgumentException("Unexpected data segment length (" + array[last].length + ", but max " + segmentLength + " expected)");
+			}
+			length+= array[last].length;
+		}
+		return length;
+	}
+	
+	protected static final long check2dArrayLength(final Object[][] array, final int segmentLength) {
+		long length= 0;
+		if (array.length > 0) {
+			final int last= array.length - 1;
+			for (int i= 0; i < last; i++) {
+				if (array[i].length != segmentLength) {
+					throw new IllegalArgumentException("Unexpected data segment length (" + array[i].length + ", but " + segmentLength + " expected)");
+				}
+			}
+			length= last * (long) segmentLength;
+			if (array[last].length > segmentLength) {
+				throw new IllegalArgumentException("Unexpected data segment length (" + array[last].length + ", but max " + segmentLength + " expected)");
+			}
+			length+= array[last].length;
+		}
+		return length;
+	}
+	
+	protected static final int[][] new2dIntArray(final long length, final int segmentLength) {
+		if (length == 0) {
+			return EMPTY_INT_2dARRAY;
+		}
+		final int[][] array= new int[1 + (int) ((length - 1) / segmentLength)][];
+		final int last= array.length - 1;
+		for (int i= 0; i < last; i++) {
+			array[i]= new int[segmentLength];
+		}
+		{	final int restLength= (int) (length % segmentLength);
+		array[last]= new int[(restLength == 0) ? segmentLength : restLength];
+		}
+		return array;
+	}
+	
+	protected static final double[][] new2dDoubleArray(final long length, final int segmentLength) {
+		if (length == 0) {
+			return EMPTY_DOUBLE_2dARRAY;
+		}
+		final double[][] array= new double[1 + (int) ((length - 1) / segmentLength)][];
+		final int last= array.length - 1;
+		for (int i= 0; i < last; i++) {
+			array[i]= new double[segmentLength];
+		}
+		{	final int restLength= (int) (length % segmentLength);
+			array[last]= new double[(restLength == 0) ? segmentLength : restLength];
+		}
+		return array;
+	}
+	
+	protected static final String[][] new2dStringArray(final long length, final int segmentLength) {
+		if (length == 0) {
+			return EMPTY_STRING_2dARRAY;
+		}
+		final String[][] array= new String[1 + (int) ((length - 1) / segmentLength)][];
+		final int last= array.length - 1;
+		for (int i= 0; i < last; i++) {
+			array[i]= new String[segmentLength];
+		}
+		{	final int restLength= (int) (length % segmentLength);
+			array[last]= new String[(restLength == 0) ? segmentLength : restLength];
+		}
+		return array;
+	}
+	
+	protected static final byte[][] new2dByteArray(final long length, final int segmentLength) {
+		if (length == 0) {
+			return EMPTY_BYTE_2dARRAY;
+		}
+		final byte[][] array= new byte[1 + (int) ((length - 1) / segmentLength)][];
+		final int last= array.length - 1;
+		for (int i= 0; i < last; i++) {
+			array[i]= new byte[segmentLength];
+		}
+		{	final int restLength= (int) (length % segmentLength);
+		array[last]= new byte[(restLength == 0) ? segmentLength : restLength];
+		}
+		return array;
+	}
+	
+	
+	protected static final int[] addIdx(final int[] idxs, final int newIdx) {
+		int i= Arrays.binarySearch(idxs, newIdx);
+		if (i >= 0) {
+			return idxs;
+		}
+		final int[] newIdxs= new int[idxs.length+1];
+		i= -1-i;
+		System.arraycopy(idxs, 0, newIdxs, 0, i);
+		newIdxs[i]= newIdx;
+		System.arraycopy(idxs, i, newIdxs, i+1, idxs.length-i);
+		return newIdxs;
+	}
+	
+	protected static final int[] insertIdx(final int[] currentIdxs, final int[] insertedIdxs) {
+		final int[] pos= new int[insertedIdxs.length];
+		for (int i= 0; i < pos.length; i++) {
+			pos[i]= Arrays.binarySearch(currentIdxs, insertedIdxs[i]);
+			if (pos[i] < 0) {
+				pos[i]= -1-pos[i];
+			}
+		}
+		final int[] newIdxs= new int[currentIdxs.length+insertedIdxs.length];
+		int l= pos.length;
+		int ci= currentIdxs.length-1;
+		while(l > 1) {
+			final int stop= pos[l-1];
+			for (; ci >= stop; ci--) {
+				newIdxs[ci+l]= currentIdxs[ci] + l;
+			}
+			l--;
+			newIdxs[ci+l]= insertedIdxs[l] + l;
+		}
+		System.arraycopy(currentIdxs, 0, newIdxs, 0, pos[0]);
+		return newIdxs;
+	}
+	
+	protected static final void updateIdxInserted(final int[] currentIdxs, final int[] insertedIdxs) {
+		int pos= Arrays.binarySearch(currentIdxs, insertedIdxs[0]);
+		if (pos < 0) {
+			pos= -1-pos;
+		}
+		for (int i= 0; i < insertedIdxs.length; ) {
+			i++;
+			int stop= (i < insertedIdxs.length) ? Arrays.binarySearch(currentIdxs, insertedIdxs[i]) : currentIdxs.length;
+			if (stop < 0) {
+				stop= -1-stop;
+			}
+			while (pos < stop) {
+				currentIdxs[pos]+= i;
+			}
+			pos= stop;
+		}
+	}
+	
+	protected static final int[] updateIdxRemoved(final int[] currentIdxs, final int[] removedIdxs) {
+		final int[] pos= new int[removedIdxs.length];
+		int naCount= 0;
+		for (int i= 0; i < pos.length; i++) {
+			pos[i]= Arrays.binarySearch(currentIdxs, removedIdxs[i]);
+			if (pos[i] < 0) {
+				pos[i]= -1-pos[i];
+			}
+			else {
+				naCount++;
+			}
+		}
+		final int[] newIdxs= (naCount == 0) ? currentIdxs : new int[currentIdxs.length-naCount];
+		int l= 0;
+		int ci= 0;
+		int ni= 0;
+		if (newIdxs != currentIdxs) {
+			System.arraycopy(currentIdxs, 0, newIdxs, 0, pos[0]);
+		}
+		while(l < removedIdxs.length) {
+			if (currentIdxs[pos[l]] == removedIdxs[l]) {
+				ci++;
+			}
+			l++;
+			final int stop= (l < removedIdxs.length) ? pos[l] : currentIdxs.length;
+			for (; ci < stop; ci++, ni++) {
+				newIdxs[ni]= currentIdxs[ci] - l;
+			}
+		}
+		return newIdxs;
+	}
+	
+	protected static final int[] deleteIdx(final int[] idxs, final int removeIdx) {
+		final int i= Arrays.binarySearch(idxs, removeIdx);
+		if (i < 0) {
+			return idxs;
+		}
+		final int[] newIdxs= new int[idxs.length-1];
+		System.arraycopy(idxs, 0, newIdxs, 0, i);
+		System.arraycopy(idxs, i+1, newIdxs, i, idxs.length-i-1);
+		return newIdxs;
+	}
+	
+	protected static final int getNewArraySize(final int length) {
+		if (length >= 0xfffffff) {
+			return Integer.MAX_VALUE;
+		}
+		return ((length+0x7) | 0xf) + 1;
+	}
+	
+	protected static final double[] ensureCapacity(final double[] currentValues, final int length) {
+		if (currentValues.length >= length) {
+			return currentValues;
+		}
+		return new double[getNewArraySize(length)];
+	}
+	
+	protected static final int[] ensureCapacity(final int[] currentValues, final int length) {
+		final int diff= currentValues.length - length;
+		if (diff >= 0 && diff <= 512) {
+			return currentValues;
+		}
+		return new int[getNewArraySize(length)];
+	}
+	
+	protected static final byte[] ensureCapacity(final byte[] currentValues, final int length) {
+		if (currentValues.length >= length) {
+			return currentValues;
+		}
+		return new byte[getNewArraySize(length)];
+	}
+	
+	protected static final String[] ensureCapacity(final String[] currentValues, final int length) {
+		if (currentValues.length >= length) {
+			return currentValues;
+		}
+		return new String[getNewArraySize(length)];
+	}
+	
+	protected static final double[] prepareInsert(final double[] currentValues, final int currentLength, final int[] idxs) {
+		final double[] newValues= ensureCapacity(currentValues, currentLength+idxs.length);
+		int i= idxs.length-1;
+		System.arraycopy(currentValues, idxs[i], newValues, idxs[i]+i+1, currentLength-idxs[i]);
+		for (i--; i >= 0; i--) {
+			System.arraycopy(currentValues, idxs[i], newValues, idxs[i]+i+1, idxs[i+1]-idxs[i]);
+		}
+		if (newValues != currentValues) {
+			System.arraycopy(currentValues, 0, newValues, 0, idxs[0]);
+		}
+		return newValues;
+	}
+	
+	protected static final int[] prepareInsert(final int[] currentValues, final int currentLength, final int[] idxs) {
+		final int[] newValues= ensureCapacity(currentValues, currentLength+idxs.length);
+		int i= idxs.length-1;
+		System.arraycopy(currentValues, idxs[i], newValues, idxs[i]+i+1, currentLength-idxs[i]);
+		for (i--; i >= 0; i--) {
+			System.arraycopy(currentValues, idxs[i], newValues, idxs[i]+i+1, idxs[i+1]-idxs[i]);
+		}
+		if (newValues != currentValues) {
+			System.arraycopy(currentValues, 0, newValues, 0, idxs[0]);
+		}
+		return newValues;
+	}
+	
+	protected static final byte[] prepareInsert(final byte[] currentValues, final int currentLength, final int[] idxs) {
+		final byte[] newValues= ensureCapacity(currentValues, currentLength+idxs.length);
+		int i= idxs.length-1;
+		System.arraycopy(currentValues, idxs[i], newValues, idxs[i]+i+1, currentLength-idxs[i]);
+		for (i--; i >= 0; i--) {
+			System.arraycopy(currentValues, idxs[i], newValues, idxs[i]+i+1, idxs[i+1]-idxs[i]);
+		}
+		if (currentValues != newValues) {
+			System.arraycopy(currentValues, 0, newValues, 0, idxs[0]);
+		}
+		return newValues;
+	}
+	
+	protected static final String[] prepareInsert(final String[] currentValues, final int currentLength, final int[] idxs) {
+		final String[] newValues= ensureCapacity(currentValues, currentLength+idxs.length);
+		int i= idxs.length-1;
+		System.arraycopy(currentValues, idxs[i], newValues, idxs[i]+i+1, currentLength-idxs[i]);
+		for (i--; i >= 0; i--) {
+			System.arraycopy(currentValues, idxs[i], newValues, idxs[i]+i+1, idxs[i+1]-idxs[i]);
+		}
+		if (currentValues != newValues) {
+			System.arraycopy(currentValues, 0, newValues, 0, idxs[0]);
+		}
+		return newValues;
+	}
+	
+	protected static final double[] remove(final double[] currentValues, final int currentLength, final int[] idxs) {
+		final double[] newValues= ensureCapacity(currentValues, currentLength-idxs.length);
+		if (currentValues != newValues) {
+			System.arraycopy(currentValues, 0, newValues, 0, idxs[0]);
+		}
+		int i= 0;
+		for (; i < idxs.length-1; i++) {
+			System.arraycopy(currentValues, idxs[i]+1, newValues, idxs[i]-i, idxs[i+1]-idxs[i]);
+		}
+		System.arraycopy(currentValues, idxs[i]+1, newValues, idxs[i]-i, currentLength-idxs[i]-1);
+		return newValues;
+	}
+	
+	protected static final int[] remove(final int[] currentValues, final int currentLength, final int[] idxs) {
+		final int[] newValues= ensureCapacity(currentValues, currentLength-idxs.length);
+		if (currentValues != newValues) {
+			System.arraycopy(currentValues, 0, newValues, 0, idxs[0]);
+		}
+		int i= 0;
+		for (; i < idxs.length-1; i++) {
+			System.arraycopy(currentValues, idxs[i]+1, newValues, idxs[i]-i, idxs[i+1]-idxs[i]);
+		}
+		System.arraycopy(currentValues, idxs[i]+1, newValues, idxs[i]-i, currentLength-idxs[i]-1);
+		return newValues;
+	}
+	
+	protected static final byte[] remove(final byte[] currentValues, final int currentLength, final int[] idxs) {
+		final byte[] newValues= ensureCapacity(currentValues, currentLength-idxs.length);
+		if (currentValues != newValues) {
+			System.arraycopy(currentValues, 0, newValues, 0, idxs[0]);
+		}
+		int i= 0;
+		for (; i < idxs.length-1; i++) {
+			System.arraycopy(currentValues, idxs[i]+1, newValues, idxs[i]-i, idxs[i+1]-idxs[i]);
+		}
+		System.arraycopy(currentValues, idxs[i]+1, newValues, idxs[i]-i, currentLength-idxs[i]-1);
+		return newValues;
+	}
+	
+	protected static final String[] remove(final String[] currentValues, final int currentLength, final int[] idxs) {
+		final String[] newValues= ensureCapacity(currentValues, currentLength-idxs.length);
+		if (currentValues != newValues) {
+			System.arraycopy(currentValues, 0, newValues, 0, idxs[0]);
+		}
+		int i= 0;
+		for (; i < idxs.length-1; i++) {
+			System.arraycopy(currentValues, idxs[i]+1, newValues, idxs[i]-i, idxs[i+1]-idxs[i]);
+		}
+		System.arraycopy(currentValues, idxs[i]+1, newValues, idxs[i]-i, currentLength-idxs[i]-1);
+		return newValues;
+	}
+	
+	
+	@Override
+	public void setNA(final int idx) {
+		throw new UnsupportedOperationException();
+	}
+	
+	@Override
+	public void setNA(final long idx) {
+		throw new UnsupportedOperationException();
+	}
+	
+	@Override
+	public boolean getLogi(final int idx) {
+		throw new UnsupportedOperationException();
+	}
+	
+	@Override
+	public boolean getLogi(final long idx) {
+		throw new UnsupportedOperationException();
+	}
+	
+	@Override
+	public void setLogi(final int idx, final boolean logi) {
+		throw new UnsupportedOperationException();
+	}
+	
+	@Override
+	public void setLogi(final long idx, final boolean logi) {
+		throw new UnsupportedOperationException();
+	}
+	
+	@Override
+	public int getInt(final int idx) {
+		throw new UnsupportedOperationException();
+	}
+	
+	@Override
+	public int getInt(final long idx) {
+		throw new UnsupportedOperationException();
+	}
+	
+	@Override
+	public void setInt(final int idx, final int integer) {
+		throw new UnsupportedOperationException();
+	}
+	
+	@Override
+	public void setInt(final long idx, final int integer) {
+		throw new UnsupportedOperationException();
+	}
+	
+	@Override
+	public double getNum(final int idx) {
+		throw new UnsupportedOperationException();
+	}
+	
+	@Override
+	public double getNum(final long idx) {
+		throw new UnsupportedOperationException();
+	}
+	
+	@Override
+	public void setNum(final int idx, final double real) {
+		throw new UnsupportedOperationException();
+	}
+	
+	@Override
+	public void setNum(final long idx, final double real) {
+		throw new UnsupportedOperationException();
+	}
+	
+	@Override
+	public String getChar(final int idx) {
+		throw new UnsupportedOperationException();
+	}
+	
+	@Override
+	public String getChar(final long idx) {
+		throw new UnsupportedOperationException();
+	}
+	
+	@Override
+	public void setChar(final int idx, final String character) {
+		throw new UnsupportedOperationException();
+	}
+	
+	@Override
+	public void setChar(final long idx, final String character) {
+		throw new UnsupportedOperationException();
+	}
+	
+	@Override
+	public byte getRaw(final int idx) {
+		throw new UnsupportedOperationException();
+	}
+	
+	@Override
+	public byte getRaw(final long idx) {
+		throw new UnsupportedOperationException();
+	}
+	
+	@Override
+	public void setRaw(final int idx, final byte raw) {
+		throw new UnsupportedOperationException();
+	}
+	
+	@Override
+	public void setRaw(final long idx, final byte raw) {
+		throw new UnsupportedOperationException();
+	}
+	
+	@Override
+	public double getCplxIm(final int idx) {
+		throw new UnsupportedOperationException();
+	}
+	
+	@Override
+	public double getCplxIm(final long idx) {
+		throw new UnsupportedOperationException();
+	}
+	
+	@Override
+	public double getCplxRe(final int idx) {
+		throw new UnsupportedOperationException();
+	}
+	
+	@Override
+	public double getCplxRe(final long idx) {
+		throw new UnsupportedOperationException();
+	}
+	
+	@Override
+	public void setCplx(final int idx, final double real, final double imaginary) {
+		throw new UnsupportedOperationException();
+	}
+	
+	@Override
+	public void setCplx(final long idx, final double real, final double imaginary) {
+		throw new UnsupportedOperationException();
+	}
+	
+	
+	protected abstract boolean isStructOnly();
+	
+	
+	@Override
+	public boolean containsNA() {
+		return (indexOfNA(0) >= 0);
+	}
+	
+	@Override
+	public long indexOfNA() {
+		return indexOfNA(0);
+	}
+	
+	@Override
+	public long indexOfNA(long fromIdx) {
+		if (fromIdx < 0) {
+			fromIdx= 0;
+		}
+		final long length= getLength();
+		while (fromIdx < length) {
+			if (isNA(fromIdx)) {
+				return fromIdx;
+			}
+			fromIdx++;
+		}
+		return -1;
+	}
+	
+	@Override
+	public boolean contains(final int integer) {
+		return (indexOf(integer, 0) >= 0);
+	}
+	
+	@Override
+	public final long indexOf(final int integer) {
+		return indexOf(integer, 0);
+	}
+	
+	@Override
+	public long indexOf(final int integer, long fromIdx) {
+		if (fromIdx < 0) {
+			fromIdx= 0;
+		}
+		final long l= getLength();
+		while (fromIdx < l) {
+			if (!isNA(fromIdx) && integer == getInt(fromIdx)) {
+				return fromIdx;
+			}
+			fromIdx++;
+		}
+		return -1;
+	}
+	
+	@Override
+	public boolean contains(final String character) {
+		return (indexOf(character, 0) >= 0);
+	}
+	
+	@Override
+	public final long indexOf(final String character) {
+		return indexOf(character, 0);
+	}
+	
+	@Override
+	public long indexOf(final String character, long fromIdx) {
+		if (character == null) {
+			return -1;
+		}
+		if (fromIdx < 0) {
+			fromIdx= 0;
+		}
+		final long l= getLength();
+		while (fromIdx < l) {
+			if (!isNA(fromIdx) && character.equals(getChar(fromIdx))) {
+				return fromIdx;
+			}
+			fromIdx++;
+		}
+		return -1;
+	}
+	
+	
+	protected int checkToArrayLength() {
+		final long length= getLength();
+		if (length > Integer.MAX_VALUE) {
+			throw new UnsupportedOperationException("Not supported for long data");
+		}
+		return (int) length;
+	}
+	
+	
+	@Override
+	public String toString() {
+		final StringBuilder sb= new StringBuilder();
+		sb.append(RDataUtils.getStoreAbbr(this));
+		sb.append(' ');
+		final long length;
+		if (isStructOnly()) {
+			sb.append("<struct only>");
+		}
+		else if ((length= getLength()) > 0) {
+			long end= (length <= 25) ? length : 10;
+			if (getStoreType() == CHARACTER) {
+				for (long idx= 0; true;) {
+					if (isNA(idx)) {
+						sb.append("NA");
+					}
+					else {
+						sb.append('"');
+						sb.append(getChar(idx));
+						sb.append('"');
+					}
+					idx++;
+					if (idx < end) {
+						sb.append(", ");
+						continue;
+					}
+					else {
+						if (end == length) {
+							break;
+						}
+						else {
+							sb.append(", .., ");
+							idx= length - 10;
+							end= length;
+							continue;
+						}
+					}
+				}
+			}
+			else {
+				for (long idx= 0; true;) {
+					if (isNA(idx)) {
+						sb.append("NA");
+					}
+					else {
+						sb.append(getChar(idx));
+					}
+					idx++;
+					if (idx < end) {
+						sb.append(", ");
+						continue;
+					}
+					else {
+						if (end == length) {
+							break;
+						}
+						else {
+							sb.append(", .., ");
+							idx= length - 10;
+							end= length;
+							continue;
+						}
+					}
+				}
+			}
+		}
+		return sb.toString();
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/AbstractRawStore.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/AbstractRawStore.java
new file mode 100644
index 0000000..0a8bb44
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/AbstractRawStore.java
@@ -0,0 +1,102 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data.impl;
+
+import org.eclipse.statet.rj.data.RObject;
+import org.eclipse.statet.rj.data.RRawStore;
+import org.eclipse.statet.rj.data.RStore;
+
+
+public abstract class AbstractRawStore extends AbstractRStore<Byte>
+		implements RRawStore {
+	
+	
+	private static final char[] HEX_CHARS= new char[] {
+			'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
+	};
+	
+	protected static final String toChar(final byte raw) {
+		return new String(new char[] { HEX_CHARS[(raw >>> 4) & 0x0F], HEX_CHARS[(raw & 0x0F)] });
+	}
+	
+	
+	@Override
+	public final byte getStoreType() {
+		return RStore.RAW;
+	}
+	
+	@Override
+	public final String getBaseVectorRClassName() {
+		return RObject.CLASSNAME_RAW;
+	}
+	
+	
+	@Override
+	public final boolean isNA(final int idx) {
+		return false;
+	}
+	
+	@Override
+	public final boolean isNA(final long idx) {
+		return false;
+	}
+	
+	@Override
+	public final boolean isMissing(final int idx) {
+		return false;
+	}
+	
+	@Override
+	public final boolean isMissing(final long idx) {
+		return false;
+	}
+	
+	@Override
+	public int getInt(final int idx) {
+		return (getRaw(idx) & 0xff);
+	}
+	
+	@Override
+	public int getInt(final long idx) {
+		return (getRaw(idx) & 0xff);
+	}
+	
+	@Override
+	public void setInt(final long idx, final int integer) {
+		setRaw(idx, AbstractIntegerStore.toRaw(integer));
+	}
+	
+	@Override
+	public void setInt(final int idx, final int integer) {
+		setRaw(idx, AbstractIntegerStore.toRaw(integer));
+	}
+	
+	@Override
+	public final String getChar(final int idx) {
+		return toChar(getRaw(idx));
+	}
+	
+	@Override
+	public final String getChar(final long idx) {
+		return toChar(getRaw(idx));
+	}
+	
+	
+	@Override
+	public long indexOfNA(final long fromIdx) {
+		return -1;
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/DefaultRObjectFactory.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/DefaultRObjectFactory.java
new file mode 100644
index 0000000..b14c3b8
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/DefaultRObjectFactory.java
@@ -0,0 +1,731 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data.impl;
+
+import java.io.IOException;
+import java.io.ObjectInput;
+
+import org.eclipse.statet.rj.data.RArray;
+import org.eclipse.statet.rj.data.RCharacterStore;
+import org.eclipse.statet.rj.data.RComplexStore;
+import org.eclipse.statet.rj.data.RDataFrame;
+import org.eclipse.statet.rj.data.RDataUtils;
+import org.eclipse.statet.rj.data.RFactorStore;
+import org.eclipse.statet.rj.data.RIntegerStore;
+import org.eclipse.statet.rj.data.RJIO;
+import org.eclipse.statet.rj.data.RLanguage;
+import org.eclipse.statet.rj.data.RList;
+import org.eclipse.statet.rj.data.RLogicalStore;
+import org.eclipse.statet.rj.data.RNumericStore;
+import org.eclipse.statet.rj.data.RObject;
+import org.eclipse.statet.rj.data.RObjectFactory;
+import org.eclipse.statet.rj.data.RRawStore;
+import org.eclipse.statet.rj.data.RStore;
+import org.eclipse.statet.rj.data.RVector;
+
+
+public class DefaultRObjectFactory implements RObjectFactory {
+	
+	
+	public static final DefaultRObjectFactory INSTANCE= new DefaultRObjectFactory();
+	
+	public static final RNumericStore NUM_STRUCT_DUMMY= new RNumericStructStore();
+	public static final RComplexStructStore CPLX_STRUCT_DUMMY= new RComplexStructStore();
+	public static final RIntegerStructStore INT_STRUCT_DUMMY= new RIntegerStructStore();
+	public static final RLogicalStructStore LOGI_STRUCT_DUMMY= new RLogicalStructStore();
+	public static final RRawStructStore RAW_STRUCT_DUMMY= new RRawStructStore();
+	public static final RCharacterStructStore CHR_STRUCT_DUMMY= new RCharacterStructStore();
+	
+	
+	private final long storeLengthFixLong= AbstractRStore.DEFAULT_LONG_DATA_SEGMENT_LENGTH;
+	
+	
+	public DefaultRObjectFactory() {
+	}
+	
+	
+	/*-- Vector --*/
+	
+	/**
+	 * Creates an R vector with the given R data store and R class name.
+	 * 
+	 * @param data the data store
+	 * @param classname the R class name
+	 * @return the R vector
+	 */
+	public <TData extends RStore<?>> RVector<TData> createVector(final TData data, final String classname) {
+		return new RVectorImpl<>(data, classname);
+	}
+	
+	/**
+	 * Creates an R vector with the given R data store.
+	 * <p>
+	 * The vector has the default R class name for data type of the given store.</p>
+	 * 
+	 * @param data the data store
+	 * @return the R vector
+	 */
+	@Override
+	public <TData extends RStore<?>> RVector<TData> createVector(final TData data) {
+		return createVector(data, data.getBaseVectorRClassName());
+	}
+	
+	
+	/**
+	 * Creates an R logical vector with values from a Java boolean array.
+	 * <p>
+	 * The vector has the default R class name 'logical'.</p>
+	 * <p>
+	 * Note that the R vector may use the array directly. For values
+	 * see {@link RStore#setLogi(int, boolean)}.</p>
+	 * 
+	 * @param logicals the logical values
+	 * @return the R logical vector
+	 */
+	public RVector<RLogicalStore> createLogiVector(final boolean[] logicals) {
+		return createVector(createLogiData(logicals), RObject.CLASSNAME_LOGICAL);
+	}
+	
+	/**
+	 * Creates an R logical vector of the given length.
+	 * <p>
+	 * The vector has the default R class name 'logical'.</p>
+	 * <p>
+	 * The function works analog to the R function <code>logical(length)</code>;
+	 * the vector is initialized with FALSE values.</p>
+	 * 
+	 * @param length the length of the vector
+	 * @return the R logical vector
+	 */
+	public RVector<RLogicalStore> createLogiVector(final int length) {
+		return createVector(createLogiData(length), RObject.CLASSNAME_LOGICAL);
+	}
+	
+	/**
+	 * Creates an R integer vector with values from a Java integer array.
+	 * <p>
+	 * The vector has the default R class name 'integer'.</p>
+	 * <p>
+	 * Note that the R vector may use the array directly. For values
+	 * see {@link RStore#setInt(int, int)}.</p>
+	 * 
+	 * @param integers the integer values
+	 * @return the R integer vector
+	 */
+	public RVector<RIntegerStore> createIntVector(final int[] integers) {
+		return createVector(createIntData(integers), RObject.CLASSNAME_INTEGER);
+	}
+	
+	/**
+	 * Creates an R integer vector of the given length.
+	 * <p>
+	 * The vector has the default R class name 'integer'.</p>
+	 * <p>
+	 * The function works analog to the R function <code>integer(length)</code>;
+	 * the vector is initialized with 0 values.</p>
+	 * 
+	 * @param length the length of the vector
+	 * @return the R integer vector
+	 */
+	public RVector<RIntegerStore> createIntVector(final int length) {
+		return createVector(createIntData(length), RObject.CLASSNAME_INTEGER);
+	}
+	
+	/**
+	 * Creates an R numeric vector with values from a Java double array.
+	 * <p>
+	 * The vector has the default R class name 'numeric'.</p>
+	 * <p>
+	 * Note that the R vector may use the array directly. For values
+	 * see {@link RStore#setNum(int, double)}.</p>
+	 * 
+	 * @param numerics the numerics values
+	 * @return the R numeric vector
+	 */
+	public RVector<RNumericStore> createNumVector(final double[] numerics) {
+		return createVector(createNumData(numerics), RObject.CLASSNAME_NUMERIC);
+	}
+	
+	/**
+	 * Creates an R numeric vector of the given length.
+	 * <p>
+	 * The vector has the default R class name 'numeric'.</p>
+	 * <p>
+	 * The function works analog to the R function <code>numeric(length)</code>;
+	 * the vector is initialized with 0.0 values.</p>
+	 * 
+	 * @param length the length of the vector
+	 * @return the R numeric vector
+	 */
+	public RVector<RNumericStore> createNumVector(final int length) {
+		return createVector(createNumData(length), RObject.CLASSNAME_NUMERIC);
+	}
+	
+	/**
+	 * Creates an R complex vector of the given length.
+	 * <p>
+	 * The vector has the default R class name 'complex'.</p>
+	 * <p>
+	 * The function works analog to the R function <code>complex(length)</code>;
+	 * the vector is initialized with 0.0 values.</p>
+	 * 
+	 * @param length the length of the vector
+	 * @return the R complex vector
+	 */
+	public RVector<RComplexStore> createCplxVector(final int length) {
+		return createVector(createCplxData(length), RObject.CLASSNAME_COMPLEX);
+	}
+	
+	/**
+	 * Creates an R character vector with values from a Java String array.
+	 * <p>
+	 * The vector has the default R class name 'character'.</p>
+	 * <p>
+	 * Note that the R vector may use the array directly. For values
+	 * see {@link RStore#setChar(int, String)}.</p>
+	 * 
+	 * @param characters the characters values
+	 * @return the R character vector
+	 */
+	public RVector<RCharacterStore> createCharVector(final String[] characters) {
+		return createVector(createCharData(characters), RObject.CLASSNAME_CHARACTER);
+	}
+	
+	/**
+	 * Creates an R character vector of the given length.
+	 * <p>
+	 * The vector has the default R class name 'character'.</p>
+	 * <p>
+	 * The function works analog to the R function <code>character(length)</code>;
+	 * the vector is initialized with "" (empty String) values.</p>
+	 * 
+	 * @param length the length of the vector
+	 * @return the R charcter vector
+	 */
+	public RVector<RCharacterStore> createCharVector(final int length) {
+		return createVector(createCharData(length), RObject.CLASSNAME_CHARACTER);
+	}
+	
+	/**
+	 * Creates an R raw vector of the specified length.
+	 * <p>
+	 * The vector has the default R class name 'raw'.</p>
+	 * <p>
+	 * The function works analog to the R function <code>raw(length)</code>;
+	 * the vector is initialized with 0.0 values.</p>
+	 * 
+	 * @param length the length of the vector
+	 * @return the R complex vector
+	 */
+	public RVector<RRawStore> createRawVector(final int length) {
+		return createVector(createRawData(length), RObject.CLASSNAME_RAW);
+	}
+	
+	/**
+	 * Creates an R (unordered) factor vector with level codes from a Java integer array.
+	 * <p>
+	 * The vector has the default R class name 'factor'.</p>
+	 * <p>
+	 * Note that the R vector may use the array directly.</p>
+	 * 
+	 * @param codes the coded levels
+	 * @param levels the labels of the levels
+	 * @return the R factor vector
+	 */
+	public RVector<RFactorStore> createFactorVector(final int[] codes, final String[] levels) {
+		return createVector(createFactorData(codes, levels), RObject.CLASSNAME_FACTOR);
+	}
+	
+	/**
+	 * Creates an R (unordered) factor vector of the specified length.
+	 * <p>
+	 * The vector has the default R class name 'factor'.</p>
+	 * 
+	 * @param length the length of the vector
+	 * @param levels the labels of the levels
+	 * @return the R factor vector
+	 */
+	public RVector<RFactorStore> createFactorVector(final int length, final String[] levels) {
+		return createVector(createFactorData(length, levels), RObject.CLASSNAME_FACTOR);
+	}
+	
+	/**
+	 * Creates an R ordered factor vector with level codes from a Java integer array.
+	 * <p>
+	 * The vector has the default R class name 'ordered'.</p>
+	 * <p>
+	 * Note that the R vector may use the array directly.</p>
+	 * 
+	 * @param codes the coded levels
+	 * @param levels the labels of the levels
+	 * @return the R factor vector
+	 */
+	public RVector<RFactorStore> createOrderedVector(final int[] codes, final String[] levels) {
+		return createVector(createOrderedData(codes, levels), RObject.CLASSNAME_ORDERED);
+	}
+	
+	/**
+	 * Creates an R ordered factor vector of the specified length.
+	 * <p>
+	 * The vector has the default R class name 'factor'.</p>
+	 * 
+	 * @param length the length of the vector
+	 * @param levels the labels of the levels
+	 * @return the R factor vector
+	 */
+	public RVector<RFactorStore> createOrderedVector(final int length, final String[] levels) {
+		return createVector(createOrderedData(length, levels), RObject.CLASSNAME_ORDERED);
+	}
+	
+	
+	/*-- Array/Matrix --*/
+	
+	public <TData extends RStore<?>> RArray<TData> createArray(final TData data, final int[] dim,
+			final String classname) {
+		return new RArrayImpl<>(data, classname, dim);
+	}
+	
+	@Override
+	public <TData extends RStore<?>> RArray<TData> createArray(final TData data, final int[] dim) {
+		return createArray(data, dim, (dim.length == 2) ? RObject.CLASSNAME_MATRIX :RObject.CLASSNAME_ARRAY);
+	}
+	
+	@Override
+	public <TData extends RStore<?>> RArray<TData> createMatrix(final TData data, final int dim1, final int dim2) {
+		return createArray(data, new int[] { dim1, dim2 }, RObject.CLASSNAME_MATRIX);
+	}
+	
+	
+	public RArray<RLogicalStore> createLogiArray(final boolean[] logicals, final int[] dim) {
+		return createArray(createLogiData(logicals), dim);
+	}
+	
+	public RArray<RLogicalStore> createLogiArray(final int[] dim) {
+		return createArray(createLogiData(RDataUtils.computeLengthFromDim(dim)), dim);
+	}
+	
+	public RArray<RIntegerStore> createIntArray(final int[] integers, final int[] dim) {
+		return createArray(createIntData(integers), dim);
+	}
+	
+	public RArray<RIntegerStore> createIntArray(final int[] dim) {
+		return createArray(createIntData(RDataUtils.computeLengthFromDim(dim)), dim);
+	}
+	
+	public RArray<RNumericStore> createNumArray(final double[] numerics, final int[] dim) {
+		return createArray(createNumData(numerics), dim);
+	}
+	
+	public RArray<RNumericStore> createNumArray(final int[] dim) {
+		return createArray(createNumData(RDataUtils.computeLengthFromDim(dim)), dim);
+	}
+	
+	public RArray<RCharacterStore> createCharArray(final String[] characters, final int[] dim) {
+		return createArray(createCharData(characters), dim);
+	}
+	
+	public RArray<RCharacterStore> createCharArray(final int[] dim) {
+		return createArray(createCharData(RDataUtils.computeLengthFromDim(dim)), dim);
+	}
+	
+	
+	public RArray<RLogicalStore> createLogiMatrix(final boolean[] logicals, final int dim1, final int dim2) {
+		return createMatrix(createLogiData(logicals), dim1, dim2);
+	}
+	
+	public RArray<RLogicalStore> createLogiMatrix(final int dim1, final int dim2) {
+		return createMatrix(createLogiData(dim1*dim2), dim1, dim2);
+	}
+	
+	public RArray<RIntegerStore> createIntMatrix(final int[] integers, final int dim1, final int dim2) {
+		return createMatrix(createIntData(integers), dim1, dim2);
+	}
+	
+	public RArray<RIntegerStore> createIntMatrix(final int dim1, final int dim2) {
+		return createMatrix(createIntData(dim1*dim2), dim1, dim2);
+	}
+	
+	public RArray<RNumericStore> createNumMatrix(final double[] numerics, final int dim1, final int dim2) {
+		return createMatrix(createNumData(numerics), dim1, dim2);
+	}
+	
+	public RArray<RNumericStore> createNumMatrix(final int dim1, final int dim2) {
+		return createMatrix(createNumData(dim1*dim2), dim1, dim2);
+	}
+	
+	public RArray<RCharacterStore> createCharMatrix(final String[] characters, final int dim1, final int dim2) {
+		return createMatrix(createCharData(characters), dim1, dim2);
+	}
+	
+	public RArray<RCharacterStore> createCharMatrix(final int dim1, final int dim2) {
+		return createMatrix(createCharData(dim1*dim2), dim1, dim2);
+	}
+	
+	
+	/*-- DataFrame --*/
+	
+	public RDataFrame createDataFrame(final RStore<?>[] colDatas, final String[] colNames) {
+		return createDataFrame(colDatas, colNames, null);
+	}
+	
+	public RDataFrame createDataFrame(final RStore<?>[] colDatas, final String[] colNames, final String[] rowNames) {
+		final RObject[] colVectors= new RObject[colDatas.length];
+		for (int i= 0; i < colVectors.length; i++) {
+			colVectors[i]= createVector(colDatas[i]);
+		}
+		return createDataFrame(colVectors, colNames, rowNames);
+	}
+	
+	public RDataFrame createDataFrame(final RObject[] colVectors,
+			final String[] colNames, final String[] rowNames) {
+		return new RDataFrame32Impl(colVectors, RObject.CLASSNAME_DATAFRAME, colNames, rowNames);
+	}
+	
+	
+	public RList createList(final RObject[] components, final String[] names, final String classname) {
+		return new RList32Impl(components, classname, names);
+	}
+	
+	@Override
+	public RList createList(final RObject[] components, final String[] names) {
+		return createList(components, names, RObject.CLASSNAME_LIST);
+	}
+	
+	
+	/*-- Language --*/
+	
+	@Override
+	public RLanguage createName(final String name) {
+		return new RLanguageImpl(RLanguage.NAME, name, RObject.CLASSNAME_NAME);
+	}
+	
+	@Override
+	public RLanguage createExpression(final String expr) {
+		return new RLanguageImpl(RLanguage.EXPRESSION, expr, RObject.CLASSNAME_EXPRESSION);
+	}
+	
+	
+	/*-- Data/RStore --*/
+	
+	@Override
+	public RLogicalStore createLogiData(final boolean[] logiValues) {
+		return new RLogicalByte32Store(logiValues);
+	}
+	
+	public RLogicalStore createLogiData(final long length) {
+		return (length <= this.storeLengthFixLong) ?
+				new RLogicalByte32Store((int) length) :
+				new RLogicalByteFix64Store(length);
+	}
+	
+	@Override
+	public RIntegerStore createIntData(final int[] intValues) {
+		return new RInteger32Store(intValues);
+	}
+	
+	public RIntegerStore createIntData(final long length) {
+		return (length <= this.storeLengthFixLong) ?
+				new RInteger32Store((int) length) :
+				new RIntegerFix64Store(length);
+	}
+	
+	@Override
+	public RNumericStore createNumData(final double[] numValues) {
+		return new RNumericB32Store(numValues);
+	}
+	
+	public RNumericStore createNumData(final long length) {
+		return (length <= this.storeLengthFixLong) ?
+				new RNumericB32Store((int) length) :
+				new RNumericBFix64Store(length);
+	}
+	
+	@Override
+	public RComplexStore createCplxData(final double[] reValues, final double[] imValues) {
+		return new RComplexB32Store(reValues, imValues, null);
+	}
+	
+	public RComplexStore createCplxData(final long length) {
+		return (length <= this.storeLengthFixLong) ?
+				new RComplexB32Store((int) length) :
+				new RComplexBFix64Store(length);
+	}
+	
+	@Override
+	public RCharacterStore createCharData(final String[] charValues) {
+		return new RCharacter32Store(charValues);
+	}
+	
+	public RCharacterStore createCharData(final long length) {
+		return (length <= this.storeLengthFixLong) ?
+				new RCharacter32Store((int) length) :
+				new RCharacterFix64Store(length);
+	}
+	
+	@Override
+	public RRawStore createRawData(final byte[] rawValues) {
+		return new RRaw32Store(rawValues);
+	}
+	
+	public RRawStore createRawData(final long length) {
+		return (length <= this.storeLengthFixLong) ?
+				new RRaw32Store((int) length) :
+				new RRawFix64Store(length);
+	}
+	
+	@Override
+	public RFactorStore createFactorData(final int[] codes, final String[] levels) {
+		return new RFactor32Store(codes, false, levels);
+	}
+	
+	public RFactorStore createFactorData(final int length, final String[] levels) {
+		return new RFactor32Store(length, false, levels);
+	}
+	
+	public RFactorStore createOrderedData(final int[] codes, final String[] levels) {
+		return new RFactor32Store(codes, true, levels);
+	}
+	
+	public RFactorStore createOrderedData(final int length, final String[] levels) {
+		return new RFactor32Store(length, true, levels);
+	}
+	
+	
+	/*-- Streaming --*/
+	
+	@Override
+	public RObject readObject(final RJIO io) throws IOException {
+		final byte type= io.readByte();
+		int options;
+		switch (type) {
+		case -1:
+			return null;
+		case RObject.TYPE_NULL:
+			return RNullImpl.INSTANCE;
+		case RObject.TYPE_VECTOR: {
+			return new RVectorImpl(io, this); }
+		case RObject.TYPE_ARRAY:
+			return new RArrayImpl(io, this);
+		case RObject.TYPE_LIST:
+			options= io.readInt();
+			return ((options & O_LENGTHGRADE_MASK) <= 3) ?
+					new RList32Impl(io, this, options) :
+					new RListFix64Impl(io, this, options);
+		case RObject.TYPE_DATAFRAME:
+			options= io.readInt();
+			return ((options & O_LENGTHGRADE_MASK) <= 3) ?
+					new RDataFrame32Impl(io, this, options) :
+					new RListFix64Impl(io, this, options);
+		case RObject.TYPE_ENVIRONMENT:
+			return new REnvironmentImpl(io, this);
+		case RObject.TYPE_LANGUAGE:
+			return new RLanguageImpl(io, this);
+		case RObject.TYPE_FUNCTION:
+			return new RFunctionImpl(io, this);
+		case RObject.TYPE_REFERENCE:
+			return new RReferenceImpl(io, this);
+		case RObject.TYPE_S4OBJECT:
+			return new RS4ObjectImpl(io, this);
+		case RObject.TYPE_OTHER:
+			return new ROtherImpl(io, this);
+		case RObject.TYPE_MISSING:
+			return RMissingImpl.INSTANCE;
+		case RObject.TYPE_PROMISE:
+			return RPromiseImpl.INSTANCE;
+		default:
+			throw new IOException("object type= " + type);
+		}
+	}
+	
+	@Override
+	public void writeObject(final RObject robject, final RJIO io) throws IOException {
+		if (robject == null) {
+			io.writeByte(-1);
+			return;
+		}
+		final byte type= robject.getRObjectType();
+		io.writeByte(type);
+		switch (type) {
+		case RObject.TYPE_NULL:
+		case RObject.TYPE_MISSING:
+		case RObject.TYPE_PROMISE:
+			return;
+		case RObject.TYPE_VECTOR:
+			((ExternalizableRObject) robject).writeExternal(io, this);
+			return;
+		case RObject.TYPE_ARRAY:
+			((ExternalizableRObject) robject).writeExternal(io, this);
+			return;
+		case RObject.TYPE_LIST:
+			((ExternalizableRObject) robject).writeExternal(io, this);
+			return;
+		case RObject.TYPE_DATAFRAME:
+			((ExternalizableRObject) robject).writeExternal(io, this);
+			return;
+		case RObject.TYPE_ENVIRONMENT:
+			((ExternalizableRObject) robject).writeExternal(io, this);
+			return;
+		case RObject.TYPE_LANGUAGE:
+			((ExternalizableRObject) robject).writeExternal(io, this);
+			return;
+		case RObject.TYPE_FUNCTION:
+			((ExternalizableRObject) robject).writeExternal(io, this);
+			return;
+		case RObject.TYPE_REFERENCE:
+			((ExternalizableRObject) robject).writeExternal(io, this);
+			return;
+		case RObject.TYPE_S4OBJECT:
+			((ExternalizableRObject) robject).writeExternal(io, this);
+			return;
+		case RObject.TYPE_OTHER:
+			((ExternalizableRObject) robject).writeExternal(io, this);
+			return;
+		default:
+			throw new IOException("object type= " + type);
+		}
+	}
+	
+	@Override
+	public RStore<?> readStore(final RJIO io, final long length) throws IOException {
+		if ((io.flags & F_ONLY_STRUCT) == 0) {
+			final byte storeType= io.readByte();
+			if (length <= Integer.MAX_VALUE) {
+				switch (storeType) {
+				case RStore.LOGICAL:
+					return new RLogicalByte32Store(io, (int) length);
+				case RStore.INTEGER:
+					return new RInteger32Store(io, (int) length);
+				case RStore.NUMERIC:
+					return new RNumericB32Store(io, (int) length);
+				case RStore.COMPLEX:
+					return new RComplexB32Store(io, (int) length);
+				case RStore.CHARACTER:
+					return new RCharacter32Store(io, (int) length);
+				case RStore.RAW:
+					return new RRaw32Store(io, (int) length);
+				case RStore.FACTOR:
+					return new RFactor32Store(io, (int) length);
+				default:
+					throw new IOException("store type= " + storeType);
+				}
+			}
+			else {
+				switch (storeType) {
+				case RStore.LOGICAL:
+					return new RLogicalByteFix64Store(io, length);
+				case RStore.INTEGER:
+					return new RIntegerFix64Store(io, length);
+				case RStore.NUMERIC:
+					return new RNumericBFix64Store(io, length);
+				case RStore.COMPLEX:
+					return new RComplexBFix64Store(io, length);
+				case RStore.CHARACTER:
+					return new RCharacterFix64Store(io, length);
+				case RStore.RAW:
+					return new RRawFix64Store(io, length);
+				case RStore.FACTOR:
+					return new RFactorFix64Store(io, length);
+				default:
+					throw new IOException("store type= " + storeType);
+				}
+			}
+		}
+		else {
+			final byte storeType= io.readByte();
+			switch (storeType) {
+			case RStore.LOGICAL:
+				return LOGI_STRUCT_DUMMY;
+			case RStore.INTEGER:
+				return INT_STRUCT_DUMMY;
+			case RStore.NUMERIC:
+				return NUM_STRUCT_DUMMY;
+			case RStore.COMPLEX:
+				return CPLX_STRUCT_DUMMY;
+			case RStore.CHARACTER:
+				return CHR_STRUCT_DUMMY;
+			case RStore.RAW:
+				return RAW_STRUCT_DUMMY;
+			case RStore.FACTOR:
+				return new RFactorStructStore(io.readBoolean(), io.readInt());
+			default:
+				throw new IOException("store type= " + storeType);
+			}
+		}
+	}
+	
+	@Override
+	public void writeStore(final RStore<?> data, final RJIO io) throws IOException {
+		if ((io.flags & F_ONLY_STRUCT) == 0) {
+			io.writeByte(data.getStoreType());
+			((ExternalizableRStore) data).writeExternal(io);
+		}
+		else {
+			final byte storeType= data.getStoreType();
+			io.writeByte(storeType);
+			if (storeType == RStore.FACTOR) {
+				final RFactorStore factor= (RFactorStore) data;
+				io.writeBoolean(factor.isOrdered());
+				io.writeInt(factor.getLevelCount());
+			}
+		}
+	}
+	
+	@Override
+	public RList readAttributeList(final RJIO io) throws IOException {
+		return new RList32Impl(io, this, io.readInt());
+	}
+	
+	@Override
+	public void writeAttributeList(final RList list, final RJIO io) throws IOException {
+		((ExternalizableRObject) list).writeExternal(io, this);
+	}
+	
+	protected final int[] readDim(final ObjectInput in) throws IOException {
+		final int length= in.readInt();
+		final int[] dim= new int[length];
+		for (int i= 0; i < length; i++) {
+			dim[i]= in.readInt();
+		}
+		return dim;
+	}
+	
+	@Override
+	public RStore<?> readNames(final RJIO io, final long length) throws IOException {
+		final byte type= io.readByte();
+		if (type == RStore.CHARACTER) {
+			return (length <= Integer.MAX_VALUE) ?
+					new RCharacter32Store(io, (int) length) :
+					new RCharacterFix64Store(io, length);
+		}
+		if (type == 0) {
+			return null;
+		}
+		throw new IOException();
+	}
+	
+	@Override
+	public void writeNames(final RStore<?> names, final RJIO io) throws IOException {
+		if (names != null) {
+			final byte type= names.getStoreType();
+			if (type == RStore.CHARACTER) {
+				io.writeByte(type);
+				((ExternalizableRStore) names).writeExternal(io);
+				return;
+			}
+		}
+		io.writeByte(0);
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/ExternalizableRObject.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/ExternalizableRObject.java
new file mode 100644
index 0000000..917de25
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/ExternalizableRObject.java
@@ -0,0 +1,28 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data.impl;
+
+import java.io.IOException;
+
+import org.eclipse.statet.rj.data.RJIO;
+import org.eclipse.statet.rj.data.RObjectFactory;
+
+
+public interface ExternalizableRObject {
+	
+	
+	public void writeExternal(final RJIO io, final RObjectFactory factory) throws IOException;
+	
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/ExternalizableRStore.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/ExternalizableRStore.java
new file mode 100644
index 0000000..c14ef89
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/ExternalizableRStore.java
@@ -0,0 +1,27 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data.impl;
+
+import java.io.IOException;
+
+import org.eclipse.statet.rj.data.RJIO;
+
+
+public interface ExternalizableRStore {
+	
+	
+	void writeExternal(RJIO io) throws IOException;
+	
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RArrayImpl.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RArrayImpl.java
new file mode 100644
index 0000000..dd6b478
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RArrayImpl.java
@@ -0,0 +1,251 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data.impl;
+
+import java.io.IOException;
+
+import org.eclipse.statet.rj.data.RArray;
+import org.eclipse.statet.rj.data.RCharacterStore;
+import org.eclipse.statet.rj.data.RDataUtils;
+import org.eclipse.statet.rj.data.RIntegerStore;
+import org.eclipse.statet.rj.data.RJIO;
+import org.eclipse.statet.rj.data.RList;
+import org.eclipse.statet.rj.data.RObject;
+import org.eclipse.statet.rj.data.RObjectFactory;
+import org.eclipse.statet.rj.data.RStore;
+
+
+public class RArrayImpl<TData extends RStore<?>> extends AbstractRObject
+		implements RArray<TData>, ExternalizableRObject {
+	
+	
+	private long length;
+	private TData data;
+	
+	private String className1;
+	private RInteger32Store dimAttribute;
+	private SimpleRList<RStore<?>> dimnamesAttribute;
+	
+	
+	public RArrayImpl(final TData data, final String className1, final int[] dim) {
+		if (data == null || className1 == null || dim == null) {
+			throw new NullPointerException();
+		}
+		this.length= RDataUtils.computeLengthFromDim(dim);
+		if (data.getLength() >= 0 && data.getLength() != this.length) {
+			throw new IllegalArgumentException("dim");
+		}
+		this.className1= className1;
+		this.dimAttribute= new RInteger32Store(dim);
+		this.data= data;
+	}
+	
+	public RArrayImpl(final RJIO io, final RObjectFactory factory) throws IOException {
+		readExternal(io, factory);
+	}
+	
+	public void readExternal(final RJIO io, final RObjectFactory factory) throws IOException {
+		//-- options
+		final int options= io.readInt();
+		//-- special attributes
+		if ((options & RObjectFactory.O_CLASS_NAME) != 0) {
+			this.className1= io.readString();
+		}
+		this.length= io.readVULong((byte) (options & RObjectFactory.O_LENGTHGRADE_MASK));
+		final int[] dim= io.readIntArray();
+		this.dimAttribute= new RInteger32Store(dim);
+		if ((options & RObjectFactory.O_WITH_NAMES) != 0) {
+			final RCharacter32Store names0= new RCharacter32Store(io, dim.length);
+			final RStore<?>[] names1= new RStore[dim.length];
+			for (int i= 0; i < dim.length; i++) {
+				names1[i]= factory.readNames(io, dim[i]);
+			}
+			this.dimnamesAttribute= new SimpleRList<>(names1, names0);
+		}
+		//-- data
+		this.data= (TData) factory.readStore(io, this.length);
+		
+		if ((options & RObjectFactory.O_CLASS_NAME) == 0) {
+			this.className1= (dim.length == 2) ? RObject.CLASSNAME_MATRIX : RObject.CLASSNAME_ARRAY;
+		}
+		//-- attributes
+		if ((options & RObjectFactory.O_WITH_ATTR) != 0) {
+			setAttributes(factory.readAttributeList(io));
+		}
+	}
+	
+	@Override
+	public void writeExternal(final RJIO io, final RObjectFactory factory) throws IOException {
+		final int n= this.dimAttribute.length();
+		//-- options
+		int options= io.getVULongGrade(this.length);
+		if (!this.className1.equals((n == 2) ?
+				RObject.CLASSNAME_MATRIX : RObject.CLASSNAME_ARRAY )) {
+			options |= RObjectFactory.O_CLASS_NAME;
+		}
+		if ((io.flags & RObjectFactory.F_ONLY_STRUCT) == 0 && this.dimnamesAttribute != null) {
+			options |= RObjectFactory.O_WITH_NAMES;
+		}
+		final RList attributes= ((io.flags & RObjectFactory.F_WITH_ATTR) != 0) ? getAttributes() : null;
+		if (attributes != null) {
+			options |= RObjectFactory.O_WITH_ATTR;
+		}
+		io.writeInt(options);
+		//-- special attributes
+		if ((options & RObjectFactory.O_CLASS_NAME) != 0) {
+			io.writeString(this.className1);
+		}
+		io.writeVULong((byte) (options & RObjectFactory.O_LENGTHGRADE_MASK), this.length);
+		io.writeInt(n);
+		this.dimAttribute.writeExternal(io);
+		if ((options & RObjectFactory.O_WITH_NAMES) != 0) {
+			((ExternalizableRStore) this.dimnamesAttribute.getNames()).writeExternal(io);
+			for (int i= 0; i < n; i++) {
+				factory.writeNames(this.dimnamesAttribute.get(i), io);
+			}
+		}
+		//-- data
+		factory.writeStore(this.data, io);
+		//-- attributes
+		if ((options & RObjectFactory.O_WITH_ATTR) != 0) {
+			factory.writeAttributeList(attributes, io);
+		}
+	}
+	
+	
+	@Override
+	public final byte getRObjectType() {
+		return TYPE_ARRAY;
+	}
+	
+	@Override
+	public String getRClassName() {
+		return this.className1;
+	}
+	
+	@Override
+	public long getLength() {
+		return this.length;
+	}
+	
+	@Override
+	public RIntegerStore getDim() {
+		return this.dimAttribute;
+	}
+	
+	@Override
+	public RCharacterStore getDimNames() {
+		if (this.dimnamesAttribute != null) {
+			return this.dimnamesAttribute.getNames();
+		}
+		return null;
+	}
+	
+	@Override
+	public RStore<?> getNames(final int dim) {
+		if (this.dimnamesAttribute != null) {
+			return this.dimnamesAttribute.get(dim);
+		}
+		return null;
+	}
+	
+	
+	@Override
+	public TData getData() {
+		return this.data;
+	}
+	
+	
+//	protected int[] getDataInsertIdxs(final int dim, final int idx) {
+//		if (dim >= this.dimAttribute.length || idx >= this.dimAttribute.intValues[dim]) {
+//			throw new IllegalArgumentException();
+//		}
+//		final int size= this.data.getLength() / this.dimAttribute.intValues[dim];
+//		final int[] dataIdxs= new int[size];
+//		int step= 1;
+//		int stepCount= 1;
+//		for (int currentDimI= 0; currentDimI < this.dimAttribute.length; currentDimI++) {
+//			final int currentDimLength= this.dimAttribute.intValues[currentDimI];
+//			if (currentDimI == dim) {
+//				final int add= step*idx;
+//				for (int i= 0; i < size; i++) {
+//					dataIdxs[i]+= add;
+//				}
+//			}
+//			else {
+//				if (currentDimI > 0) {
+//					int temp= 0;
+//					for (int i= 0; i < size; ) {
+//						final int add= step*temp;
+//						for (int j= 0; j < stepCount && i < size; i++,j++) {
+//							dataIdxs[i]+= add;
+//						}
+//						temp++;
+//						if (temp == currentDimLength) {
+//							temp= 0;
+//						}
+//					}
+//				}
+//				stepCount *= currentDimLength;
+//			}
+//			step *= currentDimLength;
+//		}
+//		return dataIdxs;
+//	}
+//	
+//	public void setDim(final int[] dim) {
+//		checkDim(getLength(), dim);
+//		this.dimAttribute= dim;
+//	}
+//	
+//	public void setDimNames(final List<RCharacterStore> list) {
+//	}
+	
+//	public void insert(final int dim, final int idx) {
+//		((RDataResizeExtension) this.data).insertNA(getDataInsertIdxs(dim, idx));
+//		this.dimAttribute[dim]++;
+//		if (this.dimnamesAttribute != null) {
+//			final RVector<RCharacterStore> names= (RVector<RCharacterStore>) this.dimnamesAttribute.get(dim);
+//			if (names != null) {
+//				names.insert(idx);
+//			}
+//		}
+//	}
+//	
+//	public void remove(final int dim, final int idx) {
+//		((RDataResizeExtension) this.data).remove(RDataUtils.getDataIdxs(this.dimAttribute, dim, idx));
+//		this.dimAttribute[dim]--;
+//		if (this.dimnamesAttribute != null) {
+//			final RVector<RCharacterStore> names= (RVector<RCharacterStore>) this.dimnamesAttribute.get(dim);
+//			if (names != null) {
+//				names.remove(idx);
+//			}
+//		}
+//	}
+	
+	
+	@Override
+	public String toString() {
+		final StringBuilder sb= new StringBuilder();
+		sb.append("RObject type=RArray, class=").append(getRClassName());
+		sb.append("\n\tlength=").append(getLength());
+		sb.append("\n\tdim=");
+		this.dimAttribute.appendTo(sb);
+		sb.append("\n\tdata: ");
+		sb.append(this.data.toString());
+		return sb.toString();
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RCharacter32Store.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RCharacter32Store.java
new file mode 100644
index 0000000..18feeab
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RCharacter32Store.java
@@ -0,0 +1,342 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data.impl;
+
+import java.io.Externalizable;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import java.util.Arrays;
+
+import org.eclipse.statet.rj.data.RJIO;
+
+
+/**
+ * This implementation is limited to length of 2<sup>31</sup>-1.
+ */
+public class RCharacter32Store extends AbstractCharacterStore
+		implements RDataResizeExtension<String>, ExternalizableRStore, Externalizable {
+	
+	
+	private int length;
+	
+	protected String[] charValues;
+	
+	
+	public RCharacter32Store() {
+		this.length= 0;
+		this.charValues= EMPTY_STRING_ARRAY;
+	}
+	
+	public RCharacter32Store(final int length) {
+		this.length= length;
+		this.charValues= new String[length];
+		Arrays.fill(this.charValues, "");
+	}
+	
+	public RCharacter32Store(final String[] values) {
+		this.length= values.length;
+		this.charValues= values;
+	}
+	
+	public RCharacter32Store(final String[] values, final int length) {
+		this.length= length;
+		this.charValues= values;
+	}
+	
+	
+	RCharacter32Store(final RCharacter32Store source, final boolean reuse) {
+		String[] values;
+		if (reuse) {
+			values= source.charValues;
+		}
+		else {
+			values= ensureCapacity(this.charValues, source.length);
+			System.arraycopy(source, 0, values, 0, source.length);
+		}
+		this.charValues= values;
+		this.length= source.length;
+	}
+	
+	
+	public RCharacter32Store(final RJIO io, final int length) throws IOException {
+		this.length= length;
+		this.charValues= new String[length];
+		io.readStringData(this.charValues, length);
+	}
+	
+	@Override
+	public void writeExternal(final RJIO io) throws IOException {
+		io.writeStringData(this.charValues, this.length);
+	}
+	
+	@Override
+	public void readExternal(final ObjectInput in) throws IOException {
+		this.length= in.readInt();
+		this.charValues= new String[this.length];
+		for (int i= 0; i < this.length; i++) {
+			final int l= in.readInt();
+			if (l >= 0) {
+				final char[] c= new char[l];
+				for (int j= 0; j < l; j++) {
+					c[j]= in.readChar();
+				}
+				this.charValues[i]= new String(c);
+			}
+//			else {
+//				this.charValues[i]= null;
+//			}
+		}
+	}
+	
+	@Override
+	public void writeExternal(final ObjectOutput out) throws IOException {
+		out.writeInt(this.length);
+		for (int i= 0; i < this.length; i++) {
+			if (this.charValues[i] != null) {
+				out.writeInt(this.charValues[i].length());
+				out.writeChars(this.charValues[i]);
+			}
+			else {
+				out.writeInt(-1);
+			}
+		}
+	}
+	
+	
+	@Override
+	protected final boolean isStructOnly() {
+		return false;
+	}
+	
+	
+	public final int length() {
+		return this.length;
+	}
+	
+	@Override
+	public final long getLength() {
+		return this.length;
+	}
+	
+	@Override
+	public boolean isNA(final int idx) {
+		return (this.charValues[idx] == null);
+	}
+	
+	@Override
+	public boolean isNA(final long idx) {
+		if (idx < 0 || idx >= length()) {
+			throw new IndexOutOfBoundsException(Long.toString(idx));
+		}
+		return (this.charValues[(int) idx] == null);
+	}
+	
+	@Override
+	public void setNA(final int idx) {
+//		if (this.charValues[idx] == null) {
+//			return;
+//		}
+		this.charValues[idx]= null;
+	}
+	
+	@Override
+	public void setNA(final long idx) {
+		if (idx < 0 || idx >= length()) {
+			throw new IndexOutOfBoundsException(Long.toString(idx));
+		}
+//		if (this.charValues[(int) idx] == null) {
+//			return;
+//		}
+		this.charValues[(int) idx]= null;
+	}
+	
+	@Override
+	public boolean isMissing(final int idx) {
+		return (this.charValues[idx] == null);
+	}
+	
+	@Override
+	public boolean isMissing(final long idx) {
+		if (idx < 0 || idx >= length()) {
+			throw new IndexOutOfBoundsException(Long.toString(idx));
+		}
+		return (this.charValues[(int) idx] == null);
+	}
+	
+	@Override
+	public String getChar(final int idx) {
+		return this.charValues[idx];
+	}
+	
+	@Override
+	public String getChar(final long idx) {
+		if (idx < 0 || idx >= length()) {
+			throw new IndexOutOfBoundsException(Long.toString(idx));
+		}
+		return this.charValues[(int) idx];
+	}
+	
+	@Override
+	public void setChar(final int idx, final String value) {
+//		assert (value != null);
+		this.charValues[idx]= value;
+	}
+	
+	@Override
+	public void setChar(final long idx, final String value) {
+		if (idx < 0 || idx >= length()) {
+			throw new IndexOutOfBoundsException(Long.toString(idx));
+		}
+//		assert (value != null);
+		this.charValues[(int) idx]= value;
+	}
+	
+	
+	private void prepareInsert(final int[] idxs) {
+		this.charValues= prepareInsert(this.charValues, this.length, idxs);
+		this.length+= idxs.length;
+	}
+	
+	public void insertChar(final int idx, final String value) {
+//		assert (value != null);
+		prepareInsert(new int[] { idx });
+		this.charValues[idx]= value;
+	}
+	
+	@Override
+	public void insertNA(final int idx) {
+		prepareInsert(new int[] { idx });
+		this.charValues[idx]= null;
+	}
+	
+	@Override
+	public void insertNA(final int[] idxs) {
+		if (idxs.length == 0) {
+			return;
+		}
+		prepareInsert(idxs);
+		for (int i= 0; i < idxs.length; i++) {
+			this.charValues[idxs[i]]= null;
+		}
+	}
+	
+	@Override
+	public void remove(final int idx) {
+		this.charValues= remove(this.charValues, this.length, new int[] { idx });
+		this.length--;
+	}
+	
+	@Override
+	public void remove(final int[] idxs) {
+		this.charValues= remove(this.charValues, this.length, idxs);
+		this.length-= idxs.length;
+	}
+	
+	
+	@Override
+	public String get(final int idx) {
+		if (idx < 0 || idx >= length()) {
+			throw new IndexOutOfBoundsException(Long.toString(idx));
+		}
+		return this.charValues[idx];
+	}
+	
+	@Override
+	public String get(final long idx) {
+		if (idx < 0 || idx >= length()) {
+			throw new IndexOutOfBoundsException(Long.toString(idx));
+		}
+		return this.charValues[(int) idx];
+	}
+	
+	@Override
+	public String[] toArray() {
+		final String[] array= new String[length()];
+		System.arraycopy(this.charValues, 0, array, 0, array.length);
+		return array;
+	}
+	
+	
+	@Override
+	public long indexOfNA(long fromIdx) {
+		if (fromIdx >= Integer.MAX_VALUE) {
+			return -1;
+		}
+		if (fromIdx < 0) {
+			fromIdx= 0;
+		}
+		final int l= length();
+		final String[] chars= this.charValues;
+		for (int i= (int) fromIdx; i < l; i++) {
+			if (chars[i] == null) {
+				return i;
+			}
+		}
+		return -1;
+	}
+	
+	public int indexOfNA(int fromIdx) {
+		if (fromIdx < 0) {
+			fromIdx= 0;
+		}
+		final int l= length();
+		final String[] chars= this.charValues;
+		for (int i= fromIdx; i < l; i++) {
+			if (chars[i] == null) {
+				return i;
+			}
+		}
+		return -1;
+	}
+	
+	@Override
+	public long indexOf(final String character, long fromIdx) {
+		if (character == null
+				|| fromIdx >= Integer.MAX_VALUE) {
+			return -1;
+		}
+		if (fromIdx < 0) {
+			fromIdx= 0;
+		}
+		final int l= length();
+		final String[] chars= this.charValues;
+		for (int i= (int) fromIdx; i < l; i++) {
+			if (chars[i] != null && chars[i].equals(character)) {
+				return i;
+			}
+		}
+		return -1;
+	}
+	
+	public int indexOf(final String character, int fromIdx) {
+		if (character == null) {
+			throw new NullPointerException();
+		}
+		if (fromIdx < 0) {
+			fromIdx= 0;
+		}
+		final int l= length();
+		final String[] chars= this.charValues;
+		while (fromIdx < l) {
+			if (chars[fromIdx] != null && chars[fromIdx].equals(character)) {
+				return fromIdx;
+			}
+			fromIdx++;
+		}
+		return -1;
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RCharacterFix64Store.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RCharacterFix64Store.java
new file mode 100644
index 0000000..27010a9
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RCharacterFix64Store.java
@@ -0,0 +1,202 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data.impl;
+
+import java.io.IOException;
+import java.util.Arrays;
+
+import org.eclipse.statet.rj.data.RJIO;
+
+
+public class RCharacterFix64Store extends AbstractCharacterStore
+		implements ExternalizableRStore {
+	
+	
+	public static final int SEGMENT_LENGTH= DEFAULT_LONG_DATA_SEGMENT_LENGTH;
+	
+	
+	private final long length;
+	
+	protected final String[][] charValues;
+	
+	
+	public RCharacterFix64Store(final long length) {
+		this.length= length;
+		this.charValues= new2dStringArray(length, SEGMENT_LENGTH);
+		for (int i= 0; i < this.charValues.length; i++) {
+			Arrays.fill(this.charValues[i], "");
+		}
+	}
+	
+	public RCharacterFix64Store(final String[][] values) {
+		this.length= check2dArrayLength(values, SEGMENT_LENGTH);
+		this.charValues= values;
+	}
+	
+	
+	public RCharacterFix64Store(final RJIO io, final long length) throws IOException {
+		this.length= length;
+		this.charValues= new2dStringArray(length, SEGMENT_LENGTH);
+		for (int i= 0; i < this.charValues.length; i++) {
+			io.readStringData(this.charValues[i], this.charValues[i].length);
+		}
+	}
+	
+	@Override
+	public void writeExternal(final RJIO io) throws IOException {
+		for (int i= 0; i < this.charValues.length; i++) {
+			io.writeStringData(this.charValues[i], this.charValues[i].length);
+		}
+	}
+	
+	
+	@Override
+	protected final boolean isStructOnly() {
+		return false;
+	}
+	
+	
+	@Override
+	public final long getLength() {
+		return this.length;
+	}
+	
+	@Override
+	public boolean isNA(final int idx) {
+		return (this.charValues[idx / SEGMENT_LENGTH][idx % SEGMENT_LENGTH] == null);
+	}
+	
+	@Override
+	public boolean isNA(final long idx) {
+		return (this.charValues[(int) (idx / SEGMENT_LENGTH)][(int) (idx % SEGMENT_LENGTH)] == null);
+	}
+	
+	@Override
+	public void setNA(final int idx) {
+		this.charValues[idx / SEGMENT_LENGTH][idx % SEGMENT_LENGTH]= null;
+	}
+	
+	@Override
+	public void setNA(final long idx) {
+		this.charValues[(int) (idx / SEGMENT_LENGTH)][(int) (idx % SEGMENT_LENGTH)]= null;
+	}
+	
+	@Override
+	public boolean isMissing(final int idx) {
+		return (this.charValues[idx / SEGMENT_LENGTH][idx % SEGMENT_LENGTH] == null);
+	}
+	
+	@Override
+	public boolean isMissing(final long idx) {
+		return (this.charValues[(int) (idx / SEGMENT_LENGTH)][(int) (idx % SEGMENT_LENGTH)] == null);
+	}
+	
+	@Override
+	public String getChar(final int idx) {
+		return this.charValues[idx / SEGMENT_LENGTH][idx % SEGMENT_LENGTH];
+	}
+	
+	@Override
+	public String getChar(final long idx) {
+		return this.charValues[(int) (idx / SEGMENT_LENGTH)][(int) (idx % SEGMENT_LENGTH)];
+	}
+	
+	@Override
+	public void setChar(final int idx, final String value) {
+//		assert (value != null);
+		this.charValues[idx / SEGMENT_LENGTH][idx % SEGMENT_LENGTH]= value;
+	}
+	
+	@Override
+	public void setChar(final long idx, final String value) {
+//		assert (value != null);
+		this.charValues[(int) (idx / SEGMENT_LENGTH)][(int) (idx % SEGMENT_LENGTH)]= value;
+	}
+	
+	
+	@Override
+	public String get(final int idx) {
+		if (idx < 0 || idx >= this.length) {
+			throw new IndexOutOfBoundsException(Long.toString(idx));
+		}
+		return this.charValues[idx / SEGMENT_LENGTH][idx % SEGMENT_LENGTH];
+	}
+	
+	@Override
+	public String get(final long idx) {
+		if (idx < 0 || idx >= this.length) {
+			throw new IndexOutOfBoundsException(Long.toString(idx));
+		}
+		return this.charValues[(int) (idx / SEGMENT_LENGTH)][(int) (idx % SEGMENT_LENGTH)];
+	}
+	
+	@Override
+	public String[] toArray() {
+		final int l= checkToArrayLength();
+		final String[] array= new String[l];
+		int k= 0;
+		for (int i= 0; i < this.charValues.length; i++) {
+			final String[] chars= this.charValues[i];
+			System.arraycopy(chars, 0, array, k, chars.length);
+			k+= chars.length;
+		}
+		return array;
+	}
+	
+	
+	@Override
+	public long indexOfNA(long fromIdx) {
+		if (fromIdx < 0) {
+			fromIdx= 0;
+		}
+		int i= (int) (fromIdx / SEGMENT_LENGTH);
+		int j= (int) (fromIdx % SEGMENT_LENGTH);
+		while (i < this.charValues.length) {
+			final String[] chars= this.charValues[i];
+			while (j < chars.length) {
+				if (chars[j] == null) {
+					return (i * (long) SEGMENT_LENGTH) + j;
+				}
+			}
+			i++;
+			j= 0;
+		}
+		return -1;
+	}
+	
+	@Override
+	public long indexOf(final String character, long fromIdx) {
+		if (character == null) {
+			return -1;
+		}
+		if (fromIdx < 0) {
+			fromIdx= 0;
+		}
+		int i= (int) (fromIdx / SEGMENT_LENGTH);
+		int j= (int) (fromIdx % SEGMENT_LENGTH);
+		while (i < this.charValues.length) {
+			final String[] chars= this.charValues[i];
+			while (j < chars.length) {
+				if (chars[j] != null && chars[j].equals(character)) {
+					return (i * (long) SEGMENT_LENGTH) + j;
+				}
+			}
+			i++;
+			j= 0;
+		}
+		return -1;
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RCharacterStructStore.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RCharacterStructStore.java
new file mode 100644
index 0000000..2c1df04
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RCharacterStructStore.java
@@ -0,0 +1,96 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data.impl;
+
+import org.eclipse.statet.rj.data.RStore;
+
+
+public class RCharacterStructStore extends AbstractCharacterStore {
+	
+	
+	public RCharacterStructStore() {
+	}
+	
+	
+	@Override
+	protected final boolean isStructOnly() {
+		return true;
+	}
+	
+	
+	@Override
+	public final long getLength() {
+		return -1;
+	}
+	
+	@Override
+	public boolean isNA(final int idx) {
+		throw new UnsupportedOperationException();
+	}
+	
+	@Override
+	public boolean isNA(final long idx) {
+		throw new UnsupportedOperationException();
+	}
+	
+	@Override
+	public boolean isMissing(final int idx) {
+		throw new UnsupportedOperationException();
+	}
+	
+	@Override
+	public boolean isMissing(final long idx) {
+		throw new UnsupportedOperationException();
+	}
+	
+	@Override
+	public String get(final int idx) {
+		throw new UnsupportedOperationException();
+	}
+	
+	@Override
+	public String get(final long idx) {
+		throw new UnsupportedOperationException();
+	}
+	
+	@Override
+	public String[] toArray() {
+		throw new UnsupportedOperationException();
+	}
+	
+	
+	@Override
+	public long indexOfNA(final long fromIdx) {
+		throw new UnsupportedOperationException();
+	}
+	
+	@Override
+	public long indexOf(final int integer, final long fromIdx) {
+		throw new UnsupportedOperationException();
+	}
+	
+	@Override
+	public long indexOf(final String character, final long fromIdx) {
+		throw new UnsupportedOperationException();
+	}
+	
+	
+	@Override
+	public boolean allEqual(final RStore<?> other) {
+		return (CHARACTER == other.getStoreType()
+				&& other.getLength() == -1 );
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RComplexB32Store.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RComplexB32Store.java
new file mode 100644
index 0000000..4f4a6e4
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RComplexB32Store.java
@@ -0,0 +1,362 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data.impl;
+
+import java.io.Externalizable;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+
+import org.eclipse.statet.rj.data.RComplexStore;
+import org.eclipse.statet.rj.data.RJIO;
+import org.eclipse.statet.rj.data.RStore;
+
+
+/**
+ * This implementation is limited to length of 2<sup>31</sup>-1.
+ */
+public class RComplexB32Store extends AbstractComplexStore
+		implements RDataResizeExtension<RComplexStore.Complex>, ExternalizableRStore, Externalizable {
+	
+	
+	private int length;
+	
+	protected double[] realValues;
+	protected double[] imaginaryValues;
+	
+	
+	public RComplexB32Store() {
+		this.length= 0;
+		this.realValues= EMPTY_DOUBLE_ARRAY;
+		this.imaginaryValues= EMPTY_DOUBLE_ARRAY;
+	}
+	
+	public RComplexB32Store(final int length) {
+		this.length= length;
+		this.realValues= new double[length];
+		this.imaginaryValues= new double[length];
+	}
+	
+	protected RComplexB32Store(final double[] realValues, final double[] imaginaryValues) {
+		this.length= realValues.length;
+		this.realValues= realValues;
+		this.imaginaryValues= imaginaryValues;
+	}
+	
+	public RComplexB32Store(final double[] realValues, final double[] imaginaryValues, final int[] naIdxs) {
+		if (realValues.length != imaginaryValues.length) {
+			throw new IllegalArgumentException();
+		}
+		this.length= realValues.length;
+		this.realValues= realValues;
+		this.imaginaryValues= imaginaryValues;
+		if (naIdxs != null) {
+			for (int i= 0; i < naIdxs.length; i++) {
+				this.realValues[naIdxs[i]]= NA_numeric_DOUBLE;
+				this.imaginaryValues[naIdxs[i]]= NA_numeric_DOUBLE;
+			}
+		}
+	}
+	
+	
+	public RComplexB32Store(final RJIO io, final int length) throws IOException {
+		this.length= length;
+		this.realValues= io.readDoubleData(new double[length], length);
+		this.imaginaryValues= io.readDoubleData(new double[length], length);
+	}
+	
+	@Override
+	public void writeExternal(final RJIO io) throws IOException {
+		io.writeDoubleData(this.realValues, this.length);
+		io.writeDoubleData(this.imaginaryValues, this.length);
+	}
+	
+	@Override
+	public void readExternal(final ObjectInput in) throws IOException {
+		this.length= in.readInt();
+		this.realValues= new double[this.length];
+		this.imaginaryValues= new double[this.length];
+		for (int i= 0; i < this.length; i++) {
+			this.realValues[i]= Double.longBitsToDouble(in.readLong());
+			this.imaginaryValues[i]= Double.longBitsToDouble(in.readLong());
+		}
+	}
+	
+	@Override
+	public void writeExternal(final ObjectOutput out) throws IOException {
+		out.writeInt(this.length);
+		for (int i= 0; i < this.length; i++) {
+			out.writeLong(Double.doubleToRawLongBits(this.realValues[i]));
+			out.writeLong(Double.doubleToRawLongBits(this.imaginaryValues[i]));
+		}
+	}
+	
+	
+	@Override
+	protected final boolean isStructOnly() {
+		return false;
+	}
+	
+	
+	protected final int length() {
+		return this.length;
+	}
+	
+	@Override
+	public final long getLength() {
+		return this.length;
+	}
+	
+	@Override
+	public boolean isNA(final int idx) {
+		final double v= this.realValues[idx];
+		return (Double.isNaN(v)
+				&& (int) Double.doubleToRawLongBits(v) == NA_numeric_INT_MATCH);
+	}
+	
+	@Override
+	public boolean isNA(final long idx) {
+		if (idx < 0 || idx >= length()) {
+			throw new IndexOutOfBoundsException(Long.toString(idx));
+		}
+		final double v= this.realValues[(int) idx];
+		return (Double.isNaN(v)
+				&& (int) Double.doubleToRawLongBits(v) == NA_numeric_INT_MATCH);
+	}
+	
+	@Override
+	public void setNA(final int idx) {
+		this.realValues[idx]= NA_numeric_DOUBLE;
+		this.imaginaryValues[idx]= NA_numeric_DOUBLE;
+	}
+	
+	@Override
+	public void setNA(final long idx) {
+		if (idx < 0 || idx >= length()) {
+			throw new IndexOutOfBoundsException(Long.toString(idx));
+		}
+		this.realValues[(int) idx]= NA_numeric_DOUBLE;
+		this.imaginaryValues[(int) idx]= NA_numeric_DOUBLE;
+	}
+	
+	@Override
+	public boolean isNaN(final int idx) {
+		final double v= this.realValues[idx];
+		return (Double.isNaN(v)
+				&& (int) Double.doubleToRawLongBits(v) != NA_numeric_INT_MATCH);
+	}
+	
+	@Override
+	public boolean isNaN(final long idx) {
+		if (idx < 0 || idx >= length()) {
+			throw new IndexOutOfBoundsException(Long.toString(idx));
+		}
+		final double value= this.realValues[(int) idx];
+		return (Double.isNaN(value)
+				&& (int) Double.doubleToRawLongBits(value) != NA_numeric_INT_MATCH);
+	}
+	
+	@Override
+	public boolean isMissing(final int idx) {
+		return (Double.isNaN(this.realValues[idx]));
+	}
+	
+	@Override
+	public boolean isMissing(final long idx) {
+		if (idx < 0 || idx >= length()) {
+			throw new IndexOutOfBoundsException(Long.toString(idx));
+		}
+		return (Double.isNaN(this.realValues[(int) idx]));
+	}
+	
+	@Override
+	public double getCplxRe(final int idx) {
+		return this.realValues[idx];
+	}
+	
+	@Override
+	public double getCplxRe(final long idx) {
+		if (idx < 0 || idx >= length()) {
+			throw new IndexOutOfBoundsException(Long.toString(idx));
+		}
+		return this.realValues[(int) idx];
+	}
+	
+	@Override
+	public double getCplxIm(final int idx) {
+		return this.imaginaryValues[idx];
+	}
+	
+	@Override
+	public double getCplxIm(final long idx) {
+		if (idx < 0 || idx >= length()) {
+			throw new IndexOutOfBoundsException(Long.toString(idx));
+		}
+		return this.imaginaryValues[(int) idx];
+	}
+	
+	@Override
+	public void setCplx(final int idx, final double real, final double imaginary) {
+		if (Double.isNaN(real) || Double.isNaN(imaginary)) {
+			this.realValues[idx]= NaN_numeric_DOUBLE;
+			this.imaginaryValues[idx]= NaN_numeric_DOUBLE;
+		}
+		else {
+			this.realValues[idx]= real;
+			this.imaginaryValues[idx]= imaginary;
+		}
+	}
+	
+	@Override
+	public void setCplx(final long idx, final double real, final double imaginary) {
+		if (idx < 0 || idx >= length()) {
+			throw new IndexOutOfBoundsException(Long.toString(idx));
+		}
+		if (Double.isNaN(real) || Double.isNaN(imaginary)) {
+			this.realValues[(int) idx]= NaN_numeric_DOUBLE;
+			this.imaginaryValues[(int) idx]= NaN_numeric_DOUBLE;
+		}
+		else {
+			this.realValues[(int) idx]= real;
+			this.imaginaryValues[(int) idx]= imaginary;
+		}
+	}
+	
+	@Override
+	public void setNum(final int idx, final double real) {
+		if (Double.isNaN(real)) {
+			this.realValues[idx]= NaN_numeric_DOUBLE;
+			this.imaginaryValues[idx]= NaN_numeric_DOUBLE;
+		}
+		else {
+			this.realValues[idx]= real;
+			this.imaginaryValues[idx]= 0.0;
+		}
+	}
+	
+	@Override
+	public void setNum(final long idx, final double real) {
+		if (idx < 0 || idx >= length()) {
+			throw new IndexOutOfBoundsException(Long.toString(idx));
+		}
+		if (Double.isNaN(real)) {
+			this.realValues[(int) idx]= NaN_numeric_DOUBLE;
+			this.imaginaryValues[(int) idx]= NaN_numeric_DOUBLE;
+		}
+		else {
+			this.realValues[(int) idx]= real;
+			this.imaginaryValues[(int) idx]= 0.0;
+		}
+	}
+	
+	
+	private void prepareInsert(final int[] idxs) {
+		this.realValues= prepareInsert(this.realValues, this.length, idxs);
+		this.imaginaryValues= prepareInsert(this.imaginaryValues, this.length, idxs);
+		this.length+= idxs.length;
+	}
+	
+	public void insertCplx(final int idx, final double realValue, final double imaginaryValue) {
+		prepareInsert(new int[] { idx });
+		if (Double.isNaN(realValue) || Double.isNaN(imaginaryValue)) {
+			this.realValues[idx]= NaN_numeric_DOUBLE;
+			this.imaginaryValues[idx]= NaN_numeric_DOUBLE;
+		}
+		else {
+			this.realValues[idx]= realValue;
+			this.imaginaryValues[idx]= imaginaryValue;
+		}
+	}
+	
+	@Override
+	public void insertNA(final int idx) {
+		prepareInsert(new int[] { idx });
+		this.realValues[idx]= NA_numeric_DOUBLE;
+		this.imaginaryValues[idx]= NA_numeric_DOUBLE;
+	}
+	
+	@Override
+	public void insertNA(final int[] idxs) {
+		if (idxs.length == 0) {
+			return;
+		}
+		prepareInsert(idxs);
+		for (int idx= 0; idx < idxs.length; idx++) {
+			this.realValues[idx]= NA_numeric_DOUBLE;
+			this.imaginaryValues[idx]= NA_numeric_DOUBLE;
+		}
+	}
+	
+	@Override
+	public void remove(final int idx) {
+		this.realValues= remove(this.realValues, this.length, new int[] { idx });
+		this.imaginaryValues= remove(this.imaginaryValues, this.length, new int[] { idx });
+		this.length--;
+	}
+	
+	@Override
+	public void remove(final int[] idxs) {
+		this.realValues= remove(this.realValues, this.length, idxs);
+		this.imaginaryValues= remove(this.imaginaryValues, this.length, idxs);
+		this.length-= idxs.length;
+	}
+	
+	
+	@Override
+	public Complex get(final int idx) {
+		if (idx < 0 || idx >= length()) {
+			throw new IndexOutOfBoundsException(Long.toString(idx));
+		}
+		final double v= this.realValues[idx];
+		return (!Double.isNaN(v)
+				|| (int) Double.doubleToRawLongBits(v) != NA_numeric_INT_MATCH) ?
+			new Complex(v, this.imaginaryValues[idx]) :
+			null;
+	}
+	
+	@Override
+	public Complex get(final long idx) {
+		if (idx < 0 || idx >= length()) {
+			throw new IndexOutOfBoundsException(Long.toString(idx));
+		}
+		final double v= this.realValues[(int) idx];
+		return (!Double.isNaN(v)
+				|| (int) Double.doubleToRawLongBits(v) != NA_numeric_INT_MATCH) ?
+			new Complex(v, this.imaginaryValues[(int) idx]) :
+			null;
+	}
+	
+	@Override
+	public Complex[] toArray() {
+		final double[] reals= this.realValues;
+		final double[] imgs= this.imaginaryValues;
+		final Complex[] array= new Complex[length()];
+		for (int i= 0; i < array.length; i++) {
+			final double v= reals[i];
+			if (!Double.isNaN(v)
+					|| (int) Double.doubleToRawLongBits(v) != NA_numeric_INT_MATCH) {
+				array[i]= new Complex(v, imgs[i]);
+			}
+		}
+		return array;
+	}
+	
+	
+	@Override
+	public boolean allEqual(final RStore<?> other) {
+		throw new UnsupportedOperationException("Not yet implemented");
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RComplexBFix64Store.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RComplexBFix64Store.java
new file mode 100644
index 0000000..70389e6
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RComplexBFix64Store.java
@@ -0,0 +1,272 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data.impl;
+
+import java.io.IOException;
+
+import org.eclipse.statet.rj.data.RJIO;
+import org.eclipse.statet.rj.data.RStore;
+
+
+public class RComplexBFix64Store extends AbstractComplexStore
+		implements ExternalizableRStore {
+	
+	
+	public static final int SEGMENT_LENGTH= DEFAULT_LONG_DATA_SEGMENT_LENGTH;
+	
+	
+	private final long length;
+	
+	protected final double[][] realValues;
+	protected final double[][] imaginaryValues;
+	
+	
+	public RComplexBFix64Store(final long length) {
+		this.length= length;
+		this.realValues= new2dDoubleArray(length, SEGMENT_LENGTH);
+		this.imaginaryValues= new2dDoubleArray(length, SEGMENT_LENGTH);
+	}
+	
+	public RComplexBFix64Store(final double[][] realValues, final double[][] imaginaryValues) {
+		this.length= check2dArrayLength(realValues, SEGMENT_LENGTH);
+		if (this.length != check2dArrayLength(imaginaryValues, SEGMENT_LENGTH)) {
+			throw new IllegalArgumentException();
+		}
+		this.realValues= realValues;
+		this.imaginaryValues= imaginaryValues;
+	}
+	
+	
+	public RComplexBFix64Store(final RJIO io, final long length) throws IOException {
+		this.length= length;
+		this.realValues= new2dDoubleArray(length, SEGMENT_LENGTH);
+		this.imaginaryValues= new2dDoubleArray(length, SEGMENT_LENGTH);
+		for (int i= 0; i < this.realValues.length; i++) {
+			io.readDoubleData(this.realValues[i], this.realValues[i].length);
+			io.readDoubleData(this.imaginaryValues[i], this.imaginaryValues[i].length);
+		}
+	}
+	
+	@Override
+	public void writeExternal(final RJIO io) throws IOException {
+		for (int i= 0; i < this.realValues.length; i++) {
+			io.writeDoubleData(this.realValues[i], this.realValues[i].length);
+			io.writeDoubleData(this.imaginaryValues[i], this.imaginaryValues[i].length);
+		}
+	}
+	
+	
+	@Override
+	protected final boolean isStructOnly() {
+		return false;
+	}
+	
+	
+	@Override
+	public final long getLength() {
+		return this.length;
+	}
+	
+	@Override
+	public boolean isNA(final int idx) {
+		final double v= this.realValues[idx / SEGMENT_LENGTH][idx % SEGMENT_LENGTH];
+		return (Double.isNaN(v)
+				&& (int) Double.doubleToRawLongBits(v) == NA_numeric_INT_MATCH);
+	}
+	
+	@Override
+	public boolean isNA(final long idx) {
+		final double v= this.realValues[(int) (idx / SEGMENT_LENGTH)][(int) (idx % SEGMENT_LENGTH)];
+		return (Double.isNaN(v)
+				&& (int) Double.doubleToRawLongBits(v) == NA_numeric_INT_MATCH);
+	}
+	
+	@Override
+	public void setNA(final int idx) {
+		this.realValues[idx / SEGMENT_LENGTH][idx % SEGMENT_LENGTH] =
+				NA_numeric_DOUBLE;
+		this.imaginaryValues[idx / SEGMENT_LENGTH][idx % SEGMENT_LENGTH] =
+				NA_numeric_DOUBLE;
+	}
+	
+	@Override
+	public void setNA(final long idx) {
+		this.realValues[(int) (idx / SEGMENT_LENGTH)][(int) (idx % SEGMENT_LENGTH)] =
+				NA_numeric_DOUBLE;
+		this.imaginaryValues[(int) (idx / SEGMENT_LENGTH)][(int) (idx % SEGMENT_LENGTH)] =
+				NA_numeric_DOUBLE;
+	}
+	
+	@Override
+	public boolean isNaN(final int idx) {
+		final double v= this.realValues[idx / SEGMENT_LENGTH][idx % SEGMENT_LENGTH];
+		return (Double.isNaN(v)
+				&& (int) Double.doubleToRawLongBits(v) != NA_numeric_INT_MATCH);
+	}
+	
+	@Override
+	public boolean isNaN(final long idx) {
+		final double value= this.realValues[(int) (idx / SEGMENT_LENGTH)][(int) (idx % SEGMENT_LENGTH)];
+		return (Double.isNaN(value)
+				&& (int) Double.doubleToRawLongBits(value) != NA_numeric_INT_MATCH);
+	}
+	
+	@Override
+	public boolean isMissing(final int idx) {
+		return (Double.isNaN(
+				this.realValues[idx / SEGMENT_LENGTH][idx % SEGMENT_LENGTH] ));
+	}
+	
+	@Override
+	public boolean isMissing(final long idx) {
+		return (Double.isNaN(
+				this.realValues[(int) (idx / SEGMENT_LENGTH)][(int) (idx % SEGMENT_LENGTH)] ));
+	}
+	
+	@Override
+	public double getCplxRe(final int idx) {
+		return this.realValues[idx / SEGMENT_LENGTH][idx % SEGMENT_LENGTH];
+	}
+	
+	@Override
+	public double getCplxRe(final long idx) {
+		return this.realValues[(int) (idx / SEGMENT_LENGTH)][(int) (idx % SEGMENT_LENGTH)];
+	}
+	
+	@Override
+	public double getCplxIm(final int idx) {
+		return this.imaginaryValues[idx / SEGMENT_LENGTH][idx % SEGMENT_LENGTH];
+	}
+	
+	@Override
+	public double getCplxIm(final long idx) {
+		return this.imaginaryValues[(int) (idx / SEGMENT_LENGTH)][(int) (idx % SEGMENT_LENGTH)];
+	}
+	
+	@Override
+	public void setCplx(final int idx, final double real, final double imaginary) {
+		if (Double.isNaN(real) || Double.isNaN(imaginary)) {
+			this.realValues[idx / SEGMENT_LENGTH][idx % SEGMENT_LENGTH] =
+					NaN_numeric_DOUBLE;
+			this.imaginaryValues[idx / SEGMENT_LENGTH][idx % SEGMENT_LENGTH] =
+					NaN_numeric_DOUBLE;
+		}
+		else {
+			this.realValues[idx / SEGMENT_LENGTH][idx % SEGMENT_LENGTH] =
+					real;
+			this.imaginaryValues[idx / SEGMENT_LENGTH][idx % SEGMENT_LENGTH] =
+					imaginary;
+		}
+	}
+	
+	@Override
+	public void setCplx(final long idx, final double real, final double imaginary) {
+		if (Double.isNaN(real) || Double.isNaN(imaginary)) {
+			this.realValues[(int) (idx / SEGMENT_LENGTH)][(int) (idx % SEGMENT_LENGTH)] =
+					NaN_numeric_DOUBLE;
+			this.imaginaryValues[(int) (idx / SEGMENT_LENGTH)][(int) (idx % SEGMENT_LENGTH)] =
+					NaN_numeric_DOUBLE;
+		}
+		else {
+			this.realValues[(int) (idx / SEGMENT_LENGTH)][(int) (idx % SEGMENT_LENGTH)] =
+					real;
+			this.imaginaryValues[(int) (idx / SEGMENT_LENGTH)][(int) (idx % SEGMENT_LENGTH)] =
+					imaginary;
+		}
+	}
+	
+	@Override
+	public void setNum(final int idx, final double real) {
+		if (Double.isNaN(real)) {
+			this.realValues[idx / SEGMENT_LENGTH][idx % SEGMENT_LENGTH] =
+					NaN_numeric_DOUBLE;
+			this.imaginaryValues[idx / SEGMENT_LENGTH][idx % SEGMENT_LENGTH] =
+					NaN_numeric_DOUBLE;
+		}
+		else {
+			this.realValues[idx / SEGMENT_LENGTH][idx % SEGMENT_LENGTH] =
+					real;
+			this.imaginaryValues[idx / SEGMENT_LENGTH][idx % SEGMENT_LENGTH] =
+					0.0;
+		}
+	}
+	
+	@Override
+	public void setNum(final long idx, final double real) {
+		if (Double.isNaN(real)) {
+			this.realValues[(int) (idx / SEGMENT_LENGTH)][(int) (idx % SEGMENT_LENGTH)] =
+					NaN_numeric_DOUBLE;
+			this.imaginaryValues[(int) (idx / SEGMENT_LENGTH)][(int) (idx % SEGMENT_LENGTH)] =
+					NaN_numeric_DOUBLE;
+		}
+		else {
+			this.realValues[(int) (idx / SEGMENT_LENGTH)][(int) (idx % SEGMENT_LENGTH)] =
+					real;
+			this.imaginaryValues[(int) (idx / SEGMENT_LENGTH)][(int) (idx % SEGMENT_LENGTH)] =
+					0.0;
+		}
+	}
+	
+	
+	@Override
+	public Complex get(final int idx) {
+		if (idx < 0 || idx >= this.length) {
+			throw new IndexOutOfBoundsException(Long.toString(idx));
+		}
+		final double v= this.realValues[idx / SEGMENT_LENGTH][idx % SEGMENT_LENGTH];
+		return (!Double.isNaN(v)
+				|| (int) Double.doubleToRawLongBits(v) != NA_numeric_INT_MATCH) ?
+			new Complex(v, this.imaginaryValues[idx / SEGMENT_LENGTH][idx % SEGMENT_LENGTH]) :
+			null;
+	}
+	
+	@Override
+	public Complex get(final long idx) {
+		if (idx < 0 || idx >= this.length) {
+			throw new IndexOutOfBoundsException(Long.toString(idx));
+		}
+		final double v= this.realValues[(int) (idx / SEGMENT_LENGTH)][(int) (idx % SEGMENT_LENGTH)];
+		return (!Double.isNaN(v)
+				|| (int) Double.doubleToRawLongBits(v) != NA_numeric_INT_MATCH) ?
+			new Complex(v, this.imaginaryValues[(int) (idx / SEGMENT_LENGTH)][(int) (idx % SEGMENT_LENGTH)]) :
+			null;
+	}
+	
+	@Override
+	public Complex[] toArray() {
+		final int l= checkToArrayLength();
+		final Complex[] array= new Complex[l];
+		int k= 0;
+		for (int i= 0; i < this.realValues.length; i++, k++) {
+			final double[] reals= this.realValues[i];
+			final double[] imgs= this.imaginaryValues[i];
+			for (int j= 0; j < reals.length; j++) {
+				final double v= reals[j];
+				if (!Double.isNaN(v)
+						|| (int) Double.doubleToRawLongBits(v) != NA_numeric_INT_MATCH) {
+					array[k]= new Complex(v, imgs[i]);
+				}
+			}
+		}
+		return array;
+	}
+	
+	
+	@Override
+	public boolean allEqual(final RStore<?> other) {
+		throw new UnsupportedOperationException("Not yet implemented");
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RComplexStructStore.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RComplexStructStore.java
new file mode 100644
index 0000000..8f2e2ca
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RComplexStructStore.java
@@ -0,0 +1,106 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data.impl;
+
+import org.eclipse.statet.rj.data.RStore;
+
+
+public class RComplexStructStore extends AbstractComplexStore {
+	
+	
+	public RComplexStructStore() {
+	}
+	
+	
+	@Override
+	protected final boolean isStructOnly() {
+		return true;
+	}
+	
+	
+	@Override
+	public final long getLength() {
+		return -1;
+	}
+	
+	@Override
+	public boolean isNA(final int idx) {
+		throw new UnsupportedOperationException();
+	}
+	
+	@Override
+	public boolean isNA(final long idx) {
+		throw new UnsupportedOperationException();
+	}
+	
+	@Override
+	public boolean isNaN(final int idx) {
+		throw new UnsupportedOperationException();
+	}
+	
+	@Override
+	public boolean isNaN(final long idx) {
+		throw new UnsupportedOperationException();
+	}
+	
+	@Override
+	public boolean isMissing(final int idx) {
+		throw new UnsupportedOperationException();
+	}
+	
+	@Override
+	public boolean isMissing(final long idx) {
+		throw new UnsupportedOperationException();
+	}
+	
+	@Override
+	public Complex get(final int idx) {
+		throw new UnsupportedOperationException();
+	}
+	
+	@Override
+	public Complex get(final long idx) {
+		throw new UnsupportedOperationException();
+	}
+	
+	@Override
+	public Complex[] toArray() {
+		throw new UnsupportedOperationException();
+	}
+	
+	
+	@Override
+	public long indexOfNA(final long fromIdx) {
+		throw new UnsupportedOperationException();
+	}
+	
+	@Override
+	public long indexOf(final int integer, final long fromIdx) {
+		throw new UnsupportedOperationException();
+	}
+	
+	@Override
+	public long indexOf(final String character, final long fromIdx) {
+		throw new UnsupportedOperationException();
+	}
+	
+	
+	@Override
+	public boolean allEqual(final RStore<?> other) {
+		return (COMPLEX == other.getStoreType()
+				&& -1 == other.getLength() );
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RDataFrame32Impl.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RDataFrame32Impl.java
new file mode 100644
index 0000000..7a711fd
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RDataFrame32Impl.java
@@ -0,0 +1,212 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data.impl;
+
+import java.io.IOException;
+
+import org.eclipse.statet.rj.data.RCharacterStore;
+import org.eclipse.statet.rj.data.RDataFrame;
+import org.eclipse.statet.rj.data.RJIO;
+import org.eclipse.statet.rj.data.RObject;
+import org.eclipse.statet.rj.data.RObjectFactory;
+import org.eclipse.statet.rj.data.RStore;
+
+
+public class RDataFrame32Impl extends RList32Impl
+		implements RDataFrame, ExternalizableRObject {
+	
+	
+	private RStore<?> rownamesAttribute;
+	private long rowCount;
+	
+	
+	public RDataFrame32Impl(final RObject[] columns, final String className1, final String[] initialNames, final String[] initialRownames) {
+		this(columns, className1, initialNames, initialRownames, true);
+	}
+	
+	protected RDataFrame32Impl(final RObject[] columns, final String className1, final String[] initialNames, final String[] initialRownames, final boolean check) {
+		super(columns, className1, initialNames);
+		if (columns.length == 0) {
+			this.rowCount= 0;
+		}
+		else {
+			this.rowCount= columns[0].getLength();
+			if (check) {
+				for (int i= 0; i < columns.length; i++) {
+					if (columns[i].getRObjectType() != RObject.TYPE_VECTOR
+							|| (columns[i].getLength() != this.rowCount)) {
+						throw new IllegalArgumentException("Length of column " + i + ": " + columns[i].getLength());
+					}
+				}
+			}
+		}
+		if (initialRownames != null && initialRownames.length == this.rowCount) {
+			this.rownamesAttribute= new RUniqueCharacter32Store(initialRownames);
+			if (this.rownamesAttribute.getLength() != this.rowCount) {
+				throw new IllegalArgumentException("Length of row names: " + this.rownamesAttribute.getLength());
+			}
+		}
+	}
+	
+	public RDataFrame32Impl(final RJIO io, final RObjectFactory factory, final int options) throws IOException {
+		super(io, factory, options);
+		
+		this.rowCount= io.readLong();
+		if ((options & RObjectFactory.O_WITH_NAMES) != 0) {
+			this.rownamesAttribute= factory.readNames(io, this.rowCount);
+		}
+	}
+	
+	@Override
+	public void writeExternal(final RJIO io, final RObjectFactory factory) throws IOException {
+		int options= 0;
+		if ((io.flags & RObjectFactory.F_ONLY_STRUCT) == 0 && this.rownamesAttribute != null) {
+			options |= RObjectFactory.O_WITH_NAMES;
+		}
+		super.doWriteExternal(io, factory, options);
+		io.writeLong(this.rowCount);
+		if ((options & RObjectFactory.O_WITH_NAMES) != 0) {
+			factory.writeNames(this.rownamesAttribute, io);
+		}
+	}
+	
+	
+	@Override
+	public byte getRObjectType() {
+		return TYPE_DATAFRAME;
+	}
+	
+	@Override
+	protected String getDefaultRClassName() {
+		return RObject.CLASSNAME_DATAFRAME;
+	}
+	
+	
+	@Override
+	public long getColumnCount() {
+		return getLength();
+	}
+	
+	@Override
+	public RCharacterStore getColumnNames() {
+		return getNames();
+	}
+	
+	public String getColumnName(final int idx) {
+		return getName(idx);
+	}
+	
+	@Override
+	public RStore<?> getColumn(final int idx) {
+		final RObject obj= get(idx);
+		return (obj != null) ? obj.getData() : null;
+	}
+	
+	@Override
+	public RStore<?> getColumn(final long idx) {
+		final RObject obj= get(idx);
+		return (obj != null) ? obj.getData() : null;
+	}
+	
+	@Override
+	public RStore<?> getColumn(final String name) {
+		final RObject obj= get(name);
+		return (obj != null) ? obj.getData() : null;
+	}
+	
+//	public void setColumn(final int idx, final RStore<?> column) {
+//		if (this.length == 0) {
+//			throw new IndexOutOfBoundsException(Long.toString(idx));
+//		}
+//		else {
+//			if (column.getLength() != this.rowCount) {
+//				throw new IllegalArgumentException();
+//			}
+//		}
+//		this.columns[idx]= new RVectorImpl(column, RDataUtils.getStoreVectorClass(column));
+//	}
+	
+	@Override
+	public boolean set(final int idx, final RObject component) {
+		if (component == null) {
+			throw new NullPointerException();
+		}
+		if (getLength() == 0) {
+			throw new IndexOutOfBoundsException(Long.toString(idx));
+		}
+		else {
+			if (component.getRObjectType() != RObject.TYPE_VECTOR) {
+				throw new IllegalArgumentException();
+			}
+			if (component.getLength() != this.rowCount) {
+				throw new IllegalArgumentException();
+			}
+		}
+		return super.set(idx, component);
+	}
+	
+//	public void insertColumn(final int idx, final String name, final RStore<?> column) {
+//		if (column == null) {
+//			throw new NullPointerException();
+//		}
+//		if (column.getDataType() <= 0) {
+//			throw new IllegalArgumentException();
+//		}
+//		if (this.length == 0) {
+//			this.rowCount= column.getLength();
+//		}
+//		else if (this.rowCount != column.getLength()) {
+//			throw new IllegalArgumentException();
+//		}
+//		prepareInsert(idx);
+//		this.columns[idx]= new RVectorImpl(column, RDataUtils.getStoreVectorClass(column));
+//		this.namesAttribute.insertChar(idx, name);
+//	}
+//
+	
+	
+	@Override
+	public long getRowCount() {
+		return this.rowCount;
+	}
+	
+	@Override
+	public RStore<?> getRowNames() {
+		return this.rownamesAttribute;
+	}
+	
+	public void insertRow(final int idx) {
+		final long length= getLength();
+		for (int i= 0; i < length; i++) {
+			((RDataResizeExtension<?>) get(i)).insertNA(idx);
+		}
+		this.rowCount++;
+//		if (this.rownamesAttribute != null) {
+//			((RDataResizeExtension) this.rownamesAttribute).insertAuto(idx);
+//		}
+	}
+	
+	public void removeRow(final int idx) {
+		final long length= getLength();
+		for (int i= 0; i < length; i++) {
+			((RDataResizeExtension<?>) this.get(i)).remove(idx);
+		}
+		this.rowCount--;
+//		if (this.rownamesAttribute != null) {
+//			this.rownamesAttribute.remove(idx);
+//		}
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RDataFrameFix64Impl.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RDataFrameFix64Impl.java
new file mode 100644
index 0000000..bb4d085
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RDataFrameFix64Impl.java
@@ -0,0 +1,149 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data.impl;
+
+import java.io.IOException;
+
+import org.eclipse.statet.rj.data.RCharacterStore;
+import org.eclipse.statet.rj.data.RDataFrame;
+import org.eclipse.statet.rj.data.RJIO;
+import org.eclipse.statet.rj.data.RObject;
+import org.eclipse.statet.rj.data.RObjectFactory;
+import org.eclipse.statet.rj.data.RStore;
+
+
+public class RDataFrameFix64Impl extends RListFix64Impl
+		implements RDataFrame, ExternalizableRObject {
+	
+	
+	private final RStore<?> rownamesAttribute;
+	private final long rowCount;
+	
+	
+	public RDataFrameFix64Impl(final RObject[][] columns, final String className1, final String[][] initialNames, final String[][] initialRownames) {
+		this(columns, className1, initialNames, initialRownames, true);
+	}
+	
+	protected RDataFrameFix64Impl(final RObject[][] columns, final String className1, final String[][] initialNames, final String[][] initialRownames, final boolean check) {
+		super(columns, className1, initialNames);
+		if (columns.length == 0) {
+			this.rowCount= 0;
+		}
+		else {
+			this.rowCount= columns[0][0].getLength();
+			if (check) {
+				for (int i= 0; i < columns.length; i++) {
+					final RObject[] segment= columns[i];
+					for (int j= 0; j < segment.length; j++) {
+						if (segment[j].getRObjectType() != RObject.TYPE_VECTOR
+								|| (segment[j].getLength() != this.rowCount)) {
+							throw new IllegalArgumentException("Length of column " + (i * (long) SEGMENT_LENGTH + j) + ": " + segment[j].getLength());
+						}
+					}
+				}
+			}
+		}
+		if (initialRownames != null) {
+			this.rownamesAttribute= new RCharacterFix64Store(initialRownames);
+			if (this.rownamesAttribute.getLength() != this.rowCount) {
+				throw new IllegalArgumentException("Length of row names: " + this.rownamesAttribute.getLength());
+			}
+		}
+		else {
+			this.rownamesAttribute= null;
+		}
+	}
+	
+	public RDataFrameFix64Impl(final RJIO io, final RObjectFactory factory, final int options) throws IOException {
+		super(io, factory, options);
+		
+		this.rowCount= io.readLong();
+		if ((options & RObjectFactory.O_WITH_NAMES) != 0) {
+			this.rownamesAttribute= factory.readNames(io, this.rowCount);
+		}
+		else {
+			this.rownamesAttribute= null;
+		}
+	}
+	
+	@Override
+	public void writeExternal(final RJIO io, final RObjectFactory factory) throws IOException {
+		int options= 0;
+		if ((io.flags & RObjectFactory.F_ONLY_STRUCT) == 0 && this.rownamesAttribute != null) {
+			options |= RObjectFactory.O_WITH_NAMES;
+		}
+		super.doWriteExternal(io, options, factory);
+		io.writeLong(this.rowCount);
+		if ((options & RObjectFactory.O_WITH_NAMES) != 0) {
+			factory.writeNames(this.rownamesAttribute, io);
+		}
+	}
+	
+	
+	@Override
+	public byte getRObjectType() {
+		return TYPE_DATAFRAME;
+	}
+	
+	@Override
+	protected String getDefaultRClassName() {
+		return RObject.CLASSNAME_DATAFRAME;
+	}
+	
+	
+	@Override
+	public long getColumnCount() {
+		return getLength();
+	}
+	
+	@Override
+	public RCharacterStore getColumnNames() {
+		return getNames();
+	}
+	
+	public String getColumnName(final int idx) {
+		return getName(idx);
+	}
+	
+	@Override
+	public RStore<?> getColumn(final int idx) {
+		final RObject obj= get(idx);
+		return (obj != null) ? obj.getData() : null;
+	}
+	
+	@Override
+	public RStore<?> getColumn(final long idx) {
+		final RObject obj= get(idx);
+		return (obj != null) ? obj.getData() : null;
+	}
+	
+	@Override
+	public RStore<?> getColumn(final String name) {
+		final RObject obj= get(name);
+		return (obj != null) ? obj.getData() : null;
+	}
+	
+	
+	@Override
+	public long getRowCount() {
+		return this.rowCount;
+	}
+	
+	@Override
+	public RStore<?> getRowNames() {
+		return this.rownamesAttribute;
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RDataResizeExtension.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RDataResizeExtension.java
new file mode 100644
index 0000000..609a1e8
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RDataResizeExtension.java
@@ -0,0 +1,27 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data.impl;
+
+import org.eclipse.statet.rj.data.RStore;
+
+
+public interface RDataResizeExtension<P> extends RStore<P> {
+	
+	void remove(int idx);
+	void remove(int[] idxs);
+	void insertNA(int idx);
+	void insertNA(int[] idxs);
+	
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/REnvironmentImpl.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/REnvironmentImpl.java
new file mode 100644
index 0000000..79ef42a
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/REnvironmentImpl.java
@@ -0,0 +1,281 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data.impl;
+
+import java.io.IOException;
+
+import org.eclipse.statet.rj.data.RCharacterStore;
+import org.eclipse.statet.rj.data.REnvironment;
+import org.eclipse.statet.rj.data.RJIO;
+import org.eclipse.statet.rj.data.RList;
+import org.eclipse.statet.rj.data.RObject;
+import org.eclipse.statet.rj.data.RObjectFactory;
+import org.eclipse.statet.rj.data.RStore;
+
+
+public class REnvironmentImpl extends AbstractRObject
+		implements REnvironment, ExternalizableRObject {
+	
+	
+	private byte specialType;
+	
+	private String className1;
+	
+	private String environmentName;
+	private long handle;
+	
+	private int length;
+	private RObject[] components;
+	
+	private RCharacter32Store namesAttribute;
+	
+	
+	protected REnvironmentImpl(final String name, final long handle,
+			final RObject[] initialComponents, String[] initialNames, final int length,
+			final byte specialType, final String className1) {
+		this.environmentName= name;
+		this.handle= handle;
+		this.components= initialComponents;
+		this.length= length;
+		if (initialNames == null) {
+			initialNames= new String[length];
+		}
+		this.namesAttribute= new RCharacter32Store(initialNames, length);
+		this.specialType= specialType;
+		this.className1= className1;
+	}
+	
+	public REnvironmentImpl(final RJIO io, final RObjectFactory factory) throws IOException {
+		readExternal(io, factory);
+	}
+	
+	public void readExternal(final RJIO io, final RObjectFactory factory) throws IOException {
+		//-- options
+		final int options= io.readInt();
+		//-- special attributes
+		this.specialType= (byte) ((options >>> 24) & 0xff);
+		this.className1= ((options & RObjectFactory.O_CLASS_NAME) != 0) ?
+				io.readString() : RObject.CLASSNAME_ENVIRONMENT;
+		//-- data
+		this.handle= io.readLong();
+		this.environmentName= io.readString();
+		final int l= this.length= (int) io.readVULong((byte) (options & RObjectFactory.O_LENGTHGRADE_MASK));
+		
+		if ((options & RObjectFactory.O_NO_CHILDREN) != 0) {
+			this.namesAttribute= null;
+			this.components= null;
+		}
+		else {
+			this.namesAttribute= new RUniqueCharacterHash32Store(io, l);
+			this.components= new RObject[l];
+			for (int i= 0; i < l; i++) {
+				this.components[i]= factory.readObject(io);
+			}
+		}
+		//-- attributes
+		if ((options & RObjectFactory.O_WITH_ATTR) != 0) {
+			setAttributes(factory.readAttributeList(io));
+		}
+	}
+	
+	@Override
+	public void writeExternal(final RJIO io, final RObjectFactory factory) throws IOException {
+		final int l= this.length;
+		//-- options
+		int options= io.getVULongGrade(l);
+		options|= (this.specialType << 24);
+		final boolean customClass= !this.className1.equals(RObject.CLASSNAME_ENVIRONMENT);
+		if (customClass) {
+			options |= RObjectFactory.O_CLASS_NAME;
+		}
+		final RList attributes= ((io.flags & RObjectFactory.F_WITH_ATTR) != 0) ? getAttributes() : null;
+		if (attributes != null) {
+			options |= RObjectFactory.O_WITH_ATTR;
+		}
+		if (this.components == null) {
+			options |= RObjectFactory.O_NO_CHILDREN;
+		}
+		io.writeInt(options);
+		//-- special attributes
+		if (customClass) {
+			io.writeString(this.className1);
+		}
+		
+		io.writeLong(this.handle);
+		io.writeString(this.environmentName);
+		io.writeVULong((byte) (options & RObjectFactory.O_LENGTHGRADE_MASK), l);
+		
+		if (this.components != null) {
+			this.namesAttribute.writeExternal(io);
+			//-- data
+			for (int i= 0; i < l; i++) {
+				factory.writeObject(this.components[i], io);
+			}
+		}
+		//-- attributes
+		if (attributes != null) {
+			factory.writeAttributeList(attributes, io);
+		}
+	}
+	
+	
+	@Override
+	public final byte getRObjectType() {
+		return TYPE_ENVIRONMENT;
+	}
+	
+	@Override
+	public String getRClassName() {
+		return this.className1;
+	}
+	
+	
+	@Override
+	public int getSpecialType() {
+		return this.specialType;
+	}
+	
+	@Override
+	public String getEnvironmentName() {
+		return this.environmentName;
+	}
+	
+	@Override
+	public long getHandle() {
+		return this.handle;
+	}
+	
+	
+	@Override
+	public long getLength() {
+		return this.length;
+	}
+	
+	@Override
+	public RCharacterStore getNames() {
+		return this.namesAttribute;
+	}
+	
+	@Override
+	public String getName(final int idx) {
+		return this.namesAttribute.getChar(idx);
+	}
+	
+	@Override
+	public String getName(final long idx) {
+		return this.namesAttribute.getChar(idx);
+	}
+	
+	@Override
+	public RObject get(final int idx) {
+		return this.components[idx];
+	}
+	
+	@Override
+	public RObject get(final long idx) {
+		if (idx < 0 || idx >= Integer.MAX_VALUE) {
+			throw new IndexOutOfBoundsException(Long.toString(idx));
+		}
+		return this.components[(int) idx];
+	}
+	
+	@Override
+	public RObject get(final String name) {
+		final int idx= this.namesAttribute.indexOf(name, 0);
+		if (idx >= 0) {
+			return this.components[idx];
+		}
+		return null;
+	}
+	
+	public RObject[] toArray() {
+		final RObject[] array= new RObject[this.length];
+		System.arraycopy(this.components, 0, array, 0, this.length);
+		return array;
+	}
+	
+	@Override
+	public RStore<?> getData() {
+		return null;
+	}
+	
+	public boolean set(final int idx, final RObject component) {
+		this.components[idx]= component;
+		return true;
+	}
+	
+	public boolean set(final String name, final RObject component) {
+		if (component == null) {
+			throw new NullPointerException();
+		}
+		final int idx= this.namesAttribute.indexOf(name, 0);
+		if (idx >= 0) {
+			this.components[idx]= component;
+			return true;
+		}
+		return false;
+	}
+	
+	public void insert(final int idx, final String name, final RObject component) {
+		if (component == null) {
+			throw new NullPointerException();
+		}
+		final int[] idxs= new int[] { idx };
+		this.components= prepareInsert(this.components, this.length, idxs);
+		this.length++;
+		if (name == null) {
+			this.namesAttribute.insertNA(idxs);
+		}
+		else {
+			this.namesAttribute.insertChar(idx, name);
+		}
+	}
+	
+	public void add(final String name, final RObject component) {
+		insert(this.length, name, component);
+	}
+	
+	public void remove(final int idx) {
+		final int[] idxs= new int[] { idx };
+		this.components= remove(this.components, this.length, idxs);
+		this.length--;
+		this.namesAttribute.remove(idxs);
+	}
+	
+	
+	public boolean containsName(final String name) {
+		return (this.namesAttribute.indexOf(name) >= 0);
+	}
+	
+	
+	@Override
+	public String toString() {
+		final StringBuilder sb= new StringBuilder();
+		sb.append("RObject type=REnvironment, class=").append(getRClassName());
+		sb.append("\n\tlength=").append(this.length);
+		if (this.components != null) {
+			sb.append("\n\tdata: ");
+			for (int i= 0; i < this.length; i++) {
+				sb.append("\n$").append(this.namesAttribute.getChar(i)).append("\n");
+				sb.append(this.components[i]);
+			}
+		}
+		else {
+			sb.append("\n<NODATA/>");
+		}
+		return sb.toString();
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RFactor32Store.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RFactor32Store.java
new file mode 100644
index 0000000..b0ebb08
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RFactor32Store.java
@@ -0,0 +1,421 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data.impl;
+
+import java.io.Externalizable;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import java.util.Arrays;
+
+import org.eclipse.statet.rj.data.RCharacterStore;
+import org.eclipse.statet.rj.data.RJIO;
+import org.eclipse.statet.rj.data.RStore;
+
+
+/**
+ * This implementation is limited to length of 2<sup>31</sup>-1.
+ */
+public class RFactor32Store extends AbstractFactorStore
+		implements RDataResizeExtension<Integer>, ExternalizableRStore, Externalizable {
+	
+	
+	private int length;
+	
+	protected int[] codes;
+	
+	protected RCharacter32Store codeLabels;
+	
+	
+	public RFactor32Store(final int length, final boolean isOrdered, final String[] levelLabels) {
+		if (levelLabels == null) {
+			throw new NullPointerException();
+		}
+		this.length= length;
+		this.isOrdered= isOrdered;
+		this.codes= new int[length];
+		Arrays.fill(this.codes, NA_integer_INT);
+		this.codeLabels= new RUniqueCharacter32Store(levelLabels);
+	}
+	
+	public RFactor32Store(final int[] codes, final boolean isOrdered, final String[] levelLabels) {
+		if (codes == null || levelLabels == null) {
+			throw new NullPointerException();
+		}
+		this.length= codes.length;
+		this.isOrdered= isOrdered;
+		this.codes= codes;
+		this.codeLabels= new RUniqueCharacter32Store(levelLabels);
+	}
+	
+	
+	public RFactor32Store(final RJIO io, final int length) throws IOException {
+		this.length= length;
+		this.isOrdered= io.readBoolean();
+		this.codes= io.readIntData(new int[length], length);
+		this.codeLabels= readLabels(io, io.readInt());
+	}
+	protected RCharacter32Store readLabels(final RJIO io, final int l) throws IOException {
+		return new RUniqueCharacter32Store(io, l);
+	}
+	
+	@Override
+	public void writeExternal(final RJIO io) throws IOException {
+		io.writeBoolean(this.isOrdered);
+		io.writeIntData(this.codes, this.length);
+		io.writeInt(this.codeLabels.length());
+		this.codeLabels.writeExternal(io);
+	}
+	
+	@Override
+	public void readExternal(final ObjectInput in) throws IOException {
+		this.isOrdered= in.readBoolean();
+		this.length= in.readInt();
+		this.codes= new int[this.length];
+		for (int i= 0; i < this.length; i++) {
+			this.codes[i]= in.readInt();
+		}
+		this.codeLabels= new RUniqueCharacter32Store();
+		this.codeLabels.readExternal(in);
+	}
+	
+	@Override
+	public void writeExternal(final ObjectOutput out) throws IOException {
+		out.writeBoolean(this.isOrdered);
+		out.writeInt(this.length);
+		for (int i= 0; i < this.length; i++) {
+			out.writeInt(this.codes[i]);
+		}
+		this.codeLabels.writeExternal(out);
+	}
+	
+	
+	@Override
+	protected final boolean isStructOnly() {
+		return false;
+	}
+	
+	
+	protected final int length() {
+		return this.length;
+	}
+	
+	@Override
+	public final long getLength() {
+		return this.length;
+	}
+	
+	@Override
+	public boolean isNA(final int idx) {
+		return (this.codes[idx] <= 0);
+	}
+	
+	@Override
+	public boolean isNA(final long idx) {
+		if (idx < 0 || idx >= length()) {
+			throw new IndexOutOfBoundsException(Long.toString(idx));
+		}
+		return (this.codes[(int) idx] <= 0);
+	}
+	
+	@Override
+	public void setNA(final int idx) {
+		this.codes[idx]= NA_integer_INT;
+	}
+	
+	@Override
+	public void setNA(final long idx) {
+		if (idx < 0 || idx >= length()) {
+			throw new IndexOutOfBoundsException(Long.toString(idx));
+		}
+		this.codes[(int) idx]= NA_integer_INT;
+	}
+	
+	@Override
+	public boolean isMissing(final int idx) {
+		return (this.codes[idx] <= 0);
+	}
+	
+	@Override
+	public boolean isMissing(final long idx) {
+		if (idx < 0 || idx >= length()) {
+			throw new IndexOutOfBoundsException(Long.toString(idx));
+		}
+		return (this.codes[(int) idx] <= 0);
+	}
+	
+	@Override
+	public int getInt(final int idx) {
+		return this.codes[idx];
+	}
+	
+	@Override
+	public int getInt(final long idx) {
+		if (idx < 0 || idx >= length()) {
+			throw new IndexOutOfBoundsException(Long.toString(idx));
+		}
+		return this.codes[(int) idx];
+	}
+	
+	@Override
+	public void setInt(final int idx, final int code) {
+		if (code <= 0 || code > this.codeLabels.length()) {
+			throw new IllegalArgumentException();
+		}
+		this.codes[idx]= code;
+	}
+	
+	@Override
+	public void setInt(final long idx, final int code) {
+		if (code <= 0 || code > this.codeLabels.length()) {
+			throw new IllegalArgumentException();
+		}
+		if (idx < 0 || idx >= length()) {
+			throw new IndexOutOfBoundsException(Long.toString(idx));
+		}
+		this.codes[(int) idx]= code;
+	}
+	
+	@Override
+	public String getChar(final int idx) {
+		final int code= this.codes[idx];
+		return (code > 0) ? this.codeLabels.getChar(code - 1): null;
+	}
+	
+	@Override
+	public String getChar(final long idx) {
+		if (idx < 0 || idx >= length()) {
+			throw new IndexOutOfBoundsException(Long.toString(idx));
+		}
+		final int code= this.codes[(int) idx];
+		return (code > 0) ? this.codeLabels.getChar(code - 1): null;
+	}
+	
+	@Override
+	public void setChar(final int idx, final String data) {
+		final int code= this.codeLabels.indexOf(data, 0) + 1;
+		if (code <= 0) {
+			throw new IllegalArgumentException();
+		}
+		this.codes[idx]= code;
+	}
+	
+	@Override
+	public void setChar(final long idx, final String data) {
+		final int code= this.codeLabels.indexOf(data, 0) + 1;
+		if (code <= 0) {
+			throw new IllegalArgumentException();
+		}
+		if (idx < 0 || idx >= length()) {
+			throw new IndexOutOfBoundsException(Long.toString(idx));
+		}
+		this.codes[(int) idx]= code;
+	}
+	
+	
+	private void prepareInsert(final int[] idxs) {
+		this.codes= prepareInsert(this.codes, this.length, idxs);
+		this.length+= idxs.length;
+	}
+	
+	public void insertChar(final int idx, final String data) {
+		final int code= this.codeLabels.indexOf(data, 0) + 1;
+		if (code <= 0) {
+			throw new IllegalArgumentException();
+		}
+		prepareInsert(new int[] { idx });
+		this.codes[idx]= code;
+	}
+	
+	@Override
+	public void insertNA(final int idx) {
+		prepareInsert(new int[] { idx });
+		this.codes[idx]= NA_integer_INT;
+	}
+	
+	@Override
+	public void insertNA(final int[] idxs) {
+		prepareInsert(idxs);
+		for (int idx= 0; idx < idxs.length; idx++) {
+			this.codes[idx]= NA_integer_INT;
+		}
+	}
+	
+	@Override
+	public void remove(final int idx) {
+		this.codes= remove(this.codes, this.length, new int[] { idx });
+		this.length--;
+	}
+	
+	@Override
+	public void remove(final int[] idxs) {
+		this.codes= remove(this.codes, this.length, idxs);
+		this.length-= idxs.length;
+	}
+	
+	
+	@Override
+	public RCharacterStore getLevels() {
+		return this.codeLabels;
+	}
+	
+	@Override
+	public int getLevelCount() {
+		return this.codeLabels.length();
+	}
+	
+	public void addLevel(final String label) {
+		insertLevel(this.codes.length, label);
+	}
+	
+	public void insertLevel(final int position, final String label) {
+		this.codeLabels.insertChar(position, label);
+		if (position < this.codeLabels.getLength()-1) {
+			final int length= length();
+			for (int i= 0; i < length; i++) {
+				if (this.codes[i] >= position) {
+					this.codes[i]++;
+				}
+			}
+		}
+	}
+	
+	public void renameLevel(final String oldLabel, final String newLabel) {
+		final int code= this.codeLabels.indexOf(oldLabel, 0) + 1;
+		if (code <= 0) {
+			throw new IllegalArgumentException();
+		}
+		this.codeLabels.setChar(code - 1, newLabel);
+	}
+	
+	public void removeLevel(final String label) {
+		final int code= this.codeLabels.indexOf(label, 0) + 1;
+		if (code <= 0) {
+			throw new IllegalArgumentException();
+		}
+		this.codeLabels.remove(code - 1);
+		final int length= length();
+		for (int i= 0; i < length; i++) {
+			if (this.codes[i] == code) {
+				this.codes[i]= NA_integer_INT;
+			}
+			else if (this.codes[i] > code) {
+				this.codes[i]--;
+			}
+		}
+	}
+	
+	@Override
+	public RCharacterStore toCharacterData() {
+		final String[] data= new String[length()];
+		final int[] ints= this.codes;
+		for (int i= 0; i < data.length; i++) {
+			final int code= ints[i];
+			if (code > 0) {
+				data[i]= this.codeLabels.getChar(this.codes[i] - 1);
+			}
+		}
+		return new RCharacter32Store(data);
+	}
+	
+	
+	@Override
+	public Integer get(final int idx) {
+		if (idx < 0 || idx >= length()) {
+			throw new IndexOutOfBoundsException(Long.toString(idx));
+		}
+		final int code= this.codes[idx];
+		return (code > 0) ?
+				Integer.valueOf(code) :
+				null;
+	}
+	
+	@Override
+	public Integer get(final long idx) {
+		if (idx < 0 || idx >= length()) {
+			throw new IndexOutOfBoundsException(Long.toString(idx));
+		}
+		final int code= this.codes[(int) idx];
+		return (code > 0) ?
+				Integer.valueOf(code) :
+				null;
+	}
+	
+	@Override
+	public Integer[] toArray() {
+		final Integer[] array= new Integer[length()];
+		final int[] ints= this.codes;
+		for (int i= 0; i < array.length; i++) {
+			final int code= ints[i];
+			if (code > 0) {
+				array[i]= Integer.valueOf(code);
+			}
+		}
+		return array;
+	}
+	
+	
+	@Override
+	public long indexOfNA(long fromIdx) {
+		if (fromIdx >= Integer.MAX_VALUE) {
+			return -1;
+		}
+		if (fromIdx < 0) {
+			fromIdx= 0;
+		}
+		final int l= length();
+		final int[] ints= this.codes;
+		for (int i= (int) fromIdx; i < l; i++) {
+			if (ints[i] == NA_integer_INT) {
+				return i;
+			}
+		}
+		return -1;
+	}
+	
+	@Override
+	public long indexOf(final int code, long fromIdx) {
+		if (fromIdx >= Integer.MAX_VALUE
+				|| code <= 0 || code > this.codeLabels.length()) {
+			return -1;
+		}
+		if (fromIdx < 0) {
+			fromIdx= 0;
+		}
+		final int l= length();
+		final int[] ints= this.codes;
+		for (int i= (int) fromIdx; i < l; i++) {
+			if (ints[i] == code) {
+				return i;
+			}
+		}
+		return -1;
+	}
+	
+	@Override
+	public long indexOf(final String character, final long fromIdx) {
+		final int code= ((character != null) ?
+				this.codeLabels.indexOf(character, 0) :
+				this.codeLabels.indexOfNA(0) ) + 1;
+		return indexOf(code, fromIdx);
+	}
+	
+	
+	@Override
+	public boolean allEqual(final RStore<?> other) {
+		throw new UnsupportedOperationException("Not yet implemented");
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RFactorFix64Store.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RFactorFix64Store.java
new file mode 100644
index 0000000..74302a6
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RFactorFix64Store.java
@@ -0,0 +1,303 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data.impl;
+
+import java.io.IOException;
+import java.util.Arrays;
+
+import org.eclipse.statet.rj.data.RCharacterStore;
+import org.eclipse.statet.rj.data.RJIO;
+import org.eclipse.statet.rj.data.RStore;
+
+
+public class RFactorFix64Store extends AbstractFactorStore
+		implements ExternalizableRStore {
+	
+	
+	public static final int SEGMENT_LENGTH= DEFAULT_LONG_DATA_SEGMENT_LENGTH;
+	
+	
+	private final long length;
+	
+	protected final int[][] codes;
+	
+	protected final RCharacter32Store codeLabels;
+	
+	
+	public RFactorFix64Store(final long length, final boolean isOrdered, final String[] levelLabels) {
+		this.length= length;
+		this.isOrdered= isOrdered;
+		this.codes= new2dIntArray(length, SEGMENT_LENGTH);
+		Arrays.fill(this.codes, NA_integer_INT);
+		this.codeLabels= new RUniqueCharacter32Store(levelLabels);
+	}
+	
+	public RFactorFix64Store(final int[][] codes, final boolean isOrdered, final String[] levelLabels) {
+		this.length= check2dArrayLength(codes, SEGMENT_LENGTH);
+		this.isOrdered= isOrdered;
+		this.codes= codes;
+		this.codeLabels= new RUniqueCharacter32Store(levelLabels);
+	}
+	
+	
+	public RFactorFix64Store(final RJIO io, final long length) throws IOException {
+		this.length= length;
+		this.isOrdered= io.readBoolean();
+		this.codes= new2dIntArray(length, SEGMENT_LENGTH);
+		for (int i= 0; i < this.codes.length; i++) {
+			io.readIntData(this.codes[i], this.codes[i].length);
+		}
+		this.codeLabels= readLabels(io, io.readInt());
+	}
+	protected RCharacter32Store readLabels(final RJIO io, final int l) throws IOException {
+		return new RUniqueCharacter32Store(io, l);
+	}
+	
+	@Override
+	public void writeExternal(final RJIO io) throws IOException {
+		io.writeBoolean(this.isOrdered);
+		for (int i= 0; i < this.codes.length; i++) {
+			io.writeIntData(this.codes[i], this.codes[i].length);
+		}
+		io.writeInt(this.codeLabels.length());
+		this.codeLabels.writeExternal(io);
+	}
+	
+	
+	@Override
+	protected final boolean isStructOnly() {
+		return false;
+	}
+	
+	
+	@Override
+	public final long getLength() {
+		return this.length;
+	}
+	
+	@Override
+	public boolean isNA(final int idx) {
+		return (this.codes[idx / SEGMENT_LENGTH][idx % SEGMENT_LENGTH] <= 0);
+	}
+	
+	@Override
+	public boolean isNA(final long idx) {
+		return (this.codes[(int) (idx / SEGMENT_LENGTH)][(int) (idx % SEGMENT_LENGTH)] <= 0);
+	}
+	
+	@Override
+	public void setNA(final int idx) {
+		this.codes[idx / SEGMENT_LENGTH][idx % SEGMENT_LENGTH] =
+				NA_integer_INT;
+	}
+	
+	@Override
+	public void setNA(final long idx) {
+		this.codes[(int) (idx / SEGMENT_LENGTH)][(int) (idx % SEGMENT_LENGTH)] =
+				NA_integer_INT;
+	}
+	
+	@Override
+	public boolean isMissing(final int idx) {
+		return (this.codes[idx / SEGMENT_LENGTH][idx % SEGMENT_LENGTH] <= 0);
+	}
+	
+	@Override
+	public boolean isMissing(final long idx) {
+		return (this.codes[(int) (idx / SEGMENT_LENGTH)][(int) (idx % SEGMENT_LENGTH)] <= 0);
+	}
+	
+	@Override
+	public int getInt(final int idx) {
+		return this.codes[idx / SEGMENT_LENGTH][idx % SEGMENT_LENGTH];
+	}
+	
+	@Override
+	public int getInt(final long idx) {
+		return this.codes[(int) (idx / SEGMENT_LENGTH)][(int) (idx % SEGMENT_LENGTH)];
+	}
+	
+	@Override
+	public void setInt(final int idx, final int code) {
+		if (code <= 0 || code > this.codeLabels.length()) {
+			throw new IllegalArgumentException();
+		}
+		this.codes[idx / SEGMENT_LENGTH][idx % SEGMENT_LENGTH]= code;
+	}
+	
+	@Override
+	public void setInt(final long idx, final int code) {
+		if (code <= 0 || code > this.codeLabels.length()) {
+			throw new IllegalArgumentException();
+		}
+		this.codes[(int) (idx / SEGMENT_LENGTH)][(int) (idx % SEGMENT_LENGTH)]= code;
+	}
+	
+	@Override
+	public String getChar(final int idx) {
+		final int code= this.codes[idx / SEGMENT_LENGTH][idx % SEGMENT_LENGTH];
+		return (code > 0) ? this.codeLabels.getChar(code - 1): null;
+	}
+	
+	@Override
+	public String getChar(final long idx) {
+		final int code= this.codes[(int) (idx / SEGMENT_LENGTH)][(int) (idx % SEGMENT_LENGTH)];
+		return (code > 0) ? this.codeLabels.getChar(code - 1): null;
+	}
+	
+	@Override
+	public void setChar(final int idx, final String data) {
+		final int code= this.codeLabels.indexOf(data, 0) + 1;
+		if (code <= 0) {
+			throw new IllegalArgumentException();
+		}
+		this.codes[idx / SEGMENT_LENGTH][idx % SEGMENT_LENGTH]= code;
+	}
+	
+	@Override
+	public void setChar(final long idx, final String data) {
+		final int code= this.codeLabels.indexOf(data, 0) + 1;
+		if (code <= 0) {
+			throw new IllegalArgumentException();
+		}
+		this.codes[(int) (idx / SEGMENT_LENGTH)][(int) (idx % SEGMENT_LENGTH)]= code;
+	}
+	
+	
+	@Override
+	public RCharacterStore getLevels() {
+		return this.codeLabels;
+	}
+	
+	@Override
+	public int getLevelCount() {
+		return this.codeLabels.length();
+	}
+	
+	@Override
+	public RCharacterStore toCharacterData() {
+		final String[][] data= new2dStringArray(this.length, SEGMENT_LENGTH);
+		for (int i= 0; i < data.length; i++) {
+			final String[] chars= data[i];
+			final int[] ints= this.codes[i];
+			for (int j= 0; j < ints.length; j++) {
+				final int code= ints[j];
+				if (code > 0) {
+					chars[j]= this.codeLabels.getChar(code - 1);
+				}
+			}
+		}
+		return new RCharacterFix64Store(data);
+	}
+	
+	
+	@Override
+	public Integer get(final int idx) {
+		if (idx < 0 || idx >= this.length) {
+			throw new IndexOutOfBoundsException(Long.toString(idx));
+		}
+		final int code= this.codes[idx / SEGMENT_LENGTH][idx % SEGMENT_LENGTH];
+		return (code > 0) ?
+				Integer.valueOf(code) :
+				null;
+	}
+	
+	@Override
+	public Integer get(final long idx) {
+		if (idx < 0 || idx >= this.length) {
+			throw new IndexOutOfBoundsException(Long.toString(idx));
+		}
+		final int code= this.codes[(int) (idx / SEGMENT_LENGTH)][(int) (idx % SEGMENT_LENGTH)];
+		return (code > 0) ?
+				Integer.valueOf(code) :
+				null;
+	}
+	
+	@Override
+	public Integer[] toArray() {
+		final int l= checkToArrayLength();
+		final Integer[] array= new Integer[l];
+		int k= 0;
+		for (int i= 0; i < this.codes.length; i++, k++) {
+			final int[] ints= this.codes[i];
+			for (int j= 0; j < ints.length; j++) {
+				final int code= ints[j];
+				if (code > 0) {
+					array[k]= Integer.valueOf(code);
+				}
+			}
+		}
+		return array;
+	}
+	
+	
+	@Override
+	public long indexOfNA(long fromIdx) {
+		if (fromIdx < 0) {
+			fromIdx= 0;
+		}
+		int i= (int) (fromIdx / SEGMENT_LENGTH);
+		int j= (int) (fromIdx % SEGMENT_LENGTH);
+		while (i < this.codes.length) {
+			final int[] ints= this.codes[i];
+			while (j < ints.length) {
+				if (ints[i] == NA_integer_INT) {
+					return (i * (long) SEGMENT_LENGTH) + j;
+				}
+			}
+			i++;
+			j= 0;
+		}
+		return -1;
+	}
+	
+	@Override
+	public long indexOf(final int code, long fromIdx) {
+		if (code <= 0 || code > this.codeLabels.length()) {
+			return -1;
+		}
+		if (fromIdx < 0) {
+			fromIdx= 0;
+		}
+		int i= (int) (fromIdx / SEGMENT_LENGTH);
+		int j= (int) (fromIdx % SEGMENT_LENGTH);
+		while (i < this.codes.length) {
+			final int[] ints= this.codes[i];
+			while (j < ints.length) {
+				if (ints[i] == code) {
+					return (i * (long) SEGMENT_LENGTH) + j;
+				}
+			}
+			i++;
+			j= 0;
+		}
+		return -1;
+	}
+	
+	@Override
+	public long indexOf(final String character, final long fromIdx) {
+		final int code= ((character != null) ?
+				this.codeLabels.indexOf(character, 0) :
+				this.codeLabels.indexOfNA(0) ) + 1;
+		return indexOf(code, fromIdx);
+	}
+	
+	
+	@Override
+	public boolean allEqual(final RStore<?> other) {
+		throw new UnsupportedOperationException("Not yet implemented");
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RFactorStructStore.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RFactorStructStore.java
new file mode 100644
index 0000000..43e79ee
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RFactorStructStore.java
@@ -0,0 +1,146 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data.impl;
+
+import org.eclipse.statet.rj.data.RCharacterStore;
+import org.eclipse.statet.rj.data.RFactorStore;
+import org.eclipse.statet.rj.data.RStore;
+
+
+public class RFactorStructStore extends AbstractFactorStore {
+	
+	
+	public static RFactorStructStore addLevels(final RFactorStore store, final RCharacterStore levels) {
+		final long levelCount= levels.getLength();
+		if (levelCount > Integer.MAX_VALUE) {
+			throw new IllegalArgumentException("levelCount > 2^31-1");
+		}
+		return new RFactorStructStore(store.isOrdered(), (int) levels.getLength()) {
+			@Override
+			public RCharacterStore getLevels() {
+				return levels;
+			}
+		};
+	}
+	
+	
+	private final int levelCount;
+	
+	
+	public RFactorStructStore(final boolean isOrdered, final int levelCount) {
+		this.isOrdered= isOrdered;
+		this.levelCount= levelCount;
+	}
+	
+	
+	@Override
+	protected final boolean isStructOnly() {
+		return true;
+	}
+	
+	
+	@Override
+	public final long getLength() {
+		return -1;
+	}
+	
+	@Override
+	public boolean isNA(final int idx) {
+		throw new UnsupportedOperationException();
+	}
+	
+	@Override
+	public boolean isNA(final long idx) {
+		throw new UnsupportedOperationException();
+	}
+	
+	@Override
+	public boolean isMissing(final int idx) {
+		throw new UnsupportedOperationException();
+	}
+	
+	@Override
+	public boolean isMissing(final long idx) {
+		throw new UnsupportedOperationException();
+	}
+	
+	@Override
+	public final int getLevelCount() {
+		return this.levelCount;
+	}
+	
+	@Override
+	public RCharacterStore getLevels() {
+		throw new UnsupportedOperationException();
+	}
+	
+	public void insertLevel(final int position, final String label) {
+		throw new UnsupportedOperationException();
+	}
+	
+	public void removeLevel(final String label) {
+		throw new UnsupportedOperationException();
+	}
+	
+	public void renameLevel(final String oldLabel, final String newLabel) {
+		throw new UnsupportedOperationException();
+	}
+	
+	@Override
+	public RCharacterStore toCharacterData() {
+		return new RCharacterStructStore();
+	}
+	
+	@Override
+	public Integer get(final int idx) {
+		throw new UnsupportedOperationException();
+	}
+	
+	@Override
+	public Integer get(final long idx) {
+		throw new UnsupportedOperationException();
+	}
+	
+	@Override
+	public final Integer[] toArray() {
+		throw new UnsupportedOperationException();
+	}
+	
+	
+	@Override
+	public long indexOfNA(final long fromIdx) {
+		throw new UnsupportedOperationException();
+	}
+	
+	@Override
+	public long indexOf(final int integer, final long fromIdx) {
+		throw new UnsupportedOperationException();
+	}
+	
+	@Override
+	public long indexOf(final String character, final long fromIdx) {
+		throw new UnsupportedOperationException();
+	}
+	
+	
+	@Override
+	public boolean allEqual(final RStore<?> other) {
+		return (FACTOR == other.getStoreType()
+				&& this.isOrdered == ((RFactorStore) other).isOrdered()
+				&& this.levelCount == ((RFactorStore) other).getLevelCount()
+				&& -1 == other.getLength() );
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RFunctionImpl.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RFunctionImpl.java
new file mode 100644
index 0000000..c06e140
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RFunctionImpl.java
@@ -0,0 +1,84 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data.impl;
+
+import java.io.IOException;
+
+import org.eclipse.statet.rj.data.RFunction;
+import org.eclipse.statet.rj.data.RJIO;
+import org.eclipse.statet.rj.data.RObjectFactory;
+import org.eclipse.statet.rj.data.RStore;
+
+
+public class RFunctionImpl extends AbstractRObject
+		implements RFunction, ExternalizableRObject {
+	
+	
+	private String headerSource;
+	private String bodySource;
+	
+	
+	public RFunctionImpl(final String header) {
+		this.headerSource= header;
+	}
+	
+	public RFunctionImpl(final RJIO io, final RObjectFactory factory) throws IOException {
+		readExternal(io, factory);
+	}
+	
+	public void readExternal(final RJIO io, final RObjectFactory factory) throws IOException {
+		/*final int options =*/ io.readInt();
+		this.headerSource= io.readString();
+	}
+	
+	@Override
+	public void writeExternal(final RJIO io, final RObjectFactory factory) throws IOException {
+		io.writeInt(/*options*/ 0);
+		io.writeString(this.headerSource);
+	}
+	
+	
+	@Override
+	public byte getRObjectType() {
+		return TYPE_FUNCTION;
+	}
+	
+	@Override
+	public String getRClassName() {
+		return "function";
+	}
+	
+	
+	@Override
+	public long getLength() {
+		return 0;
+	}
+	
+	@Override
+	public String getHeaderSource() {
+		return this.headerSource;
+	}
+	
+	@Override
+	public String getBodySource() {
+		return this.bodySource;
+	}
+	
+	@Override
+	public RStore<?> getData() {
+		return null;
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RInteger32Store.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RInteger32Store.java
new file mode 100644
index 0000000..054bb79
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RInteger32Store.java
@@ -0,0 +1,306 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data.impl;
+
+import java.io.Externalizable;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+
+import org.eclipse.statet.rj.data.RJIO;
+
+
+/**
+ * This implementation is limited to length of 2<sup>31</sup>-1.
+ */
+public class RInteger32Store extends AbstractIntegerStore
+		implements RDataResizeExtension<Integer>, ExternalizableRStore, Externalizable {
+	
+	
+	private int length;
+	
+	protected int[] intValues;
+	
+	
+	public RInteger32Store() {
+		this.length= 0;
+		this.intValues= EMPTY_INT_ARRAY;
+	}
+	
+	public RInteger32Store(final int length) {
+		this.intValues= new int[length];
+		this.length= length;
+	}
+	
+	public RInteger32Store(final int[] values) {
+		this.length= values.length;
+		this.intValues= values;
+	}
+	
+	public RInteger32Store(final int[] values, final int length) {
+		this.length= length;
+		this.intValues= values;
+	}
+	
+	public RInteger32Store(final int[] values, final int[] naIdxs) {
+		this.length= values.length;
+		this.intValues= values;
+		if (naIdxs != null) {
+			for (int i= 0; i < naIdxs.length; i++) {
+				this.intValues[naIdxs[i]]= NA_integer_INT;
+			}
+		}
+	}
+	
+	
+	public RInteger32Store(final RJIO io, final int length) throws IOException {
+		this.length= length;
+		this.intValues= io.readIntData(new int[length], length);
+	}
+	
+	@Override
+	public void writeExternal(final RJIO io) throws IOException {
+		io.writeIntData(this.intValues, this.length);
+	}
+	
+	@Override
+	public void readExternal(final ObjectInput in) throws IOException {
+		this.length= in.readInt();
+		this.intValues= new int[this.length];
+		for (int i= 0; i < this.length; i++) {
+			this.intValues[i]= in.readInt();
+		}
+	}
+	
+	@Override
+	public void writeExternal(final ObjectOutput out) throws IOException {
+		out.writeInt(this.length);
+		for (int i= 0; i < this.length; i++) {
+			out.writeInt(this.intValues[i]);
+		}
+	}
+	
+	
+	@Override
+	protected final boolean isStructOnly() {
+		return false;
+	}
+	
+	
+	protected final int length() {
+		return this.length;
+	}
+	
+	@Override
+	public final long getLength() {
+		return this.length;
+	}
+	
+	@Override
+	public boolean isNA(final int idx) {
+		return (this.intValues[idx] == NA_integer_INT);
+	}
+	
+	@Override
+	public boolean isNA(final long idx) {
+		if (idx < 0 || idx >= length()) {
+			throw new IndexOutOfBoundsException(Long.toString(idx));
+		}
+		return (this.intValues[(int) idx] == NA_integer_INT);
+	}
+	
+	@Override
+	public void setNA(final int idx) {
+		this.intValues[idx]= NA_integer_INT;
+	}
+	
+	@Override
+	public void setNA(final long idx) {
+		if (idx < 0 || idx >= length()) {
+			throw new IndexOutOfBoundsException(Long.toString(idx));
+		}
+		this.intValues[(int) idx]= NA_integer_INT;
+	}
+	
+	@Override
+	public boolean isMissing(final int idx) {
+		return (this.intValues[idx] == NA_integer_INT);
+	}
+	
+	@Override
+	public boolean isMissing(final long idx) {
+		if (idx < 0 || idx >= length()) {
+			throw new IndexOutOfBoundsException(Long.toString(idx));
+		}
+		return (this.intValues[(int) idx] == NA_integer_INT);
+	}
+	
+	@Override
+	public int getInt(final int idx) {
+		return this.intValues[idx];
+	}
+	
+	@Override
+	public int getInt(final long idx) {
+		if (idx < 0 || idx >= length()) {
+			throw new IndexOutOfBoundsException(Long.toString(idx));
+		}
+		return this.intValues[(int) idx];
+	}
+	
+	@Override
+	public void setInt(final int idx, final int value) {
+//		assert (value != NA_integer_INT);
+		this.intValues[idx]= value;
+	}
+	
+	@Override
+	public void setInt(final long idx, final int value) {
+//		assert (value != NA_integer_INT);
+		if (idx < 0 || idx >= length()) {
+			throw new IndexOutOfBoundsException(Long.toString(idx));
+		}
+		this.intValues[(int) idx]= value;
+	}
+	
+	
+	private void prepareInsert(final int[] idxs) {
+		this.intValues= prepareInsert(this.intValues, this.length, idxs);
+		this.length+= idxs.length;
+	}
+	
+	public void insertInt(final int idx, final int value) {
+//		assert (value != NA_integer_INT);
+		prepareInsert(new int[] { idx });
+		this.intValues[idx]= value;
+	}
+	
+	@Override
+	public void insertNA(final int idx) {
+		prepareInsert(new int[] { idx });
+		this.intValues[idx]= NA_integer_INT;
+	}
+	
+	@Override
+	public void insertNA(final int[] idxs) {
+		if (idxs.length == 0) {
+			return;
+		}
+		prepareInsert(idxs);
+		for (int idx= 0; idx < idxs.length; idx++) {
+			this.intValues[idxs[idx]+idx]= NA_integer_INT;
+		}
+	}
+	
+	@Override
+	public void remove(final int idx) {
+		this.intValues= remove(this.intValues, this.length, new int[] { idx });
+		this.length --;
+	}
+	
+	@Override
+	public void remove(final int[] idxs) {
+		this.intValues= remove(this.intValues, this.length, idxs);
+		this.length-= idxs.length;
+	}
+	
+	
+	@Override
+	public Integer get(final int idx) {
+		if (idx < 0 || idx >= length()) {
+			throw new IndexOutOfBoundsException(Long.toString(idx));
+		}
+		final int v= this.intValues[idx];
+		return (v != NA_integer_INT) ?
+				Integer.valueOf(v) : null;
+	}
+	
+	@Override
+	public Integer get(final long idx) {
+		if (idx < 0 || idx >= length()) {
+			throw new IndexOutOfBoundsException(Long.toString(idx));
+		}
+		final int v= this.intValues[(int) idx];
+		return (v != NA_integer_INT) ?
+				Integer.valueOf(v) : null;
+	}
+	
+	@Override
+	public Integer[] toArray() {
+		final Integer[] array= new Integer[length()];
+		final int[] ints= this.intValues;
+		for (int i= 0; i < array.length; i++) {
+			final int v= ints[i];
+			if (v != NA_integer_INT) {
+				array[i]= Integer.valueOf(v);
+			}
+		}
+		return array;
+	}
+	
+	
+	@Override
+	public final long indexOfNA(long fromIdx) {
+		if (fromIdx >= Integer.MAX_VALUE) {
+			return -1;
+		}
+		if (fromIdx < 0) {
+			fromIdx= 0;
+		}
+		final int l= length();
+		final int[] ints= this.intValues;
+		for (int i= (int) fromIdx; i < l; i++) {
+			if (ints[i] == NA_integer_INT) {
+				return i;
+			}
+		}
+		return -1;
+	}
+	
+	@Override
+	public final long indexOf(final int integer, long fromIdx) {
+		if (fromIdx >= Integer.MAX_VALUE
+				|| integer == NA_integer_INT ) {
+			return -1;
+		}
+		if (fromIdx < 0) {
+			fromIdx= 0;
+		}
+		final int l= length();
+		final int[] ints= this.intValues;
+		for (int i= (int) fromIdx; i < l; i++) {
+			if (ints[i] == integer) {
+				return i;
+			}
+		}
+		return -1;
+	}
+	
+	
+	public void appendTo(final StringBuilder sb) {
+		sb.append('[');
+		final int l= length();
+		if (l > 0) {
+			final int[] ints= this.intValues;
+			for (int i= 0; i < l; i++) {
+				sb.append(ints[i]);
+				sb.append(", ");
+			}
+			sb.delete(sb.length()-2, sb.length());
+		}
+		sb.append(']');
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RIntegerFix64Store.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RIntegerFix64Store.java
new file mode 100644
index 0000000..9339939
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RIntegerFix64Store.java
@@ -0,0 +1,212 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data.impl;
+
+import java.io.IOException;
+
+import org.eclipse.statet.rj.data.RJIO;
+
+
+public class RIntegerFix64Store extends AbstractIntegerStore
+		implements ExternalizableRStore {
+	
+	
+	public static final int SEGMENT_LENGTH= DEFAULT_LONG_DATA_SEGMENT_LENGTH;
+	
+	
+	private final long length;
+	
+	protected final int[][] intValues;
+	
+	
+	public RIntegerFix64Store(final long length) {
+		this.length= length;
+		this.intValues= new2dIntArray(length, SEGMENT_LENGTH);
+	}
+	
+	public RIntegerFix64Store(final int[][] values) {
+		this.length= check2dArrayLength(values, SEGMENT_LENGTH);
+		this.intValues= values;
+	}
+	
+	
+	public RIntegerFix64Store(final RJIO io, final long length) throws IOException {
+		this.length= length;
+		this.intValues= new2dIntArray(length, SEGMENT_LENGTH);
+		for (int i= 0; i < this.intValues.length; i++) {
+			io.readIntData(this.intValues[i], this.intValues[i].length);
+		}
+	}
+	
+	@Override
+	public void writeExternal(final RJIO io) throws IOException {
+		for (int i= 0; i < this.intValues.length; i++) {
+			io.writeIntData(this.intValues[i], this.intValues[i].length);
+		}
+	}
+	
+	
+	@Override
+	protected final boolean isStructOnly() {
+		return false;
+	}
+	
+	
+	@Override
+	public final long getLength() {
+		return this.length;
+	}
+	
+	@Override
+	public boolean isNA(final int idx) {
+		return (this.intValues[idx / SEGMENT_LENGTH][idx % SEGMENT_LENGTH] == NA_integer_INT);
+	}
+	
+	@Override
+	public boolean isNA(final long idx) {
+		return (this.intValues[(int) (idx / SEGMENT_LENGTH)][(int) (idx % SEGMENT_LENGTH)] == NA_integer_INT);
+	}
+	
+	@Override
+	public void setNA(final int idx) {
+		this.intValues[idx / SEGMENT_LENGTH][idx % SEGMENT_LENGTH] =
+				NA_integer_INT;
+	}
+	
+	@Override
+	public void setNA(final long idx) {
+		this.intValues[(int) (idx / SEGMENT_LENGTH)][(int) (idx % SEGMENT_LENGTH)] =
+				NA_integer_INT;
+	}
+	
+	@Override
+	public boolean isMissing(final int idx) {
+		return (this.intValues[idx / SEGMENT_LENGTH][idx % SEGMENT_LENGTH] == NA_integer_INT);
+	}
+	
+	@Override
+	public boolean isMissing(final long idx) {
+		return (this.intValues[(int) (idx / SEGMENT_LENGTH)][(int) (idx % SEGMENT_LENGTH)] == NA_integer_INT);
+	}
+	
+	@Override
+	public int getInt(final int idx) {
+		return this.intValues[idx / SEGMENT_LENGTH][idx % SEGMENT_LENGTH];
+	}
+	
+	@Override
+	public int getInt(final long idx) {
+		return this.intValues[(int) (idx / SEGMENT_LENGTH)][(int) (idx % SEGMENT_LENGTH)];
+	}
+	
+	@Override
+	public void setInt(final int idx, final int value) {
+//		assert (value != NA_integer_INT);
+		this.intValues[idx / SEGMENT_LENGTH][idx % SEGMENT_LENGTH] =
+				value;
+	}
+	
+	@Override
+	public void setInt(final long idx, final int value) {
+//		assert (value != NA_integer_INT);
+		this.intValues[(int) (idx / SEGMENT_LENGTH)][(int) (idx % SEGMENT_LENGTH)] =
+				value;
+	}
+	
+	
+	@Override
+	public Integer get(final int idx) {
+		if (idx < 0 || idx >= this.length) {
+			throw new IndexOutOfBoundsException(Long.toString(idx));
+		}
+		final int v= this.intValues[idx / SEGMENT_LENGTH][idx % SEGMENT_LENGTH];
+		return (v != NA_integer_INT) ?
+			Integer.valueOf(v) :
+			null;
+	}
+	
+	@Override
+	public Integer get(final long idx) {
+		if (idx < 0 || idx >= this.length) {
+			throw new IndexOutOfBoundsException(Long.toString(idx));
+		}
+		final int v= this.intValues[(int) (idx / SEGMENT_LENGTH)][(int) (idx % SEGMENT_LENGTH)];
+		return (v != NA_integer_INT) ?
+			Integer.valueOf(v) :
+			null;
+	}
+	
+	@Override
+	public Integer[] toArray() {
+		final int l= checkToArrayLength();
+		final Integer[] array= new Integer[l];
+		int k= 0;
+		for (int i= 0; i < this.intValues.length; i++, k++) {
+			final int[] ints= this.intValues[i];
+			for (int j= 0; j < ints.length; j++) {
+				final int v= ints[j];
+				if (v != NA_integer_INT) {
+					array[k]= Integer.valueOf(v);
+				}
+			}
+		}
+		return array;
+	}
+	
+	
+	@Override
+	public long indexOfNA(long fromIdx) {
+		if (fromIdx < 0) {
+			fromIdx= 0;
+		}
+		int i= (int) (fromIdx / SEGMENT_LENGTH);
+		int j= (int) (fromIdx % SEGMENT_LENGTH);
+		while (i < this.intValues.length) {
+			final int[] ints= this.intValues[i];
+			while (j < ints.length) {
+				if (ints[i] == NA_integer_INT) {
+					return (i * (long) SEGMENT_LENGTH) + j;
+				}
+			}
+			i++;
+			j= 0;
+		}
+		return -1;
+	}
+	
+	@Override
+	public final long indexOf(final int integer, long fromIdx) {
+		if (integer == NA_integer_INT ) {
+			return -1;
+		}
+		if (fromIdx < 0) {
+			fromIdx= 0;
+		}
+		int i= (int) (fromIdx / SEGMENT_LENGTH);
+		int j= (int) (fromIdx % SEGMENT_LENGTH);
+		while (i < this.intValues.length) {
+			final int[] ints= this.intValues[i];
+			while (j < ints.length) {
+				if (ints[i] == integer) {
+					return (i * (long) SEGMENT_LENGTH) + j;
+				}
+			}
+			i++;
+			j= 0;
+		}
+		return -1;
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RIntegerStructStore.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RIntegerStructStore.java
new file mode 100644
index 0000000..8fad89c
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RIntegerStructStore.java
@@ -0,0 +1,96 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data.impl;
+
+import org.eclipse.statet.rj.data.RStore;
+
+
+public class RIntegerStructStore extends AbstractIntegerStore {
+	
+	
+	public RIntegerStructStore() {
+	}
+	
+	
+	@Override
+	protected final boolean isStructOnly() {
+		return true;
+	}
+	
+	
+	@Override
+	public final long getLength() {
+		return -1;
+	}
+	
+	@Override
+	public boolean isNA(final int idx) {
+		throw new UnsupportedOperationException();
+	}
+	
+	@Override
+	public boolean isNA(final long idx) {
+		throw new UnsupportedOperationException();
+	}
+	
+	@Override
+	public boolean isMissing(final int idx) {
+		throw new UnsupportedOperationException();
+	}
+	
+	@Override
+	public boolean isMissing(final long idx) {
+		throw new UnsupportedOperationException();
+	}
+	
+	@Override
+	public Integer get(final int idx) {
+		throw new UnsupportedOperationException();
+	}
+	
+	@Override
+	public Integer get(final long idx) {
+		throw new UnsupportedOperationException();
+	}
+	
+	@Override
+	public final Integer[] toArray() {
+		throw new UnsupportedOperationException();
+	}
+	
+	
+	@Override
+	public long indexOfNA(final long fromIdx) {
+		throw new UnsupportedOperationException();
+	}
+	
+	@Override
+	public long indexOf(final int integer, final long fromIdx) {
+		throw new UnsupportedOperationException();
+	}
+	
+	@Override
+	public long indexOf(final String character, final long fromIdx) {
+		throw new UnsupportedOperationException();
+	}
+	
+	
+	@Override
+	public boolean allEqual(final RStore<?> other) {
+		return (INTEGER == other.getStoreType()
+				&& -1 == other.getLength() );
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RLanguageImpl.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RLanguageImpl.java
new file mode 100644
index 0000000..041887c
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RLanguageImpl.java
@@ -0,0 +1,146 @@
+/*=============================================================================#
+ # Copyright (c) 2010, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data.impl;
+
+import java.io.IOException;
+
+import org.eclipse.statet.rj.data.RJIO;
+import org.eclipse.statet.rj.data.RLanguage;
+import org.eclipse.statet.rj.data.RObjectFactory;
+import org.eclipse.statet.rj.data.RStore;
+
+
+public class RLanguageImpl extends AbstractRObject
+		implements RLanguage, ExternalizableRObject {
+	
+	
+	public static final String getBaseClassname(final byte type) {
+		switch (type) {
+		case NAME:
+			return CLASSNAME_NAME;
+		case CALL:
+			return CLASSNAME_CALL;
+		default:
+			return CLASSNAME_EXPRESSION;
+		}
+	}
+	
+	
+	private byte type;
+	
+	private String className1;
+	
+	private String source;
+	
+	
+	public RLanguageImpl(final byte type, final String source, final String className1) {
+		this.type= type;
+		this.className1= (className1 != null) ? className1 : getBaseClassname(type);
+		this.source= source;
+	}
+	
+	public RLanguageImpl(final byte type, final String className1) {
+		this.type= type;
+		this.className1= (className1 != null) ? className1 : getBaseClassname(type);
+	}
+	
+	public RLanguageImpl(final RJIO io, final RObjectFactory factory) throws IOException {
+		readExternal(io, factory);
+	}
+	
+	public void readExternal(final RJIO io, final RObjectFactory factory) throws IOException {
+		//-- options
+		final int options= io.readInt();
+		//-- special attributes
+		this.type= io.readByte();
+		this.className1= ((options & RObjectFactory.O_CLASS_NAME) != 0) ?
+				io.readString() :
+				getBaseClassname(this.type);
+		//-- data
+		if ((io.flags & RObjectFactory.F_ONLY_STRUCT) == 0) {
+			this.source= io.readString();
+		}
+	}
+	
+	@Override
+	public void writeExternal(final RJIO io, final RObjectFactory factory) throws IOException {
+		int options= 0;
+		if (!this.className1.equals(getBaseClassname(this.type))) {
+			options |= RObjectFactory.O_CLASS_NAME;
+		}
+		io.writeInt(options);
+		io.writeByte(this.type);
+		//-- special attributes
+		if ((options & RObjectFactory.O_CLASS_NAME) != 0) {
+			io.writeString(this.className1);
+		}
+		//-- data
+		if ((io.flags & RObjectFactory.F_ONLY_STRUCT) == 0) {
+			io.writeString(this.source);
+		}
+	}
+	
+	
+	@Override
+	public byte getRObjectType() {
+		return TYPE_LANGUAGE;
+	}
+	
+	@Override
+	public byte getLanguageType() {
+		return this.type;
+	}
+	
+	@Override
+	public String getRClassName() {
+		return this.className1;
+	}
+	
+	
+	@Override
+	public long getLength() {
+		return 0;
+	}
+	
+	@Override
+	public String getSource() {
+		return this.source;
+	}
+	
+	@Override
+	public RStore<?> getData() {
+		return null;
+	}
+	
+	
+	@Override
+	public String toString() {
+		final StringBuilder sb= new StringBuilder();
+		sb.append("RObject type=RLanguage, class=").append(getRClassName());
+		if (this.source != null) {
+			sb.append("\n\tsource: ");
+			final int idx= this.source.indexOf('\n');
+			if (idx >= 0) {
+				sb.append(this.source.substring(0, idx));
+				sb.append(" ...");
+			}
+			else {
+				sb.append(this.source);
+			}
+		}
+		return sb.toString();
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RList32Impl.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RList32Impl.java
new file mode 100644
index 0000000..8acb469
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RList32Impl.java
@@ -0,0 +1,285 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data.impl;
+
+import java.io.IOException;
+
+import org.eclipse.statet.rj.data.RCharacterStore;
+import org.eclipse.statet.rj.data.RJIO;
+import org.eclipse.statet.rj.data.RList;
+import org.eclipse.statet.rj.data.RObject;
+import org.eclipse.statet.rj.data.RObjectFactory;
+import org.eclipse.statet.rj.data.RStore;
+
+
+public class RList32Impl extends AbstractRObject
+		implements RList, ExternalizableRObject {
+	
+	
+	private int length;
+	private RObject[] components; // null of RObject.F_NOCHILDREN
+	
+	private String className1;
+	private RCharacter32Store namesAttribute;
+	
+	
+	public RList32Impl(final RObject[] initialComponents, final String[] initialNames) {
+		this(initialComponents, RObject.CLASSNAME_LIST, initialNames, initialComponents.length);
+	}
+	
+	public RList32Impl(final RObject[] initialComponents, final String className1, final String[] initialNames) {
+		this(initialComponents, className1, initialNames, initialComponents.length);
+	}
+	
+	public RList32Impl(final RObject[] initialComponents, final String className1, String[] initialNames, final int length) {
+		this.length= length;
+		this.components= initialComponents;
+		this.className1= className1;
+		if (initialNames == null && initialComponents != null) {
+			initialNames= new String[length];
+		}
+		this.namesAttribute= (initialNames != null) ? createNamesStore(initialNames) : null;
+	}
+	
+	protected RCharacter32Store createNamesStore(final String[] names) {
+		return new RCharacter32Store(names, this.length);
+	}
+	
+	public RList32Impl(final RObject[] initialComponents, final RCharacter32Store initialNames) {
+		this.components= initialComponents;
+		this.length= this.components.length;
+		this.namesAttribute= initialNames;
+	}
+	
+	public RList32Impl(final RJIO io, final RObjectFactory factory, final int options) throws IOException {
+		//-- special attributes
+		this.className1= ((options & RObjectFactory.O_CLASS_NAME) != 0) ?
+				io.readString() : ((getRObjectType() == RObject.TYPE_DATAFRAME) ?
+						RObject.CLASSNAME_DATAFRAME : RObject.CLASSNAME_LIST);
+		final int l= this.length= checkShortLength(
+				io.readVULong((byte) (options & RObjectFactory.O_LENGTHGRADE_MASK)) );
+		
+		if ((options & RObjectFactory.O_NO_CHILDREN) != 0) {
+			this.namesAttribute= null;
+			this.components= null;
+		}
+		else {
+			this.namesAttribute= (RCharacter32Store) factory.readNames(io, l);
+			//-- data
+			this.components= new RObject[l];
+			for (int i= 0; i < l; i++) {
+				this.components[i]= factory.readObject(io);
+			}
+		}
+		//-- attributes
+		if ((options & RObjectFactory.O_WITH_ATTR) != 0) {
+			setAttributes(factory.readAttributeList(io));
+		}
+	}
+	
+	@Override
+	public void writeExternal(final RJIO io, final RObjectFactory factory) throws IOException {
+		doWriteExternal(io, factory, 0);
+	}
+	protected final void doWriteExternal(final RJIO io, final RObjectFactory factory, int options) throws IOException {
+		final int l= this.length;
+		//-- options
+		options |= io.getVULongGrade(l);
+		if (!this.className1.equals(getDefaultRClassName())) {
+			options |= RObjectFactory.O_CLASS_NAME;
+		}
+		final RList attributes= ((io.flags & RObjectFactory.F_WITH_ATTR) != 0) ? getAttributes() : null;
+		if (attributes != null) {
+			options |= RObjectFactory.O_WITH_ATTR;
+		}
+		if (this.components == null) {
+			options |= RObjectFactory.O_NO_CHILDREN;
+		}
+		io.writeInt(options);
+		//-- special attributes
+		if ((options & RObjectFactory.O_CLASS_NAME) != 0) {
+			io.writeString(this.className1);
+		}
+		io.writeVULong((byte) (options & RObjectFactory.O_LENGTHGRADE_MASK), l);
+		
+		if ((options & RObjectFactory.O_NO_CHILDREN) == 0) {
+			factory.writeNames(this.namesAttribute, io);
+			//-- data
+			for (int i= 0; i < l; i++) {
+				factory.writeObject(this.components[i], io);
+			}
+		}
+		//-- attributes
+		if (attributes != null) {
+			factory.writeAttributeList(attributes, io);
+		}
+	}
+	
+	
+	@Override
+	public byte getRObjectType() {
+		return TYPE_LIST;
+	}
+	
+	protected String getDefaultRClassName() {
+		return RObject.CLASSNAME_LIST;
+	}
+	
+	@Override
+	public final String getRClassName() {
+		return this.className1;
+	}
+	
+	
+	protected int length() {
+		return this.length;
+	}
+	
+	@Override
+	public long getLength() {
+		return this.length;
+	}
+	
+	@Override
+	public final RCharacterStore getNames() {
+		return this.namesAttribute;
+	}
+	
+	@Override
+	public final String getName(final int idx) {
+		if (this.namesAttribute != null) {
+			return this.namesAttribute.getChar(idx);
+		}
+		return null;
+	}
+	
+	@Override
+	public final String getName(final long idx) {
+		if (this.namesAttribute != null) {
+			return this.namesAttribute.getChar(idx);
+		}
+		return null;
+	}
+	
+	@Override
+	public final RObject get(final int idx) {
+		return this.components[idx];
+	}
+	
+	@Override
+	public final RObject get(final long idx) {
+		if (idx < 0 || idx >= Integer.MAX_VALUE) {
+			throw new IndexOutOfBoundsException(Long.toString(idx));
+		}
+		return this.components[(int) idx];
+	}
+	
+	@Override
+	public final RObject get(final String name) {
+		if (this.namesAttribute != null) {
+			final int idx= this.namesAttribute.indexOf(name, 0);
+			if (idx >= 0) {
+				return this.components[idx];
+			}
+		}
+		return null;
+	}
+	
+	@Override
+	public final RStore<?> getData() {
+		return null;
+	}
+	
+	
+	public boolean set(final int idx, final RObject component) {
+		this.components[idx]= component;
+		return true;
+	}
+	
+//	public boolean set(final long idx, final RObject component) {
+//		if (idx < 0 || idx >= Integer.MAX_VALUE) {
+//			throw new IndexOutOfBoundsException(Long.toString(idx));
+//		}
+//		this.components[(int) idx]= component;
+//		return true;
+//	}
+	
+	public final boolean set(final String name, final RObject component) {
+		if (component == null) {
+			throw new NullPointerException();
+		}
+		final int idx= this.namesAttribute.indexOf(name, 0);
+		if (idx >= 0) {
+			set(idx, component);
+			return true;
+		}
+		return false;
+	}
+	
+	public void insert(final int idx, final String name, final RObject component) {
+		if (component == null) {
+			throw new NullPointerException();
+		}
+		final int[] idxs= new int[] { idx };
+		this.components= prepareInsert(this.components, this.length, idxs);
+		this.length++;
+		if (name == null) {
+			this.namesAttribute.insertNA(idxs);
+		}
+		else {
+			this.namesAttribute.insertChar(idx, name);
+		}
+	}
+	
+	public void add(final String name, final RObject component) {
+		insert(this.length, name, component);
+	}
+	
+	public void remove(final int idx) {
+		final int[] idxs= new int[] { idx };
+		this.components= remove(this.components, this.length, idxs);
+		this.length--;
+		this.namesAttribute.remove(idxs);
+	}
+	
+	
+	@Override
+	public String toString() {
+		final StringBuilder sb= new StringBuilder();
+		sb.append("RObject type=RList, class=").append(getRClassName());
+		sb.append("\n\tlength=").append(this.length);
+		if (this.components != null) {
+			sb.append("\n\tdata: ");
+			for (int i= 0; i < this.length; i++) {
+				if (i > 100) {
+					sb.append("\n... ");
+					break;
+				}
+				if (this.namesAttribute == null || this.namesAttribute.isNA(i)) {
+					sb.append("\n[[").append((i + 1)).append("]]\n");
+				}
+				else {
+					sb.append("\n$").append(this.namesAttribute.getChar(i)).append("\n");
+				}
+				sb.append(this.components[i]);
+			}
+		}
+		else {
+			sb.append("\n<NODATA/>");
+		}
+		return sb.toString();
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RListFix64Impl.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RListFix64Impl.java
new file mode 100644
index 0000000..cd0affc
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RListFix64Impl.java
@@ -0,0 +1,239 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data.impl;
+
+import java.io.IOException;
+
+import org.eclipse.statet.rj.data.RCharacterStore;
+import org.eclipse.statet.rj.data.RJIO;
+import org.eclipse.statet.rj.data.RList;
+import org.eclipse.statet.rj.data.RObject;
+import org.eclipse.statet.rj.data.RObjectFactory;
+import org.eclipse.statet.rj.data.RStore;
+
+
+public class RListFix64Impl extends AbstractRObject
+		implements RList, ExternalizableRObject {
+	
+	
+	public static final int SEGMENT_LENGTH= AbstractRStore.DEFAULT_LONG_DATA_SEGMENT_LENGTH;
+	
+	
+	private final long length;
+	private final RObject[][] components; // null of RObject.F_NOCHILDREN
+	
+	private final String className1;
+	private final RCharacterStore namesAttribute;
+	
+	
+	public RListFix64Impl(final RObject[][] initialComponents, final String[][] initialNames) {
+		this(initialComponents, RObject.CLASSNAME_LIST, initialNames);
+	}
+	
+	public RListFix64Impl(final RObject[][] initialComponents, final String className1, final String[][] initialNames) {
+		this.length= check2dArrayLength(initialComponents, SEGMENT_LENGTH);
+		this.components= initialComponents;
+		this.className1= className1;
+		if (initialNames != null) {
+			this.namesAttribute= new RCharacterFix64Store(initialNames);
+			if (this.namesAttribute.getLength() != this.length) {
+				throw new IllegalArgumentException("Different length of components and names.");
+			}
+		}
+		else {
+			this.namesAttribute= null;
+		}
+	}
+	
+	public RListFix64Impl(final RObject[][] initialComponents, final RCharacter32Store initialNames) {
+		this.components= initialComponents;
+		this.length= this.components.length;
+		this.className1= RObject.CLASSNAME_LIST;
+		this.namesAttribute= initialNames;
+	}
+	
+	public RListFix64Impl(final long length, final String className1) {
+		this.length= length;
+		this.className1= className1;
+		this.components= null;
+		this.namesAttribute= null;
+	}
+	
+	public RListFix64Impl(final RJIO io, final RObjectFactory factory, final int options) throws IOException {
+		//-- special attributes
+		this.className1= ((options & RObjectFactory.O_CLASS_NAME) != 0) ?
+				io.readString() : ((getRObjectType() == RObject.TYPE_DATAFRAME) ?
+						RObject.CLASSNAME_DATAFRAME : RObject.CLASSNAME_LIST);
+		final long l= this.length= io.readVULong((byte) (options & RObjectFactory.O_LENGTHGRADE_MASK));
+		
+		if ((options & RObjectFactory.O_NO_CHILDREN) != 0) {
+			this.namesAttribute= null;
+			this.components= null;
+		}
+		else {
+			this.namesAttribute= (RCharacterStore) factory.readNames(io, l);
+			//-- data
+			this.components= new2dRObjectArray(options, SEGMENT_LENGTH);
+			for (int i= 0; i < this.components.length; i++) {
+				final RObject[] segment= this.components[i];
+				for (int j= 0; j < segment.length; j++) {
+					segment[j]= factory.readObject(io);
+				}
+			}
+		}
+		//-- attributes
+		if ((options & RObjectFactory.O_WITH_ATTR) != 0) {
+			setAttributes(factory.readAttributeList(io));
+		}
+	}
+	
+	@Override
+	public void writeExternal(final RJIO io, final RObjectFactory factory) throws IOException {
+		doWriteExternal(io, 0, factory);
+	}
+	protected final void doWriteExternal(final RJIO io, int options, final RObjectFactory factory) throws IOException {
+		final long l= this.length;
+		//-- options
+		options |= io.getVULongGrade(l);
+		if (!this.className1.equals(getDefaultRClassName())) {
+			options |= RObjectFactory.O_CLASS_NAME;
+		}
+		final RList attributes= ((io.flags & RObjectFactory.F_WITH_ATTR) != 0) ? getAttributes() : null;
+		if (attributes != null) {
+			options |= RObjectFactory.O_WITH_ATTR;
+		}
+		if (this.components == null) {
+			options |= RObjectFactory.O_NO_CHILDREN;
+		}
+		io.writeInt(options);
+		//-- special attributes
+		if ((options & RObjectFactory.O_CLASS_NAME) != 0) {
+			io.writeString(this.className1);
+		}
+		io.writeVULong((byte) (options & RObjectFactory.O_LENGTHGRADE_MASK), l);
+		
+		if ((options & RObjectFactory.O_NO_CHILDREN) == 0) {
+			factory.writeNames(this.namesAttribute, io);
+			//-- data
+			for (int i= 0; i < this.components.length; i++) {
+				final RObject[] segment= this.components[i];
+				for (int j= 0; j < segment.length; j++) {
+					factory.writeObject(segment[j], io);
+				}
+			}
+		}
+		//-- attributes
+		if (attributes != null) {
+			factory.writeAttributeList(attributes, io);
+		}
+	}
+	
+	
+	@Override
+	public byte getRObjectType() {
+		return TYPE_LIST;
+	}
+	
+	protected String getDefaultRClassName() {
+		return RObject.CLASSNAME_LIST;
+	}
+	
+	@Override
+	public final String getRClassName() {
+		return this.className1;
+	}
+	
+	
+	@Override
+	public long getLength() {
+		return this.length;
+	}
+	
+	@Override
+	public final RCharacterStore getNames() {
+		return this.namesAttribute;
+	}
+	
+	@Override
+	public final String getName(final int idx) {
+		if (this.namesAttribute != null) {
+			return this.namesAttribute.getChar(idx);
+		}
+		return null;
+	}
+	
+	@Override
+	public final String getName(final long idx) {
+		if (this.namesAttribute != null) {
+			return this.namesAttribute.getChar(idx);
+		}
+		return null;
+	}
+	
+	@Override
+	public final RObject get(final int idx) {
+		return this.components[idx / SEGMENT_LENGTH][idx % SEGMENT_LENGTH];
+	}
+	
+	@Override
+	public final RObject get(final long idx) {
+		return this.components[(int) (idx / SEGMENT_LENGTH)][(int) (idx % SEGMENT_LENGTH)];
+	}
+	
+	@Override
+	public final RObject get(final String name) {
+		if (this.namesAttribute != null) {
+			final long idx= this.namesAttribute.indexOf(name);
+			if (idx >= 0) {
+				return get(idx);
+			}
+		}
+		return null;
+	}
+	
+	@Override
+	public final RStore<?> getData() {
+		return null;
+	}
+	
+	
+	@Override
+	public String toString() {
+		final StringBuilder sb= new StringBuilder();
+		sb.append("RObject type=RList, class=").append(getRClassName());
+		sb.append("\n\tlength=").append(this.length);
+		if (this.components != null) {
+			sb.append("\n\tdata: ");
+			for (int i= 0; i < this.length; i++) {
+				if (i > 100) {
+					sb.append("\n... ");
+					break;
+				}
+				if (this.namesAttribute == null || this.namesAttribute.isNA(i)) {
+					sb.append("\n[[").append((i + 1)).append("]]\n");
+				}
+				else {
+					sb.append("\n$").append(this.namesAttribute.getChar(i)).append("\n");
+				}
+				sb.append(this.components[i]);
+			}
+		}
+		else {
+			sb.append("\n<NODATA/>");
+		}
+		return sb.toString();
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RLogicalByte32Store.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RLogicalByte32Store.java
new file mode 100644
index 0000000..e3b0182
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RLogicalByte32Store.java
@@ -0,0 +1,340 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data.impl;
+
+import java.io.Externalizable;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+
+import org.eclipse.statet.rj.data.RJIO;
+
+
+/**
+ * Based on byte array.
+ * 
+ * This implementation is limited to length of 2<sup>31</sup>-1.
+ */
+public class RLogicalByte32Store extends AbstractLogicalStore
+		implements RDataResizeExtension<Boolean>, ExternalizableRStore, Externalizable {
+	
+	
+	public static final byte TRUE= TRUE_BYTE;
+	public static final byte FALSE= FALSE_BYTE;
+	
+	
+	private int length;
+	
+	private byte[] boolValues;
+	
+	
+	public RLogicalByte32Store() {
+		this.length= 0;
+		this.boolValues= EMPTY_BYTE_ARRAY;
+	}
+	
+	public RLogicalByte32Store(final int length) {
+		this.length= length;
+		this.boolValues= new byte[length];
+	}
+	
+	public RLogicalByte32Store(final boolean[] values) {
+		this.length= values.length;
+		this.boolValues= new byte[values.length];
+		for (int i= values.length-1; i >= 0; i--) {
+			this.boolValues[i]= (values[i]) ? TRUE_BYTE : FALSE_BYTE;
+		}
+	}
+	
+	public RLogicalByte32Store(final boolean[] values, final int[] naIdxs) {
+		this.length= values.length;
+		this.boolValues= new byte[values.length];
+		for (int i= values.length-1; i >= 0; i--) {
+			this.boolValues[i]= (values[i]) ? TRUE_BYTE : FALSE_BYTE;
+		}
+		if (naIdxs != null) {
+			for (int i= 0; i < naIdxs.length; i++) {
+				this.boolValues[naIdxs[i]]= NA_logical_BYTE;
+			}
+		}
+	}
+	
+	public RLogicalByte32Store(final byte[] values) {
+		this.length= values.length;
+		this.boolValues= values;
+	}
+	
+	public RLogicalByte32Store(final byte[] values, final byte trueCode, final byte naCode) {
+		this.length= values.length;
+		if (trueCode != TRUE_BYTE || naCode != NA_logical_BYTE) {
+			for (int i= values.length-1; i >= 0; i--) {
+				final int value= values[i];
+				if (value == trueCode) {
+					values[i]= TRUE_BYTE;
+				}
+				else if (value == naCode) {
+					values[i]= NA_logical_BYTE;
+				}
+				else {
+					values[i]= FALSE_BYTE;
+				}
+			}
+		}
+		this.boolValues= values;
+	}
+	
+	
+	public RLogicalByte32Store(final RJIO io, final int length) throws IOException {
+		this.length= length;
+		this.boolValues= io.readByteData(new byte[length], length);
+	}
+	
+	@Override
+	public void writeExternal(final RJIO io) throws IOException {
+		io.writeByteData(this.boolValues, this.length);
+	}
+	
+	@Override
+	public void readExternal(final ObjectInput in) throws IOException {
+		this.length= in.readInt();
+		this.boolValues= new byte[this.length];
+		in.readFully(this.boolValues, 0, this.length);
+	}
+	
+	@Override
+	public void writeExternal(final ObjectOutput out) throws IOException {
+		out.writeInt(this.length);
+		out.write(this.boolValues, 0, this.length);
+	}
+	
+	
+	@Override
+	protected final boolean isStructOnly() {
+		return false;
+	}
+	
+	
+	protected final int length() {
+		return this.length;
+	}
+	
+	@Override
+	public final long getLength() {
+		return this.length;
+	}
+	
+	@Override
+	public boolean isNA(final int idx) {
+		return (this.boolValues[idx] == NA_logical_BYTE);
+	}
+	
+	@Override
+	public boolean isNA(final long idx) {
+		if (idx < 0 || idx >= length()) {
+			throw new IndexOutOfBoundsException(Long.toString(idx));
+		}
+		return (this.boolValues[(int) idx] == NA_logical_BYTE);
+	}
+	
+	@Override
+	public boolean isMissing(final int idx) {
+		return (this.boolValues[idx] == NA_logical_BYTE);
+	}
+	
+	@Override
+	public boolean isMissing(final long idx) {
+		if (idx < 0 || idx >= length()) {
+			throw new IndexOutOfBoundsException(Long.toString(idx));
+		}
+		return (this.boolValues[(int) idx] == NA_logical_BYTE);
+	}
+	
+	@Override
+	public void setNA(final int idx) {
+		this.boolValues[idx]= NA_logical_BYTE;
+	}
+	
+	@Override
+	public void setNA(final long idx) {
+		if (idx < 0 || idx >= length()) {
+			throw new IndexOutOfBoundsException(Long.toString(idx));
+		}
+		this.boolValues[(int) idx]= NA_logical_BYTE;
+	}
+	
+	@Override
+	public boolean getLogi(final int idx) {
+		return (this.boolValues[idx] == TRUE_BYTE);
+	}
+	
+	@Override
+	public boolean getLogi(final long idx) {
+		if (idx < 0 || idx >= length()) {
+			throw new IndexOutOfBoundsException(Long.toString(idx));
+		}
+		return (this.boolValues[(int) idx] == TRUE_BYTE);
+	}
+	
+	@Override
+	public void setLogi(final int idx, final boolean value) {
+		this.boolValues[idx]= (value) ? TRUE_BYTE : FALSE_BYTE;
+	}
+	
+	@Override
+	public void setLogi(final long idx, final boolean value) {
+		if (idx < 0 || idx >= length()) {
+			throw new IndexOutOfBoundsException(Long.toString(idx));
+		}
+		this.boolValues[(int) idx]= (value) ? TRUE_BYTE : FALSE_BYTE;
+	}
+	
+	
+	private void prepareInsert(final int[] idxs) {
+		this.boolValues= prepareInsert(this.boolValues, this.length, idxs);
+		this.length+= idxs.length;
+	}
+	
+	public void insertLogi(final int idx, final boolean value) {
+		prepareInsert(new int[] { idx });
+		this.boolValues[idx]= value ? TRUE_BYTE : FALSE_BYTE;
+	}
+	
+	@Override
+	public void insertNA(final int idx) {
+		prepareInsert(new int[] { idx });
+		this.boolValues[idx]= NA_logical_BYTE;
+	}
+	
+	@Override
+	public void insertNA(final int[] idxs) {
+		if (idxs.length == 0) {
+			return;
+		}
+		prepareInsert(idxs);
+		for (int idx= 0; idx < idxs.length; idx++) {
+			this.boolValues[idxs[idx]+idx]= NA_logical_BYTE;
+		}
+	}
+	
+	@Override
+	public void remove(final int idx) {
+		this.boolValues= remove(this.boolValues, this.length, new int[] { idx });
+		this.length--;
+	}
+	
+	@Override
+	public void remove(final int[] idxs) {
+		this.boolValues= remove(this.boolValues, this.length, idxs);
+		this.length-= idxs.length;
+	}
+	
+	
+	@Override
+	public Boolean get(final int idx) {
+		if (idx < 0 || idx >= length()) {
+			throw new IndexOutOfBoundsException(Long.toString(idx));
+		}
+		switch(this.boolValues[idx]) {
+		case TRUE_BYTE:
+			return Boolean.TRUE;
+		case FALSE_BYTE:
+			return Boolean.FALSE;
+		default:
+			return null;
+		}
+	}
+	
+	@Override
+	public Boolean get(final long idx) {
+		if (idx < 0 || idx >= length()) {
+			throw new IndexOutOfBoundsException(Long.toString(idx));
+		}
+		switch(this.boolValues[(int) idx]) {
+		case TRUE_BYTE:
+			return Boolean.TRUE;
+		case FALSE_BYTE:
+			return Boolean.FALSE;
+		default:
+			return null;
+		}
+	}
+	
+	@Override
+	public Boolean[] toArray() {
+		final Boolean[] array= new Boolean[length()];
+		final byte[] bools= this.boolValues;
+		for (int i= 0; i < array.length; i++) {
+			switch(bools[i]) {
+			case TRUE_BYTE:
+				array[i]= Boolean.TRUE;
+				continue;
+			case FALSE_BYTE:
+				array[i]= Boolean.FALSE;
+				continue;
+			default:
+				continue;
+			}
+		}
+		return array;
+	}
+	
+	
+	@Override
+	public long indexOfNA(long fromIdx) {
+		if (fromIdx >= Integer.MAX_VALUE) {
+			return -1;
+		}
+		if (fromIdx < 0) {
+			fromIdx= 0;
+		}
+		final long l= getLength();
+		final byte[] bools= this.boolValues;
+		for (int i= (int) fromIdx; i < l; i++) {
+			if (bools[i] == NA_logical_BYTE) {
+				return i;
+			}
+		}
+		return -1;
+	}
+	
+	@Override
+	public long indexOf(final int integer, long fromIdx) {
+		if (fromIdx >= Integer.MAX_VALUE
+				|| integer == NA_integer_INT ) {
+			return -1;
+		}
+		if (fromIdx < 0) {
+			fromIdx= 0;
+		}
+		final int l= length();
+		final byte[] bools= this.boolValues;
+		if (integer != 0) {
+			for (int i= (int) fromIdx; i < l; i++) {
+				if (bools[i] == TRUE_BYTE) {
+					return i;
+				}
+			}
+		}
+		else {
+			for (int i= (int) fromIdx; i < l; i++) {
+				if (bools[i] == FALSE_BYTE) {
+					return i;
+				}
+			}
+		}
+		return -1;
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RLogicalByteFix64Store.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RLogicalByteFix64Store.java
new file mode 100644
index 0000000..5be518d
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RLogicalByteFix64Store.java
@@ -0,0 +1,247 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data.impl;
+
+import java.io.IOException;
+
+import org.eclipse.statet.rj.data.RJIO;
+
+
+/**
+ * Based on byte array.
+ * 
+ * This implementation is limited to length of 2<sup>31</sup>-1.
+ */
+public class RLogicalByteFix64Store extends AbstractLogicalStore
+		implements ExternalizableRStore {
+	
+	
+	public static final byte TRUE= TRUE_BYTE;
+	public static final byte FALSE= FALSE_BYTE;
+	
+	public static final int SEGMENT_LENGTH= DEFAULT_LONG_DATA_SEGMENT_LENGTH;
+	
+	
+	private final long length;
+	
+	private final byte[][] boolValues;
+	
+	
+	public RLogicalByteFix64Store(final long length) {
+		this.length= length;
+		this.boolValues= new2dByteArray(length, SEGMENT_LENGTH);
+	}
+	
+	public RLogicalByteFix64Store(final byte[][] values) {
+		this.length= check2dArrayLength(values, SEGMENT_LENGTH);
+		this.boolValues= values;
+	}
+	
+	
+	public RLogicalByteFix64Store(final RJIO io, final long length) throws IOException {
+		this.length= length;
+		this.boolValues= new2dByteArray(length, SEGMENT_LENGTH);
+		for (int i= 0; i < this.boolValues.length; i++) {
+			io.readByteData(this.boolValues[i], this.boolValues[i].length);
+		}
+	}
+	
+	@Override
+	public void writeExternal(final RJIO io) throws IOException {
+		for (int i= 0; i < this.boolValues.length; i++) {
+			io.writeByteData(this.boolValues[i], this.boolValues[i].length);
+		}
+	}
+	
+	
+	@Override
+	protected final boolean isStructOnly() {
+		return false;
+	}
+	
+	
+	@Override
+	public final long getLength() {
+		return this.length;
+	}
+	
+	@Override
+	public boolean isNA(final int idx) {
+		return (this.boolValues[idx / SEGMENT_LENGTH][idx % SEGMENT_LENGTH] == NA_logical_BYTE);
+	}
+	
+	@Override
+	public boolean isNA(final long idx) {
+		return (this.boolValues[(int) (idx / SEGMENT_LENGTH)][(int) (idx % SEGMENT_LENGTH)] == NA_logical_BYTE);
+	}
+	
+	@Override
+	public boolean isMissing(final int idx) {
+		return (this.boolValues[idx / SEGMENT_LENGTH][idx % SEGMENT_LENGTH] == NA_logical_BYTE);
+	}
+	
+	@Override
+	public boolean isMissing(final long idx) {
+		return (this.boolValues[(int) (idx / SEGMENT_LENGTH)][(int) (idx % SEGMENT_LENGTH)] == NA_logical_BYTE);
+	}
+	
+	@Override
+	public void setNA(final int idx) {
+		this.boolValues[idx / SEGMENT_LENGTH][idx % SEGMENT_LENGTH] =
+				NA_logical_BYTE;
+	}
+	
+	@Override
+	public void setNA(final long idx) {
+		this.boolValues[(int) (idx / SEGMENT_LENGTH)][(int) (idx % SEGMENT_LENGTH)] =
+				NA_logical_BYTE;
+	}
+	
+	@Override
+	public boolean getLogi(final int idx) {
+		return (this.boolValues[idx / SEGMENT_LENGTH][idx % SEGMENT_LENGTH] == TRUE_BYTE);
+	}
+	
+	@Override
+	public boolean getLogi(final long idx) {
+		return (this.boolValues[(int) (idx / SEGMENT_LENGTH)][(int) (idx % SEGMENT_LENGTH)] == TRUE_BYTE);
+	}
+	
+	@Override
+	public void setLogi(final int idx, final boolean value) {
+		this.boolValues[idx / SEGMENT_LENGTH][idx % SEGMENT_LENGTH] =
+				(value) ? TRUE_BYTE : FALSE_BYTE;
+	}
+	
+	@Override
+	public void setLogi(final long idx, final boolean value) {
+		this.boolValues[(int) (idx / SEGMENT_LENGTH)][(int) (idx % SEGMENT_LENGTH)] =
+				(value) ? TRUE_BYTE : FALSE_BYTE;
+	}
+	
+	
+	@Override
+	public Boolean get(final int idx) {
+		if (idx < 0 || idx >= this.length) {
+			throw new IndexOutOfBoundsException(Long.toString(idx));
+		}
+		switch(this.boolValues[idx / SEGMENT_LENGTH][idx % SEGMENT_LENGTH]) {
+		case TRUE_BYTE:
+			return Boolean.TRUE;
+		case FALSE_BYTE:
+			return Boolean.FALSE;
+		default:
+			return null;
+		}
+	}
+	
+	@Override
+	public Boolean get(final long idx) {
+		if (idx < 0 || idx >= this.length) {
+			throw new IndexOutOfBoundsException(Long.toString(idx));
+		}
+		switch(this.boolValues[(int) (idx / SEGMENT_LENGTH)][(int) (idx % SEGMENT_LENGTH)]) {
+		case TRUE_BYTE:
+			return Boolean.TRUE;
+		case FALSE_BYTE:
+			return Boolean.FALSE;
+		default:
+			return null;
+		}
+	}
+	
+	@Override
+	public Boolean[] toArray() {
+		final int l= checkToArrayLength();
+		final Boolean[] array= new Boolean[l];
+		int k= 0;
+		for (int i= 0; i < this.boolValues.length; i++, k++) {
+			final byte[] bools= this.boolValues[i];
+			for (int j= 0; j < bools.length; j++) {
+				switch(bools[j]) {
+				case TRUE_BYTE:
+					array[k]= Boolean.TRUE;
+					continue;
+				case FALSE_BYTE:
+					array[k]= Boolean.FALSE;
+					continue;
+				default:
+					continue;
+				}
+			}
+		}
+		return array;
+	}
+	
+	
+	@Override
+	public long indexOfNA(long fromIdx) {
+		if (fromIdx < 0) {
+			fromIdx= 0;
+		}
+		int i= (int) (fromIdx / SEGMENT_LENGTH);
+		int j= (int) (fromIdx % SEGMENT_LENGTH);
+		{	while (i < this.boolValues.length) {
+				final byte[] bools= this.boolValues[i];
+				while (j < bools.length) {
+					if (bools[i] == NA_logical_BYTE) {
+						return (i * (long) SEGMENT_LENGTH) + j;
+					}
+				}
+				i++;
+				j= 0;
+			}
+		}
+		return -1;
+	}
+	
+	@Override
+	public long indexOf(final int integer, long fromIdx) {
+		if (integer == NA_integer_INT ) {
+			return -1;
+		}
+		if (fromIdx < 0) {
+			fromIdx= 0;
+		}
+		int i= (int) (fromIdx / SEGMENT_LENGTH);
+		int j= (int) (fromIdx % SEGMENT_LENGTH);
+		if (integer != 0) {
+			while (i < this.boolValues.length) {
+				final byte[] bools= this.boolValues[i];
+				while (j < bools.length) {
+					if (bools[i] == TRUE_BYTE) {
+						return (i * (long) SEGMENT_LENGTH) + j;
+					}
+				}
+				i++;
+				j= 0;
+			}
+		}
+		else {
+			while (i < this.boolValues.length) {
+				final byte[] bools= this.boolValues[i];
+				while (j < bools.length) {
+					if (bools[i] == FALSE_BYTE) {
+						return (i * (long) SEGMENT_LENGTH) + j;
+					}
+				}
+				i++;
+				j= 0;
+			}
+		}
+		return -1;
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RLogicalInt32Store.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RLogicalInt32Store.java
new file mode 100644
index 0000000..ae5faab
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RLogicalInt32Store.java
@@ -0,0 +1,300 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data.impl;
+
+import java.io.IOException;
+
+import org.eclipse.statet.rj.data.RJIO;
+
+
+/**
+ * Based on int array.
+ * 
+ * This implementation is limited to length of 2<sup>31</sup>-1.
+ */
+public class RLogicalInt32Store extends AbstractLogicalStore
+		implements RDataResizeExtension<Boolean>, ExternalizableRStore {
+	
+	
+	private int length;
+	
+	protected int[] boolValues;
+	
+	
+	public RLogicalInt32Store() {
+		this.boolValues= EMPTY_INT_ARRAY;
+		this.length= 0;
+	}
+	
+	public RLogicalInt32Store(final boolean[] values, final int[] naIdxs) {
+		this.boolValues= new int[values.length];
+		for (int i= values.length-1; i >= 0; i--) {
+			this.boolValues[i]= values[i] ? TRUE_INT : FALSE_INT;
+		}
+		this.length= this.boolValues.length;
+		if (naIdxs != null) {
+			for (int i= 0; i < naIdxs.length; i++) {
+				this.boolValues[naIdxs[i]]= NA_logical_INT;
+			}
+		}
+	}
+	
+	/**
+	 * Create new logical data based on the given Java int array
+	 * encoded as follows:
+	 * <code>FALSE</code>= 0
+	 * <code>NA</code>= 2
+	 * <code>TRUE</code>= anything else (default value 1)
+	 * 
+	 * @param values encoded value array, used directly (not copied)
+	 */
+	public RLogicalInt32Store(final int[] values) {
+		this.length= values.length;
+		this.boolValues= values;
+	}
+	
+	public RLogicalInt32Store(final RJIO io, final int length) throws IOException {
+		this.length= length;
+		this.boolValues= new int[length];
+		for (int i= 0; i < this.length; i++) {
+			final byte b= io.readByte();
+			if (b == TRUE_BYTE) {
+				this.boolValues[i]= TRUE_INT;
+			}
+			else if (b == NA_logical_BYTE) {
+				this.boolValues[i]= NA_integer_INT;
+			}
+			else {
+				this.boolValues[i]= FALSE_INT;
+			}
+		}
+	}
+	
+	@Override
+	public void writeExternal(final RJIO io) throws IOException {
+		for (int i= 0; i < this.length; i++) {
+			switch (this.boolValues[i]) {
+			case FALSE_INT:
+				io.writeByte(FALSE_BYTE);
+				continue;
+			case NA_logical_INT:
+				io.writeByte(NA_logical_BYTE);
+				continue;
+			default:
+				io.writeByte(TRUE_BYTE);
+				continue;
+			}
+		}
+	}
+	
+	
+	@Override
+	protected final boolean isStructOnly() {
+		return false;
+	}
+	
+	
+	protected final int length() {
+		return this.length;
+	}
+	
+	@Override
+	public final long getLength() {
+		return this.length;
+	}
+	
+	@Override
+	public boolean isNA(final int idx) {
+		return (this.boolValues[idx] == NA_logical_INT);
+	}
+	
+	@Override
+	public boolean isNA(final long idx) {
+		if (idx < 0 || idx >= length()) {
+			throw new IndexOutOfBoundsException(Long.toString(idx));
+		}
+		return (this.boolValues[(int) idx] == NA_logical_INT);
+	}
+	
+	@Override
+	public boolean isMissing(final int idx) {
+		return (this.boolValues[idx] == NA_logical_INT);
+	}
+	
+	@Override
+	public boolean isMissing(final long idx) {
+		if (idx < 0 || idx >= length()) {
+			throw new IndexOutOfBoundsException(Long.toString(idx));
+		}
+		return (this.boolValues[(int) idx] == NA_logical_INT);
+	}
+	
+	@Override
+	public void setNA(final int idx) {
+		this.boolValues[idx]= NA_logical_INT;
+	}
+	
+	@Override
+	public void setNA(final long idx) {
+		if (idx < 0 || idx >= length()) {
+			throw new IndexOutOfBoundsException(Long.toString(idx));
+		}
+		this.boolValues[(int) idx]= NA_logical_INT;
+	}
+	
+	@Override
+	public boolean getLogi(final int idx) {
+		return (this.boolValues[idx] != FALSE_INT);
+	}
+	
+	@Override
+	public boolean getLogi(final long idx) {
+		if (idx < 0 || idx >= length()) {
+			throw new IndexOutOfBoundsException(Long.toString(idx));
+		}
+		return (this.boolValues[(int) idx] != FALSE_INT);
+	}
+	
+	@Override
+	public void setLogi(final int idx, final boolean value) {
+		this.boolValues[idx]= value ? TRUE_INT : FALSE_INT;
+	}
+	
+	@Override
+	public void setLogi(final long idx, final boolean value) {
+		if (idx < 0 || idx >= length()) {
+			throw new IndexOutOfBoundsException(Long.toString(idx));
+		}
+		this.boolValues[(int) idx]= value ? TRUE_INT : FALSE_INT;
+	}
+	
+	
+	private void prepareInsert(final int[] idxs) {
+		this.boolValues= prepareInsert(this.boolValues, this.length, idxs);
+		this.length+= idxs.length;
+	}
+	
+	public void insertLogi(final int idx, final boolean value) {
+		prepareInsert(new int[] { idx });
+		this.boolValues[idx]= value ? TRUE_INT : FALSE_INT;
+	}
+	
+	@Override
+	public void insertNA(final int idx) {
+		prepareInsert(new int[] { idx });
+		this.boolValues[idx]= NA_logical_INT;
+	}
+	
+	@Override
+	public void insertNA(final int[] idxs) {
+		if (idxs.length == 0) {
+			return;
+		}
+		prepareInsert(idxs);
+		for (int idx= 0; idx < idxs.length; idx++) {
+			this.boolValues[idxs[idx]+idx]= NA_logical_INT;
+		}
+	}
+	
+	@Override
+	public void remove(final int idx) {
+		this.boolValues= remove(this.boolValues, this.length, new int[] { idx });
+		this.length--;
+	}
+	
+	@Override
+	public void remove(final int[] idxs) {
+		this.boolValues= remove(this.boolValues, this.length, idxs);
+		this.length-= idxs.length;
+	}
+	
+	
+	@Override
+	public Boolean get(final int idx) {
+		if (idx < 0 || idx >= length()) {
+			throw new IndexOutOfBoundsException(Long.toString(idx));
+		}
+		return (this.boolValues[idx] != NA_logical_INT) ?
+				((this.boolValues[idx] == TRUE_INT) ? Boolean.TRUE : Boolean.FALSE) : null;
+	}
+	
+	@Override
+	public Boolean get(final long idx) {
+		if (idx < 0 || idx >= length()) {
+			throw new IndexOutOfBoundsException(Long.toString(idx));
+		}
+		return (this.boolValues[(int) idx] != NA_logical_INT) ?
+				((this.boolValues[(int) idx] == TRUE_INT) ? Boolean.TRUE : Boolean.FALSE) : null;
+	}
+	
+	@Override
+	public Boolean[] toArray() {
+		final Boolean[] array= new Boolean[length()];
+		for (int i= 0; i < array.length; i++) {
+			if (this.boolValues[i] != NA_logical_INT) {
+				array[i]= (this.boolValues[i] == TRUE_INT) ? Boolean.TRUE : Boolean.FALSE;
+			}
+		}
+		return array;
+	}
+	
+	
+	@Override
+	public long indexOfNA(long fromIdx) {
+		if (fromIdx >= Integer.MAX_VALUE) {
+			return -1;
+		}
+		if (fromIdx < 0) {
+			fromIdx= 0;
+		}
+		final long l= getLength();
+		final int[] ints= this.boolValues;
+		for (int i= (int) fromIdx; i < l; i++) {
+			if (ints[i] == NA_integer_INT) {
+				return i;
+			}
+		}
+		return -1;
+	}
+	
+	@Override
+	public long indexOf(final int integer, long fromIdx) {
+		if (fromIdx >= Integer.MAX_VALUE
+				|| integer == NA_integer_INT ) {
+			return -1;
+		}
+		if (fromIdx < 0) {
+			fromIdx= 0;
+		}
+		final int l= length();
+		final int[] ints= this.boolValues;
+		if (integer != 0) {
+			for (int i= (int) fromIdx; i < l; i++) {
+				if (ints[i] == TRUE_INT) {
+					return i;
+				}
+			}
+		}
+		else {
+			for (int i= (int) fromIdx; i < l; i++) {
+				if (ints[i] == FALSE_INT) {
+					return i;
+				}
+			}
+		}
+		return -1;
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RLogicalStructStore.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RLogicalStructStore.java
new file mode 100644
index 0000000..00adf52
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RLogicalStructStore.java
@@ -0,0 +1,96 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data.impl;
+
+import org.eclipse.statet.rj.data.RStore;
+
+
+public class RLogicalStructStore extends AbstractLogicalStore {
+	
+	
+	public RLogicalStructStore() {
+	}
+	
+	
+	@Override
+	protected final boolean isStructOnly() {
+		return true;
+	}
+	
+	
+	@Override
+	public final long getLength() {
+		return -1;
+	}
+	
+	@Override
+	public boolean isNA(final int idx) {
+		throw new UnsupportedOperationException();
+	}
+	
+	@Override
+	public boolean isNA(final long idx) {
+		throw new UnsupportedOperationException();
+	}
+	
+	@Override
+	public boolean isMissing(final int idx) {
+		throw new UnsupportedOperationException();
+	}
+	
+	@Override
+	public boolean isMissing(final long idx) {
+		throw new UnsupportedOperationException();
+	}
+	
+	@Override
+	public Boolean get(final int idx) {
+		throw new UnsupportedOperationException();
+	}
+	
+	@Override
+	public Boolean get(final long idx) {
+		throw new UnsupportedOperationException();
+	}
+	
+	@Override
+	public final Boolean[] toArray() {
+		throw new UnsupportedOperationException();
+	}
+	
+	
+	@Override
+	public long indexOfNA(final long fromIdx) {
+		throw new UnsupportedOperationException();
+	}
+	
+	@Override
+	public long indexOf(final int integer, final long fromIdx) {
+		throw new UnsupportedOperationException();
+	}
+	
+	@Override
+	public long indexOf(final String character, final long fromIdx) {
+		throw new UnsupportedOperationException();
+	}
+	
+	
+	@Override
+	public boolean allEqual(final RStore<?> other) {
+		return (LOGICAL == other.getStoreType()
+				&& -1 == other.getLength() );
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RMissingImpl.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RMissingImpl.java
new file mode 100644
index 0000000..10b13ac
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RMissingImpl.java
@@ -0,0 +1,84 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data.impl;
+
+import org.eclipse.statet.rj.data.RList;
+import org.eclipse.statet.rj.data.RObject;
+import org.eclipse.statet.rj.data.RStore;
+
+
+/**
+ * Default implementation of an R object of type {@link RObject#TYPE_MISSING MISSING}.
+ * 
+ * @since de.walware.rj.data 0.5
+ */
+public class RMissingImpl implements RObject {
+	
+	
+	public static final RMissingImpl INSTANCE= new RMissingImpl();
+	
+	
+	public RMissingImpl() {
+	}
+	
+	
+	@Override
+	public byte getRObjectType() {
+		return TYPE_MISSING;
+	}
+	
+	@Override
+	public String getRClassName() {
+		return "<missing>";
+	}
+	
+	/**
+	 * Returns the length of the object. The length of {@link RObject#TYPE_MISSING MISSING}
+	 * is always zero.
+	 * 
+	 * @return the length
+	 */
+	@Override
+	public long getLength() {
+		return 0;
+	}
+	
+	@Override
+	public RStore<?> getData() {
+		return null;
+	}
+	
+	@Override
+	public RList getAttributes() {
+		return null;
+	}
+	
+	@Override
+	public int hashCode() {
+		return 68462137;
+	}
+	
+	@Override
+	public boolean equals(final Object obj) {
+		return (this == obj || (
+				(obj instanceof RObject) && ((RObject) obj).getRObjectType() == RObject.TYPE_MISSING) );
+	}
+	
+	@Override
+	public String toString() {
+		return "RObject type=RMissingImpl";
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RNullImpl.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RNullImpl.java
new file mode 100644
index 0000000..00b311e
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RNullImpl.java
@@ -0,0 +1,79 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data.impl;
+
+import org.eclipse.statet.rj.data.RList;
+import org.eclipse.statet.rj.data.RObject;
+import org.eclipse.statet.rj.data.RStore;
+
+
+public class RNullImpl implements RObject {
+	
+	
+	public static final RNullImpl INSTANCE= new RNullImpl();
+	
+	
+	public RNullImpl() {
+	}
+	
+	
+	@Override
+	public byte getRObjectType() {
+		return TYPE_NULL;
+	}
+	
+	@Override
+	public String getRClassName() {
+		return CLASSNAME_NULL;
+	}
+	
+	/**
+	 * Returns the length of the object. The length of {@link RObject#TYPE_NULL NULL}
+	 * is always zero.
+	 * 
+	 * @return the length
+	 */
+	@Override
+	public long getLength() {
+		return 0;
+	}
+	
+	@Override
+	public RStore<?> getData() {
+		return null;
+	}
+	
+	@Override
+	public RList getAttributes() {
+		return null;
+	}
+	
+	@Override
+	public int hashCode() {
+		return 15677;
+	}
+	
+	@Override
+	public boolean equals(final Object obj) {
+		return (this == obj || (
+				(obj instanceof RObject) && ((RObject) obj).getRObjectType() == RObject.TYPE_NULL) );
+	}
+	
+	@Override
+	public String toString() {
+		return "RObject type=RNullImpl";
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RNumericB32Store.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RNumericB32Store.java
new file mode 100644
index 0000000..a3d7488
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RNumericB32Store.java
@@ -0,0 +1,270 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data.impl;
+
+import java.io.Externalizable;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+
+import org.eclipse.statet.rj.data.RJIO;
+
+
+/**
+ * This implementation is limited to length of 2<sup>31</sup>-1.
+ */
+public class RNumericB32Store extends AbstractNumericStore
+		implements RDataResizeExtension<Double>, ExternalizableRStore, Externalizable {
+	
+	
+	private int length;
+	
+	protected double[] realValues;
+	
+	
+	public RNumericB32Store() {
+		this.length= 0;
+		this.realValues= EMPTY_DOUBLE_ARRAY;
+	}
+	
+	public RNumericB32Store(final int length) {
+		this.length= length;
+		this.realValues= new double[length];
+	}
+	
+	public RNumericB32Store(final double[] values) {
+		this.length= values.length;
+		this.realValues= values;
+	}
+	
+	public RNumericB32Store(final double[] values, final int[] naIdxs) {
+		this.length= values.length;
+		this.realValues= values;
+		if (naIdxs != null) {
+			for (int i= 0; i < naIdxs.length; i++) {
+				this.realValues[naIdxs[i]]= NA_numeric_DOUBLE;
+			}
+		}
+	}
+	
+	
+	public RNumericB32Store(final RJIO io, final int length) throws IOException {
+		this.length= length;
+		this.realValues= io.readDoubleData(new double[length], length);
+	}
+	
+	@Override
+	public void writeExternal(final RJIO io) throws IOException {
+		io.writeDoubleData(this.realValues, this.length);
+	}
+	
+	@Override
+	public void readExternal(final ObjectInput in) throws IOException, ClassNotFoundException {
+		this.length= in.readInt();
+		this.realValues= new double[this.length];
+		for (int i= 0; i < this.length; i++) {
+			this.realValues[i]= Double.longBitsToDouble(in.readLong());
+		}
+	}
+	
+	@Override
+	public void writeExternal(final ObjectOutput out) throws IOException {
+		out.writeInt(this.length);
+		for (int i= 0; i < this.length; i++) {
+			out.writeLong(Double.doubleToRawLongBits(this.realValues[i]));
+		}
+	}
+	
+	
+	@Override
+	protected final boolean isStructOnly() {
+		return false;
+	}
+	
+	
+	protected final int length() {
+		return this.length;
+	}
+	
+	@Override
+	public final long getLength() {
+		return this.length;
+	}
+	
+	@Override
+	public boolean isNA(final int idx) {
+		final double v= this.realValues[idx];
+		return (Double.isNaN(v)
+				&& (int) Double.doubleToRawLongBits(v) == NA_numeric_INT_MATCH);
+	}
+	
+	@Override
+	public boolean isNA(final long idx) {
+		if (idx < 0 || idx >= length()) {
+			throw new IndexOutOfBoundsException(Long.toString(idx));
+		}
+		final double v= this.realValues[(int) idx];
+		return (Double.isNaN(v)
+				&& (int) Double.doubleToRawLongBits(v) == NA_numeric_INT_MATCH);
+	}
+	
+	@Override
+	public void setNA(final int idx) {
+		this.realValues[idx]= NA_numeric_DOUBLE;
+	}
+	
+	@Override
+	public void setNA(final long idx) {
+		if (idx < 0 || idx >= length()) {
+			throw new IndexOutOfBoundsException(Long.toString(idx));
+		}
+		this.realValues[(int) idx]= NA_numeric_DOUBLE;
+	}
+	
+	@Override
+	public boolean isNaN(final int idx) {
+		final double v= this.realValues[idx];
+		return (Double.isNaN(v)
+				&& (int) Double.doubleToRawLongBits(v) != NA_numeric_INT_MATCH);
+	}
+	
+	@Override
+	public boolean isNaN(final long idx) {
+		if (idx < 0 || idx >= length()) {
+			throw new IndexOutOfBoundsException(Long.toString(idx));
+		}
+		final double v= this.realValues[(int) idx];
+		return (Double.isNaN(v)
+				&& (int) Double.doubleToRawLongBits(v) != NA_numeric_INT_MATCH);
+	}
+	
+	@Override
+	public boolean isMissing(final int idx) {
+		return (Double.isNaN(this.realValues[idx]));
+	}
+	
+	@Override
+	public boolean isMissing(final long idx) {
+		if (idx < 0 || idx >= length()) {
+			throw new IndexOutOfBoundsException(Long.toString(idx));
+		}
+		return (Double.isNaN(this.realValues[(int) idx]));
+	}
+	
+	@Override
+	public double getNum(final int idx) {
+		return this.realValues[idx];
+	}
+	
+	@Override
+	public double getNum(final long idx) {
+		if (idx < 0 || idx >= length()) {
+			throw new IndexOutOfBoundsException(Long.toString(idx));
+		}
+		return this.realValues[(int) idx];
+	}
+	
+	@Override
+	public void setNum(final int idx, final double value) {
+		this.realValues[idx]= (Double.isNaN(value)) ? NaN_numeric_DOUBLE : value;
+	}
+	
+	@Override
+	public void setNum(final long idx, final double value) {
+		if (idx < 0 || idx >= length()) {
+			throw new IndexOutOfBoundsException(Long.toString(idx));
+		}
+		this.realValues[(int) idx]= (Double.isNaN(value)) ? NaN_numeric_DOUBLE : value;
+	}
+	
+	
+	private void prepareInsert(final int[] idxs) {
+		this.realValues= prepareInsert(this.realValues, this.length, idxs);
+		this.length+= idxs.length;
+	}
+	
+	public void insertNum(final int idx, final double value) {
+		prepareInsert(new int[] { idx });
+		this.realValues[idx]= (Double.isNaN(value)) ? NaN_numeric_DOUBLE : value;
+	}
+	
+	@Override
+	public void insertNA(final int idx) {
+		prepareInsert(new int[] { idx });
+		this.realValues[idx]= NA_numeric_DOUBLE;
+	}
+	
+	@Override
+	public void insertNA(final int[] idxs) {
+		if (idxs.length == 0) {
+			return;
+		}
+		prepareInsert(idxs);
+		for (int idx= 0; idx < idxs.length; idx++) {
+			this.realValues[idx]= NA_numeric_DOUBLE;
+		}
+	}
+	
+	@Override
+	public void remove(final int idx) {
+		this.realValues= remove(this.realValues, this.length, new int[] { idx });
+		this.length--;
+	}
+	
+	@Override
+	public void remove(final int[] idxs) {
+		this.realValues= remove(this.realValues, this.length, idxs);
+		this.length-= idxs.length;
+	}
+	
+	
+	@Override
+	public Double get(final int idx) {
+		if (idx < 0 || idx >= this.length) {
+			throw new IndexOutOfBoundsException(Long.toString(idx));
+		}
+		final double v= this.realValues[idx];
+		return (!Double.isNaN(v)
+				|| (int) Double.doubleToRawLongBits(v) != NA_numeric_INT_MATCH) ?
+						Double.valueOf(v) : null;
+	}
+	
+	@Override
+	public Double get(final long idx) {
+		if (idx < 0 || idx >= this.length) {
+			throw new IndexOutOfBoundsException(Long.toString(idx));
+		}
+		final double v= this.realValues[(int) idx];
+		return (!Double.isNaN(v)
+				|| (int) Double.doubleToRawLongBits(v) != NA_numeric_INT_MATCH) ?
+						Double.valueOf(v) : null;
+	}
+	
+	
+	@Override
+	public Double[] toArray() {
+		final Double[] array= new Double[length()];
+		final double[] reals= this.realValues;
+		for (int i= 0; i < array.length; i++) {
+			final double v= reals[i];
+			if (!Double.isNaN(v)
+					|| (int) Double.doubleToRawLongBits(v) != NA_numeric_INT_MATCH) {
+				array[i]= Double.valueOf(v);
+			}
+		}
+		return array;
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RNumericBFix64Store.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RNumericBFix64Store.java
new file mode 100644
index 0000000..4fc2759
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RNumericBFix64Store.java
@@ -0,0 +1,190 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data.impl;
+
+import java.io.IOException;
+
+import org.eclipse.statet.rj.data.RJIO;
+
+
+public class RNumericBFix64Store extends AbstractNumericStore
+		implements ExternalizableRStore {
+	
+	
+	public static final int SEGMENT_LENGTH= DEFAULT_LONG_DATA_SEGMENT_LENGTH;
+	
+	
+	private final long length;
+	
+	protected final double[][] realValues;
+	
+	
+	public RNumericBFix64Store(final long length) {
+		this.length= length;
+		this.realValues= new2dDoubleArray(length, SEGMENT_LENGTH);
+	}
+	
+	public RNumericBFix64Store(final double[][] values) {
+		this.length= check2dArrayLength(values, SEGMENT_LENGTH);
+		this.realValues= values;
+	}
+	
+	
+	public RNumericBFix64Store(final RJIO io, final long length) throws IOException {
+		this.length= length;
+		this.realValues= new2dDoubleArray(length, SEGMENT_LENGTH);
+		for (int i= 0; i < this.realValues.length; i++) {
+			io.readDoubleData(this.realValues[i], this.realValues[i].length);
+		}
+	}
+	
+	@Override
+	public void writeExternal(final RJIO io) throws IOException {
+		for (int i= 0; i < this.realValues.length; i++) {
+			io.writeDoubleData(this.realValues[i], this.realValues[i].length);
+		}
+	}
+	
+	
+	@Override
+	protected final boolean isStructOnly() {
+		return false;
+	}
+	
+	
+	@Override
+	public final long getLength() {
+		return this.length;
+	}
+	
+	@Override
+	public boolean isNA(final int idx) {
+		final double v= this.realValues[idx / SEGMENT_LENGTH][idx % SEGMENT_LENGTH];
+		return (Double.isNaN(v)
+				&& (int) Double.doubleToRawLongBits(v) == NA_numeric_INT_MATCH);
+	}
+	
+	@Override
+	public boolean isNA(final long idx) {
+		final double v= this.realValues[(int) (idx / SEGMENT_LENGTH)][(int) (idx % SEGMENT_LENGTH)];
+		return (Double.isNaN(v)
+				&& (int) Double.doubleToRawLongBits(v) == NA_numeric_INT_MATCH);
+	}
+	
+	@Override
+	public void setNA(final int idx) {
+		this.realValues[idx / SEGMENT_LENGTH][idx % SEGMENT_LENGTH] =
+				NA_numeric_DOUBLE;
+	}
+	
+	@Override
+	public void setNA(final long idx) {
+		this.realValues[(int) (idx / SEGMENT_LENGTH)][(int) (idx % SEGMENT_LENGTH)] =
+				NA_numeric_DOUBLE;
+	}
+	
+	@Override
+	public boolean isNaN(final int idx) {
+		final double v= this.realValues[idx / SEGMENT_LENGTH][idx % SEGMENT_LENGTH];
+		return (Double.isNaN(v)
+				&& (int) Double.doubleToRawLongBits(v) != NA_numeric_INT_MATCH);
+	}
+	
+	@Override
+	public boolean isNaN(final long idx) {
+		final double v= this.realValues[(int) (idx / SEGMENT_LENGTH)][(int) (idx % SEGMENT_LENGTH)];
+		return (Double.isNaN(v)
+				&& (int) Double.doubleToRawLongBits(v) != NA_numeric_INT_MATCH);
+	}
+	
+	@Override
+	public boolean isMissing(final int idx) {
+		return (Double.isNaN(
+				this.realValues[idx / SEGMENT_LENGTH][idx % SEGMENT_LENGTH] ));
+	}
+	
+	@Override
+	public boolean isMissing(final long idx) {
+		return (Double.isNaN(
+				this.realValues[(int) (idx / SEGMENT_LENGTH)][(int) (idx % SEGMENT_LENGTH)] ));
+	}
+	
+	@Override
+	public double getNum(final int idx) {
+		return this.realValues[idx / SEGMENT_LENGTH][idx % SEGMENT_LENGTH];
+	}
+	
+	@Override
+	public double getNum(final long idx) {
+		return this.realValues[(int) (idx / SEGMENT_LENGTH)][(int) (idx % SEGMENT_LENGTH)];
+	}
+	
+	@Override
+	public void setNum(final int idx, final double value) {
+		this.realValues[idx / SEGMENT_LENGTH][idx % SEGMENT_LENGTH] =
+				(Double.isNaN(value)) ? NaN_numeric_DOUBLE : value;
+	}
+	
+	@Override
+	public void setNum(final long idx, final double value) {
+		this.realValues[(int) (idx / SEGMENT_LENGTH)][(int) (idx % SEGMENT_LENGTH)] =
+				(Double.isNaN(value)) ? NaN_numeric_DOUBLE : value;
+	}
+	
+	
+	@Override
+	public Double get(final int idx) {
+		if (idx < 0 || idx >= this.length) {
+			throw new IndexOutOfBoundsException(Long.toString(idx));
+		}
+		final double v= this.realValues[idx / SEGMENT_LENGTH][idx % SEGMENT_LENGTH];
+		return (!Double.isNaN(v)
+				|| (int) Double.doubleToRawLongBits(v) != NA_numeric_INT_MATCH) ?
+			Double.valueOf(v) :
+			null;
+	}
+	
+	@Override
+	public Double get(final long idx) {
+		if (idx < 0 || idx >= this.length) {
+			throw new IndexOutOfBoundsException(Long.toString(idx));
+		}
+		final double v= this.realValues[(int) (idx / SEGMENT_LENGTH)][(int) (idx % SEGMENT_LENGTH)];
+		return (!Double.isNaN(v)
+				|| (int) Double.doubleToRawLongBits(v) != NA_numeric_INT_MATCH) ?
+			Double.valueOf(v) :
+			null;
+	}
+	
+	
+	@Override
+	public Double[] toArray() {
+		final int l= checkToArrayLength();
+		final Double[] array= new Double[l];
+		int k= 0;
+		for (int i= 0; i < this.realValues.length; i++, k++) {
+			final double[] reals= this.realValues[i];
+			for (int j= 0; j < reals.length; j++) {
+				final double v= reals[j];
+				if (!Double.isNaN(v)
+						|| (int) Double.doubleToRawLongBits(v) != NA_numeric_INT_MATCH) {
+					array[k]= Double.valueOf(v);
+				}
+			}
+		}
+		return array;
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RNumericStructStore.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RNumericStructStore.java
new file mode 100644
index 0000000..f0d005e
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RNumericStructStore.java
@@ -0,0 +1,106 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data.impl;
+
+import org.eclipse.statet.rj.data.RStore;
+
+
+public class RNumericStructStore extends AbstractNumericStore {
+	
+	
+	public RNumericStructStore() {
+	}
+	
+	
+	@Override
+	protected final boolean isStructOnly() {
+		return true;
+	}
+	
+	
+	@Override
+	public final long getLength() {
+		return -1;
+	}
+	
+	@Override
+	public boolean isNA(final int idx) {
+		throw new UnsupportedOperationException();
+	}
+	
+	@Override
+	public boolean isNA(final long idx) {
+		throw new UnsupportedOperationException();
+	}
+	
+	@Override
+	public boolean isNaN(final int idx) {
+		throw new UnsupportedOperationException();
+	}
+	
+	@Override
+	public boolean isNaN(final long idx) {
+		throw new UnsupportedOperationException();
+	}
+	
+	@Override
+	public boolean isMissing(final int idx) {
+		throw new UnsupportedOperationException();
+	}
+	
+	@Override
+	public boolean isMissing(final long idx) {
+		throw new UnsupportedOperationException();
+	}
+	
+	@Override
+	public Double get(final int idx) {
+		throw new UnsupportedOperationException();
+	}
+	
+	@Override
+	public Double get(final long idx) {
+		throw new UnsupportedOperationException();
+	}
+	
+	@Override
+	public final Double[] toArray() {
+		throw new UnsupportedOperationException();
+	}
+	
+	
+	@Override
+	public long indexOfNA(final long fromIdx) {
+		throw new UnsupportedOperationException();
+	}
+	
+	@Override
+	public long indexOf(final int integer, final long fromIdx) {
+		throw new UnsupportedOperationException();
+	}
+	
+	@Override
+	public long indexOf(final String character, final long fromIdx) {
+		throw new UnsupportedOperationException();
+	}
+	
+	
+	@Override
+	public boolean allEqual(final RStore<?> other) {
+		return (NUMERIC == other.getStoreType()
+				&& -1 == other.getLength() );
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RObjectStore.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RObjectStore.java
new file mode 100644
index 0000000..a8d2f27
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RObjectStore.java
@@ -0,0 +1,27 @@
+/*=============================================================================#
+ # Copyright (c) 2013, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data.impl;
+
+import org.eclipse.statet.rj.data.RObject;
+
+
+public abstract class RObjectStore {
+	
+	
+	public abstract RObject get(long idx);
+	
+	public abstract void set(long idx, RObject item);
+	
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/ROtherImpl.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/ROtherImpl.java
new file mode 100644
index 0000000..719fd8b
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/ROtherImpl.java
@@ -0,0 +1,97 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data.impl;
+
+import java.io.IOException;
+
+import org.eclipse.statet.rj.data.RJIO;
+import org.eclipse.statet.rj.data.RList;
+import org.eclipse.statet.rj.data.RObjectFactory;
+import org.eclipse.statet.rj.data.RStore;
+
+
+public class ROtherImpl extends AbstractRObject
+		implements ExternalizableRObject {
+	
+	
+	private String className1;
+	
+	
+	public ROtherImpl(final String className1) {
+		if (className1 == null) {
+			throw new NullPointerException();
+		}
+		this.className1= className1;
+	}
+	
+	public ROtherImpl(final String className1, final RList attributes) {
+		if (className1 == null) {
+			throw new NullPointerException();
+		}
+		this.className1= className1;
+		setAttributes(attributes);
+	}
+	
+	public ROtherImpl(final RJIO io, final RObjectFactory factory) throws IOException {
+		readExternal(io, factory);
+	}
+	
+	public void readExternal(final RJIO io, final RObjectFactory factory) throws IOException {
+		//-- options
+		final int options= io.readInt();
+		//-- special attributes
+		this.className1= io.readString();
+		//-- attributes
+		if ((options & RObjectFactory.O_WITH_ATTR) != 0) {
+			setAttributes(factory.readAttributeList(io));
+		}
+	}
+	
+	@Override
+	public void writeExternal(final RJIO io, final RObjectFactory factory) throws IOException {
+		final RList attributes= ((io.flags & RObjectFactory.F_WITH_ATTR) != 0) ? getAttributes() : null;
+		//-- options
+		final int options= (attributes != null) ? RObjectFactory.O_WITH_ATTR : 0;
+		io.writeInt(options);
+		//-- special attributes
+		io.writeString(this.className1);
+		//-- attributes
+		if (attributes != null) {
+			factory.writeAttributeList(attributes, io);
+		}
+	}
+	
+	
+	@Override
+	public byte getRObjectType() {
+		return TYPE_OTHER;
+	}
+	
+	@Override
+	public String getRClassName() {
+		return this.className1;
+	}
+	
+	@Override
+	public long getLength() {
+		return 0;
+	}
+	
+	@Override
+	public RStore<?> getData() {
+		return null;
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RPromiseImpl.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RPromiseImpl.java
new file mode 100644
index 0000000..bbf6043
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RPromiseImpl.java
@@ -0,0 +1,62 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data.impl;
+
+import org.eclipse.statet.rj.data.RList;
+import org.eclipse.statet.rj.data.RObject;
+import org.eclipse.statet.rj.data.RStore;
+
+
+/**
+ * Default implementation of an R object of type {@link RObject#TYPE_PROMISE PROMISE}.
+ * 
+ * @since de.walware.rj.data 0.6
+ */
+public class RPromiseImpl implements RObject {
+	
+	
+	public static final RPromiseImpl INSTANCE= new RPromiseImpl();
+	
+	
+	public RPromiseImpl() {
+	}
+	
+	
+	@Override
+	public byte getRObjectType() {
+		return TYPE_PROMISE;
+	}
+	
+	@Override
+	public String getRClassName() {
+		return "<promise>";
+	}
+	
+	@Override
+	public long getLength() {
+		return 0;
+	}
+	
+	@Override
+	public RStore<?> getData() {
+		return null;
+	}
+	
+	@Override
+	public RList getAttributes() {
+		return null;
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RRaw32Store.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RRaw32Store.java
new file mode 100644
index 0000000..59d87d0
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RRaw32Store.java
@@ -0,0 +1,213 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data.impl;
+
+import java.io.Externalizable;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+
+import org.eclipse.statet.rj.data.RJIO;
+import org.eclipse.statet.rj.data.RStore;
+
+
+/**
+ * This implementation is limited to length of 2<sup>31</sup>-1.
+ */
+public class RRaw32Store extends AbstractRawStore
+		implements RDataResizeExtension<Byte>, ExternalizableRStore, Externalizable {
+	
+	
+	private int length;
+	
+	protected byte[] byteValues;
+	
+	
+	public RRaw32Store() {
+		this.byteValues= EMPTY_BYTE_ARRAY;
+		this.length= 0;
+	}
+	
+	public RRaw32Store(final int length) {
+		this.byteValues= new byte[length];
+		this.length= length;
+	}
+	
+	public RRaw32Store(final byte[] values) {
+		this.byteValues= values;
+		this.length= this.byteValues.length;
+	}
+	
+	
+	public RRaw32Store(final RJIO io, final int length) throws IOException {
+		this.length= length;
+		this.byteValues= io.readByteData(new byte[length], length);
+	}
+	
+	@Override
+	public void writeExternal(final RJIO io) throws IOException {
+		io.writeByteData(this.byteValues, this.length);
+	}
+	
+	@Override
+	public void readExternal(final ObjectInput in) throws IOException {
+		this.length= in.readInt();
+		this.byteValues= new byte[this.length];
+		in.readFully(this.byteValues, 0, this.length);
+	}
+	
+	@Override
+	public void writeExternal(final ObjectOutput out) throws IOException {
+		out.writeInt(this.length);
+		out.write(this.byteValues, 0, this.length);
+	}
+	
+	
+	@Override
+	protected final boolean isStructOnly() {
+		return false;
+	}
+	
+	
+	protected final int length() {
+		return this.length;
+	}
+	
+	@Override
+	public final long getLength() {
+		return this.length;
+	}
+	
+	@Override
+	public byte getRaw(final int idx) {
+		return this.byteValues[idx];
+	}
+	
+	@Override
+	public byte getRaw(final long idx) {
+		if (idx < 0 || idx >= length()) {
+			throw new IndexOutOfBoundsException(Long.toString(idx));
+		}
+		return this.byteValues[(int) idx];
+	}
+	
+	@Override
+	public void setRaw(final int idx, final byte value) {
+		this.byteValues[idx]= value;
+	}
+	
+	@Override
+	public void setRaw(final long idx, final byte value) {
+		if (idx < 0 || idx >= length()) {
+			throw new IndexOutOfBoundsException(Long.toString(idx));
+		}
+		this.byteValues[(int) idx]= value;
+	}
+	
+	
+	private void prepareInsert(final int[] idxs) {
+		this.byteValues= prepareInsert(this.byteValues, this.length, idxs);
+		this.length+= idxs.length;
+	}
+	
+	public void insert(final int idx, final byte value) {
+		prepareInsert(new int[] { idx });
+		this.byteValues[idx]= value;
+	}
+	
+	@Override
+	public void insertNA(final int idx) {
+		prepareInsert(new int[] { idx });
+		this.byteValues[idx]= NA_byte_BYTE;
+	}
+	
+	@Override
+	public void insertNA(final int[] idxs) {
+		if (idxs.length == 0) {
+			return;
+		}
+		prepareInsert(idxs);
+		for (int idx= 0; idx < idxs.length; idx++) {
+			this.byteValues[idx]= NA_byte_BYTE;
+		}
+	}
+	
+	@Override
+	public void remove(final int idx) {
+		this.byteValues= remove(this.byteValues, this.length, new int[] { idx });
+		this.length--;
+	}
+	
+	@Override
+	public void remove(final int[] idxs) {
+		this.byteValues= remove(this.byteValues, this.length, idxs);
+		this.length-= idxs.length;
+	}
+	
+	
+	@Override
+	public Byte get(final int idx) {
+		if (idx < 0 || idx >= length()) {
+			throw new IndexOutOfBoundsException(Long.toString(idx));
+		}
+		return Byte.valueOf(this.byteValues[idx]);
+	}
+	
+	@Override
+	public Byte get(final long idx) {
+		if (idx < 0 || idx >= length()) {
+			throw new IndexOutOfBoundsException(Long.toString(idx));
+		}
+		return Byte.valueOf(this.byteValues[(int) idx]);
+	}
+	
+	@Override
+	public Byte[] toArray() {
+		final Byte[] array= new Byte[length()];
+		final byte[] raws= this.byteValues;
+		for (int i= 0; i < array.length; i++) {
+			array[i]= Byte.valueOf(raws[i]);
+		}
+		return array;
+	}
+	
+	
+	@Override
+	public long indexOf(final int integer, long fromIdx) {
+		if (fromIdx >= Integer.MAX_VALUE
+				|| (integer & 0xffffff00) != 0 ) {
+			return -1;
+		}
+		if (fromIdx < 0) {
+			fromIdx= 0;
+		}
+		final byte raw= (byte) (integer & 0xff);
+		final int l= length();
+		final byte[] raws= this.byteValues;
+		for (int i= (int) fromIdx; i < l; i++) {
+			if (raws[i] == raw) {
+				return i;
+			}
+		}
+		return -1;
+	}
+	
+	
+	@Override
+	public boolean allEqual(final RStore<?> other) {
+		throw new UnsupportedOperationException("Not yet implemented");
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RRawFix64Store.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RRawFix64Store.java
new file mode 100644
index 0000000..ae29f32
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RRawFix64Store.java
@@ -0,0 +1,154 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data.impl;
+
+import java.io.IOException;
+
+import org.eclipse.statet.rj.data.RJIO;
+import org.eclipse.statet.rj.data.RStore;
+
+
+public class RRawFix64Store extends AbstractRawStore
+		implements ExternalizableRStore {
+	
+	
+	public static final int SEGMENT_LENGTH= DEFAULT_LONG_DATA_SEGMENT_LENGTH;
+	
+	
+	private final long length;
+	
+	protected final byte[][] byteValues;
+	
+	
+	public RRawFix64Store(final long length) {
+		this.length= length;
+		this.byteValues= new2dByteArray(length, SEGMENT_LENGTH);
+	}
+	
+	public RRawFix64Store(final byte[][] values) {
+		this.length= check2dArrayLength(values, SEGMENT_LENGTH);
+		this.byteValues= values;
+	}
+	
+	
+	public RRawFix64Store(final RJIO io, final long length) throws IOException {
+		this.length= length;
+		this.byteValues= new2dByteArray(length, SEGMENT_LENGTH);
+		for (int i= 0; i < this.byteValues.length; i++) {
+			io.readByteData(this.byteValues[i], this.byteValues[i].length);
+		}
+	}
+	
+	@Override
+	public void writeExternal(final RJIO io) throws IOException {
+		for (int i= 0; i < this.byteValues.length; i++) {
+			io.writeByteData(this.byteValues[i], this.byteValues[i].length);
+		}
+	}
+	
+	
+	@Override
+	protected final boolean isStructOnly() {
+		return false;
+	}
+	
+	
+	@Override
+	public final long getLength() {
+		return this.length;
+	}
+	
+	@Override
+	public byte getRaw(final int idx) {
+		return this.byteValues[idx / SEGMENT_LENGTH][idx % SEGMENT_LENGTH];
+	}
+	
+	@Override
+	public byte getRaw(final long idx) {
+		return this.byteValues[(int) (idx / SEGMENT_LENGTH)][(int) (idx % SEGMENT_LENGTH)];
+	}
+	
+	@Override
+	public void setRaw(final int idx, final byte value) {
+		this.byteValues[idx / SEGMENT_LENGTH][idx % SEGMENT_LENGTH] =
+				value;
+	}
+	
+	@Override
+	public void setRaw(final long idx, final byte value) {
+		this.byteValues[(int) (idx / SEGMENT_LENGTH)][(int) (idx % SEGMENT_LENGTH)] =
+				value;
+	}
+	
+	
+	@Override
+	public Byte get(final int idx) {
+		if (idx < 0 || idx >= this.length) {
+			throw new IndexOutOfBoundsException(Long.toString(idx));
+		}
+		return Byte.valueOf(this.byteValues[idx / SEGMENT_LENGTH][idx % SEGMENT_LENGTH]);
+	}
+	
+	@Override
+	public Byte get(final long idx) {
+		if (idx < 0 || idx >= this.length) {
+			throw new IndexOutOfBoundsException(Long.toString(idx));
+		}
+		return Byte.valueOf(this.byteValues[(int) (idx / SEGMENT_LENGTH)][(int) (idx % SEGMENT_LENGTH)]);
+	}
+	
+	@Override
+	public Byte[] toArray() {
+		final int l= checkToArrayLength();
+		final Byte[] array= new Byte[l];
+		int k= 0;
+		for (int i= 0; i < this.byteValues.length; i++, k++) {
+			final byte[] raws= this.byteValues[i];
+			for (int j= 0; j < raws.length; j++) {
+				array[k]= Byte.valueOf(raws[j]);
+			}
+		}
+		return array;
+	}
+	
+	
+	@Override
+	public long indexOf(final int integer, final long fromIdx) {
+		if ((integer & 0xffffff00) != 0) {
+			return -1;
+		}
+		final byte raw= (byte) (integer & 0xff);
+		int i= (int) (fromIdx / SEGMENT_LENGTH);
+		int j= (int) (fromIdx % SEGMENT_LENGTH);
+		while (i < this.byteValues.length) {
+			final byte[] raws= this.byteValues[i];
+			while (j < raws.length) {
+				if (raws[i] == raw) {
+					return (i * (long) SEGMENT_LENGTH) + j;
+				}
+			}
+			i++;
+			j= 0;
+		}
+		return -1;
+	}
+	
+	
+	@Override
+	public boolean allEqual(final RStore<?> other) {
+		throw new UnsupportedOperationException("Not yet implemented");
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RRawStructStore.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RRawStructStore.java
new file mode 100644
index 0000000..1f62049
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RRawStructStore.java
@@ -0,0 +1,76 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data.impl;
+
+import org.eclipse.statet.rj.data.RStore;
+
+
+public class RRawStructStore extends AbstractRawStore {
+	
+	
+	public RRawStructStore() {
+	}
+	
+	
+	@Override
+	protected final boolean isStructOnly() {
+		return true;
+	}
+	
+	
+	@Override
+	public final long getLength() {
+		return -1;
+	}
+	
+	@Override
+	public Byte get(final int idx) {
+		throw new UnsupportedOperationException();
+	}
+	
+	@Override
+	public Byte get(final long idx) {
+		throw new UnsupportedOperationException();
+	}
+	
+	@Override
+	public final Byte[] toArray() {
+		throw new UnsupportedOperationException();
+	}
+	
+	
+	@Override
+	public long indexOfNA(final long fromIdx) {
+		throw new UnsupportedOperationException();
+	}
+	
+	@Override
+	public long indexOf(final int integer, final long fromIdx) {
+		throw new UnsupportedOperationException();
+	}
+	
+	@Override
+	public long indexOf(final String character, final long fromIdx) {
+		throw new UnsupportedOperationException();
+	}
+	
+	
+	@Override
+	public boolean allEqual(final RStore<?> other) {
+		return (RAW == other.getStoreType()
+				&& -1 == other.getLength() );
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RReferenceImpl.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RReferenceImpl.java
new file mode 100644
index 0000000..b38f85d
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RReferenceImpl.java
@@ -0,0 +1,121 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data.impl;
+
+import java.io.IOException;
+
+import org.eclipse.statet.rj.data.RDataUtils;
+import org.eclipse.statet.rj.data.RJIO;
+import org.eclipse.statet.rj.data.RList;
+import org.eclipse.statet.rj.data.RObject;
+import org.eclipse.statet.rj.data.RObjectFactory;
+import org.eclipse.statet.rj.data.RReference;
+import org.eclipse.statet.rj.data.RStore;
+
+
+public class RReferenceImpl implements RReference, ExternalizableRObject {
+	
+	
+	private long handle;
+	private byte type;
+	private String baseClassName;
+	
+	
+	public RReferenceImpl(final long handler, final byte type, final String baseClass) {
+		this.handle= handler;
+		this.type= type;
+		this.baseClassName= baseClass;
+	}
+	
+	public RReferenceImpl(final RJIO io, final RObjectFactory factory) throws IOException {
+		readExternal(io, factory);
+	}
+	
+	public void readExternal(final RJIO io, final RObjectFactory factory) throws IOException {
+		this.handle= io.readLong();
+		this.type= io.readByte();
+		this.baseClassName= io.readString();
+	}
+	
+	@Override
+	public void writeExternal(final RJIO io, final RObjectFactory factory) throws IOException {
+		io.writeLong(this.handle);
+		io.writeByte(this.type);
+		io.writeString(this.baseClassName);
+	}
+	
+	
+	@Override
+	public byte getRObjectType() {
+		return TYPE_REFERENCE;
+	}
+	
+	@Override
+	public byte getReferencedRObjectType() {
+		return this.type;
+	}
+	
+	@Override
+	public String getRClassName() {
+		return this.baseClassName;
+	}
+	
+	@Override
+	public long getLength() {
+		return 0;
+	}
+	
+	@Override
+	public long getHandle() {
+		return this.handle;
+	}
+	
+	@Override
+	public RObject getResolvedRObject() {
+		return null;
+	}
+	
+	@Override
+	public RStore<?> getData() {
+		return null;
+	}
+	
+	@Override
+	public RList getAttributes() {
+		return null;
+	}
+	
+	
+	@Override
+	public int hashCode() {
+		return (int) this.handle;
+	}
+	
+	@Override
+	public boolean equals(final Object obj) {
+		return (this == obj
+				|| (obj instanceof RReference
+						&& this.handle == ((RReference) obj).getHandle() ));
+	}
+	
+	@Override
+	public String toString() {
+		final StringBuilder sb= new StringBuilder();
+		sb.append("RObjectReference type= ").append(RDataUtils.getObjectTypeName(this.type));
+		sb.append(", class= ").append(getRClassName());
+		return sb.toString();
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RS4ObjectImpl.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RS4ObjectImpl.java
new file mode 100644
index 0000000..3ebdb4d
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RS4ObjectImpl.java
@@ -0,0 +1,194 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data.impl;
+
+import java.io.IOException;
+
+import org.eclipse.statet.rj.data.RCharacterStore;
+import org.eclipse.statet.rj.data.RJIO;
+import org.eclipse.statet.rj.data.RObject;
+import org.eclipse.statet.rj.data.RObjectFactory;
+import org.eclipse.statet.rj.data.RS4Object;
+import org.eclipse.statet.rj.data.RStore;
+
+
+public class RS4ObjectImpl extends AbstractRObject
+		implements RS4Object, ExternalizableRObject {
+	
+	
+	private String className;
+	
+	private int dataSlotIdx;
+	private RCharacter32Store slotNames;
+	private RObject[] slotValues;
+	
+	
+	public RS4ObjectImpl(final String className, final String[] slotNames, final RObject[] slotValues) {
+		if (className == null || slotNames == null || slotValues == null) {
+			throw new NullPointerException();
+		}
+		this.className= className;
+		this.slotNames= new RCharacter32Store(slotNames);
+		
+		this.dataSlotIdx= this.slotNames.indexOf(".Data", 0);
+		this.slotValues= slotValues;
+	}
+	
+	public RS4ObjectImpl(final RJIO io, final RObjectFactory factory) throws IOException {
+		readExternal(io, factory);
+	}
+	
+	public void readExternal(final RJIO io, final RObjectFactory factory) throws IOException {
+		//-- options
+		final int options= io.readInt();
+		//-- special attributes
+		this.className= io.readString();
+		//-- data
+		final int l= (int) io.readVULong((byte) (options & RObjectFactory.O_LENGTHGRADE_MASK));
+		
+		this.dataSlotIdx= io.readInt();
+		this.slotNames= new RCharacter32Store(io, l);
+		this.slotValues= new RObject[l];
+		for (int i= 0; i < l; i++) {
+			this.slotValues[i]= factory.readObject(io);
+		}
+	}
+	
+	@Override
+	public void writeExternal(final RJIO io, final RObjectFactory factory) throws IOException {
+		final int l= this.slotValues.length;
+		//-- options
+		final int options= io.getVULongGrade(l);
+		io.writeInt(options);
+		//-- special attributes
+		io.writeString(this.className);
+		//-- data
+		io.writeVULong((byte) (options & RObjectFactory.O_LENGTHGRADE_MASK), l);
+		
+		io.writeInt(this.dataSlotIdx);
+		this.slotNames.writeExternal(io);
+		for (int i= 0; i < l; i++) {
+			factory.writeObject(this.slotValues[i], io);
+		}
+	}
+	
+	@Override
+	public byte getRObjectType() {
+		return TYPE_S4OBJECT;
+	}
+	
+	@Override
+	public String getRClassName() {
+		return this.className;
+	}
+	
+	
+	@Override
+	public long getLength() {
+		return this.slotValues.length;
+	}
+	
+	@Override
+	public boolean hasDataSlot() {
+		return (this.dataSlotIdx >= 0);
+	}
+	
+	@Override
+	public RObject getDataSlot() {
+		return (this.dataSlotIdx >= 0) ? this.slotValues[this.dataSlotIdx] : null;
+	}
+	
+	public byte getDataType() {
+		return (this.dataSlotIdx >= 0 && this.slotValues[this.dataSlotIdx] != null) ?
+				this.slotValues[this.dataSlotIdx].getData().getStoreType() : 0;
+	}
+	
+	@Override
+	public RStore<?> getData() {
+		return (this.dataSlotIdx >= 0 && this.slotValues[this.dataSlotIdx] != null) ?
+				this.slotValues[this.dataSlotIdx].getData() : null;
+	}
+	
+	@Override
+	public RCharacterStore getNames() {
+		return this.slotNames;
+	}
+	
+	@Override
+	public String getName(final int idx) {
+		return this.slotNames.getChar(idx);
+	}
+	
+	@Override
+	public String getName(final long idx) {
+		return this.slotNames.getChar(idx);
+	}
+	
+	@Override
+	public RObject get(final int idx) {
+		return this.slotValues[idx];
+	}
+	
+	@Override
+	public RObject get(final long idx) {
+		if (idx < 0 || idx >= Integer.MAX_VALUE) {
+			throw new IndexOutOfBoundsException(Long.toString(idx));
+		}
+		return this.slotValues[(int) idx];
+	}
+	
+	@Override
+	public RObject get(final String name) {
+		final int idx= this.slotNames.indexOf(name, 0);
+		if (idx >= 0) {
+			return this.slotValues[idx];
+		}
+		throw new IllegalArgumentException();
+	}
+	
+	
+	public void insert(final int idx, final String name, final RObject component) {
+		throw new UnsupportedOperationException();
+	}
+	
+	public void add(final String name, final RObject component) {
+		throw new UnsupportedOperationException();
+	}
+	
+	public void remove(final int idx) {
+		throw new UnsupportedOperationException();
+	}
+	
+	public boolean set(final int idx, final RObject value) {
+		this.slotValues[idx]= value;
+		return true;
+	}
+	
+	public boolean set(final String name, final RObject component) {
+		if (this.dataSlotIdx >= 0 && name.equals(".Data")) {
+			this.slotValues[this.dataSlotIdx]= component;
+			return true;
+		}
+		else {
+			final int i= this.slotNames.indexOf(name, 0);
+			if (i >= 0) {
+				this.slotValues[i]= component;
+				return true;
+			}
+		}
+		return false;
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RUniqueCharacter32Store.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RUniqueCharacter32Store.java
new file mode 100644
index 0000000..176d50d
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RUniqueCharacter32Store.java
@@ -0,0 +1,102 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data.impl;
+
+import java.io.IOException;
+
+import org.eclipse.statet.rj.data.RJIO;
+
+
+public class RUniqueCharacter32Store extends RCharacter32Store {
+	
+	
+	public RUniqueCharacter32Store() {
+		super();
+	}
+	
+	public RUniqueCharacter32Store(final String[] initialValues) {
+		super(initialValues, initialValues.length);
+	}
+	
+	RUniqueCharacter32Store(final RCharacter32Store source, final boolean reuse) {
+		super(source, reuse);
+	}
+	
+	public RUniqueCharacter32Store(final RJIO io, final int length) throws IOException {
+		super(io, length);
+	}
+	
+	
+	@Override
+	public void setChar(final int idx, final String value) {
+		if (indexOf(value) >= 0) {
+			if (indexOf(value) == idx) {
+				return;
+			}
+			throw new IllegalArgumentException();
+		}
+		super.setChar(idx, value);
+	}
+	
+	@Override
+	public void setChar(final long idx, final String value) {
+		if (idx < 0 || idx >= getLength()) {
+			throw new IndexOutOfBoundsException(Long.toString(idx));
+		}
+		setChar((int) idx, value);
+	}
+	
+	@Override
+	public void insertChar(final int idx, final String value) {
+		if (indexOf(value) >= 0) {
+			throw new IllegalArgumentException();
+		}
+		super.insertChar(idx, value);
+	}
+	
+	@Override
+	public void setNA(final int idx) {
+	}
+	
+	@Override
+	public void setNA(final long idx) {
+	}
+	
+	@Override
+	public void insertNA(final int idx) {
+	}
+	
+	@Override
+	public void insertNA(final int[] idxs) {
+	}
+	
+	protected void insertAuto(final int idx) {
+		insertChar(idx, createAuto(idx));
+	}
+	
+	protected String createAuto(final int idx) {
+		final String nr= Integer.toString(idx+1);
+		if (indexOf(nr) < 0) {
+			return nr;
+		}
+		for (int i= 1; ; i++) {
+			final String sub= nr+'.'+Integer.toString(i);
+			if (indexOf(sub) < 0) {
+				return sub;
+			}
+		}
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RUniqueCharacterHash32Store.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RUniqueCharacterHash32Store.java
new file mode 100644
index 0000000..66c7707
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RUniqueCharacterHash32Store.java
@@ -0,0 +1,97 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data.impl;
+
+import java.io.IOException;
+import java.util.HashMap;
+
+import org.eclipse.statet.rj.data.RJIO;
+
+
+public class RUniqueCharacterHash32Store extends RUniqueCharacter32Store {
+	
+	
+	private final HashMap<String, Integer> map;
+	
+	
+	public RUniqueCharacterHash32Store(final String names[]) {
+		super(names);
+		this.map= new HashMap<>();
+		initMap();
+	}
+	
+	RUniqueCharacterHash32Store(final RCharacter32Store source, final boolean reuse) {
+		super(source, reuse);
+		this.map= new HashMap<>();
+		initMap();
+	}
+	
+	public RUniqueCharacterHash32Store(final RJIO io, final int length) throws IOException {
+		super(io, length);
+		this.map= new HashMap<>();
+		initMap();
+	}
+	
+	
+	protected void initMap() {
+		final int length= (int) getLength();
+		for (int idx= 0; idx < length; idx++) {
+			if (this.charValues[idx] != null) {
+				this.map.put(this.charValues[idx], idx);
+			}
+		}
+	}
+	
+	
+	@Override
+	public void setChar(final int idx, final String value) {
+		final String previous= getChar(idx);
+		super.setChar(idx, value);
+		this.map.remove(previous);
+		this.map.put(value, idx);
+	}
+	
+	@Override
+	public void setChar(final long idx, final String value) {
+		if (idx < 0 || idx >= getLength()) {
+			throw new IndexOutOfBoundsException(Long.toString(idx));
+		}
+		setChar((int) idx, value);
+	}
+	
+	@Override
+	public void insertChar(final int idx, final String name) {
+		super.insertChar(idx, name);
+		this.map.put(name, idx);
+	}
+	
+	@Override
+	public void remove(final int idx) {
+		this.map.remove(getChar(idx));
+		super.remove(idx);
+	}
+	
+	
+	@Override
+	public boolean contains(final String value) {
+		return (value != null && this.map.containsKey(value));
+	}
+	
+	@Override
+	public long indexOf(final String name, final long fromIdx) {
+		return this.map.get(name);
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RVectorImpl.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RVectorImpl.java
new file mode 100644
index 0000000..03cf1de
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RVectorImpl.java
@@ -0,0 +1,188 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data.impl;
+
+import java.io.IOException;
+
+import org.eclipse.statet.rj.data.RJIO;
+import org.eclipse.statet.rj.data.RList;
+import org.eclipse.statet.rj.data.RObjectFactory;
+import org.eclipse.statet.rj.data.RStore;
+import org.eclipse.statet.rj.data.RVector;
+
+
+public class RVectorImpl<TData extends RStore<?>> extends AbstractRObject
+		implements RVector<TData>, ExternalizableRObject {
+	
+	
+	private TData data;
+	private long length;
+	
+	private String className1;
+	private RStore<?> namesAttribute;
+	
+	
+	public RVectorImpl(final TData data, final String className1) {
+		this(data, data.getLength(), className1, null);
+	}
+	
+	public RVectorImpl(final TData data) {
+		this(data, data.getLength(), data.getBaseVectorRClassName(), null);
+	}
+	
+	public RVectorImpl(final TData data, final String className1, final String[] initialNames) {
+		this(data, data.getLength(), className1, initialNames);
+	}
+	
+	public RVectorImpl(final TData data, final long length, final String className1, final String[] initialNames) {
+		if (data == null || className1 == null) {
+			throw new NullPointerException();
+		}
+		if ((initialNames != null && initialNames.length != length)
+				|| (data.getLength() >= 0 && data.getLength() != length) ) {
+			throw new IllegalArgumentException();
+		}
+		this.data= data;
+		this.length= length;
+		this.className1= className1;
+		if (initialNames != null) {
+			this.namesAttribute= new RCharacter32Store(initialNames);
+		}
+	}
+	
+	public RVectorImpl(final TData data, final String className1, final RStore<?> initialNames) {
+		if (data == null || className1 == null) {
+			throw new NullPointerException();
+		}
+		if ((initialNames != null && initialNames.getLength() != data.getLength())) {
+			throw new IllegalArgumentException();
+		}
+		this.data= data;
+		this.length= data.getLength();
+		this.className1= className1;
+		this.namesAttribute= initialNames;
+	}
+	
+	public RVectorImpl(final RJIO io, final RObjectFactory factory) throws IOException {
+		readExternal(io, factory);
+	}
+	
+	public void readExternal(final RJIO io, final RObjectFactory factory) throws IOException {
+		//-- options
+		final int options= io.readInt();
+		//-- special attributes
+		if ((options & RObjectFactory.O_CLASS_NAME) != 0) {
+			this.className1= io.readString();
+		}
+		this.length= io.readVULong((byte) (options & RObjectFactory.O_LENGTHGRADE_MASK));
+		if ((options & RObjectFactory.O_WITH_NAMES) != 0) {
+			this.namesAttribute= factory.readNames(io, this.length);
+		}
+		//-- data
+		this.data= (TData) factory.readStore(io, this.length);
+		if ((options & RObjectFactory.O_CLASS_NAME) == 0) {
+			this.className1= this.data.getBaseVectorRClassName();
+		}
+		// attributes
+		if ((options & RObjectFactory.O_WITH_ATTR) != 0) {
+			setAttributes(factory.readAttributeList(io));
+		}
+	}
+	
+	@Override
+	public void writeExternal(final RJIO io, final RObjectFactory factory) throws IOException {
+		//-- options
+		int options= io.getVULongGrade(this.length);
+		if (!this.className1.equals(this.data.getBaseVectorRClassName())) {
+			options |= RObjectFactory.O_CLASS_NAME;
+		}
+		if ((io.flags & RObjectFactory.F_ONLY_STRUCT) == 0 && this.namesAttribute != null) {
+			options |= RObjectFactory.O_WITH_NAMES;
+		}
+		final RList attributes= ((io.flags & RObjectFactory.F_WITH_ATTR) != 0) ? getAttributes() : null;
+		if (attributes != null) {
+			options |= RObjectFactory.O_WITH_ATTR;
+		}
+		io.writeInt(options);
+		//-- special attributes
+		if ((options & RObjectFactory.O_CLASS_NAME) != 0) {
+			io.writeString(this.className1);
+		}
+		io.writeVULong((byte) (options & RObjectFactory.O_LENGTHGRADE_MASK), this.length);
+		if ((options & RObjectFactory.O_WITH_NAMES) != 0) {
+			factory.writeNames(this.namesAttribute, io);
+		}
+		//-- data
+		factory.writeStore(this.data, io);
+		// attributes
+		if ((options & RObjectFactory.O_WITH_ATTR) != 0) {
+			factory.writeAttributeList(attributes, io);
+		}
+	}
+	
+	
+	@Override
+	public byte getRObjectType() {
+		return TYPE_VECTOR;
+	}
+	
+	@Override
+	public String getRClassName() {
+		return this.className1;
+	}
+	
+	@Override
+	public long getLength() {
+		return this.length;
+	}
+	
+	@Override
+	public RStore<?> getNames() {
+		return this.namesAttribute;
+	}
+	
+	
+	@Override
+	public TData getData() {
+		return this.data;
+	}
+	
+	
+	public void setData(final TData data) {
+		this.data= data;
+	}
+	
+	public void insert(final int idx) {
+		((RDataResizeExtension<?>) this.data).insertNA(idx);
+		this.length++;
+	}
+	
+	public void remove(final int idx) {
+		((RDataResizeExtension<?>) this.data).remove(idx);
+		this.length--;
+	}
+	
+	
+	@Override
+	public String toString() {
+		final StringBuilder sb= new StringBuilder();
+		sb.append("RObject type=RVector, class=").append(getRClassName());
+		sb.append("\n\tlength=").append(getLength());
+		sb.append("\n\tdata: ");
+		sb.append(this.data.toString());
+		return sb.toString();
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/SimpleRList.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/SimpleRList.java
new file mode 100644
index 0000000..88f4ff1
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/SimpleRList.java
@@ -0,0 +1,57 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data.impl;
+
+import org.eclipse.statet.rj.data.RCharacterStore;
+
+
+public class SimpleRList<T> {
+	
+	
+	private final RCharacter32Store names;
+	private final T[] values;
+	
+	
+	public SimpleRList(final T[] values, final RCharacter32Store names) {
+		this.names= names;
+		this.values= values;
+	}
+	
+	
+	public int getLength() {
+		return this.names.length();
+	}
+	
+	public RCharacterStore getNames() {
+		return this.names;
+	}
+	
+	public String getName(final int idx) {
+		return this.names.get(idx);
+	}
+	
+	public T get(final int idx) {
+		return this.values[idx];
+	}
+	
+	public T get(final String name) {
+		final int idx= this.names.indexOf(name, 0);
+		if (idx >= 0) {
+			return this.values[idx];
+		}
+		return null;
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.server.remotetools/.classpath b/core/org.eclipse.statet.rj.server.remotetools/.classpath
new file mode 100644
index 0000000..eca7bdb
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server.remotetools/.classpath
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
+	<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+	<classpathentry kind="src" path="src"/>
+	<classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/core/org.eclipse.statet.rj.server.remotetools/.gitignore b/core/org.eclipse.statet.rj.server.remotetools/.gitignore
new file mode 100644
index 0000000..ef319c8
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server.remotetools/.gitignore
@@ -0,0 +1,3 @@
+/bin
+/binShaj
+/target
diff --git a/core/org.eclipse.statet.rj.server.remotetools/.project b/core/org.eclipse.statet.rj.server.remotetools/.project
new file mode 100644
index 0000000..988eb46
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server.remotetools/.project
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>org.eclipse.statet.rj.server.remotetools</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.jdt.core.javabuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.pde.ManifestBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.pde.SchemaBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.jdt.core.javanature</nature>
+		<nature>org.eclipse.pde.PluginNature</nature>
+	</natures>
+</projectDescription>
diff --git a/core/org.eclipse.statet.rj.server.remotetools/.settings/org.eclipse.core.resources.prefs b/core/org.eclipse.statet.rj.server.remotetools/.settings/org.eclipse.core.resources.prefs
new file mode 100644
index 0000000..99f26c0
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server.remotetools/.settings/org.eclipse.core.resources.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+encoding/<project>=UTF-8
diff --git a/core/org.eclipse.statet.rj.server.remotetools/.settings/org.eclipse.core.runtime.prefs b/core/org.eclipse.statet.rj.server.remotetools/.settings/org.eclipse.core.runtime.prefs
new file mode 100644
index 0000000..5a0ad22
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server.remotetools/.settings/org.eclipse.core.runtime.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+line.separator=\n
diff --git a/core/org.eclipse.statet.rj.server.remotetools/.settings/org.eclipse.jdt.core.prefs b/core/org.eclipse.statet.rj.server.remotetools/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000..ccb1eaa
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server.remotetools/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,325 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.codeComplete.argumentPrefixes=
+org.eclipse.jdt.core.codeComplete.argumentSuffixes=
+org.eclipse.jdt.core.codeComplete.fieldPrefixes=
+org.eclipse.jdt.core.codeComplete.fieldSuffixes=
+org.eclipse.jdt.core.codeComplete.localPrefixes=
+org.eclipse.jdt.core.codeComplete.localSuffixes=
+org.eclipse.jdt.core.codeComplete.staticFieldPrefixes=
+org.eclipse.jdt.core.codeComplete.staticFieldSuffixes=
+org.eclipse.jdt.core.codeComplete.staticFinalFieldPrefixes=
+org.eclipse.jdt.core.codeComplete.staticFinalFieldSuffixes=
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=1.8
+org.eclipse.jdt.core.compiler.debug.lineNumber=generate
+org.eclipse.jdt.core.compiler.debug.localVariable=generate
+org.eclipse.jdt.core.compiler.debug.sourceFile=generate
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.source=1.8
+org.eclipse.jdt.core.formatter.align_fields_grouping_blank_lines=2147483647
+org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_assignment=0
+org.eclipse.jdt.core.formatter.alignment_for_binary_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_compact_if=16
+org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=80
+org.eclipse.jdt.core.formatter.alignment_for_enum_constants=0
+org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16
+org.eclipse.jdt.core.formatter.alignment_for_expressions_in_for_loop_header=0
+org.eclipse.jdt.core.formatter.alignment_for_method_declaration=0
+org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16
+org.eclipse.jdt.core.formatter.alignment_for_parameterized_type_references=0
+org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_resources_in_try=85
+org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=16
+org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_type_arguments=0
+org.eclipse.jdt.core.formatter.alignment_for_type_parameters=0
+org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch=16
+org.eclipse.jdt.core.formatter.blank_lines_after_imports=2
+org.eclipse.jdt.core.formatter.blank_lines_after_package=1
+org.eclipse.jdt.core.formatter.blank_lines_before_field=0
+org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=1
+org.eclipse.jdt.core.formatter.blank_lines_before_imports=1
+org.eclipse.jdt.core.formatter.blank_lines_before_member_type=1
+org.eclipse.jdt.core.formatter.blank_lines_before_method=1
+org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=2
+org.eclipse.jdt.core.formatter.blank_lines_before_package=1
+org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=1
+org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=1
+org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_block=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_lambda_body=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=false
+org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=false
+org.eclipse.jdt.core.formatter.comment.format_block_comments=true
+org.eclipse.jdt.core.formatter.comment.format_header=false
+org.eclipse.jdt.core.formatter.comment.format_html=true
+org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=true
+org.eclipse.jdt.core.formatter.comment.format_line_comments=true
+org.eclipse.jdt.core.formatter.comment.format_source_code=true
+org.eclipse.jdt.core.formatter.comment.indent_parameter_description=false
+org.eclipse.jdt.core.formatter.comment.indent_root_tags=true
+org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert
+org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=do not insert
+org.eclipse.jdt.core.formatter.comment.line_length=100
+org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries=false
+org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries=true
+org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments=false
+org.eclipse.jdt.core.formatter.compact_else_if=true
+org.eclipse.jdt.core.formatter.continuation_indentation=2
+org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=2
+org.eclipse.jdt.core.formatter.disabling_tag=@formatter\:off
+org.eclipse.jdt.core.formatter.enabling_tag=@formatter\:on
+org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false
+org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true
+org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true
+org.eclipse.jdt.core.formatter.indent_empty_lines=true
+org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true
+org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true
+org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true
+org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=false
+org.eclipse.jdt.core.formatter.indentation.size=4
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_enum_constant=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_label=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_type_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert
+org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert
+org.eclipse.jdt.core.formatter.insert_space_after_lambda_arrow=insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources=insert
+org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert
+org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=insert
+org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert
+org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw=insert
+org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.join_lines_in_comments=true
+org.eclipse.jdt.core.formatter.join_wrapped_lines=true
+org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=false
+org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false
+org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=false
+org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false
+org.eclipse.jdt.core.formatter.lineSplit=100
+org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false
+org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=false
+org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0
+org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=1
+org.eclipse.jdt.core.formatter.parentheses_positions_in_annotation=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_catch_clause=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_enum_constant_declaration=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_for_statment=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_if_while_statement=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_lambda_declaration=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_method_delcaration=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_method_invocation=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_switch_statement=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_try_clause=common_lines
+org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=true
+org.eclipse.jdt.core.formatter.tabulation.char=tab
+org.eclipse.jdt.core.formatter.tabulation.size=4
+org.eclipse.jdt.core.formatter.use_on_off_tags=false
+org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false
+org.eclipse.jdt.core.formatter.wrap_before_assignment_operator=false
+org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true
+org.eclipse.jdt.core.formatter.wrap_before_conditional_operator=false
+org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch=true
+org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true
+org.eclipse.jdt.core.javaFormatter=org.eclipse.jdt.core.defaultJavaFormatter
diff --git a/core/org.eclipse.statet.rj.server.remotetools/.settings/org.eclipse.jdt.ui.prefs b/core/org.eclipse.statet.rj.server.remotetools/.settings/org.eclipse.jdt.ui.prefs
new file mode 100644
index 0000000..e62a4f5
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server.remotetools/.settings/org.eclipse.jdt.ui.prefs
@@ -0,0 +1,131 @@
+cleanup.add_default_serial_version_id=true
+cleanup.add_generated_serial_version_id=false
+cleanup.add_missing_annotations=true
+cleanup.add_missing_deprecated_annotations=true
+cleanup.add_missing_methods=false
+cleanup.add_missing_nls_tags=false
+cleanup.add_missing_override_annotations=true
+cleanup.add_missing_override_annotations_interface_methods=true
+cleanup.add_serial_version_id=false
+cleanup.always_use_blocks=true
+cleanup.always_use_parentheses_in_expressions=true
+cleanup.always_use_this_for_non_static_field_access=true
+cleanup.always_use_this_for_non_static_method_access=false
+cleanup.convert_functional_interfaces=false
+cleanup.convert_to_enhanced_for_loop=false
+cleanup.correct_indentation=false
+cleanup.format_source_code=false
+cleanup.format_source_code_changes_only=false
+cleanup.insert_inferred_type_arguments=false
+cleanup.make_local_variable_final=true
+cleanup.make_parameters_final=true
+cleanup.make_private_fields_final=true
+cleanup.make_type_abstract_if_missing_method=false
+cleanup.make_variable_declarations_final=true
+cleanup.never_use_blocks=false
+cleanup.never_use_parentheses_in_expressions=false
+cleanup.organize_imports=true
+cleanup.qualify_static_field_accesses_with_declaring_class=false
+cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true
+cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=false
+cleanup.qualify_static_member_accesses_with_declaring_class=true
+cleanup.qualify_static_method_accesses_with_declaring_class=false
+cleanup.remove_private_constructors=true
+cleanup.remove_redundant_type_arguments=true
+cleanup.remove_trailing_whitespaces=false
+cleanup.remove_trailing_whitespaces_all=true
+cleanup.remove_trailing_whitespaces_ignore_empty=false
+cleanup.remove_unnecessary_casts=true
+cleanup.remove_unnecessary_nls_tags=true
+cleanup.remove_unused_imports=true
+cleanup.remove_unused_local_variables=false
+cleanup.remove_unused_private_fields=true
+cleanup.remove_unused_private_members=false
+cleanup.remove_unused_private_methods=true
+cleanup.remove_unused_private_types=true
+cleanup.sort_members=false
+cleanup.sort_members_all=false
+cleanup.use_anonymous_class_creation=false
+cleanup.use_blocks=true
+cleanup.use_blocks_only_for_return_and_throw=false
+cleanup.use_lambda=true
+cleanup.use_parentheses_in_expressions=false
+cleanup.use_this_for_non_static_field_access=true
+cleanup.use_this_for_non_static_field_access_only_if_necessary=false
+cleanup.use_this_for_non_static_method_access=true
+cleanup.use_this_for_non_static_method_access_only_if_necessary=true
+cleanup.use_type_arguments=false
+cleanup_profile=_StatET
+cleanup_settings_version=2
+eclipse.preferences.version=1
+editor_save_participant_org.eclipse.jdt.ui.postsavelistener.cleanup=true
+formatter_profile=_StatET
+formatter_settings_version=12
+org.eclipse.jdt.ui.exception.name=e
+org.eclipse.jdt.ui.gettersetter.use.is=true
+org.eclipse.jdt.ui.ignorelowercasenames=true
+org.eclipse.jdt.ui.importorder=\#;java;javax;com.ibm.icu;org.osgi;org.eclipse;;org.eclipse.statet.jcommons;org.eclipse.statet.ecommons;org.eclipse.statet;
+org.eclipse.jdt.ui.javadoc=true
+org.eclipse.jdt.ui.keywordthis=true
+org.eclipse.jdt.ui.ondemandthreshold=99
+org.eclipse.jdt.ui.overrideannotation=true
+org.eclipse.jdt.ui.staticondemandthreshold=99
+org.eclipse.jdt.ui.text.custom_code_templates=<?xml version\="1.0" encoding\="UTF-8" standalone\="no"?><templates><template autoinsert\="true" context\="gettercomment_context" deleted\="false" description\="Comment for getter method" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.gettercomment" name\="gettercomment">/**\n * @return the ${bare_field_name}\n */</template><template autoinsert\="true" context\="settercomment_context" deleted\="false" description\="Comment for setter method" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.settercomment" name\="settercomment">/**\n * @param ${param} the ${bare_field_name} to set\n */</template><template autoinsert\="true" context\="constructorcomment_context" deleted\="false" description\="Comment for created constructors" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.constructorcomment" name\="constructorcomment">/**\n * ${tags}\n */</template><template autoinsert\="false" context\="filecomment_context" deleted\="false" description\="Comment for created Java files" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.filecomment" name\="filecomment">/*\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\#\n \# Copyright (c) ${year} ${user} and others.\n # \n # This program and the accompanying materials are made available under the\n # terms of the Eclipse Public License 2.0 which is available at\n # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n # which is available at https://www.apache.org/licenses/LICENSE-2.0.\n # \n # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n # \n \# Contributors\:\n \#     ${user} - initial API and implementation\n \#\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=*/</template><template autoinsert\="false" context\="typecomment_context" deleted\="false" description\="Comment for created types" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.typecomment" name\="typecomment">/**\n * \n * ${tags}\n */</template><template autoinsert\="true" context\="fieldcomment_context" deleted\="false" description\="Comment for fields" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.fieldcomment" name\="fieldcomment">/**\n * \n */</template><template autoinsert\="true" context\="methodcomment_context" deleted\="false" description\="Comment for non-overriding methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.methodcomment" name\="methodcomment">/**\n * ${tags}\n */</template><template autoinsert\="false" context\="overridecomment_context" deleted\="false" description\="Comment for overriding methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.overridecomment" name\="overridecomment"/><template autoinsert\="true" context\="delegatecomment_context" deleted\="false" description\="Comment for delegate methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.delegatecomment" name\="delegatecomment">/**\n * ${tags}\n * ${see_to_target}\n */</template><template autoinsert\="false" context\="newtype_context" deleted\="false" description\="Newly created files" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.newtype" name\="newtype">${filecomment}\n\n${package_declaration}\n\n${typecomment}\n${type_declaration}</template><template autoinsert\="true" context\="classbody_context" deleted\="false" description\="Code in new class type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.classbody" name\="classbody">\n</template><template autoinsert\="true" context\="interfacebody_context" deleted\="false" description\="Code in new interface type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.interfacebody" name\="interfacebody">\n</template><template autoinsert\="true" context\="enumbody_context" deleted\="false" description\="Code in new enum type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.enumbody" name\="enumbody">\n</template><template autoinsert\="true" context\="annotationbody_context" deleted\="false" description\="Code in new annotation type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.annotationbody" name\="annotationbody">\n</template><template autoinsert\="true" context\="catchblock_context" deleted\="false" description\="Code in new catch blocks" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.catchblock" name\="catchblock">// ${todo} Auto-generated catch block\n${exception_var}.printStackTrace();</template><template autoinsert\="true" context\="methodbody_context" deleted\="false" description\="Code in created method stubs" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.methodbody" name\="methodbody">// ${todo} Auto-generated method stub\n${body_statement}</template><template autoinsert\="true" context\="constructorbody_context" deleted\="false" description\="Code in created constructor stubs" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.constructorbody" name\="constructorbody">${body_statement}\n// ${todo} Auto-generated constructor stub</template><template autoinsert\="true" context\="getterbody_context" deleted\="false" description\="Code in created getters" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.getterbody" name\="getterbody">return ${field};</template><template autoinsert\="true" context\="setterbody_context" deleted\="false" description\="Code in created setters" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.setterbody" name\="setterbody">${field} \= ${param};</template></templates>
+sp_cleanup.add_default_serial_version_id=true
+sp_cleanup.add_generated_serial_version_id=false
+sp_cleanup.add_missing_annotations=true
+sp_cleanup.add_missing_deprecated_annotations=true
+sp_cleanup.add_missing_methods=false
+sp_cleanup.add_missing_nls_tags=false
+sp_cleanup.add_missing_override_annotations=true
+sp_cleanup.add_missing_override_annotations_interface_methods=true
+sp_cleanup.add_serial_version_id=false
+sp_cleanup.always_use_blocks=true
+sp_cleanup.always_use_parentheses_in_expressions=true
+sp_cleanup.always_use_this_for_non_static_field_access=true
+sp_cleanup.always_use_this_for_non_static_method_access=false
+sp_cleanup.convert_functional_interfaces=false
+sp_cleanup.convert_to_enhanced_for_loop=false
+sp_cleanup.correct_indentation=false
+sp_cleanup.format_source_code=false
+sp_cleanup.format_source_code_changes_only=false
+sp_cleanup.insert_inferred_type_arguments=false
+sp_cleanup.make_local_variable_final=true
+sp_cleanup.make_parameters_final=true
+sp_cleanup.make_private_fields_final=true
+sp_cleanup.make_type_abstract_if_missing_method=false
+sp_cleanup.make_variable_declarations_final=false
+sp_cleanup.never_use_blocks=false
+sp_cleanup.never_use_parentheses_in_expressions=false
+sp_cleanup.on_save_use_additional_actions=true
+sp_cleanup.organize_imports=true
+sp_cleanup.qualify_static_field_accesses_with_declaring_class=false
+sp_cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true
+sp_cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=false
+sp_cleanup.qualify_static_member_accesses_with_declaring_class=true
+sp_cleanup.qualify_static_method_accesses_with_declaring_class=false
+sp_cleanup.remove_private_constructors=true
+sp_cleanup.remove_redundant_type_arguments=true
+sp_cleanup.remove_trailing_whitespaces=false
+sp_cleanup.remove_trailing_whitespaces_all=false
+sp_cleanup.remove_trailing_whitespaces_ignore_empty=true
+sp_cleanup.remove_unnecessary_casts=true
+sp_cleanup.remove_unnecessary_nls_tags=false
+sp_cleanup.remove_unused_imports=false
+sp_cleanup.remove_unused_local_variables=false
+sp_cleanup.remove_unused_private_fields=false
+sp_cleanup.remove_unused_private_members=false
+sp_cleanup.remove_unused_private_methods=false
+sp_cleanup.remove_unused_private_types=true
+sp_cleanup.sort_members=false
+sp_cleanup.sort_members_all=false
+sp_cleanup.use_anonymous_class_creation=false
+sp_cleanup.use_blocks=true
+sp_cleanup.use_blocks_only_for_return_and_throw=false
+sp_cleanup.use_lambda=false
+sp_cleanup.use_parentheses_in_expressions=false
+sp_cleanup.use_this_for_non_static_field_access=true
+sp_cleanup.use_this_for_non_static_field_access_only_if_necessary=false
+sp_cleanup.use_this_for_non_static_method_access=true
+sp_cleanup.use_this_for_non_static_method_access_only_if_necessary=true
+sp_cleanup.use_type_arguments=false
diff --git a/core/org.eclipse.statet.rj.server.remotetools/META-INF/MANIFEST.MF b/core/org.eclipse.statet.rj.server.remotetools/META-INF/MANIFEST.MF
new file mode 100644
index 0000000..fc1cbdc
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server.remotetools/META-INF/MANIFEST.MF
@@ -0,0 +1,8 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-SymbolicName: org.eclipse.statet.rj.server.remotetools
+Bundle-Version: 2.1.0.qualifier
+Bundle-Vendor: Eclipse.org
+Bundle-Name: StatET RJ - Server - Remote Tools
+Bundle-RequiredExecutionEnvironment: JavaSE-1.8
+Require-Bundle: org.eclipse.statet.rj.server;bundle-version="[2.1.0,2.2.0)"
diff --git a/core/org.eclipse.statet.rj.server.remotetools/about.html b/core/org.eclipse.statet.rj.server.remotetools/about.html
new file mode 100644
index 0000000..e71ae66
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server.remotetools/about.html
@@ -0,0 +1,37 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+		"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+<title>About</title>
+</head>
+<body lang="EN-US">
+<h2>About This Content</h2>
+
+<p>December 1, 2017</p>
+<h3>License</h3>
+
+<p>
+	The Eclipse Foundation makes available all content in this plug-in
+	(&quot;Content&quot;). Unless otherwise indicated below, the Content
+	is provided to you under the terms and conditions of the Eclipse
+	Public License Version 2.0 (&quot;EPL&quot;), or the Apache License,
+	Version 2.0 (AL). A copy of the EPL is available at <a href="https://www.eclipse.org/legal/epl-2.0">https://www.eclipse.org/legal/epl-2.0</a>.
+	For purposes of the EPL, &quot;Program&quot; will mean the Content.
+	A copy of the AL is available at <a href="https://www.apache.org/licenses/LICENSE-2.0">https://www.apache.org/licenses/LICENSE-2.0</a>.
+</p>
+
+<p>
+	If you did not receive this Content directly from the Eclipse
+	Foundation, the Content is being redistributed by another party
+	(&quot;Redistributor&quot;) and different terms and conditions may
+	apply to your use of any object code in the Content. Check the
+	Redistributor's license that was provided with the Content. If no such
+	license exists, contact the Redistributor. Unless otherwise indicated
+	below, the terms and conditions of the EPL or AL still apply to any
+	source code in the Content and such source code may be obtained at <a
+	href="https://www.eclipse.org/">https://www.eclipse.org</a>.
+</p>
+
+</body>
+</html>
diff --git a/core/org.eclipse.statet.rj.server.remotetools/about_files/LICENSE.txt b/core/org.eclipse.statet.rj.server.remotetools/about_files/LICENSE.txt
new file mode 100644
index 0000000..d645695
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server.remotetools/about_files/LICENSE.txt
@@ -0,0 +1,202 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
diff --git a/core/org.eclipse.statet.rj.server.remotetools/build.properties b/core/org.eclipse.statet.rj.server.remotetools/build.properties
new file mode 100644
index 0000000..3fac0f6
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server.remotetools/build.properties
@@ -0,0 +1,12 @@
+source..= srcShaj/
+output..= binShaj/
+javacDefaultEncoding..= UTF-8
+
+bin.includes = META-INF/,\
+               about.html,\
+               about_files/,\
+               startup.sh,\
+               startup.cmd,\
+               startup.ps1,\
+               security.policy
+src.includes= .settings/org.eclipse.core.resources.prefs
diff --git a/core/org.eclipse.statet.rj.server.remotetools/security.policy b/core/org.eclipse.statet.rj.server.remotetools/security.policy
new file mode 100644
index 0000000..6e902c1
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server.remotetools/security.policy
@@ -0,0 +1,7 @@
+grant codeBase "file:${{java.ext.dirs}}/*" {

+	permission java.security.AllPermission;

+};

+

+grant {

+	permission java.security.AllPermission;

+};

diff --git a/core/org.eclipse.statet.rj.server.remotetools/startup.cmd b/core/org.eclipse.statet.rj.server.remotetools/startup.cmd
new file mode 100644
index 0000000..f76decb
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server.remotetools/startup.cmd
@@ -0,0 +1,411 @@
+echo off
+
+rem #=============================================================================#
+rem # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+rem # 
+rem # This program and the accompanying materials are made available under the
+rem # terms of the Eclipse Public License 2.0 which is available at
+rem # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+rem # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+rem # 
+rem # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+rem # 
+rem # Contributors:
+rem #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+rem #=============================================================================#
+
+
+rem ##
+rem # Windows batch script to start R server (for StatET)
+rem ##
+rem # Usually you have to change only the CONFIG sections. You should set at least:
+rem #     R_HOME
+rem #     JAVA_HOME
+rem # Depending on the system configuration, it can be required to set:
+rem #     S_HOSTADDRESS
+rem # 
+rem # The authentication is set to 'fx' (method using SSH) by default.
+rem ##
+rem # Usage of this script:
+rem #     startup.cmd <address> [options]
+rem #     startup.cmd <name> [options]
+rem # It starts the R server asynchronously in background by default.
+rem #     <address>                        the complete RMI-address
+rem #     <name>                           the session name only (the hostname
+rem #                                      should be set in this file)
+rem # Options:
+rem #     -wd=<working directory>          initial R working directory
+rem #     -debug                           enables debug output and
+rem #                                      runs R in foreground
+rem #
+rem # Note: This script does not start an RMI registry! You have to launch it
+rem # as system daemon or manually (see Java documentation), e.g. by:
+rem #     $JAVA_HOME/bin/rmiregistry.exe
+rem ##
+rem # Author: Stephan Wahlbrink <sw@wahlbrink.eu>
+rem ###############################################################################
+
+rem ###############################################################################
+rem # SCRIPT - INIT / READING PARAMETERS ##########################################
+rem ###############################################################################
+if [ -z "$1" ]
+then
+	echo Missing address or name for R server
+	exit -1
+fi
+set ADDRESS=$1
+set S_NAME=`basename $ADDRESS`
+set S_HOSTADDRESS=
+set S_REGISTRYPORT=
+if [ "$ADDRESS" != "$S_NAME" ]
+then
+	set S_HOSTADDRESS=`expr "$ADDRESS" : "[^/]*\/\/\([^:/]*\).*"`
+	set S_REGISTRYPORT=`expr "$ADDRESS" : "[^/]*\/\/[^:/]*:\([0-9]\+\)\/.*"`
+fi
+shift
+set WD=~
+set SCRIPT=`readlink -f "$0"`
+
+until [ -z "$1" ]  # Until all parameters used up
+do
+	case "$1" in
+	-wd=*)
+		WD=${1##-wd=}
+		;;
+#	-host=*)
+#		S_HOSTADDRESS=${1##-host=}
+#		;;
+	-debug*)
+		DEBUG=1
+		echo Debug mode enabled
+		;;
+	-dev*)
+		DEV=1
+		echo Development mode enabled
+		;;
+	*)
+		echo Unknown parameter: $1
+		;;
+	esac
+	shift
+done
+rem ###############################################################################
+
+rem ###############################################################################
+rem # CONFIG - SYSTEM SETTINGS ####################################################
+rem ###############################################################################
+rem # Configure the startup in the following sections
+
+rem ###############################################################################
+rem # Required system specific settings
+rem # 
+rem # Set the path to home of R and Java.
+rem # If parts of the R installation (e.g. the documentation) are located in not
+rem # sub-directories of R home, it is often required to set additional variables
+rem # specifying the several installation locations (see example).
+rem # 
+rem # Example:
+rem #     R_HOME=/usr/lib/R
+rem #     R_DOC_DIR=/usr/share/doc/R
+rem #     R_SHARE_DIR=/usr/share/R
+rem #     R_INCLUDE_DIR=/usr/include/R
+rem #     R_LIBS_SITE=/usr/local/lib/R/site-library
+rem #     JAVA_HOME=/usr/lib/jvm/java-6-sun
+
+set R_HOME=
+set JAVA_HOME=
+
+rem #rem ##############################################################################
+rem # Set the home and work directory of this R server.
+rem # The home must contain the jar files of this server, if this file is in this
+rem # directory, you don't have to change the value.
+rem # The working directory is for files like log files
+rem ##
+rem # Example:
+rem #     RJS_HOME=`dirname "$SCRIPT"`
+rem #     RJS_WORK=~/.RJServer
+
+set RJS_HOME=`dirname "$SCRIPT"`
+set RJS_WORK=~/.RJServer
+
+rem ###############################################################################
+rem # Set explicitly the hostname and port you want to use to access the RMI 
+rem # registry/R server.
+rem # It is recommended to use the IP address instead of a name.
+rem # By default, the hostname is extracted form the specified RMI address 
+rem # (script parameter). Nevertheless there are some reasons to set it explicitly
+rem # here, e.g.:
+rem #  - For SSH tunnel connections '127.0.0.1' (localhost) is sufficient;
+rem #    recommend, if no other network connections are used; and required if the 
+rem #    public IP address is blocked by the firewall.
+rem #  - To make sure that the correct IP address is set even the hostname is 
+rem #    used in the RMI address.
+rem ##
+rem # Usage:
+rem #     S_HOSTADDRESS=<ip or hostname>
+rem #     S_REGISTRYPORT=<port of rmi-registry>
+rem # Example:
+rem #     S_HOSTADDRESS=192.168.1.80
+
+rem set S_HOSTADDRESS=
+
+
+rem #rem ##############################################################################
+# Add additional java options here
+rem ##
+rem # Example:
+rem #     JAVA_OPTS="-server -Dorg.eclipse.statet.rj.rmi.disableSocketFactory=true"
+
+set JAVA_OPTS="-server"
+set JAVA_OPTS_LIB=
+
+
+rem ###############################################################################
+rem # CONFIG - AUTHENTICATION METHODS #############################################
+rem ###############################################################################
+rem # You must specify the method (exactly one) to use for authentication when 
+rem # clients wants to connect to the R.
+rem # There are several methods available. The methods provided by default
+rem # are described in the following subsections. To change the method uncomment
+rem # the lines of method you want to use and comment the previous AUTH definition.
+rem ##
+rem # General usage:
+rem #     RJ parm:     -auth=<method-id>[:<config>]
+rem #                  -auth=<classname>[:<config>]
+rem # 
+rem # <config> option depends on the selected method
+
+rem ###############################################################################
+rem # Authentication method: disabled / 'none'
+rem # 
+rem # Disables authentication. Anybody can connect to R. Use it only if you are in 
+rem # a secure environment! All users can connect to R get full user rights!
+rem ##
+rem # General usage:
+rem #     RJ param:    -auth=none
+rem # 
+rem # Script Usage:
+rem #     AUTH=none
+
+rem set AUTH=none
+
+rem ###############################################################################
+rem # Authentication method: password file / 'name-pass'
+rem # 
+rem # Authentication using loginname-password combination.
+rem ##
+rem # General usage:
+rem #     RJ Param:    -auth=name-pass:file=<passwordfile>
+rem # 
+rem # Script usage:
+rem #     AUTH=name-pass:file
+rem #     AUTH_PW_FILE=~/.RJServer/logins
+rem # 
+rem # <passwordfile> is the path to a property file with
+rem #     pairs of loginname and password, for example:
+rem #         myname=mypassword
+rem #     Make sure that only authorized users can read this file!
+
+rem set AUTH=name-pass:file
+rem set AUTH_PW_FILE=~/.RJServer/logins
+
+rem ###############################################################################
+rem # Authentication method: local user account / 'local-shaj'
+rem # 
+rem # Authentication using your local loginname-password combination (PAM).
+rem # The 'Shaj' library is required for this method. It is provided in sources and
+rem # binary form for several platforms. If no binary match your environment, you
+rem # have to build it for your system. You find the files inside the folder
+rem #     shaj
+rem # of this remotetools package.
+rem ##
+rem # General Usage:
+rem #     RJ Param:    -auth=local-shaj
+rem #     Java Prop:   java.library.path=<folder of library>
+rem # 
+rem # Script Usage:
+rem #     AUTH=local-shaj
+rem #     AUTH_SHAJ_LD_DIR=<folder of library>
+rem # Example:
+rem #     AUTH=local-shaj
+rem #     AUTH_SHAJ_LD_DIR="$RJS_HOME/shaj/linux-x64"
+
+rem set AUTH=local-shaj
+rem set AUTH_SHAJ_LD_DIR="$RJS_HOME/shaj/<platform>"
+
+rem ###############################################################################
+rem # Authentication method: ssh / 'fx' (exchange over file)
+rem # 
+rem # Authentication for automatic startup (via ssh by StatET).
+rem ##
+rem # General Usage:
+rem #     RJ Param:    -auth=fx:file=<keyfile>
+rem # 
+rem # Script Usage:
+rem #     AUTH=fx:file
+rem #     AUTH_FX_FILE=<keyfile>
+rem #     AUTH_FX_USER=$USER
+rem #     AUTH_FX_MASK=600
+rem # 
+rem # <keyfile> a (empty). The fs permission to edit the files represents the
+rem #     right to login into R, so:
+rem #     The file must be writable for authorized user only!
+rem #     If the script setup is used, the files is created automatically and
+rem #     the permission is set according to AUTH_FX_USER and AUTH_FX_MASK
+
+set AUTH=fx:file
+set AUTH_FX_FILE="$RJS_WORK/session-$S_NAME.lock"
+set AUTH_FX_USER=$USER
+set AUTH_FX_MASK=600
+
+
+rem ###############################################################################
+rem # SCRIPT - STARTUP SERVER #####################################################
+rem ###############################################################################
+rem # Usually you don't have to edit the lines below
+
+rem set $JAVA_HOME/bin/rmiregistry &
+
+mkdir -p "$RJS_WORK"
+
+rem ## Final RMI address
+if [ -n "$S_HOSTADDRESS" ]
+then
+	set S_ADDRESS="//$S_HOSTADDRESS"
+	if [ -n "$S_REGISTRYPORT" ]
+	then
+		set S_ADDRESS="$S_ADDRESS:$S_REGISTRYPORT"
+	fi
+	set S_ADDRESS="$S_ADDRESS/$S_NAME"
+else
+	set S_ADDRESS="//$S_NAME"
+fi
+
+rem ## Finish auth configuration
+if [ "$FORCE_AUTH" ]
+then
+	set AUTH="$FORCE_AUTH"
+fi
+
+if [ "$AUTH" = "name-pass:file" ]
+then
+	set AUTH="name-pass:file=$AUTH_PW_FILE"
+fi
+
+if [ "$AUTH" = "local-shaj" ]
+then
+	set AUTH=local-shaj
+	set JAVA_OPTS_LIB="$JAVA_OPTS_LIB:$AUTH_SHAJ_LD_DIR"
+	set JAVA_CP="$JAVA_CP:$RJS_HOME/shaj/auth.jar"
+fi
+
+if [ "$AUTH" = "fx:file" ]
+then
+	set AUTH="fx:file=$AUTH_FX_FILE"
+	set AUTH_FX_FOLDER=`dirname "$AUTH_FX_FILE"`
+	mkdir -p "$AUTH_FX_FOLDER"
+	echo "00000000" > "$AUTH_FX_FILE"
+	if [ $AUTH_FX_USER ]
+	then
+		chown $AUTH_FX_USER "$AUTH_FX_FILE"
+	fi
+	if [ $AUTH_FX_MASK ]
+	then
+		chmod $AUTH_FX_MASK "$AUTH_FX_FILE"
+	fi
+fi
+
+OPTS="-auth=$AUTH"
+if [ $DEBUG ]
+then
+	OPTS="$OPTS -verbose"
+fi
+
+rem ## Java config
+if [ $DEV ]
+then
+	set JAVA_CP="$RJS_HOME/../org.eclipse.statet.rj.server/bin:$RJS_HOME/../org.eclipse.statet.rj.data/bin:$RJS_HOME/bin:$RJS_HOME/binShaj"
+	set RMI_BASE="file://$RJS_HOME/../org.eclipse.statet.rj.server/bin"
+	set RJAVA_CP=
+else
+	set JAVA_CP="$RJS_HOME/org.eclipse.statet.rj.server.jar:$RJS_HOME/org.eclipse.statet.rj.data.jar:$JAVA_CP"
+	set RMI_BASE="file://$RJS_HOME/org.eclipse.statet.rj.server.jar"
+	set RJAVA_CP=
+fi
+
+set JAVA_OPTS="$JAVA_OPTS -Djava.security.policy=$RJS_HOME/security.policy -Djava.rmi.server.codebase=$RMI_BASE"
+if [ -n "$S_HOSTADDRESS" ]
+then
+	set JAVA_OPTS="$JAVA_OPTS -Djava.rmi.server.hostname=$S_HOSTADDRESS"
+fi
+if [ -n "$JAVA_OPTS_LIB" ]
+then
+	set JAVA_OPTS="$JAVA_OPTS -Djava.library.path=$JAVA_OPTS_LIB"
+fi
+if [ -n "$RJAVA_CP" ]
+then
+	set JAVA_OPTS="$JAVA_OPTS -Drjava.class.path=$RJAVA_CP"
+fi
+
+rem ## Other environment
+set PATH=$R_HOME/bin:$PATH
+set LD_LIBRARY_PATH=$R_HOME/lib
+
+export PATH
+export LD_LIBRARY_PATH
+export JAVA_HOME
+export R_HOME
+export R_LIBS
+export R_LIBS_USER
+export R_LIBS_SITE
+export R_DOC_DIR
+export R_SHARE_DIR
+export R_INCLUDE_DIR
+export LC_ALL
+
+cd "$WD"
+
+set START_EXEC="$JAVA_HOME/bin/java -cp $JAVA_CP $JAVA_OPTS org.eclipse.statet.rj.server.RMIServerControl start $S_ADDRESS $OPTS"
+rem echo $START_EXEC
+
+if [ $DEBUG ]
+then
+	echo S_HOSTADDRESS = $S_HOSTADDRESS
+	echo S_REGISTRYPORT = $S_REGISTRYPORT
+	echo PATH = $PATH
+	echo LD_LIBRARY_PATH = $LD_LIBRARY_PATH
+	echo R_HOME = $R_HOME
+	echo JAVA_HOME = $JAVA_HOME
+	echo CLASSPATH = $JAVA_CP
+	echo JAVA_OPTIONS = $JAVA_OPTS
+	echo AUTH = $AUTH
+	
+	rem # Start server directly
+	$START_EXEC
+	START_EXIT=$?
+	START_PID=$!
+	exit $START_EXIT
+else
+	rem # First check if running or dead server is already bound
+	CLEAN_EXEC="$JAVA_HOME/bin/java -cp $JAVA_CP $JAVA_OPTS org.eclipse.statet.rj.server.RMIServerControl clean $S_ADDRESS"
+	$CLEAN_EXEC
+	CLEAN_EXIT=$?
+	if [ $CLEAN_EXIT -ne 0 ]
+	then
+		echo "Check and cleanup of old server failed (CODE=$CLEAN_EXIT), cancelling startup."
+		exit $CLEAN_EXIT
+	fi
+	
+	rem # Start server detached
+	nohup $START_EXEC > "$RJS_WORK/session-$S_NAME.out" 2>&1 < /dev/null &
+	START_EXIT=$?
+	START_PID=$!
+	if [ $START_EXIT -eq 0 ]
+	then
+		echo "Started server in background (PID=$START_PID)."
+		exit 0
+	else
+		echo "Startup failed"
+		exit $START_EXIT
+	fi
+fi
diff --git a/core/org.eclipse.statet.rj.server.remotetools/startup.ps1 b/core/org.eclipse.statet.rj.server.remotetools/startup.ps1
new file mode 100644
index 0000000..93c4757
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server.remotetools/startup.ps1
@@ -0,0 +1,420 @@
+ #=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================#
+
+##
+# Shell (PowerShell) script to start R server (for StatET)
+##
+# Usually you have to change only the CONFIG sections. You should set at least:
+#     R_HOME
+#     JAVA_HOME
+# Depending on the system configuration, it can be required to set:
+#     S_HOSTADDRESS
+# 
+# The authentication is set to 'none' by default.
+##
+# Usage of this script:
+#     startup.sh <address> [options]
+#     startup.sh <name> [options]
+# It starts the R server asynchronously in background by default.
+#     <address>                        the complete RMI-address
+#     <name>                           the session name only (the hostname
+#                                      should be set in this file)
+# Options:
+#     -wd=<working directory>          initial R working directory
+#     -debug                           enables debug output and
+#                                      runs R in foreground
+#
+# Note: This script does not start an RMI registry! You have to launch it
+# as system daemon or manually (see Java documentation), e.g. by:
+#     %JAVA_HOME%/bin/rmiregistry.exe -J-Djava.rmi.server.codebase=file:///<path to file org.eclipse.statet.rj.server.jar>
+# or in a detached process (not official):
+#     %JAVA_HOME%/bin/javaw.exe -Djava.rmi.server.codebase=file:///<path to file org.eclipse.statet.rj.server.jar> sun.rmi.registry.RegistryImpl
+##
+# Author: Stephan Wahlbrink <sw@wahlbrink.eu>
+###############################################################################
+
+###############################################################################
+# SCRIPT - INIT / READING PARAMETERS ##########################################
+###############################################################################
+param([String] $ADDRESS)
+
+if ([String]::IsNullOrEmpty("$ADDRESS"))
+{
+	echo "Missing address or name for R server"
+	exit -1
+}
+
+$S_NAME=$ADDRESS -replace '.*\/([^/]+)$', '$1'
+$S_HOSTADDRESS=""
+$S_REGISTRYPORT=""
+if ( $ADDRESS -ne $S_NAME )
+{
+	$S_HOSTADDRESS=$ADDRESS -replace '[^/]*\/\/([^:/]*).*', '$1'
+	$S_REGISTRYPORT=$ADDRESS -replace '[^/]*\/\/[^:/]*:?([0-9]*)\/.*', '$1'
+}
+
+$WD=$HOME
+$SCRIPT=$MyInvocation.MyCommand.Path
+
+foreach ($1 in $Args) {
+	switch -wildcard ("$1") {
+	"-wd=*" {
+		$WD=$1.Substring(4)
+		}
+#	"-host=*" {
+#		$S_HOSTADDRESS=$1.Substring(6)
+#		}
+	"-debug*" {
+		$DEBUG=1
+		echo "Debug mode enabled"
+		}
+	"-dev*" {
+		$DEV=1
+		echo "Development mode enabled"
+		}
+	default {
+		echo "Unknown parameter: $1"
+		}
+	}
+}
+###############################################################################
+
+###############################################################################
+# CONFIG - SYSTEM SETTINGS ####################################################
+###############################################################################
+# Configure the startup in the following sections
+
+###############################################################################
+# Required system specific settings
+# 
+# Set the path to home of R and Java.
+# If parts of the R installation (e.g. the documentation) are located in not
+# sub-directories of R home, it is often required to set additional variables
+# specifying the several installation locations (see example).
+# 
+# Example:
+#     R_HOME="/usr/lib/R"
+#     R_ARCH="/x64"
+#     R_DOC_DIR="/usr/share/doc/R"
+#     R_SHARE_DIR="/usr/share/R"
+#     R_INCLUDE_DIR="/usr/include/R"
+#     R_LIBS_SITE="/usr/local/lib/R/site-library"
+#     JAVA_HOME="/usr/lib/jvm/java-6-sun"
+
+$R_HOME=""
+$R_ARCH="/x64"
+$JAVA_HOME=""
+
+###############################################################################
+# Set the home and work directory of this R server.
+# The home must contain the jar files of this server, if this file is in this
+# directory, you don't have to change the value.
+# The working directory is for files like log files
+##
+# Example:
+#     RJS_HOME=`dirname "$SCRIPT"`
+#     RJS_WORK="~/.RJServer"
+
+$RJS_HOME=Split-Path -Path $SCRIPT -Parent 
+$RJS_WORK="$HOME/.RJServer"
+
+###############################################################################
+# Set explicitly the hostname and port you want to use to access the RMI 
+# registry/R server.
+# It is recommended to use the IP address instead of a name.
+# By default, the hostname is extracted form the specified RMI address 
+# (script parameter). Nevertheless there are some reasons to set it explicitly
+# here, e.g.:
+#  - For SSH tunnel connections '127.0.0.1' (localhost) is sufficient;
+#    recommend, if no other network connections are used; and required if the 
+#    public IP address is blocked by the firewall.
+#  - To make sure that the correct IP address is set even the hostname is 
+#    used in the RMI address.
+##
+# Usage:
+#     S_HOSTADDRESS=<ip or hostname>
+#     S_REGISTRYPORT=<port of rmi-registry>
+# Example:
+#     S_HOSTADDRESS=192.168.1.80
+
+#$S_HOSTADDRESS=""
+
+
+###############################################################################
+# Add additional java options here
+##
+# Example:
+#     JAVA_OPTS="-server -Dorg.eclipse.statet.rj.rmi.disableSocketFactory=true"
+
+$JAVA_OPTS=@("-server")
+$JAVA_OPTS_LIB=@()
+
+
+###############################################################################
+# CONFIG - AUTHENTICATION METHODS #############################################
+###############################################################################
+# You must specify the method (exactly one) to use for authentication when 
+# clients wants to connect to the R.
+# There are several methods available. The methods provided by default
+# are described in the following subsections. To change the method uncomment
+# the lines of method you want to use and comment the previous AUTH definition.
+##
+# General usage:
+#     RJ parm:     -auth=<method-id>[:<config>]
+#                  -auth=<classname>[:<config>]
+# 
+# <config> option depends on the selected method
+
+###############################################################################
+# Authentication method: disabled / 'none'
+# 
+# Disables authentication. Anybody can connect to R. Use it only if you are in 
+# a secure environment! All users can connect to R get full user rights!
+##
+# General usage:
+#     RJ param:    -auth=none
+# 
+# Script Usage:
+#     AUTH=none
+
+$AUTH="none"
+
+###############################################################################
+# Authentication method: password file / 'name-pass'
+# 
+# Authentication using loginname-password combination.
+##
+# General usage:
+#     RJ Param:    -auth=name-pass:file=<passwordfile>
+# 
+# Script usage:
+#     AUTH="name-pass:file"
+#     AUTH_PW_FILE="~/.RJServer/logins"
+# 
+# <passwordfile> is the path to a property file with
+#     pairs of loginname and password, for example:
+#         myname=mypassword
+#     Make sure that only authorized users can read this file!
+
+#$AUTH="name-pass:file"
+#$AUTH_PW_FILE="$HOME/.RJServer/logins"
+
+###############################################################################
+# Authentication method: local user account / 'local-shaj'
+# 
+# Authentication using your local loginname-password combination (PAM).
+# The 'Shaj' library is required for this method. It is provided in sources and
+# binary form for several platforms. If no binary match your environment, you
+# have to build it for your system. You find the files inside the folder
+#     shaj
+# of this remotetools package.
+##
+# General Usage:
+#     RJ Param:    -auth=local-shaj
+#     Java Prop:   java.library.path=<folder of library>
+# 
+# Script Usage:
+#     AUTH="local-shaj"
+#     AUTH_SHAJ_LD_DIR="<folder of library>"
+# Example:
+#     AUTH=local-shaj
+#     AUTH_SHAJ_LD_DIR="$RJS_HOME/shaj/linux-x64"
+
+#$AUTH="local-shaj"
+#$AUTH_SHAJ_LD_DIR="$RJS_HOME/shaj/<platform>"
+
+###############################################################################
+# Authentication method: ssh / 'fx' (exchange over file)
+# 
+# Authentication for automatic startup (via ssh by StatET).
+##
+# General Usage:
+#     RJ Param:    -auth=fx:file=<keyfile>
+# 
+# Script Usage:
+#     AUTH="fx:file"
+#     AUTH_FX_FILE="<keyfile>"
+#     AUTH_FX_USER=$USER
+#     AUTH_FX_MASK="600"
+# 
+# <keyfile> a (empty). The fs permission to edit the files represents the
+#     right to login into R, so:
+#     The file must be writable for authorized user only!
+#     If the script setup is used, the files is created automatically and
+#     the permission is set according to AUTH_FX_USER and AUTH_FX_MASK
+
+#$AUTH="fx:file"
+$AUTH_FX_FILE="$RJS_WORK/session-$S_NAME.lock"
+$AUTH_FX_USER=[System.Security.Principal.WindowsIdentity]::GetCurrent().Name
+$AUTH_FX_MASK=new-object System.Security.AccessControl.FileSystemAccessRule $AUTH_FX_USER, 'FullControl', 'Allow'
+
+
+###############################################################################
+# SCRIPT - STARTUP SERVER #####################################################
+###############################################################################
+# Usually you don't have to edit the lines below
+$PATH_SEP=";"
+
+#$JAVA_HOME/bin/rmiregistry &
+
+if ( !( Test-Path "$RJS_WORK" ) ) {
+	mkdir -p "$RJS_WORK"
+}
+
+## Final RMI address
+if ( $S_HOSTADDRESS )
+{
+	$S_ADDRESS="//$S_HOSTADDRESS"
+	if ( $S_REGISTRYPORT ) {
+		$S_ADDRESS="$S_ADDRESS:$S_REGISTRYPORT"
+	}
+	$S_ADDRESS="$S_ADDRESS/$S_NAME"
+} else {
+	$S_ADDRESS="///$S_NAME"
+}
+
+## Finish auth configuration
+if ( $FORCE_AUTH )
+{
+	$AUTH="$FORCE_AUTH"
+}
+
+if ( $AUTH -eq "name-pass:file" )
+{
+	$AUTH="name-pass:file=$AUTH_PW_FILE"
+}
+
+if ( $AUTH -eq "local-shaj" )
+{
+	$AUTH="local-shaj"
+	$JAVA_OPTS_LIB="$JAVA_OPTS_LIB$PATH_SEP$AUTH_SHAJ_LD_DIR"
+	$JAVA_CP="$JAVA_CP$PATH_SEP$RJS_HOME/shaj/auth.jar"
+}
+
+if ( "$AUTH" -eq "fx:file" )
+{
+	$AUTH="fx:file=$AUTH_FX_FILE"
+	$AUTH_FX_FOLDER=Split-Path -Path $AUTH_FX_FILE -Parent
+	mkdir -p "$AUTH_FX_FOLDER"
+	echo "00000000" > "$AUTH_FX_FILE"
+	
+	$ACL=Get-Acl "$AUTH_FX_FILE"
+	$ACL.SetAccessRule($AUTH_FX_MASK)
+	#$SystemAccessRule = new-object System.Security.AccessControl.FileSystemAccessRule 'SYSTEM', 'FullControl', 'Allow'
+	#$ACL.SetAccessRule($SystemAccessRule)
+	$ACL.SetAccessRuleProtection($True, $False)
+	Set-Acl "$AUTH_FX_FILE" $ACL
+}
+
+$OPTS=@("-auth=$AUTH")
+if ( $DEBUG )
+{
+	$OPTS+="-verbose"
+}
+
+## Java config
+$JAVA_EXE="$JAVA_HOME/bin/java.exe"
+if ( $DEV )
+{
+	$JAVA_CP="$RJS_HOME/../org.eclipse.statet.rj.server/bin$PATH_SEP$RJS_HOME/../org.eclipse.statet.rj.data/bin$PATH_SEP$RJS_HOME/bin$PATH_SEP$RJS_HOME/binShaj"
+	$RMI_BASE="file://$RJS_HOME/../org.eclipse.statet.rj.server/bin"
+	$RJAVA_CP=""
+} else {
+	$JAVA_CP="$RJS_HOME/org.eclipse.statet.rj.server.jar$PATH_SEP$RJS_HOME/org.eclipse.statet.rj.data.jar$PATH_SEP$JAVA_CP"
+	$RMI_BASE="file://$RJS_HOME/org.eclipse.statet.rj.server.jar"
+	$RJAVA_CP=""
+}
+
+$JAVA_OPTS+="-Djava.security.policy=$RJS_HOME/security.policy"
+$JAVA_OPTS+="-Djava.rmi.server.codebase=$RMI_BASE"
+if ( $S_HOSTADDRESS )
+{
+	$JAVA_OPTS+="-Djava.rmi.server.hostname=$S_HOSTADDRESS"
+}
+if ( $JAVA_OPTS_LIB )
+{
+	$JAVA_OPTS+="-Djava.library.path=$JAVA_OPTS_LIB"
+}
+if ( $RJAVA_CP )
+{
+	$JAVA_OPTS+="-Drjava.class.path=$RJAVA_CP"
+}
+
+## Other environment
+$PATH="$R_HOME/bin$R_ARCH$PATH_SEP$Env:PATH"
+$LD_LIBRARY_PATH="$R_HOME/lib"
+
+$env:PATH = $PATH
+$env:JAVA_HOME = $JAVA_HOME
+$env:R_HOME = $R_HOME
+$env:R_ARCH = $R_ARCH
+$env:R_LIBS = $R_LIBS
+$env:R_LIBS_USER = $R_LIBS_USER
+$env:R_LIBS_SITE = $R_LIBS_SITE
+$env:R_DOC_DIR = $R_DOC_DIR
+$env:R_SHARE_DIR = $R_SHARE_DIR
+$env:R_INCLUDE_DIR = $R_INCLUDE_DIR
+$env:LC_ALL = $LC_ALL
+
+cd $WD
+
+$START_ARGS=@('-cp',$JAVA_CP)+$JAVA_OPTS+@('org.eclipse.statet.rj.server.RMIServerControl','start',$S_ADDRESS)+$OPTS
+#echo "$JAVA_EXE $START_ARGS"
+
+if ( $DEBUG )
+{
+	echo "S_HOSTADDRESS = $S_HOSTADDRESS"
+	echo "S_REGISTRYPORT = $S_REGISTRY_PORT"
+	echo "PATH = $PATH"
+	echo "LD_LIBRARY_PATH = $LD_LIBRARY_PATH"
+	echo "R_HOME = $R_HOME"
+	echo "R_ARCH = $R_ARCH"
+	echo "JAVA_HOME = $JAVA_HOME"
+	echo "JAVA_EXE = $JAVA_EXE"
+	echo "CLASSPATH = $JAVA_CP"
+	echo "JAVA_OPTIONS = $JAVA_OPTS"
+	echo "AUTH = $AUTH"
+	
+	# Start server directly
+	& $JAVA_EXE $START_ARGS
+	$START_EXIT=$LastExitCode
+	exit $START_EXIT
+} else {
+	# First check if running or dead server is already bound
+	$CLEAN_ARGS=@('-cp',$JAVA_CP)+$JAVA_OPTS+@('org.eclipse.statet.rj.server.RMIServerControl','clean',$S_ADDRESS)
+	& $JAVA_EXE $CLEAN_ARGS
+	$CLEAN_EXIT=$LastExitcode
+	if ( $CLEAN_EXIT -ne 0 )
+	{
+		echo "Check and cleanup of old server failed (CODE=$CLEAN_EXIT), cancelling startup."
+		exit $CLEAN_EXIT
+	}
+	
+	# Start server detached
+	$JAVA_EXE="$JAVA_HOME/bin/javaw.exe"
+	$START_PROCESS=Start-Process $JAVA_EXE -NoNewWindow -PassThru`
+			-RedirectStandardOutput "$RJS_WORK/session-$S_NAME.out" `
+			-RedirectStandardError "$RJS_WORK/session-$S_NAME.err" `
+			$START_ARGS
+	#$START_EXIT=
+	$START_PID=$START_PROCESS.Id
+	if ( ! $START_PROCESS.HasExited )
+	{
+		echo "Started server in background (PID=$START_PID)."
+		exit 0
+	} else {
+		echo "Startup failed"
+		exit -1
+	}
+}
diff --git a/core/org.eclipse.statet.rj.server.remotetools/startup.sh b/core/org.eclipse.statet.rj.server.remotetools/startup.sh
new file mode 100644
index 0000000..04273e4
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server.remotetools/startup.sh
@@ -0,0 +1,464 @@
+#!/bin/sh
+
+ #=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================#
+
+
+##
+# Shell script to start R server (for StatET)
+##
+# Usually you have to change only the CONFIG sections. You should set at least:
+#     R_HOME
+#     JAVA_HOME
+# Depending on the system configuration, it can be required to set:
+#     S_HOSTADDRESS
+# 
+# The authentication is set to 'fx' (method using SSH) by default.
+##
+# Usage of this script:
+#     startup.sh <address> [options]
+#     startup.sh <name> [options]
+# It starts the R server asynchronously in background by default.
+#     <address>                        the complete RMI-address
+#     <name>                           the session name only (the hostname
+#                                      should be set in this file)
+# Options:
+#     -wd=<working directory>          initial R working directory
+#     -debug                           enables debug output and
+#                                      runs R in foreground
+#
+# Note: This script does not start an RMI registry! You have to launch it
+# as system daemon or manually (see Java documentation), e.g. by:
+#     $JAVA_HOME/bin/rmiregistry -J-Djava.rmi.server.codebase=file:///<path to file org.eclipse.statet.rj.server.jar> &
+# or if appropriate by uncommenting the section "Start registry" in this script.
+##
+# Author: Stephan Wahlbrink <sw@wahlbrink.eu>
+###############################################################################
+
+###############################################################################
+# SCRIPT - INIT / READING PARAMETERS ##########################################
+###############################################################################
+OS=`uname | tr '[:upper:]' '[:lower:]'`
+case "$OS" in
+darwin)
+	C_READLINK=greadlink
+	LD_LIB_VAR="DYLD_LIBRARY_PATH"
+	LD_PRELOAD_VAR="DYLD_INSERT_LIBRARIES"
+	;;
+*)
+	C_READLINK=readlink
+	LD_LIB_VAR="LD_LIBRARY_PATH"
+	LD_PRELOAD_VAR="LD_PRELOAD"
+	;;
+esac
+
+if [ -z "$1" ]
+then
+	echo "Missing address or name for R server"
+	exit -1
+fi
+ADDRESS=$1
+S_NAME=`basename $ADDRESS`
+S_HOSTADDRESS=""
+S_REGISTRYPORT=""
+if [ "$ADDRESS" != "$S_NAME" ]
+then
+	S_HOSTADDRESS=`expr "$ADDRESS" : "[^/]*\/\/\([^:/]*\).*"`
+	S_REGISTRYPORT=`expr "$ADDRESS" : "[^/]*\/\/[^:/]*:\([0-9]\+\)\/.*"`
+fi
+shift
+WD=~
+SCRIPT=`$C_READLINK -f "$0"`
+
+until [ -z "$1" ]
+do
+	case "$1" in
+	-wd=*)
+		WD=${1##-wd=}
+		;;
+#	-host=*)
+#		S_HOSTADDRESS=${1##-host=}
+#		;;
+	-debug*)
+		DEBUG=1
+		echo Debug mode enabled
+		;;
+	-dev*)
+		DEV=1
+		echo Development mode enabled
+		;;
+	*)
+		echo Unknown parameter: $1
+		;;
+	esac
+	shift
+done
+###############################################################################
+
+###############################################################################
+# CONFIG - SYSTEM SETTINGS ####################################################
+###############################################################################
+# Configure the startup in the following sections
+
+###############################################################################
+# Required system specific settings
+# 
+# Set the path to home of R and Java.
+# If parts of the R installation (e.g. the documentation) are located in not
+# sub-directories of R home, it is often required to set additional variables
+# specifying the several installation locations (see example).
+# 
+# Example:
+#     R_HOME="/usr/lib/R"
+#     R_ARCH="/x64"
+#     R_DOC_DIR="/usr/share/doc/R"
+#     R_SHARE_DIR="/usr/share/R"
+#     R_INCLUDE_DIR="/usr/include/R"
+#     R_LIBS_SITE="/usr/local/lib/R/site-library"
+#     JAVA_HOME="/usr/lib/jvm/java-6-sun"
+
+R_HOME=
+JAVA_HOME=
+
+###############################################################################
+# Set the home and work directory of this R server.
+# The home must contain the jar files of this server, if this file is in this
+# directory, you don't have to change the value.
+# The working directory is for files like log files
+##
+# Example:
+#     RJS_HOME=`dirname "$SCRIPT"`
+#     RJS_WORK="~/R/rj-consoleserver/work"
+
+RJS_HOME=`dirname "$SCRIPT"`
+RJS_WORK=~/.RJServer
+
+###############################################################################
+# Set explicitly the hostname and port you want to use to access the RMI 
+# registry/R server.
+# It is recommended to use the IP address instead of a name.
+# By default, the hostname is extracted form the specified RMI address 
+# (script parameter). Nevertheless there are some reasons to set it explicitly
+# here, e.g.:
+#  - For SSH tunnel connections '127.0.0.1' (localhost) is sufficient;
+#    recommend, if no other network connections are used; and required if the 
+#    public IP address is blocked by the firewall.
+#  - To make sure that the correct IP address is set even the hostname is 
+#    used in the RMI address.
+##
+# Usage:
+#     S_HOSTADDRESS=<ip or hostname>
+#     S_REGISTRYPORT=<port of rmi-registry>
+# Example:
+#     S_HOSTADDRESS=192.168.1.80
+
+#S_HOSTADDRESS=""
+
+
+###############################################################################
+# Add additional java options here
+##
+# Example:
+#     JAVA_OPTS="-server -Djava.net.preferIPv4Stack=true"
+#     JAVA_OPTS="-server -Dorg.eclipse.statet.rj.rmi.disableSocketFactory=true"
+
+JAVA_OPTS="-server"
+JAVA_OPTS_LIB=
+
+
+###############################################################################
+# CONFIG - AUTHENTICATION METHODS #############################################
+###############################################################################
+# You must specify the method (exactly one) to use for authentication when 
+# clients wants to connect to the R.
+# There are several methods available. The methods provided by default
+# are described in the following subsections. To change the method uncomment
+# the lines of method you want to use and comment the previous AUTH definition.
+##
+# General usage:
+#     RJ parm:     -auth=<method-id>[:<config>]
+#                  -auth=<classname>[:<config>]
+# 
+# <config> option depends on the selected method
+
+###############################################################################
+# Authentication method: disabled / 'none'
+# 
+# Disables authentication. Anybody can connect to R. Use it only if you are in 
+# a secure environment! All users can connect to R get full user rights!
+##
+# General usage:
+#     RJ param:    -auth=none
+# 
+# Script Usage:
+#     AUTH="none"
+
+#AUTH="none"
+
+###############################################################################
+# Authentication method: password file / 'name-pass'
+# 
+# Authentication using loginname-password combination.
+##
+# General usage:
+#     RJ Param:    -auth=name-pass:file=<passwordfile>
+# 
+# Script usage:
+#     AUTH="name-pass:file"
+#     AUTH_PW_FILE="~/.RJServer/logins"
+# 
+# <passwordfile> is the path to a property file with
+#     pairs of loginname and password, for example:
+#         myname=mypassword
+#     Make sure that only authorized users can read this file!
+
+#AUTH="name-pass:file"
+#AUTH_PW_FILE="~/.RJServer/logins"
+
+###############################################################################
+# Authentication method: local user account / 'local-shaj'
+# 
+# Authentication using your local loginname-password combination (PAM).
+# The 'Shaj' library is required for this method. It is provided in sources and
+# binary form for several platforms. If no binary match your environment, you
+# have to build it for your system. You find the files inside the folder
+#     shaj
+# of this remotetools package.
+##
+# General Usage:
+#     RJ Param:    -auth=local-shaj
+#     Java Prop:   java.library.path=<folder of library>
+# 
+# Script Usage:
+#     AUTH="local-shaj"
+#     AUTH_SHAJ_LD_DIR="<folder of library>"
+# Example:
+#     AUTH=local-shaj
+#     AUTH_SHAJ_LD_DIR="$RJS_HOME/shaj/linux-x64"
+
+#AUTH="local-shaj"
+#AUTH_SHAJ_LD_DIR="$RJS_HOME/shaj/<platform>"
+
+###############################################################################
+# Authentication method: ssh / 'fx' (exchange over file)
+# 
+# Authentication for automatic startup (via ssh by StatET).
+##
+# General Usage:
+#     RJ Param:    -auth=fx:file=<keyfile>
+# 
+# Script Usage:
+#     AUTH="fx:file"
+#     AUTH_FX_FILE="<keyfile>"
+#     AUTH_FX_USER=$USER
+#     AUTH_FX_MASK="600"
+# 
+# <keyfile> a (empty). The fs permission to edit the files represents the
+#     right to login into R, so:
+#     The file must be writable for authorized user only!
+#     If the script setup is used, the files is created automatically and
+#     the permission is set according to AUTH_FX_USER and AUTH_FX_MASK
+
+AUTH="fx:file"
+AUTH_FX_FILE="$RJS_WORK/session-$S_NAME.lock"
+AUTH_FX_USER=$USER
+AUTH_FX_MASK=600
+
+
+###############################################################################
+# SCRIPT - STARTUP SERVER #####################################################
+###############################################################################
+# Usually you don't have to edit the lines below
+PATH_SEP=":"
+
+mkdir -p "$RJS_WORK"
+
+## Final RMI address
+if [ -n "$S_HOSTADDRESS" ]
+then
+	S_ADDRESS="//$S_HOSTADDRESS"
+	if [ -n "$S_REGISTRYPORT" ]
+	then
+		S_ADDRESS="$S_ADDRESS:$S_REGISTRYPORT"
+	fi
+	S_ADDRESS="$S_ADDRESS/$S_NAME"
+else
+	S_ADDRESS="///$S_NAME"
+fi
+
+S_FINAL_REGISTRYPORT="$S_REGISTRYPORT"
+if [ -z "$S_FINAL_REGISTRYPORT" ]
+then
+	S_FINAL_REGISTRYPORT=1099
+fi
+
+## Finish auth configuration
+if [ "$FORCE_AUTH" ]
+then
+	AUTH="$FORCE_AUTH"
+fi
+
+if [ "$AUTH" = "name-pass:file" ]
+then
+	AUTH="name-pass:file=$AUTH_PW_FILE"
+fi
+
+if [ "$AUTH" = "local-shaj" ]
+then
+	AUTH="local-shaj"
+	JAVA_OPTS_LIB="$JAVA_OPTS_LIB$PATH_SEP$AUTH_SHAJ_LD_DIR"
+	JAVA_CP="$JAVA_CP$PATH_SEP$RJS_HOME/shaj/auth.jar"
+fi
+
+if [ "$AUTH" = "fx:file" ]
+then
+	AUTH="fx:file=$AUTH_FX_FILE"
+	AUTH_FX_FOLDER=`dirname "$AUTH_FX_FILE"`
+	mkdir -p "$AUTH_FX_FOLDER"
+	echo "00000000" > "$AUTH_FX_FILE"
+	if [ $AUTH_FX_USER ]
+	then
+		chown $AUTH_FX_USER "$AUTH_FX_FILE"
+	fi
+	if [ $AUTH_FX_MASK ]
+	then
+		chmod $AUTH_FX_MASK "$AUTH_FX_FILE"
+	fi
+fi
+
+OPTS="-auth=$AUTH"
+if [ $DEBUG ]
+then
+	OPTS="$OPTS -verbose"
+fi
+
+## Java config
+JAVA_EXE="$JAVA_HOME/bin/java"
+if [ $DEV ]
+then
+	JAVA_CP="$RJS_HOME/../org.eclipse.statet.rj.server/bin$PATH_SEP$RJS_HOME/../org.eclipse.statet.rj.data/bin$PATH_SEP$RJS_HOME/bin$PATH_SEP$RJS_HOME/binShaj"
+	RMI_BASE="file://$RJS_HOME/../org.eclipse.statet.rj.server/bin"
+	RJAVA_CP=
+else
+	JAVA_CP="$RJS_HOME/org.eclipse.statet.rj.server.jar$PATH_SEP$RJS_HOME/org.eclipse.statet.rj.data.jar$PATH_SEP$JAVA_CP"
+	RMI_BASE="file://$RJS_HOME/org.eclipse.statet.rj.server.jar"
+	RJAVA_CP=
+fi
+
+JAVA_OPTS="$JAVA_OPTS -Djava.security.policy=$RJS_HOME/security.policy"
+JAVA_OPTS="$JAVA_OPTS -Djava.rmi.server.codebase=$RMI_BASE"
+if [ -n "$S_HOSTADDRESS" ]
+then
+	JAVA_OPTS="$JAVA_OPTS -Djava.rmi.server.hostname=$S_HOSTADDRESS"
+fi
+if [ -n "$JAVA_OPTS_LIB" ]
+then
+	JAVA_OPTS="$JAVA_OPTS -Djava.library.path=$JAVA_OPTS_LIB"
+fi
+if [ -n "$RJAVA_CP" ]
+then
+	JAVA_OPTS="$JAVA_OPTS -Drjava.class.path=$RJAVA_CP"
+fi
+
+## Other environment
+PATH=$R_HOME/bin$PATH_SEP$PATH
+LD_LIB_PATH=$R_HOME/lib
+#LD_PRELOAD_VALUE=$JAVA_HOME/jre/lib/amd64/server/libjsig.so
+
+
+## Start registry
+# For codebase see also:
+# http://docs.oracle.com/javase/7/docs/technotes/guides/rmi/enhancements-7.html
+
+# Netcat (nc) is used to test if the registry port is in use
+#nc -z $S_HOSTADDRESS $S_FINAL_REGISTRYPORT
+#if [ $? -ne 0 ]
+#then
+#	echo "No registry found at port $S_FINAL_REGISTRYPORT, starting registry..."
+#	nohup $JAVA_HOME/bin/rmiregistry $S_REGISTRYPORT "-J-Djava.rmi.server.codebase=$RMI_BASE" >> "$RJS_WORK/registry-$S_FINAL_REGISTRYPORT.out" 2>&1 < /dev/null &
+#	sleep 1
+#fi
+
+
+## Prepare start
+
+export PATH
+export $LD_LIB_VAR=$LD_LIB_PATH
+export $LD_PRELOAD_VAR=$LD_PRELOAD_VALUE
+export JAVA_HOME
+export R_HOME
+#export R_ARCH
+export R_LIBS
+export R_LIBS_USER
+export R_LIBS_SITE
+export R_DOC_DIR
+export R_SHARE_DIR
+export R_INCLUDE_DIR
+export LC_ALL
+
+cd "$WD"
+
+START_ARGS="-cp $JAVA_CP $JAVA_OPTS org.eclipse.statet.rj.server.RMIServerControl start $S_ADDRESS $OPTS"
+#echo $JAVA_EXE $START_ARGS
+
+if [ $DEBUG ]
+then
+	echo "S_HOSTADDRESS = $S_HOSTADDRESS"
+	echo "S_REGISTRYPORT = $S_REGISTRYPORT"
+	echo "S_FINAL_REGISTRYPORT = $S_FINAL_REGISTRYPORT"
+	echo "PATH = $PATH"
+	# ${!LD_LIB_VAR} does not work e.g. in dash
+	echo "$LD_LIB_VAR = $LD_LIB_PATH"
+	echo "$LD_PRELOAD_VAR = $LD_PRELOAD_VALUE"
+	echo "R_HOME = $R_HOME"
+	echo "R_ARCH = $R_ARCH"
+	echo "JAVA_HOME = $JAVA_HOME"
+	echo "JAVA_EXE = $JAVA_EXE"
+	echo "CLASSPATH = $JAVA_CP"
+	echo "JAVA_OPTIONS = $JAVA_OPTS"
+	echo "AUTH = $AUTH"
+	
+	# Start server directly
+	echo "Starting server ..."
+	$JAVA_EXE $START_ARGS
+	START_EXIT=$?
+	START_PID=$!
+	exit $START_EXIT
+else
+	# First check if running or dead server is already bound
+	CLEAN_ARGS="-cp $JAVA_CP $JAVA_OPTS org.eclipse.statet.rj.server.RMIServerControl clean $S_ADDRESS"
+	$JAVA_EXE $CLEAN_ARGS
+	CLEAN_EXIT=$?
+	if [ $CLEAN_EXIT -ne 0 ]
+	then
+		echo "Check and cleanup of old server failed (CODE=$CLEAN_EXIT), cancelling startup."
+		exit $CLEAN_EXIT
+	fi
+	
+	# Start server detached
+	echo "Starting server ..."
+	echo "`date --rfc-3339=seconds` RJServer Startup Script" > "$RJS_WORK/session-$S_NAME.out"
+	echo "INFO: [Startup:$S_NAME] Cmd: $JAVA_EXE $START_ARGS" >> "$RJS_WORK/session-$S_NAME.out"
+	nohup $JAVA_EXE $START_ARGS >> "$RJS_WORK/session-$S_NAME.out" 2>&1 < /dev/null &
+	START_EXIT=$?
+	START_PID=$!
+	if [ $START_EXIT -eq 0 ]
+	then
+		echo "Started server in background (PID=$START_PID)."
+		exit 0
+	else
+		echo "Startup failed"
+		exit $START_EXIT
+	fi
+fi
diff --git a/core/org.eclipse.statet.rj.server.rpkg/.classpath b/core/org.eclipse.statet.rj.server.rpkg/.classpath
new file mode 100644
index 0000000..eca7bdb
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server.rpkg/.classpath
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
+	<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+	<classpathentry kind="src" path="src"/>
+	<classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/core/org.eclipse.statet.rj.server.rpkg/.gitignore b/core/org.eclipse.statet.rj.server.rpkg/.gitignore
new file mode 100644
index 0000000..934e0e0
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server.rpkg/.gitignore
@@ -0,0 +1,2 @@
+/bin
+/target
diff --git a/core/org.eclipse.statet.rj.server.rpkg/.project b/core/org.eclipse.statet.rj.server.rpkg/.project
new file mode 100644
index 0000000..2e87065
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server.rpkg/.project
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>org.eclipse.statet.rj.server.rpkg</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.pde.ManifestBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.pde.SchemaBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.pde.PluginNature</nature>
+	</natures>
+</projectDescription>
diff --git a/core/org.eclipse.statet.rj.server.rpkg/.settings/org.eclipse.core.resources.prefs b/core/org.eclipse.statet.rj.server.rpkg/.settings/org.eclipse.core.resources.prefs
new file mode 100644
index 0000000..99f26c0
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server.rpkg/.settings/org.eclipse.core.resources.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+encoding/<project>=UTF-8
diff --git a/core/org.eclipse.statet.rj.server.rpkg/.settings/org.eclipse.core.runtime.prefs b/core/org.eclipse.statet.rj.server.rpkg/.settings/org.eclipse.core.runtime.prefs
new file mode 100644
index 0000000..5a0ad22
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server.rpkg/.settings/org.eclipse.core.runtime.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+line.separator=\n
diff --git a/core/org.eclipse.statet.rj.server.rpkg/META-INF/MANIFEST.MF b/core/org.eclipse.statet.rj.server.rpkg/META-INF/MANIFEST.MF
new file mode 100644
index 0000000..aab93da
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server.rpkg/META-INF/MANIFEST.MF
@@ -0,0 +1,9 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-SymbolicName: org.eclipse.statet.rj.server.rpkg
+Bundle-Version: 2.1.0.qualifier
+Bundle-Vendor: Eclipse.org
+Bundle-Name: StatET RJ - Server - R Package
+Bundle-RequiredExecutionEnvironment: JavaSE-1.8
+Require-Bundle: org.eclipse.statet.rj.data;bundle-version="[2.1.0,2.2.0)",
+ org.eclipse.statet.rj.server;bundle-version="[2.1.0,2.2.0)"
diff --git a/core/org.eclipse.statet.rj.server.rpkg/about.html b/core/org.eclipse.statet.rj.server.rpkg/about.html
new file mode 100644
index 0000000..e71ae66
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server.rpkg/about.html
@@ -0,0 +1,37 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+		"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+<title>About</title>
+</head>
+<body lang="EN-US">
+<h2>About This Content</h2>
+
+<p>December 1, 2017</p>
+<h3>License</h3>
+
+<p>
+	The Eclipse Foundation makes available all content in this plug-in
+	(&quot;Content&quot;). Unless otherwise indicated below, the Content
+	is provided to you under the terms and conditions of the Eclipse
+	Public License Version 2.0 (&quot;EPL&quot;), or the Apache License,
+	Version 2.0 (AL). A copy of the EPL is available at <a href="https://www.eclipse.org/legal/epl-2.0">https://www.eclipse.org/legal/epl-2.0</a>.
+	For purposes of the EPL, &quot;Program&quot; will mean the Content.
+	A copy of the AL is available at <a href="https://www.apache.org/licenses/LICENSE-2.0">https://www.apache.org/licenses/LICENSE-2.0</a>.
+</p>
+
+<p>
+	If you did not receive this Content directly from the Eclipse
+	Foundation, the Content is being redistributed by another party
+	(&quot;Redistributor&quot;) and different terms and conditions may
+	apply to your use of any object code in the Content. Check the
+	Redistributor's license that was provided with the Content. If no such
+	license exists, contact the Redistributor. Unless otherwise indicated
+	below, the terms and conditions of the EPL or AL still apply to any
+	source code in the Content and such source code may be obtained at <a
+	href="https://www.eclipse.org/">https://www.eclipse.org</a>.
+</p>
+
+</body>
+</html>
diff --git a/core/org.eclipse.statet.rj.server.rpkg/build.properties b/core/org.eclipse.statet.rj.server.rpkg/build.properties
new file mode 100644
index 0000000..93163f1
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server.rpkg/build.properties
@@ -0,0 +1,4 @@
+bin.includes = META-INF/,\
+               pkg/,\
+               about.html
+src.includes= .settings/org.eclipse.core.resources.prefs
diff --git a/core/org.eclipse.statet.rj.server.rpkg/pkg/DESCRIPTION b/core/org.eclipse.statet.rj.server.rpkg/pkg/DESCRIPTION
new file mode 100644
index 0000000..588539a
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server.rpkg/pkg/DESCRIPTION
@@ -0,0 +1,13 @@
+Encoding: UTF-8
+Package: rj
+Version: 2.1.0-11
+Title: RJ - R Package for high-level Java-R library RJ
+Author: Stephan Wahlbrink and others
+Maintainer: Eclipse StatET Project <statet-dev@eclipse.org>
+Depends: R (>= 2.11.0)
+Suggests: rj.gd
+SystemRequirements: java
+Description: R interface for the high-level Java-R library RJ.  The
+  package also includes callback functions for StatET.
+License: Eclipse Public License 2.0 | Apache License 2.0
+URL: https://www.eclipse.org/statet
diff --git a/core/org.eclipse.statet.rj.server.rpkg/pkg/NAMESPACE b/core/org.eclipse.statet.rj.server.rpkg/pkg/NAMESPACE
new file mode 100644
index 0000000..6d74100
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server.rpkg/pkg/NAMESPACE
@@ -0,0 +1,6 @@
+export(.rj.originals, .rj.tmp)
+export(.console.loadHistory, .console.saveHistory, .console.addtoHistory)
+export(statet.help, statet.help.start, .statet.initDebug, .statet.initHelp)
+S3method(print, "help_files_with_topic")
+export(print.help_files_with_topic)
+export(openInEditor, openPackageManager, statet.chooseFile, statet.showHistory)
diff --git a/core/org.eclipse.statet.rj.server.rpkg/pkg/R/console.R b/core/org.eclipse.statet.rj.server.rpkg/pkg/R/console.R
new file mode 100644
index 0000000..2b2f948
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server.rpkg/pkg/R/console.R
@@ -0,0 +1,40 @@
+ #=============================================================================#
+ # Copyright (c) 2010, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================#
+
+
+.console.loadHistory <- function(filename = ".Rhistory") {
+	if (!is.character(filename) || length(filename) != 1) {
+		stop("Illegal argument: filename")
+	}
+	.rj_ui.execCommand("console/loadHistory", list(
+					filename = filename ), TRUE)
+	return (invisible())
+}
+.console.saveHistory <- function(filename = ".Rhistory") {
+	if (!is.character(filename) || length(filename) != 1) {
+		stop("Illegal argument: filename")
+	}
+	.rj_ui.execCommand("console/saveHistory", list(
+					filename = filename ), TRUE)
+	return (invisible())
+}
+.console.addtoHistory <- function(line) {
+	if (missing(line) || !is.character(line) || length(line) != 1) {
+		stop("Illegal argument: line")
+	}
+	.rj_ui.execCommand("console/addtoHistory", list(
+					line = line ), FALSE)
+	return (invisible())
+}
+
diff --git a/core/org.eclipse.statet.rj.server.rpkg/pkg/R/dataaccess.R b/core/org.eclipse.statet.rj.server.rpkg/pkg/R/dataaccess.R
new file mode 100644
index 0000000..0870db1
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server.rpkg/pkg/R/dataaccess.R
@@ -0,0 +1,193 @@
+ #=============================================================================#
+ # Copyright (c) 2012, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================#
+
+
+## data access (org.eclipse.statet.rj.services.utils.dataaccess) / data editor
+
+sda002.checkDataStruct <- function(x.env, x.expr, xClass1, xDim) {
+	x <- eval(expr= x.expr)
+	if (class(x)[1] != xClass1) {
+		return (FALSE)
+	}
+	d <- dim(x)
+	if (length(d) < 2L) {
+		return (length(x) == xDim[1L])
+	}
+	else if (length(d) == 2) {
+		return (d[1L] == xDim[1L] && d[2L] == xDim[2L])
+	}
+	else {
+		return (FALSE)
+	}
+}
+
+sda002.getDataVectorValues <- function(x.env, x.expr, idxs, rowMapping) {
+	rowIdxs <- if (missing(rowMapping))
+				idxs[1L]:idxs[2L]
+			else
+				get(rowMapping, envir= .rj.tmp)[idxs[1L]:idxs[2L]]
+	x <- eval(expr= x.expr) [rowIdxs, drop= FALSE]
+	names(x) <- NULL
+	x
+}
+
+sda002.setDataVectorValues <- function(x.env, x.expr, idxs, values) {
+	expr <- quote(x[idxs[1L]:idxs[2L]] <- values)
+	expr[[2]][[2]] <- x.expr[[1]]
+	eval(expr= as.expression(expr))
+	TRUE
+}
+
+sda002.getDataVectorRowNames <- function(x.env, x.expr, idxs, rowMapping) {
+	x.names <- names(
+			eval(expr= x.expr) )
+	if (is.null(x.names) && missing(rowMapping)) {
+		return (NULL)
+	}
+	rowIdxs <- if (missing(rowMapping))
+				idxs[1L]:idxs[2L]
+			else
+				get(rowMapping, envir= .rj.tmp)[idxs[1L]:idxs[2L]]
+	if (!is.null(x.names))
+		names(rowIdxs) <- x.names[rowIdxs]
+	rowIdxs
+}
+
+sda002.getDataMatrixValues <- function(x.env, x.expr, idxs, rowMapping) {
+	rowIdxs <- if (missing(rowMapping))
+				idxs[1L]:idxs[2L]
+			else
+				get(rowMapping, envir= .rj.tmp)[idxs[1L]:idxs[2L]]
+	x <- eval(expr= x.expr) [rowIdxs, idxs[3L]:idxs[4L], drop= FALSE]
+	rownames(x) <- NULL
+	x
+}
+
+sda002.getDataMatrixRowNames <- function(x.env, x.expr, idxs, rowMapping) {
+	x.names <- rownames(
+			eval(expr= x.expr) )
+	if (is.null(x.names) && missing(rowMapping)) {
+		return (NULL)
+	}
+	rowIdxs <- if (missing(rowMapping))
+				idxs[1L]:idxs[2L]
+			else
+				get(rowMapping, envir= .rj.tmp)[idxs[1L]:idxs[2L]]
+	if (!is.null(x.names))
+		names(rowIdxs) <- x.names[rowIdxs]
+	rowIdxs
+}
+
+sda002.getDataArrayDimNames <- function(x.env, x.expr, idxs) {
+	x.dimnames <- dimnames(
+			eval(expr= x.expr) )
+	if (is.null(x.dimnames)) {
+		return (NULL)
+	}
+	names(x.dimnames)[idxs[1L]:idxs[2L]]
+}
+
+sda002.getDataArrayDimItemNames <- function(x.env, x.expr, dimIdx, idxs) {
+	x.dimnames <- dimnames(
+			eval(expr= x.expr) )
+	if (is.null(x.dimnames)) {
+		return (NULL)
+	}
+	x.dimnames[[dimIdx]][idxs[1L]:idxs[2L]]
+}
+
+sda002.getDataFrameValues <- function(x.env, x.expr, idxs, rowMapping) {
+	rowIdxs <- if (missing(rowMapping))
+				idxs[1L]:idxs[2L]
+			else
+				get(rowMapping, envir= .rj.tmp)[idxs[1L]:idxs[2L]]
+	x <- eval(expr= x.expr) [rowIdxs, idxs[3L]:idxs[4L], drop= FALSE]
+	attr(x, 'row.names') <- NULL
+	x
+}
+
+sda002.getDataFrameRowNames <- function(x.env, x.expr, idxs, rowMapping) {
+	x.names <- attr(
+			eval(expr= x.expr),
+			'row.names', exact= TRUE )
+	if (is.null(x.names) && missing(rowMapping)) {
+		return (NULL)
+	}
+	rowIdxs <- if (missing(rowMapping))
+				idxs[1L]:idxs[2L]
+			else
+				get(rowMapping, envir= .rj.tmp)[idxs[1L]:idxs[2L]]
+	if (!is.null(x.names))
+		names(rowIdxs) <- x.names[rowIdxs]
+	rowIdxs
+}
+
+
+.getDataLevelValues <- function(x, max = 1000) {
+	if (is.factor(x)) {
+		values <- levels(x)
+		if (any(is.na(x))) {
+			values <- c(values, NA)
+		}
+	}
+	else {
+		values <- sort(unique(x), na.last= TRUE)
+	}
+	if (length(values) > max) {
+		return (NULL)
+	}
+	return (values)
+}
+
+.getDataIntervalValues <- function(x) {
+	values <- c(min(x, na.rm= TRUE), max(x, na.rm= TRUE), if (any(is.na(x))) 1L else 0L)
+	return (values)
+}
+
+.searchDataTextValues <- function(x, type, pattern, max = 1000) {
+	if (type == 0L) { # Eclipse
+		values <- grep(pattern, x, ignore.case= TRUE, value= TRUE)
+	}
+	else if (type == 1L) {
+		values <- grep(pattern, x, ignore.case= FALSE, value= TRUE)
+	}
+	else if (type == 2L) {
+		values <- match(pattern, x)
+		if (!is.na(values)) {
+			values <- pattern
+		}
+		else {
+			values <- character(0)
+		}
+	}
+	else {
+		stop("Illegal argument: type")
+	}
+	if (length(values) > max) {
+		return (NULL)
+	}
+	return (values)
+}
+
+
+.formatInfo.maxLength <- 2L^20L
+.formatInfo.sampleLength <- 2L^19L
+
+.getFormatInfo <- function(x) {
+	if (length(x) > .formatInfo.maxLength) {
+		x <- sample(x, .formatInfo.sampleLength)
+	}
+	return (format.info(x))
+}
+
diff --git a/core/org.eclipse.statet.rj.server.rpkg/pkg/R/dbg.R b/core/org.eclipse.statet.rj.server.rpkg/pkg/R/dbg.R
new file mode 100644
index 0000000..62214d2
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server.rpkg/pkg/R/dbg.R
@@ -0,0 +1,59 @@
+ #=============================================================================#
+ # Copyright (c) 2011, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================#
+
+
+## RJ dbg
+
+
+#' Initializes the debug tools
+dbg.init <- function(..) {
+	error("Operation not supported")
+}
+
+
+dbg.checkBreakpoint <- function() {
+	if (tracingState(FALSE)) {
+		on.exit(tracingState(TRUE))
+	}
+	
+	answer <- .Call("Re_ExecJCommand", "dbg:checkBreakpoint", sys.call(), 0L,
+			PACKAGE= "(embedding)" )
+	
+	if (!is.null(answer)) {
+		envir <- sys.frame(-1)
+		eval(expr= answer, envir= envir)
+	}
+}
+
+dbg.checkEB <- function() {
+	if (tracingState(FALSE)) {
+		on.exit(tracingState(TRUE))
+	}
+	
+	if ("rj" %in% loadedNamespaces()) {
+		answer <- .Call("Re_ExecJCommand", "dbg:checkEB", NULL, 0L,
+				PACKAGE= "(embedding)" )
+		
+		if (!is.null(answer)) {
+			envir <- sys.frame(-1)
+			eval(expr= answer, envir= envir)
+		}
+	}
+}
+
+dbg.checkTB <- function(expr, env) {
+	answer <- .Call("Re_ExecJCommand", "dbg:checkTB", list(expr, env), 0L,
+			PACKAGE= "(embedding)" )
+}
+
diff --git a/core/org.eclipse.statet.rj.server.rpkg/pkg/R/init.R b/core/org.eclipse.statet.rj.server.rpkg/pkg/R/init.R
new file mode 100644
index 0000000..fc9add9
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server.rpkg/pkg/R/init.R
@@ -0,0 +1,166 @@
+ #=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================#
+
+
+## RJ init
+
+.rj.config <- new.env()
+.rj.config$isDebug <- FALSE
+
+#' Initializes the package
+.onLoad <- function(libname, pkgname) {
+	utilsEnv <- getNamespace("utils")
+	assign("help", envir = .rj.originals, value = get("help", envir = utilsEnv))
+	assign("help.start", envir = .rj.originals, value = get("help.start", envir = utilsEnv))
+	
+	return (invisible(TRUE))
+}
+
+.rj.originals <- new.env()
+
+
+## Tmp
+
+#' Environment for temporary R objects
+.rj.tmp <- new.env()
+
+#' Returns the next available id (a element name with the specified prefix)
+#' 
+#' @param prefix prefix of the element name, usually a key for a element type
+#' @param envir optional environment, default is \code{.rj.tmp}
+#' @return the id
+#' @returnType char
+tmp.createId <- function(prefix, envir = .rj.tmp) {
+	i <- 1L; 
+	repeat {
+		name <- paste(prefix, i, sep= "")
+		if (!exists(name, envir = envir, inherits = FALSE)) {
+			assign(name, NULL, envir= envir)
+			return(name); 
+		}
+		i <- i + 1L; 
+	}
+}
+
+tmp.set <- function(name, value, envir = .rj.tmp) {
+	assign(name, value, envir= envir)
+	return (invisible())
+}
+
+tmp.remove <- function(name, envir = .rj.tmp) {
+	if (exists(name, envir= envir, inherits= FALSE)) {
+		rm(list= name, envir= envir, inherits= FALSE)
+	}
+	return (invisible())
+}
+
+tmp.removeAll <- function(id, envir = .rj.tmp) {
+	names <- ls(envir= envir, pattern= paste0("^\\Q", id, "\\E"))
+	if (length(names)) {
+		rm(list= names, envir= envir, inherits= FALSE)
+	}
+	return (invisible())
+}
+
+tmp.setReverseIndex <- function(name, index, len = NA, envir = .rj.tmp) {
+	index = get(index, envir= envir, inherits= FALSE)
+	if (is.na(len)) {
+		len <- length(index)
+	}
+	index.r <- rep.int(NA_integer_, len)
+	index.r[index] <- 1L:length(index)
+	assign(name, index.r, envir= envir)
+	return (invisible())
+}
+
+tmp.setWhichIndex <- function(name, filter, envir = .rj.tmp) {
+	filter <- get(filter, envir= envir, inherits= FALSE)
+	filter <- which(filter)
+	assign(name, filter, envir= envir)
+	return (invisible())
+}
+
+tmp.setFilteredIndex <- function(name, filter, index, envir = .rj.tmp) {
+	filter <- get(filter, envir= envir, inherits= FALSE)
+	index <- get(index, envir= envir, inherits= FALSE)
+	if (length(dim(index)) > 1L) {
+		idx <- index[,1L]
+		index <- index[filter[idx],]
+	}
+	else {
+		index <- index[filter[index]]
+	}
+	assign(name, index, envir= envir)
+	return (invisible())
+}
+
+tmp.getFilteredCount <- function(index, filter, envir = .rj.tmp) {
+	filter <- get(filter, envir= envir, inherits= FALSE)
+	if (missing(index)) {
+		return (sum(filter))
+	}
+	index <- get(index, envir= envir, inherits= FALSE)
+	if (length(dim(index)) > 1L) {
+		index <- index[,1L]
+	}
+	return (sum(filter[index]))
+}
+
+tmp.clear <- function(envir = .rj.tmp) {
+	toRemove <- ls(envir= envir)
+	toRemove <- toRemove[toRemove != "help"] # TODO Remove in RJ-1.2
+	rm(list= toRemove, envir= envir)
+}
+
+
+## Internal utils
+
+.rj.errorHandler <- function(e) {
+	if (.rj.config$isDebug) {
+		print(e)
+	}
+}
+
+patchPackage <- function(name, value, envir, ns = TRUE) {
+	if (exists(name, envir)) {
+		unlockBinding(name, envir)
+		on.exit(lockBinding(name, envir), add= TRUE)
+		assign(name, value, envir)
+	}
+	if (ns && getRversion() < "2.15.0") {
+		envName <- environmentName(envir)
+		if (envName == "base") {
+			ns <- "base"
+		}
+		else if (!is.null(envName) && substring(envName, 1L, 8L) == "package:") {
+			ns <- asNamespace(substring(envName, 9L))
+		}
+		else {
+			ns <- NULL
+		}
+		if (!is.null(ns)) {
+			assignInNamespace(name, value, ns= ns)
+		}
+	}
+	return (invisible(TRUE))
+}
+
+resolveVisible <- function(result) {
+	if (result$visible) {
+		return (result$value)
+	}
+	else {
+		return (invisible(result$value))
+	}
+}
diff --git a/core/org.eclipse.statet.rj.server.rpkg/pkg/R/statet_help.R b/core/org.eclipse.statet.rj.server.rpkg/pkg/R/statet_help.R
new file mode 100644
index 0000000..f24d000
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server.rpkg/pkg/R/statet_help.R
@@ -0,0 +1,233 @@
+ #=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================#
+
+
+## StatET help
+
+.getHelpFile <- function(file) {
+	path <- dirname(file)
+	dirpath <- dirname(path)
+	if(!file.exists(dirpath))
+		stop(gettextf("invalid '%s' argument", "file"), domain= NA)
+	pkgname <- basename(dirpath)
+	RdDB <- file.path(path, pkgname)
+	if(!file.exists(paste(RdDB, "rdx", sep= ".")))
+		stop(gettextf("package %s exists but was not installed under R >= 2.10.0 so help cannot be accessed", sQuote(pkgname)), domain= NA)
+	tools:::fetchRdDB(RdDB, basename(file))
+}
+
+#' Creates rhelp url, mostly compatible to \code{help}
+#' 
+#' @param topic 
+#' @param package 
+#' @param ... for compatibility
+#' @returnType character
+#' @return URL in rhelp schema
+.getRHelpUrl <- function(helpObj) {
+	if (inherits(helpObj, "packageInfo")) {
+		return (paste("rhelp:///page", helpObj$name, "", sep= "/"))
+	}
+	if (inherits(helpObj, "help_files_with_topic")) {
+		topic <- attr(helpObj, "topic", exact= TRUE)
+		if (is.null(topic)) {
+			topic <- "help"
+			package <- "utils"
+		}
+		else {
+			package <- attr(helpObj, "call", exact= TRUE)[["package"]]
+		}
+		if (is.name(y <- substitute(package))) {
+			package <- as.character(y)
+		}
+		if (is.character(package)
+				&& length(package) == 1 && !is.na(package)) {
+			return (paste("rhelp:///page", package, topic, sep= "/"))
+		}
+		else {
+			return (paste("rhelp:///topic", topic, sep= "/"))
+		}
+	}
+	stop("Unexpected help information.")
+}
+
+#' Creates HTML help page for the given help page(s).
+#' 
+#' @param x vector of help pages (as returns by original \code{help}
+#' @return HTML page for a single page, otherwise \code{NULL}
+#' @returnType character
+.getLiveHelp <- function(x) {
+	paths <- as.character(x)
+	if(!length(paths)) {
+		writeLines(c(gettextf("No documentation for '%s' in specified packages and libraries:",
+								topic),
+						gettextf("you could try '??%s'",
+								topic)))
+		return (invisible(NULL))
+	}
+	
+	if (attr(x, "tried_all_packages", exact= TRUE)) {
+		paths <- unique(dirname(dirname(paths)))
+		msg <- gettextf("Help for topic '%s' is not in any loaded package but can be found in the following packages:",
+				topic)
+		writeLines(c(strwrap(msg), "",
+						paste(" ", formatDL(c(gettext("Package"), basename(paths)),
+										c(gettext("Library"), dirname(paths)),
+										indent= 22))))
+		return (invisible(NULL))
+	}
+	
+	file <- NULL
+	if (length(paths) > 1L) {
+		p <- paths
+		msg <- gettextf("Help on topic '%s' was found in the following packages:",
+				topic)
+		paths <- dirname(dirname(paths))
+		txt <- formatDL(c("Package", basename(paths)),
+				c("Library", dirname(paths)),
+				indent= 22L)
+		writeLines(c(strwrap(msg), "", paste(" ", txt), ""))
+		if (interactive()) {
+			fp <- file.path(paths, "Meta", "Rd.rds")
+			tp <- basename(p)
+			titles <- tp
+			if(type == "html" || type == "latex")
+				tp <- tools::file_path_sans_ext(tp)
+			for (i in seq_along(fp)) {
+				tmp <- try(.readRDS(fp[i]))
+				titles[i] <- if(inherits(tmp, "try-error"))
+							"unknown title" else
+							tmp[tools::file_path_sans_ext(tmp$File) == tp[i], "Title"]
+			}
+			txt <- paste(titles, " {", basename(paths), "}", sep= "")
+			## the default on menu() is currtently graphics = FALSE
+			res <- menu(txt, title= gettext("Choose one"),
+					graphics= getOption("menu.graphics"))
+			if (res > 0) {
+				file <- p[res]
+			} else {
+				file <- NULL
+			}
+		} else {
+			file <- paths[1L]
+			writeLines(gettext("\nUsing the first match ..."))
+		}
+	} else {
+		file <- paths
+	}
+	
+	if (is.null(file)) {
+		return (invisible(NULL))
+	}
+	
+	file <- sub("/html/([^/]*)\\.html$", "/help/\\1", file)
+	if (getRversion() < "2.11.0") {
+		rd <- .getHelpFile(file)
+	}
+	else {
+		rd <- utils:::.getHelpFile(file)
+	}
+	
+	renderRd(rd, basename(dirname(dirname(file))))
+}
+
+.showHelp <- function(url) {
+	if (missing(url) || !is.character(url) || length(url) != 1) {
+		stop("Illegal argument: url")
+	}
+	.rj_ui.execCommand("r/showHelp", list(
+					url= url ), wait= FALSE)
+}
+
+#' Shows R help in StatET. This is a console command for R help in StatET
+#' mainly compatible to the original \code{help}.
+#' 
+#' @seealso help
+#' @export
+statet.help <- function(topic, package= NULL, lib.loc= NULL,
+		verbose= getOption("verbose"),
+		try.all.packages= getOption("help.try.all.packages"), ...,
+		live= FALSE ) {
+	nextCall <- match.call(expand.dots= TRUE)
+	callName <- nextCall[[1]]
+	
+	if (is.null(nextCall$topic) && !is.null(nextCall$package)) {
+		packageInfo <- list(name= nextCall$package)
+		class(packageInfo) <- "packageInfo"
+		
+		result <- list(value= packageInfo, visible= TRUE)
+	}
+	else {
+		nextCall[[1]] <- substitute(utils::help)
+		nextCall$live <- NULL
+		nextCall$help_type <- "html"
+		
+		result <- withVisible(eval(nextCall, envir= parent.frame()))
+		
+		result.call <- attr(result$value, "call", exact= TRUE)
+		if (!is.null(result.call)) {
+			result.call[[1]] <- callName
+			attr(result$value, "call") <- result.call
+		}
+		
+	}
+	
+	if (live) {
+		help.statet <- .getLiveHelp(result$value)
+		if (!is.null(help.statet)) {
+			help.statet <- paste(help.statet, collapse= "\n")
+			help.statet <- paste("html:///", help.statet, sep= "")
+		}
+	}
+	else if (is.null(.rj.tmp$help)
+			|| inherits(result$value, "packageInfo") ) {
+		help.statet <- .getRHelpUrl(result$value)
+	}
+	else {
+		return (resolveVisible(result))
+	}
+	if (is.character(help.statet) && !is.na(help.statet)) {
+		.showHelp(help.statet)
+	}
+	return (invisible())
+}
+
+#' Shows the R help start page in StatET. This is a console command for R help in StatET
+#' mainly compatible to the original \code{help.start}.
+#' 
+#' At moment no argument functionality is supported.
+#' 
+#' @param ... for compatibility
+#' @seealso help.start
+#' @export
+statet.help.start <- function(...) {
+	.showHelp("rhelp:///")
+	return (invisible())
+}
+
+
+statet.print.help <- function(x, ...) {
+	type <- attr(x, "type", exact= TRUE)
+	if (length(x) == 0
+			|| (!is.null(type) && type != "html")
+			|| is.null(.rj.tmp$help) ) {
+		# NextMethod ?
+		return (utils:::print.help_files_with_topic(x, ...))
+	}
+	help.statet <- .getRHelpUrl(x)
+	if (is.character(help.statet)
+			&& length(help.statet) == 1 && !is.na(help.statet)) {
+		.showHelp(help.statet)
+	}
+	return (invisible(x))
+}
diff --git a/core/org.eclipse.statet.rj.server.rpkg/pkg/R/statet_internal.R b/core/org.eclipse.statet.rj.server.rpkg/pkg/R/statet_internal.R
new file mode 100644
index 0000000..502d5e7
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server.rpkg/pkg/R/statet_internal.R
@@ -0,0 +1,343 @@
+ #=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================#
+
+
+## StatET utilities
+
+#' Estimates a value for the parameter max.level of \code{str}
+#' for the given R element.
+#' 
+#' @param x the R element to show
+#' @param max.elements maximum elements to show
+#' @param max.levels maximum levels to show
+#' @returnType integer
+#' @return a value for max.level
+#' @author Stephan Wahlbrink <sw@wahlbrink.eu>
+#' @export
+estimateStrDepth <- function(x, max.elements = 2000L, max.levels = 10L) {
+	deeplength <- function(x, level = 0L) {
+		if (isS4(x)) {
+			xslots <- slotNames(class(x))
+			xlen <- length(xslots)
+			if (level == 0L || xlen == 0L) {
+				return (xlen)
+			}
+			else {
+				s <- 0L
+				for (xslot in xslots) {
+					s <- s + deeplength(slot(x, xslot), level = level-1L)
+				}
+				return (s)
+			}
+		}
+		if (is.list(x)) {
+			xlen <- length(x)
+			if (level == 0L || xlen == 0L || is.data.frame(x)) {
+				return (xlen)
+			}
+			else {
+				return (sum(sapply(x, deeplength, level = level-1L, USE.NAMES=FALSE)))
+			}
+		}
+		return (0L)
+	}
+	
+	level <- -1L
+	s <- 0L
+	while (level < max.levels && s < max.elements) {
+		level <- level + 1L
+		s.level <- deeplength(x, level)
+		if (s.level == 0L) {
+			return (NA)
+		}
+		s <- s + s.level
+	}
+	return (level)
+}
+
+#' Captures output of \code{str} for the given R element.
+#' The output is limited to the specified number of R elements.
+#' 
+#' @param x the R element to show
+#' @param limit maximum elements to show
+#' @returnType character
+#' @return output of \code{str}
+#' @author Stephan Wahlbrink <sw@wahlbrink.eu>
+#' @export
+.statet.captureStr <- function(x, limit = 2000L) {
+	savedOptions <- options(width = 10000L)
+	on.exit(options(savedOptions))
+	levels <- estimateStrDepth(x, max.elements = limit)
+	if (!is.na(levels) && levels <= 1L && getRversion() >= "2.11.0") {
+		output <- capture.output(str(x, max.level = 1L, list.len = limit - 1L))
+	}
+	else {
+		output <- capture.output(str(x, max.level = levels))
+	}
+	return (output)
+}
+
+
+.statet.prepareSrcfile <- function(filename, path) {
+	map <- .rj.tmp$statet.SrcfileMap
+	if (is.null(map)) {
+		map <- list()
+	}
+	map[[filename]] <- NULL
+	map[[filename]] <- path
+	if (length(map) > 20) {
+		map[[1]] <- NULL
+	}
+	.rj.tmp$statet.SrcfileMap <- map
+	return (invisible(NULL))
+}
+
+.statet.extSrcfile <- function(srcfile) {
+	map <- .rj.tmp$statet.SrcfileMap
+	path <- NULL
+	if (is.null(map) || is.null(srcfile$filename)) {
+		return (srcfile)
+	}
+	idx <- which(names(map) == srcfile$filename)
+	if (length(idx) != 1) {
+		return (srcfile)
+	}
+	path <- map[[idx]]
+	
+	if (idx <= 10) {
+		map[[idx]] <- NULL
+		map[[srcfile$filename]] <- path
+		.rj.tmp$statet.SrcfileMap <- map
+	}
+	
+	srcfile$statet.Path <- path
+	return (srcfile)
+}
+
+.addElementIds <- function(expr, elementIds) {
+	names <- names(elementIds)
+	for (i in seq_along(names)) {
+		if (!is.na(names[i])) {
+			path <- elementIds[[i]]
+			tryCatch(attr(expr[[path]], "statet.ElementId") <- names[i],
+					error = .rj.errorHandler )
+		}
+	}
+	return (expr)
+}
+
+.statet.prepareCommand <- function(lines, filename = "<text>",
+		srcfileAttributes, elementIds) {
+	# create srcfile object
+	srcfile <- srcfilecopy(filename, lines)
+	if (!missing(srcfileAttributes)) {
+		names <- names(srcfileAttributes)
+		for (i in seq_along(names)) {
+			if (!is.na(names[i])) {
+				assign(names[i], srcfileAttributes[[i]], envir= srcfile)
+			}
+		}
+	}
+	
+	# parse command
+	expr <- parse(text= lines, srcfile= srcfile, encoding= "UTF-8")
+	
+	# attach element ids
+	if (!missing(elementIds)) {
+		expr <- .addElementIds(expr, elementIds)
+	}
+	
+	# finish
+	.rj.tmp$statet.CommandExpr <- expr
+	invisible(expr)
+}
+
+.statet.evalCommand <- function() {
+	expr <- .rj.tmp$statet.CommandExpr
+	if (is.null(expr)) {
+		stop("Commands not available.")
+	}
+	srcrefs <- attr(expr, "srcref", exact= TRUE)
+	exi <- call("{", expr[[1]])
+	if (1 <= length(srcrefs)) {
+		attr(exi, "srcref") <- list(NULL, srcrefs[[1]])
+	}
+	eval(exi, parent.frame())
+}
+
+.statet.prepareSource <- function(info) {
+	assign("statet.NextSourceInfo", info, envir= .rj.tmp)
+}
+
+.statet.extSource <- function(expr) {
+	info <- .rj.tmp$statet.NextSourceInfo
+	if (is.null(info)) {
+		return (expr)
+	}
+	on.exit(rm("statet.NextSourceInfo", envir= .rj.tmp))
+	if (is.null(expr)) {
+		return (expr)
+	}
+	srcfile <- attr(expr, "srcfile", exact= TRUE)
+	if (is.null(srcfile)
+			|| is.null(srcfile$statet.Path) || is.null(srcfile$timestamp)
+			|| srcfile$statet.Path != info$path
+			|| (unclass(srcfile$timestamp) != info$timestamp
+				&& abs(unclass(srcfile$timestamp) - info$timestamp) != 3600 )
+			|| length(expr) != info$exprsLength ) {
+		return (expr)
+	}
+	expr <- .addElementIds(expr, info$elementIds)
+	return (expr)
+}
+
+
+.searchExpr <- function(expr, cond, max.depth= 5, depth= 1) {
+	if (expr[[1]] == "{") {
+		for (i in seq_along(expr)) {
+			if (cond(expr[[i]])) {
+				return (i);
+			}
+		}
+	}
+	for (i in seq_along(expr)) {
+		if (depth < max.depth && length(expr[[i]]) > 1) {
+			idx <- .searchExpr(expr= expr[[i]], cond= cond,
+					max.depth= max.depth, depth= depth + 1)
+			if (!is.null(idx)) {
+				return (c(i, idx))
+			}
+		}
+	}
+	return (NULL)
+}
+
+
+#### R env / R lib path (R pkg manager)
+
+renv.checkLibs <- function() {
+	libs <- .libPaths()
+	result <- file.info(libs)$mtime
+	names(result) <- libs
+	
+	result
+}
+
+renv.getBioCVersion <- function() {
+	v <- tools:::.BioC_version_associated_with_R_version
+	if (is.function(v)) {
+		v <- v()
+	}
+	return (v)
+}
+
+renv.getAvailPkgs <- function(repo) {
+	fields= c('Package', 'Version', 'Priority', 'License',
+			'Depends', 'Imports', 'LinkingTo', 'Suggests', 'Enhances')
+	result <- available.packages(contriburl= contrib.url(repo), fields= fields,
+			filter= c('R_version', 'OS_type', 'subarch') )
+	result[, fields, drop= FALSE]
+}
+
+renv.getInstPkgs <- function(lib) {
+	names <- list.files(lib)
+	fields <- c('Package', 'Version', 'Title', 'Built')
+	result <- matrix(NA_character_, nrow= length(names), ncol= length(fields))
+	num <- 0L
+	for (name in names) {
+		pkgpath <- file.path(lib, name)
+		if (file.access(pkgpath, 5L)) {
+			next
+		}
+		if (file.exists(file <- file.path(pkgpath, 'Meta', 'package.rds'))) {
+			md <- try(readRDS(file))
+			if (inherits(md, 'try-error')) {
+				next
+			}
+			descr <- md$DESCRIPTION[fields]
+			if (is.null(descr)) {
+				next
+			}
+			enc <- md$DESCRIPTION['Encoding']
+			if (!is.na(enc)) {
+				txt <- try(iconv(descr[3L], from= enc, to= "UTF-8"))
+				if (!inherits(txt, "try-error")) {
+					descr[3L] <- txt
+				}
+			}
+			descr[1L] <- name
+			result[num <- num + 1, ] <- descr
+		}
+	}
+	result[seq.int(from= 1L, length.out= num), , drop= FALSE]
+}
+
+renv.getInstPkgDetail <- function(lib, name) {
+	fields <- c('Priority', 'License',
+			'Depends', 'Imports', 'LinkingTo', 'Suggests', 'Enhances' )
+	file <- file.path(lib, name, 'Meta', 'package.rds')
+	md <- readRDS(file)
+	md$DESCRIPTION[fields]
+}
+
+renv.isValidLibLoc <- function(path) {
+	# path <- normalizePath(path)
+	current <- path
+	repeat {
+		if (file.access(current, 0L) == 0L) { # exists
+			result <-  file.access(current, 3L) # writable
+			names(result) <- path
+			return (result)
+		}
+		parent <- dirname(current)
+		if (nchar(parent) <= 1L || parent == current) {
+			return (-1L)
+		}
+		current <- parent
+	}
+}
+
+
+#### R help
+
+#' Returns the package description for the specified package
+#' 
+#' @param lib the library location
+#' @param name the package name
+rhelp.loadPkgDescr <- function(lib, name) {
+	fields <- c('Version', 'Title', 'Description', 'Author', 'Maintainer', 'URL', 'Built')
+	file <- file.path(lib, name, 'Meta', 'package.rds')
+	md <- readRDS(file)
+	descr <- md$DESCRIPTION[fields]
+	if (is.null(descr)) {
+		return (NULL)
+	}
+	enc <- md$DESCRIPTION['Encoding']
+	if (!is.na(enc)) {
+		txt <- try(iconv(descr[2L:5L], from= enc, to= "UTF-8"))
+		if (!inherits(txt, "try-error")) {
+			descr[2L:5L] <- txt
+		}
+	}
+	return (descr)
+}
+
+#' Returns the help files for the specified package
+#' 
+#' @param lib the library location
+#' @param name the package name
+rhelp.loadPkgRd <- function(lib, name) {
+	error("Operation not supported")
+}
+
diff --git a/core/org.eclipse.statet.rj.server.rpkg/pkg/R/statet_workbench.R b/core/org.eclipse.statet.rj.server.rpkg/pkg/R/statet_workbench.R
new file mode 100644
index 0000000..af4525f
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server.rpkg/pkg/R/statet_workbench.R
@@ -0,0 +1,106 @@
+ #=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================#
+
+
+## StatET workbench
+
+#' Opens a file in an editor in StatET
+#' @param filename name of file to open
+#' 
+#' @export
+openInEditor <- function(name, fileName, elementName, filename) {
+	if (!missing(filename)) {
+		fileName <- filename
+	}
+	if (missing(name) && missing(fileName) && missing(elementName)) {
+		stop("Missing argument: name")
+	}
+	if (missing(fileName) && missing(elementName)) {
+		# auto
+		fileName <- NULL
+		elementName <- NULL
+		if (is.character(name) && length(name) == 1) {
+			fileName <- name
+		}
+		else {
+			elementName <- substitute(name)
+		}
+	}
+	else if (!missing(elementName)) {
+		fileName <- NULL
+		elementName # test, if it refers to an existing element
+		elementName <- substitute(elementName)
+	}
+	else if (!missing(fileName)) {
+		elementName <- NULL
+	}
+	
+	if (!is.null(fileName)) {
+		if (!is.character(fileName) || length(fileName) != 1) {
+			stop("Illegal argument: fileName")
+		}
+		.rj_ui.execCommand("common/showFile", list(
+						filename= fileName ), wait= TRUE)
+	}
+	else {
+		elementName <- deparse(elementName, backtick= TRUE, control= c(),
+				width.cutoff= 500, nlines= 2L)
+		if (length(elementName) != 1) {
+			stop("Illegal argument: elementName")
+		}
+		.rj_ui.execCommand("showElement", list(
+						elementName= elementName ), wait= TRUE)
+	}
+	return (invisible())
+}
+
+#' Opens the package manager in StatET
+#' 
+#' @export
+openPackageManager <- function() {
+	.rj_ui.execCommand("r/openPackageManager", wait= FALSE)
+	return (invisible())
+}
+
+#' Asks the user to choose a file using the StatET GUI.
+#' 
+#' @param new if the choosen file can be new (does not yet exits)
+#' @export
+statet.chooseFile <- function(new = FALSE) {
+	if (!is.logical(new) || length(new) != 1) {
+		stop("Illegal argument: new")
+	}
+	answer <- .rj_ui.execCommand("common/chooseFile", list(
+					newResource= new ), wait= TRUE)
+	if (is.null(answer)) { # operation cancelled
+		return (invisible())
+	}
+	return (answer$filename)
+}
+
+#' Shows the Cmd History view in StatET
+#' 
+#' @export
+statet.showHistory <- function() {
+	.rj_ui.execCommand("common/showHistory", wait= FALSE)
+	return (invisible())
+}
+
+
+.statet.initDebug <- function(...) {
+	dbg.init(...)
+}
+
+.statet.initHelp <- function(...) {
+}
diff --git a/core/org.eclipse.statet.rj.server.rpkg/pkg/R/uicommands.R b/core/org.eclipse.statet.rj.server.rpkg/pkg/R/uicommands.R
new file mode 100644
index 0000000..a764c5f
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server.rpkg/pkg/R/uicommands.R
@@ -0,0 +1,47 @@
+ #=============================================================================#
+ # Copyright (c) 2010, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================#
+
+
+## RJ UI
+
+#' Sends an UI command to the GUI which executes the command
+#' if it is supported
+#' 
+#' @param commandId the id of the UI command
+#' @param args an optional list with arguments (meaning depends on UI command)
+#' @param wait if R must wait until the command is executed
+#'     (necessary if you need a return value)
+#' @returnType char
+.rj_ui.execCommand <- function(commandId, args = list(), wait = TRUE) {
+	if (missing(commandId)) {
+		stop("Missing param: commandId")
+	}
+	if (!is.list(args)) {
+		stop("Illegal argument: args must be a list")
+	}
+	if (length(args) > 0) {
+		args.names <- names(args)
+		if (is.null(args.names) || any(is.na(args.names))) {
+			stop("Illegal argument: args must be named")
+		}
+	}
+	
+	options <- 0L
+	if (wait) {
+		options <- options + 1L
+	}
+	.Call("Re_ExecJCommand", paste("ui", commandId, sep=":"), args, options,
+						PACKAGE= "(embedding)" )
+}
+
diff --git a/core/org.eclipse.statet.rj.server/.classpath b/core/org.eclipse.statet.rj.server/.classpath
new file mode 100644
index 0000000..3dfe0c4
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/.classpath
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8">
+		<attributes>
+			<attribute name="owner.project.facets" value="java"/>
+		</attributes>
+	</classpathentry>
+	<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+	<classpathentry kind="src" path="src"/>
+	<classpathentry kind="src" path="srcEExtensions"/>
+	<classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/core/org.eclipse.statet.rj.server/.gitignore b/core/org.eclipse.statet.rj.server/.gitignore
new file mode 100644
index 0000000..ed620ff
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/.gitignore
@@ -0,0 +1,3 @@
+/bin
+/target
+/doc
diff --git a/core/org.eclipse.statet.rj.server/.project b/core/org.eclipse.statet.rj.server/.project
new file mode 100644
index 0000000..d27385d
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/.project
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>org.eclipse.statet.rj.server</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.wst.common.project.facet.core.builder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.jdt.core.javabuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.pde.ManifestBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.pde.SchemaBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.jdt.core.javanature</nature>
+		<nature>org.eclipse.pde.PluginNature</nature>
+		<nature>org.eclipse.wst.common.modulecore.ModuleCoreNature</nature>
+		<nature>org.eclipse.wst.common.project.facet.core.nature</nature>
+	</natures>
+</projectDescription>
diff --git a/core/org.eclipse.statet.rj.server/.settings/org.eclipse.core.resources.prefs b/core/org.eclipse.statet.rj.server/.settings/org.eclipse.core.resources.prefs
new file mode 100644
index 0000000..99f26c0
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/.settings/org.eclipse.core.resources.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+encoding/<project>=UTF-8
diff --git a/core/org.eclipse.statet.rj.server/.settings/org.eclipse.core.runtime.prefs b/core/org.eclipse.statet.rj.server/.settings/org.eclipse.core.runtime.prefs
new file mode 100644
index 0000000..5a0ad22
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/.settings/org.eclipse.core.runtime.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+line.separator=\n
diff --git a/core/org.eclipse.statet.rj.server/.settings/org.eclipse.jdt.core.prefs b/core/org.eclipse.statet.rj.server/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000..ccb1eaa
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,325 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.codeComplete.argumentPrefixes=
+org.eclipse.jdt.core.codeComplete.argumentSuffixes=
+org.eclipse.jdt.core.codeComplete.fieldPrefixes=
+org.eclipse.jdt.core.codeComplete.fieldSuffixes=
+org.eclipse.jdt.core.codeComplete.localPrefixes=
+org.eclipse.jdt.core.codeComplete.localSuffixes=
+org.eclipse.jdt.core.codeComplete.staticFieldPrefixes=
+org.eclipse.jdt.core.codeComplete.staticFieldSuffixes=
+org.eclipse.jdt.core.codeComplete.staticFinalFieldPrefixes=
+org.eclipse.jdt.core.codeComplete.staticFinalFieldSuffixes=
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=1.8
+org.eclipse.jdt.core.compiler.debug.lineNumber=generate
+org.eclipse.jdt.core.compiler.debug.localVariable=generate
+org.eclipse.jdt.core.compiler.debug.sourceFile=generate
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.source=1.8
+org.eclipse.jdt.core.formatter.align_fields_grouping_blank_lines=2147483647
+org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_assignment=0
+org.eclipse.jdt.core.formatter.alignment_for_binary_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_compact_if=16
+org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=80
+org.eclipse.jdt.core.formatter.alignment_for_enum_constants=0
+org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16
+org.eclipse.jdt.core.formatter.alignment_for_expressions_in_for_loop_header=0
+org.eclipse.jdt.core.formatter.alignment_for_method_declaration=0
+org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16
+org.eclipse.jdt.core.formatter.alignment_for_parameterized_type_references=0
+org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_resources_in_try=85
+org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=16
+org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_type_arguments=0
+org.eclipse.jdt.core.formatter.alignment_for_type_parameters=0
+org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch=16
+org.eclipse.jdt.core.formatter.blank_lines_after_imports=2
+org.eclipse.jdt.core.formatter.blank_lines_after_package=1
+org.eclipse.jdt.core.formatter.blank_lines_before_field=0
+org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=1
+org.eclipse.jdt.core.formatter.blank_lines_before_imports=1
+org.eclipse.jdt.core.formatter.blank_lines_before_member_type=1
+org.eclipse.jdt.core.formatter.blank_lines_before_method=1
+org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=2
+org.eclipse.jdt.core.formatter.blank_lines_before_package=1
+org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=1
+org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=1
+org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_block=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_lambda_body=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=false
+org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=false
+org.eclipse.jdt.core.formatter.comment.format_block_comments=true
+org.eclipse.jdt.core.formatter.comment.format_header=false
+org.eclipse.jdt.core.formatter.comment.format_html=true
+org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=true
+org.eclipse.jdt.core.formatter.comment.format_line_comments=true
+org.eclipse.jdt.core.formatter.comment.format_source_code=true
+org.eclipse.jdt.core.formatter.comment.indent_parameter_description=false
+org.eclipse.jdt.core.formatter.comment.indent_root_tags=true
+org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert
+org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=do not insert
+org.eclipse.jdt.core.formatter.comment.line_length=100
+org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries=false
+org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries=true
+org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments=false
+org.eclipse.jdt.core.formatter.compact_else_if=true
+org.eclipse.jdt.core.formatter.continuation_indentation=2
+org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=2
+org.eclipse.jdt.core.formatter.disabling_tag=@formatter\:off
+org.eclipse.jdt.core.formatter.enabling_tag=@formatter\:on
+org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false
+org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true
+org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true
+org.eclipse.jdt.core.formatter.indent_empty_lines=true
+org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true
+org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true
+org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true
+org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=false
+org.eclipse.jdt.core.formatter.indentation.size=4
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_enum_constant=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_label=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_type_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert
+org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert
+org.eclipse.jdt.core.formatter.insert_space_after_lambda_arrow=insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources=insert
+org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert
+org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=insert
+org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert
+org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw=insert
+org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.join_lines_in_comments=true
+org.eclipse.jdt.core.formatter.join_wrapped_lines=true
+org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=false
+org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false
+org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=false
+org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false
+org.eclipse.jdt.core.formatter.lineSplit=100
+org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false
+org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=false
+org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0
+org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=1
+org.eclipse.jdt.core.formatter.parentheses_positions_in_annotation=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_catch_clause=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_enum_constant_declaration=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_for_statment=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_if_while_statement=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_lambda_declaration=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_method_delcaration=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_method_invocation=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_switch_statement=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_try_clause=common_lines
+org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=true
+org.eclipse.jdt.core.formatter.tabulation.char=tab
+org.eclipse.jdt.core.formatter.tabulation.size=4
+org.eclipse.jdt.core.formatter.use_on_off_tags=false
+org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false
+org.eclipse.jdt.core.formatter.wrap_before_assignment_operator=false
+org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true
+org.eclipse.jdt.core.formatter.wrap_before_conditional_operator=false
+org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch=true
+org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true
+org.eclipse.jdt.core.javaFormatter=org.eclipse.jdt.core.defaultJavaFormatter
diff --git a/core/org.eclipse.statet.rj.server/.settings/org.eclipse.jdt.ui.prefs b/core/org.eclipse.statet.rj.server/.settings/org.eclipse.jdt.ui.prefs
new file mode 100644
index 0000000..e62a4f5
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/.settings/org.eclipse.jdt.ui.prefs
@@ -0,0 +1,131 @@
+cleanup.add_default_serial_version_id=true
+cleanup.add_generated_serial_version_id=false
+cleanup.add_missing_annotations=true
+cleanup.add_missing_deprecated_annotations=true
+cleanup.add_missing_methods=false
+cleanup.add_missing_nls_tags=false
+cleanup.add_missing_override_annotations=true
+cleanup.add_missing_override_annotations_interface_methods=true
+cleanup.add_serial_version_id=false
+cleanup.always_use_blocks=true
+cleanup.always_use_parentheses_in_expressions=true
+cleanup.always_use_this_for_non_static_field_access=true
+cleanup.always_use_this_for_non_static_method_access=false
+cleanup.convert_functional_interfaces=false
+cleanup.convert_to_enhanced_for_loop=false
+cleanup.correct_indentation=false
+cleanup.format_source_code=false
+cleanup.format_source_code_changes_only=false
+cleanup.insert_inferred_type_arguments=false
+cleanup.make_local_variable_final=true
+cleanup.make_parameters_final=true
+cleanup.make_private_fields_final=true
+cleanup.make_type_abstract_if_missing_method=false
+cleanup.make_variable_declarations_final=true
+cleanup.never_use_blocks=false
+cleanup.never_use_parentheses_in_expressions=false
+cleanup.organize_imports=true
+cleanup.qualify_static_field_accesses_with_declaring_class=false
+cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true
+cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=false
+cleanup.qualify_static_member_accesses_with_declaring_class=true
+cleanup.qualify_static_method_accesses_with_declaring_class=false
+cleanup.remove_private_constructors=true
+cleanup.remove_redundant_type_arguments=true
+cleanup.remove_trailing_whitespaces=false
+cleanup.remove_trailing_whitespaces_all=true
+cleanup.remove_trailing_whitespaces_ignore_empty=false
+cleanup.remove_unnecessary_casts=true
+cleanup.remove_unnecessary_nls_tags=true
+cleanup.remove_unused_imports=true
+cleanup.remove_unused_local_variables=false
+cleanup.remove_unused_private_fields=true
+cleanup.remove_unused_private_members=false
+cleanup.remove_unused_private_methods=true
+cleanup.remove_unused_private_types=true
+cleanup.sort_members=false
+cleanup.sort_members_all=false
+cleanup.use_anonymous_class_creation=false
+cleanup.use_blocks=true
+cleanup.use_blocks_only_for_return_and_throw=false
+cleanup.use_lambda=true
+cleanup.use_parentheses_in_expressions=false
+cleanup.use_this_for_non_static_field_access=true
+cleanup.use_this_for_non_static_field_access_only_if_necessary=false
+cleanup.use_this_for_non_static_method_access=true
+cleanup.use_this_for_non_static_method_access_only_if_necessary=true
+cleanup.use_type_arguments=false
+cleanup_profile=_StatET
+cleanup_settings_version=2
+eclipse.preferences.version=1
+editor_save_participant_org.eclipse.jdt.ui.postsavelistener.cleanup=true
+formatter_profile=_StatET
+formatter_settings_version=12
+org.eclipse.jdt.ui.exception.name=e
+org.eclipse.jdt.ui.gettersetter.use.is=true
+org.eclipse.jdt.ui.ignorelowercasenames=true
+org.eclipse.jdt.ui.importorder=\#;java;javax;com.ibm.icu;org.osgi;org.eclipse;;org.eclipse.statet.jcommons;org.eclipse.statet.ecommons;org.eclipse.statet;
+org.eclipse.jdt.ui.javadoc=true
+org.eclipse.jdt.ui.keywordthis=true
+org.eclipse.jdt.ui.ondemandthreshold=99
+org.eclipse.jdt.ui.overrideannotation=true
+org.eclipse.jdt.ui.staticondemandthreshold=99
+org.eclipse.jdt.ui.text.custom_code_templates=<?xml version\="1.0" encoding\="UTF-8" standalone\="no"?><templates><template autoinsert\="true" context\="gettercomment_context" deleted\="false" description\="Comment for getter method" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.gettercomment" name\="gettercomment">/**\n * @return the ${bare_field_name}\n */</template><template autoinsert\="true" context\="settercomment_context" deleted\="false" description\="Comment for setter method" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.settercomment" name\="settercomment">/**\n * @param ${param} the ${bare_field_name} to set\n */</template><template autoinsert\="true" context\="constructorcomment_context" deleted\="false" description\="Comment for created constructors" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.constructorcomment" name\="constructorcomment">/**\n * ${tags}\n */</template><template autoinsert\="false" context\="filecomment_context" deleted\="false" description\="Comment for created Java files" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.filecomment" name\="filecomment">/*\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\#\n \# Copyright (c) ${year} ${user} and others.\n # \n # This program and the accompanying materials are made available under the\n # terms of the Eclipse Public License 2.0 which is available at\n # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n # which is available at https://www.apache.org/licenses/LICENSE-2.0.\n # \n # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n # \n \# Contributors\:\n \#     ${user} - initial API and implementation\n \#\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=*/</template><template autoinsert\="false" context\="typecomment_context" deleted\="false" description\="Comment for created types" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.typecomment" name\="typecomment">/**\n * \n * ${tags}\n */</template><template autoinsert\="true" context\="fieldcomment_context" deleted\="false" description\="Comment for fields" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.fieldcomment" name\="fieldcomment">/**\n * \n */</template><template autoinsert\="true" context\="methodcomment_context" deleted\="false" description\="Comment for non-overriding methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.methodcomment" name\="methodcomment">/**\n * ${tags}\n */</template><template autoinsert\="false" context\="overridecomment_context" deleted\="false" description\="Comment for overriding methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.overridecomment" name\="overridecomment"/><template autoinsert\="true" context\="delegatecomment_context" deleted\="false" description\="Comment for delegate methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.delegatecomment" name\="delegatecomment">/**\n * ${tags}\n * ${see_to_target}\n */</template><template autoinsert\="false" context\="newtype_context" deleted\="false" description\="Newly created files" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.newtype" name\="newtype">${filecomment}\n\n${package_declaration}\n\n${typecomment}\n${type_declaration}</template><template autoinsert\="true" context\="classbody_context" deleted\="false" description\="Code in new class type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.classbody" name\="classbody">\n</template><template autoinsert\="true" context\="interfacebody_context" deleted\="false" description\="Code in new interface type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.interfacebody" name\="interfacebody">\n</template><template autoinsert\="true" context\="enumbody_context" deleted\="false" description\="Code in new enum type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.enumbody" name\="enumbody">\n</template><template autoinsert\="true" context\="annotationbody_context" deleted\="false" description\="Code in new annotation type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.annotationbody" name\="annotationbody">\n</template><template autoinsert\="true" context\="catchblock_context" deleted\="false" description\="Code in new catch blocks" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.catchblock" name\="catchblock">// ${todo} Auto-generated catch block\n${exception_var}.printStackTrace();</template><template autoinsert\="true" context\="methodbody_context" deleted\="false" description\="Code in created method stubs" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.methodbody" name\="methodbody">// ${todo} Auto-generated method stub\n${body_statement}</template><template autoinsert\="true" context\="constructorbody_context" deleted\="false" description\="Code in created constructor stubs" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.constructorbody" name\="constructorbody">${body_statement}\n// ${todo} Auto-generated constructor stub</template><template autoinsert\="true" context\="getterbody_context" deleted\="false" description\="Code in created getters" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.getterbody" name\="getterbody">return ${field};</template><template autoinsert\="true" context\="setterbody_context" deleted\="false" description\="Code in created setters" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.setterbody" name\="setterbody">${field} \= ${param};</template></templates>
+sp_cleanup.add_default_serial_version_id=true
+sp_cleanup.add_generated_serial_version_id=false
+sp_cleanup.add_missing_annotations=true
+sp_cleanup.add_missing_deprecated_annotations=true
+sp_cleanup.add_missing_methods=false
+sp_cleanup.add_missing_nls_tags=false
+sp_cleanup.add_missing_override_annotations=true
+sp_cleanup.add_missing_override_annotations_interface_methods=true
+sp_cleanup.add_serial_version_id=false
+sp_cleanup.always_use_blocks=true
+sp_cleanup.always_use_parentheses_in_expressions=true
+sp_cleanup.always_use_this_for_non_static_field_access=true
+sp_cleanup.always_use_this_for_non_static_method_access=false
+sp_cleanup.convert_functional_interfaces=false
+sp_cleanup.convert_to_enhanced_for_loop=false
+sp_cleanup.correct_indentation=false
+sp_cleanup.format_source_code=false
+sp_cleanup.format_source_code_changes_only=false
+sp_cleanup.insert_inferred_type_arguments=false
+sp_cleanup.make_local_variable_final=true
+sp_cleanup.make_parameters_final=true
+sp_cleanup.make_private_fields_final=true
+sp_cleanup.make_type_abstract_if_missing_method=false
+sp_cleanup.make_variable_declarations_final=false
+sp_cleanup.never_use_blocks=false
+sp_cleanup.never_use_parentheses_in_expressions=false
+sp_cleanup.on_save_use_additional_actions=true
+sp_cleanup.organize_imports=true
+sp_cleanup.qualify_static_field_accesses_with_declaring_class=false
+sp_cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true
+sp_cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=false
+sp_cleanup.qualify_static_member_accesses_with_declaring_class=true
+sp_cleanup.qualify_static_method_accesses_with_declaring_class=false
+sp_cleanup.remove_private_constructors=true
+sp_cleanup.remove_redundant_type_arguments=true
+sp_cleanup.remove_trailing_whitespaces=false
+sp_cleanup.remove_trailing_whitespaces_all=false
+sp_cleanup.remove_trailing_whitespaces_ignore_empty=true
+sp_cleanup.remove_unnecessary_casts=true
+sp_cleanup.remove_unnecessary_nls_tags=false
+sp_cleanup.remove_unused_imports=false
+sp_cleanup.remove_unused_local_variables=false
+sp_cleanup.remove_unused_private_fields=false
+sp_cleanup.remove_unused_private_members=false
+sp_cleanup.remove_unused_private_methods=false
+sp_cleanup.remove_unused_private_types=true
+sp_cleanup.sort_members=false
+sp_cleanup.sort_members_all=false
+sp_cleanup.use_anonymous_class_creation=false
+sp_cleanup.use_blocks=true
+sp_cleanup.use_blocks_only_for_return_and_throw=false
+sp_cleanup.use_lambda=false
+sp_cleanup.use_parentheses_in_expressions=false
+sp_cleanup.use_this_for_non_static_field_access=true
+sp_cleanup.use_this_for_non_static_field_access_only_if_necessary=false
+sp_cleanup.use_this_for_non_static_method_access=true
+sp_cleanup.use_this_for_non_static_method_access_only_if_necessary=true
+sp_cleanup.use_type_arguments=false
diff --git a/core/org.eclipse.statet.rj.server/.settings/org.eclipse.wst.common.component b/core/org.eclipse.statet.rj.server/.settings/org.eclipse.wst.common.component
new file mode 100644
index 0000000..73cd796
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/.settings/org.eclipse.wst.common.component
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?><project-modules id="moduleCoreId" project-version="1.5.0">

+    <wb-module deploy-name="org.eclipse.statet.rj.server">

+        <wb-resource deploy-path="/" source-path="/src"/>

+    </wb-module>

+</project-modules>

diff --git a/core/org.eclipse.statet.rj.server/.settings/org.eclipse.wst.common.project.facet.core.xml b/core/org.eclipse.statet.rj.server/.settings/org.eclipse.wst.common.project.facet.core.xml
new file mode 100644
index 0000000..f4ef8aa
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/.settings/org.eclipse.wst.common.project.facet.core.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<faceted-project>
+  <installed facet="java" version="1.8"/>
+</faceted-project>
diff --git a/core/org.eclipse.statet.rj.server/META-INF/MANIFEST.MF b/core/org.eclipse.statet.rj.server/META-INF/MANIFEST.MF
new file mode 100644
index 0000000..6ae2bcb
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/META-INF/MANIFEST.MF
@@ -0,0 +1,23 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-SymbolicName: org.eclipse.statet.rj.server;singleton:=true
+Bundle-Version: 2.1.0.qualifier
+Bundle-Vendor: Eclipse.org
+Bundle-Name: StatET RJ - Server - Core
+Bundle-RequiredExecutionEnvironment: JavaSE-1.8
+Require-Bundle: org.eclipse.statet.rj.data;bundle-version="[2.1.0,2.2.0)",
+ org.eclipse.swt;bundle-version="3.6.0";resolution:=optional,
+ com.cenqua.shaj;bundle-version="1.0.0";resolution:=optional
+Import-Package: org.osgi.framework;resolution:=optional,
+ org.eclipse.core.runtime;resolution:=optional
+Export-Package: org.eclipse.statet.rj,
+ org.eclipse.statet.rj.server,
+ org.eclipse.statet.rj.server.dbg,
+ org.eclipse.statet.rj.server.e.srvext,
+ org.eclipse.statet.rj.server.gr,
+ org.eclipse.statet.rj.server.osgi,
+ org.eclipse.statet.rj.server.srv,
+ org.eclipse.statet.rj.server.srv.engine,
+ org.eclipse.statet.rj.server.srvext,
+ org.eclipse.statet.rj.server.srvext.auth,
+ org.eclipse.statet.rj.server.util
diff --git a/core/org.eclipse.statet.rj.server/about.html b/core/org.eclipse.statet.rj.server/about.html
new file mode 100644
index 0000000..e71ae66
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/about.html
@@ -0,0 +1,37 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+		"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+<title>About</title>
+</head>
+<body lang="EN-US">
+<h2>About This Content</h2>
+
+<p>December 1, 2017</p>
+<h3>License</h3>
+
+<p>
+	The Eclipse Foundation makes available all content in this plug-in
+	(&quot;Content&quot;). Unless otherwise indicated below, the Content
+	is provided to you under the terms and conditions of the Eclipse
+	Public License Version 2.0 (&quot;EPL&quot;), or the Apache License,
+	Version 2.0 (AL). A copy of the EPL is available at <a href="https://www.eclipse.org/legal/epl-2.0">https://www.eclipse.org/legal/epl-2.0</a>.
+	For purposes of the EPL, &quot;Program&quot; will mean the Content.
+	A copy of the AL is available at <a href="https://www.apache.org/licenses/LICENSE-2.0">https://www.apache.org/licenses/LICENSE-2.0</a>.
+</p>
+
+<p>
+	If you did not receive this Content directly from the Eclipse
+	Foundation, the Content is being redistributed by another party
+	(&quot;Redistributor&quot;) and different terms and conditions may
+	apply to your use of any object code in the Content. Check the
+	Redistributor's license that was provided with the Content. If no such
+	license exists, contact the Redistributor. Unless otherwise indicated
+	below, the terms and conditions of the EPL or AL still apply to any
+	source code in the Content and such source code may be obtained at <a
+	href="https://www.eclipse.org/">https://www.eclipse.org</a>.
+</p>
+
+</body>
+</html>
diff --git a/core/org.eclipse.statet.rj.server/build.properties b/core/org.eclipse.statet.rj.server/build.properties
new file mode 100644
index 0000000..d33d5e2
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/build.properties
@@ -0,0 +1,13 @@
+source..= src/,\
+          srcEExtensions/
+output..= bin/
+extra..= platform:/plugin/org.eclipse.core.runtime
+javacDefaultEncoding..= UTF-8
+
+bin.includes = META-INF/,\
+               plugin.xml,\
+               .,\
+               about.html,\
+               localhost.policy
+src.includes= .settings/org.eclipse.core.resources.prefs,\
+              schema/
diff --git a/core/org.eclipse.statet.rj.server/localhost.policy b/core/org.eclipse.statet.rj.server/localhost.policy
new file mode 100644
index 0000000..6e902c1
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/localhost.policy
@@ -0,0 +1,7 @@
+grant codeBase "file:${{java.ext.dirs}}/*" {

+	permission java.security.AllPermission;

+};

+

+grant {

+	permission java.security.AllPermission;

+};

diff --git a/core/org.eclipse.statet.rj.server/plugin.xml b/core/org.eclipse.statet.rj.server/plugin.xml
new file mode 100644
index 0000000..41fd781
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/plugin.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<?eclipse version="3.4"?>
+<!--
+ #=============================================================================#
+ # Copyright (c) 2010, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================#
+-->
+
+<plugin>
+   
+   <extension-point id="org.eclipse.statet.rj.RSetups"
+         name="R Setups (Installations and Libraries)"
+         schema="schema/RSetups.exsd"/>
+   
+</plugin>
diff --git a/core/org.eclipse.statet.rj.server/schema/RSetups.exsd b/core/org.eclipse.statet.rj.server/schema/RSetups.exsd
new file mode 100644
index 0000000..8c9bf96
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/schema/RSetups.exsd
@@ -0,0 +1,300 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<schema targetNamespace="org.eclipse.statet.rj" xmlns="http://www.w3.org/2001/XMLSchema">
+<annotation>
+      <appinfo>
+         <meta.schema id="rSetups"
+               plugin="org.eclipse.statet.rj.server"
+               name="R Setups (Installations and Libraries)"/>
+      </appinfo>
+      <documentation>
+         This extension-point allows the definition and supply of R setups by Eclipse plug-ins. The definitions can be used to setup a correct environment to start R. In StatET they appear as preconfigured R environments.
+&lt;p&gt;An R setup (&lt;code&gt;setup&lt;/code&gt;) is identified by an unique id. It is composed of the base R installation and optional additional R library locations.
+An installation element (&lt;code&gt;base&lt;/code&gt;) provides the valid R home location for one or multiple platforms. Via the library locations (&lt;code&gt;library&lt;/code&gt;) it is possible to supply additional libraries with R packages to the R library path.&lt;/p&gt;
+&lt;p&gt;
+To separate platform dependent resources (base or library locations), Eclipse offers two options:&lt;/p&gt;
+&lt;ul&gt;
+&lt;li&gt;(A) Fragments and specification of platform filter: A plug-in and for each platform, which should be supported, one fragment must be created. In the plug-in, the resource location is specified as usual as a directory name, but it does not provide the resources. Each fragment is assigned to one platform by the Eclipse bundle manifest headers &lt;code&gt;Eclipse-PlatformFilter&lt;/code&gt; for the variables &apos;osgi.os&apos; and &apos;osgi.arch&apos; and provides the platform dependent resources in the directory specified in the plug-in.&lt;/li&gt;
+&lt;li&gt;(B) Platform specific directories: The resource location is specified as operation system dependend in the plug-in by prefixing &lt;code&gt;$os$/&lt;/code&gt; to the directory name. When loading the resources, &lt;code&gt;$os$&lt;/code&gt; is resolved to &lt;code&gt;os/&amp;lt;osgi.os&amp;gt;/&amp;lt;osgi.arch&amp;gt;&lt;/code&gt;, whereas &lt;code&gt;&amp;lt;osgi.os&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;osgi.arch&amp;gt;&lt;/code&gt; are replace by the known constants defining the platform.&lt;/li&gt;
+&lt;/ul&gt;
+&lt;p&gt;
+Both methods can also be combined. The method (A) allows separate installation and updates, while the handling with method (B) is more compact. Known constants for the operation systems (&apos;osgi.os&apos;) and system architectures (&apos;osgi.arch&apos;) can be found in the class &lt;code&gt;org.eclipse.core.runtime.Platform&lt;/code&gt;.
+&lt;p&gt;
+Additional hints for bundles providing base or library elements:&lt;/p&gt;
+&lt;ul&gt;
+&lt;li&gt;When integrating the plug-in or fragment in a feature set, it is recommend to enable &lt;code&gt;unpack&lt;/code&gt; option for that bundle.&lt;/li&gt;
+&lt;/ul&gt;
+&lt;p&gt;
+The existence and documentation of this extension-point does not give any advice whether it is legal to distribute R and/or R packages together with other software in your individual situation.&lt;/p&gt;
+      </documentation>
+   </annotation>
+
+   <element name="extension">
+      <annotation>
+         <appinfo>
+            <meta.element />
+         </appinfo>
+      </annotation>
+      <complexType>
+         <choice minOccurs="1" maxOccurs="unbounded">
+            <element ref="setup"/>
+            <element ref="base"/>
+            <element ref="library"/>
+         </choice>
+         <attribute name="point" type="string" use="required">
+            <annotation>
+               <documentation>
+                  
+               </documentation>
+            </annotation>
+         </attribute>
+         <attribute name="id" type="string">
+            <annotation>
+               <documentation>
+                  
+               </documentation>
+            </annotation>
+         </attribute>
+         <attribute name="name" type="string">
+            <annotation>
+               <documentation>
+                  
+               </documentation>
+               <appinfo>
+                  <meta.attribute translatable="true"/>
+               </appinfo>
+            </annotation>
+         </attribute>
+      </complexType>
+   </element>
+
+   <element name="setup">
+      <annotation>
+         <documentation>
+            The element presents a single R setup.
+It is identified by its unique id. To make it useful for a platform, it is necessary to register at least the base element for that R setup and platform.
+         </documentation>
+      </annotation>
+      <complexType>
+         <attribute name="id" type="string" use="required">
+            <annotation>
+               <documentation>
+                  A unique id for the R setup.
+               </documentation>
+               <appinfo>
+                  <meta.attribute kind="identifier"/>
+               </appinfo>
+            </annotation>
+         </attribute>
+         <attribute name="name" type="string" use="required">
+            <annotation>
+               <documentation>
+                  A name for the R setup.
+&lt;p&gt;
+The name is used in GUIs, so that the user can identify the R setup&lt;/p&gt;
+               </documentation>
+               <appinfo>
+                  <meta.attribute translatable="true"/>
+               </appinfo>
+            </annotation>
+         </attribute>
+         <attribute name="version" type="string">
+            <annotation>
+               <documentation>
+                  The version string for the R version. This property is only for information like the name.
+               </documentation>
+            </annotation>
+         </attribute>
+         <attribute name="inheritBase" type="string">
+            <annotation>
+               <documentation>
+                  The id of an R setup, the base elements (R installations) are inherited from.
+&lt;p&gt;
+Using this attribute enables to reuse the base installations with other R libraries. It is recommend to inheret only from R setups controlled by you or defined cleary with version number.&lt;/p&gt;
+               </documentation>
+               <appinfo>
+                  <meta.attribute kind="identifier" basedOn="org.eclipse.statet.rj.RSetups/setup/@id"/>
+               </appinfo>
+            </annotation>
+         </attribute>
+      </complexType>
+   </element>
+
+   <element name="base">
+      <annotation>
+         <documentation>
+            The element provides a R base installation with a valid R home location (correponding to the environment variable &lt;code&gt;R_HOME&lt;/code&gt;).
+&lt;p&gt;
+It is invalid to register multiple base installation for the same R setup. See general description how to provide installations for several platforms.&lt;/p&gt;
+         </documentation>
+      </annotation>
+      <complexType>
+         <attribute name="setupId" type="string" use="required">
+            <annotation>
+               <documentation>
+                  The id of the R setup.
+               </documentation>
+               <appinfo>
+                  <meta.attribute kind="identifier" basedOn="org.eclipse.statet.rj.RSetups/setup/@id"/>
+               </appinfo>
+            </annotation>
+         </attribute>
+         <attribute name="location" type="string" use="required">
+            <annotation>
+               <documentation>
+                  The R home directory location of the base installation.
+The sub-directories are &lt;code&gt;bin&lt;/code&gt;, &lt;code&gt;doc&lt;/code&gt;, ...
+               </documentation>
+               <appinfo>
+                  <meta.attribute kind="resource"/>
+               </appinfo>
+            </annotation>
+         </attribute>
+      </complexType>
+   </element>
+
+   <element name="library">
+      <annotation>
+         <documentation>
+            The element provides an R library with R packages.
+         </documentation>
+      </annotation>
+      <complexType>
+         <attribute name="setupId" type="string" use="required">
+            <annotation>
+               <documentation>
+                  The id of the R setup.
+               </documentation>
+               <appinfo>
+                  <meta.attribute kind="identifier" basedOn="org.eclipse.statet.rj.RSetups/setup/@id"/>
+               </appinfo>
+            </annotation>
+         </attribute>
+         <attribute name="group">
+            <annotation>
+               <documentation>
+                  The id of the group the library should be registered in. The ids correspond to the environment variables for the groups:&lt;ul&gt;
+&lt;li&gt;&lt;code&gt;R_LIBS_SITE&lt;/code&gt; - R site library&lt;/li&gt;
+&lt;li&gt;&lt;code&gt;R_LIBS&lt;/code&gt; - Additional R library&lt;/li&gt;
+&lt;li&gt;&lt;code&gt;R_LIBS_USER&lt;/code&gt; - R user library&lt;/li&gt;
+&lt;/ul&gt;
+If not specified, &lt;code&gt;R_LIBS&lt;/code&gt; is used.
+               </documentation>
+            </annotation>
+            <simpleType>
+               <restriction base="string">
+                  <enumeration value="R_LIBS_SITE">
+                  </enumeration>
+                  <enumeration value="R_LIBS">
+                  </enumeration>
+                  <enumeration value="R_LIBS_USER">
+                  </enumeration>
+               </restriction>
+            </simpleType>
+         </attribute>
+         <attribute name="location" type="string" use="required">
+            <annotation>
+               <documentation>
+                  The directory location of the R library.
+The sub-directories represent the R packages.
+               </documentation>
+               <appinfo>
+                  <meta.attribute kind="resource"/>
+               </appinfo>
+            </annotation>
+         </attribute>
+      </complexType>
+   </element>
+
+   <annotation>
+      <appinfo>
+         <meta.section type="since"/>
+      </appinfo>
+      <documentation>
+         0.5.0
+      </documentation>
+   </annotation>
+
+   <annotation>
+      <appinfo>
+         <meta.section type="examples"/>
+      </appinfo>
+      <documentation>
+         &lt;i&gt;Definition of an R setup, its base installation and an add-on:&lt;/i&gt;&lt;br/&gt;
+&lt;br/&gt;
+&lt;i&gt;1)&lt;/i&gt; General definition of the R setup and definition of the location for the base installation, suppporting one or multiple platforms by using method (A). Both declared in the &lt;code&gt;plugin.xml&lt;/code&gt;:
+&lt;pre&gt;
+&lt;extension point=&quot;org.eclipse.statet.rj.RSetups&quot;&gt; 
+   &lt;setup id=&quot;myapp.RSetup&quot;
+         name=&quot;Integrated R Engine&quot;
+         version=&quot;2.10.1&quot;&gt;
+   &lt;/setup&gt;
+   &lt;base 
+         setupId=&quot;myapp.RSetup&quot;
+         location=&quot;rhome/&quot;&gt;
+   &lt;/base&gt;
+&lt;/extension&gt;
+&lt;/pre&gt;
+The R home directories can be provided directly in the same plug-in (only a single platform is possible) or by platform specified fragments. The directory named &lt;code&gt;rhome&lt;/code&gt; is always located at the root of the plug-in or fragment.
+&lt;br/&gt;
+When using method (A) with fragments to support multiple platforms, a platform filter for 32-bit Windows in the &lt;code&gt;MANIFEST.MF&lt;/code&gt; file of the fragment would be:
+&lt;pre&gt;
+Eclipse-PlatformFilter: (&amp; (osgi.os=win32) (osgi.arch=x86))
+&lt;/pre&gt;
+
+&lt;br/&gt;
+&lt;i&gt;2)&lt;/i&gt; An application plug-in which provides an special analysis methods, can plug-in its R package to the R setup for several platforms by using method (B). Library declared in the &lt;code&gt;plugin.xml&lt;/code&gt;:
+&lt;pre&gt;
+&lt;extension point=&quot;org.eclipse.statet.rj.RSetups&quot;&gt; 
+   &lt;library 
+         setupId=&quot;myapp.RSetup&quot;
+         location=&quot;$os$/rpackages/&quot;&gt;
+   &lt;/library&gt;
+&lt;/extension&gt;
+&lt;/pre&gt;
+
+The directory structure for the platfrom specific R libraries would look like:
+&lt;pre&gt;
+&lt;plug-in root&gt;
+  + os
+    + linux
+      + x86
+        + rpackages
+          - package1
+          - package2
+      + x86_64
+        + rpackages
+          - package1
+          - package2
+    + win32
+      + x86
+        + rpackages
+          - package1
+          - package2
+      + x86_64
+        + rpackages
+          - package1
+          - package2
+&lt;/pre&gt;
+      </documentation>
+   </annotation>
+
+   <annotation>
+      <appinfo>
+         <meta.section type="copyright"/>
+      </appinfo>
+      <documentation>
+         Copyright (c) 2010, 2017 Stephan Wahlbrink and others.
+
+This program and the accompanying materials are made available under the
+terms of the Eclipse Public License 2.0 which is available at
+https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+which is available at https://www.apache.org/licenses/LICENSE-2.0.
+
+SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+
+Contributors:
+    Stephan Wahlbrink &lt;sw@wahlbrink.eu&gt; - initial API and implementation
+      </documentation>
+   </annotation>
+
+</schema>
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/RjClosedException.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/RjClosedException.java
new file mode 100644
index 0000000..f31e282
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/RjClosedException.java
@@ -0,0 +1,35 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj;
+
+
+/**
+ * Exception indicating that the used connection (to R) is already closed
+ */
+public class RjClosedException extends RjException {
+	
+	
+	private static final long serialVersionUID= 5199233227969338152L;
+	
+	
+	public RjClosedException(final String message) {
+		super(message);
+	}
+	
+	public RjClosedException(final String message, final Throwable cause) {
+		super(message, cause);
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/RjException.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/RjException.java
new file mode 100644
index 0000000..39b10f4
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/RjException.java
@@ -0,0 +1,32 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj;
+
+
+public class RjException extends Exception{
+	
+	
+	private static final long serialVersionUID= -2512905056010292440L;
+	
+	
+	public RjException(final String message) {
+		super(message);
+	}
+	
+	public RjException(final String message, final Throwable cause) {
+		super(message, cause);
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/RjInitFailedException.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/RjInitFailedException.java
new file mode 100644
index 0000000..113edf5
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/RjInitFailedException.java
@@ -0,0 +1,35 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj;
+
+
+/**
+ * Exception indicating that the initialization failed
+ */
+public class RjInitFailedException extends RjException {
+	
+	
+	private static final long serialVersionUID= -6199674887137008313L;
+	
+	
+	public RjInitFailedException(final String message) {
+		super(message);
+	}
+	
+	public RjInitFailedException(final String message, final Throwable cause) {
+		super(message, cause);
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/RjInvalidConfigurationException.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/RjInvalidConfigurationException.java
new file mode 100644
index 0000000..77f55d6
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/RjInvalidConfigurationException.java
@@ -0,0 +1,35 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj;
+
+
+/**
+ * Exception indicating that setting the configuration failed because it is invalid
+ */
+public class RjInvalidConfigurationException extends RjException {
+	
+	
+	private static final long serialVersionUID= 6709030537472523580L;
+	
+	
+	public RjInvalidConfigurationException(final String message) {
+		super(message);
+	}
+	
+	public RjInvalidConfigurationException(final String message, final Throwable cause) {
+		super(message, cause);
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/AutoIdMap.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/AutoIdMap.java
new file mode 100644
index 0000000..bc89ecf
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/AutoIdMap.java
@@ -0,0 +1,55 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server;
+
+
+final class AutoIdMap<E> {
+	
+	
+	private Object[] currentArray;
+	
+	
+	public AutoIdMap() {
+		this.currentArray= new Object[16];
+	}
+	
+	
+	public synchronized int put(final E e) {
+		final int size= this.currentArray.length;
+		for (int i= 1; i < size; i++) {
+			if (this.currentArray[i] == null) {
+				this.currentArray[i]= e;
+				return i;
+			}
+		}
+		final Object[] newArray= new Object[size+16];
+		System.arraycopy(this.currentArray, 0, newArray, 0, size);
+		newArray[size]= e;
+		this.currentArray= newArray;
+		return size;
+	}
+	
+	@SuppressWarnings("unchecked")
+	public E get(final int id) {
+		return (E) this.currentArray[id];
+	}
+	
+	public void remove(final int id) {
+		if (id > 0 && id < this.currentArray.length) {
+			this.currentArray[id]= null;
+		}
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/BinExchange.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/BinExchange.java
new file mode 100644
index 0000000..876f7df
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/BinExchange.java
@@ -0,0 +1,432 @@
+/*=============================================================================#
+ # Copyright (c) 2008, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server;
+
+import java.io.Externalizable;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import java.io.OutputStream;
+import java.rmi.Remote;
+
+import org.eclipse.statet.rj.RjException;
+
+
+/**
+ * Communication exchange object for a binary array/file
+ */
+public class BinExchange implements RjsComObject, Externalizable {
+	
+	private final static int C2S=                  0x00010000;
+	private final static int S2C=                  0x00020000;
+	private final static int OM_2=                 0x000f0000;
+	private final static int OC_2= ~OM_2;
+	
+	private final static int UPLOAD=               0x00100000;
+	private final static int DOWNLOAD=             0x00200000;
+	private final static int OM_TYPE=              0x00f00000;
+	
+	private static final int OM_CUSTOM=            0x0000ffff;
+	
+	private final static int DEFAULT_BUFFER_SIZE= 8192;
+	
+	
+	private final static AutoIdMap<OutputStream> gCOutList= new AutoIdMap<>();
+	
+	
+	static RjsComConfig.PathResolver gSPathResolver= new RjsComConfig.PathResolver() {
+		@Override
+		public File resolve(final Remote client, final String path) throws RjException {
+			final File file= new File(path);
+			if (!file.isAbsolute()) {
+				throw new RjException("Relative path not supported.");
+			}
+			return file;
+		}
+	};
+	
+	
+	private int options;
+	private Remote ref;
+	
+	private String remoteFilePath;
+	private RjsStatus status;
+	
+	private long inputLength;
+	private InputStream inputStream;
+	private int outputId;
+	private byte[] bytes;
+	
+	
+	/**
+	 * Constructor for clients to upload a file
+	 * @param in input stream to read the content from
+	 * @param length length
+	 * @param path remote file path 
+	 */
+	public BinExchange(final InputStream in, final long length, final String path, final Remote ref, final int options) {
+		if (path == null || in == null || ref == null) {
+			throw new NullPointerException();
+		}
+		if (path.length() <= 0) {
+			throw new IllegalArgumentException("Invalid path: empty.");
+		}
+		if (length < 0) {
+			throw new IllegalArgumentException("Invalid length: negative.");
+		}
+		
+		this.options= ((C2S | UPLOAD) | (OM_CUSTOM & options));
+		this.ref= ref;
+		this.remoteFilePath= path;
+		this.inputLength= length;
+		this.inputStream= in;
+		this.outputId= 0;
+	}
+	
+	/**
+	 * Constructor for clients to download a file
+	 * @param out output stream to write the content to
+	 * @param path remote file path
+	 * @param options
+	 */
+	public BinExchange(final OutputStream out, final String path, final Remote ref, final int options) {
+		if (path == null || out == null || ref == null) {
+			throw new NullPointerException();
+		}
+		if (path.length() == 0) {
+			throw new IllegalArgumentException("Illegal path argument.");
+		}
+		
+		this.options= (C2S | DOWNLOAD) | (OM_CUSTOM & options);
+		this.ref= ref;
+		this.inputLength= -1;
+		this.inputStream= null;
+		this.outputId= gCOutList.put(out);
+		this.remoteFilePath= path;
+	}
+	
+	/**
+	 * Constructor for clients to download a file into a byte array
+	 * @param path remote file path
+	 * @param options
+	 */
+	public BinExchange(final String path, final Remote ref, final int options) {
+		if (path == null || ref == null) {
+			throw new NullPointerException();
+		}
+		if (path.length() == 0) {
+			throw new IllegalArgumentException("Illegal path argument.");
+		}
+		
+		this.options= (C2S | DOWNLOAD) | (OM_CUSTOM & options);
+		this.ref= ref;
+		this.inputLength= -1;
+		this.inputStream= null;
+		this.outputId= 0;
+		this.remoteFilePath= path;
+	}
+	
+	/**
+	 * Constructor for automatic deserialization
+	 */
+	public BinExchange() {
+	}
+	
+	
+	@Override
+	public int getComType() {
+		return T_FILE_EXCHANGE;
+	}
+	
+	public boolean isOK() {
+		return (this.status == null || this.status.getSeverity() == RjsStatus.OK);
+	}
+	
+	public RjsStatus getStatus() {
+		return this.status;
+	}
+	
+	public String getFilePath() {
+		return this.remoteFilePath;
+	}
+	
+	public byte[] getBytes() {
+		return this.bytes;
+	}
+	
+	public void clear() {
+		gCOutList.remove(this.outputId);
+	}
+	
+	
+	@Override
+	public void readExternal(final ObjectInput in) throws IOException, ClassNotFoundException {
+		final int readOptions= in.readInt();
+		this.remoteFilePath= in.readUTF();
+		
+		switch (readOptions & (OM_TYPE | OM_2)) {
+		
+		case C2S | UPLOAD: {
+			this.ref= (Remote) in.readObject();
+			long length= this.inputLength= in.readLong();
+			FileOutputStream output= null;
+			try {
+				final File file= (gSPathResolver != null) ? gSPathResolver.resolve(this.ref, this.remoteFilePath) : new File(this.remoteFilePath);
+				output= new FileOutputStream(file, false);
+				final byte[] buffer= new byte[DEFAULT_BUFFER_SIZE];
+				while (length > 0L) {
+					final int n= in.read(buffer, 0, (int) Math.min(DEFAULT_BUFFER_SIZE, length));
+					if (n == -1) {
+						throw new IOException("Unexcepted end of stream.");
+					}
+					output.write(buffer, 0, n);
+					length-= n;
+				}
+				this.status= RjsStatus.OK_STATUS;
+			}
+			catch (final RjException e) {
+				this.status= new RjsStatus(RjsStatus.ERROR, 0, e.getMessage());
+				throw new IOException("Failed to resolve file path.");
+			}
+			catch (final IOException e) {
+				this.status= new RjsStatus(RjsStatus.ERROR, 0, e.getMessage());
+				throw new IOException("Failed to write stream to file.");
+			}
+			finally {
+				if (output != null) {
+					try {
+						output.close();
+					}
+					catch (final IOException e) {}
+				}
+			}
+			this.options= (readOptions & OC_2) | S2C;
+			return; }
+		
+		case C2S | DOWNLOAD: {
+			this.ref= (Remote) in.readObject();
+			this.outputId= in.readInt();
+			this.options= (readOptions & OC_2) | S2C;
+			return; }
+			
+		case S2C | UPLOAD: {
+			this.status= new RjsStatus(in);
+			this.options= (readOptions & OC_2);
+			return; }
+		
+		case S2C | DOWNLOAD: {
+			this.outputId= in.readInt();
+			this.status= new RjsStatus(in);
+			if (this.status.getSeverity() == RjsStatus.OK) {
+				long length= this.inputLength= in.readLong();
+				boolean writing= false;
+				try {
+					if (this.outputId > 0) {
+						final OutputStream out= gCOutList.get(this.outputId);
+						final byte[] buffer= new byte[DEFAULT_BUFFER_SIZE];
+						while (length > 0) {
+							final int n= in.read(buffer, 0, (int) Math.min(DEFAULT_BUFFER_SIZE, length));
+							if (n == -1) {
+								throw new IOException("Unexcepted end of stream.");
+							}
+							length-= n;
+							writing= true;
+							out.write(buffer, 0, n);
+							writing= false;
+						}
+					}
+					else {
+						if (length > Integer.MAX_VALUE) {
+							throw new UnsupportedOperationException();
+						}
+						this.bytes= new byte[(int) length];
+						while (length > 0) {
+							final int n= in.read(this.bytes, (int) (this.inputLength-length), (int) length);
+							if (n == -1) {
+								throw new IOException("Unexcepted end of stream.");
+							}
+							length-= n;
+						}
+					}
+				}
+				catch (IOException e) {
+					if (writing) {
+						this.status= new RjsStatus(RjsStatus.ERROR, 0, "Writing download to stream failed: " + e.getMessage());
+						try {
+							while (length > 0) {
+								final long n= in.skip(length);
+								if (n == -1) {
+									throw new IOException("Unexcepted end of stream.");
+								}
+								length-= n;
+							}
+							return;
+						}
+						catch (final IOException e2) {
+							e= e2;
+						}
+					}
+					throw e;
+				}
+			}
+			this.options= (readOptions & OC_2);
+			return; }
+		
+		default:
+			throw new IllegalStateException();
+		}
+	}
+	
+	@Override
+	public void writeExternal(final ObjectOutput out) throws IOException {
+		out.writeInt(this.options);
+		out.writeUTF(this.remoteFilePath);
+		
+		switch (this.options & (OM_TYPE | OM_2)) {
+		
+		case C2S | UPLOAD: {
+			out.writeObject(this.ref);
+			out.writeLong(this.inputLength);
+			if (this.inputStream != null) {
+				final byte[] buffer= new byte[DEFAULT_BUFFER_SIZE];
+				long length= this.inputLength;
+				while (length > 0) {
+					final int n= this.inputStream.read(buffer, 0, (int) Math.min(DEFAULT_BUFFER_SIZE, length));
+					if (n == -1) {
+						throw new IOException("Unexcepted end of stream.");
+					}
+					out.write(buffer, 0, n);
+					length-= n;
+				}
+			}
+			else if (this.bytes != null) {
+				out.writeLong(this.inputLength);
+				out.write(this.bytes, 0, (int) this.inputLength);
+			}
+			else {
+				throw new IOException("Missing file content.");
+			}
+			return; }
+		
+		case C2S | DOWNLOAD: {
+			out.writeObject(this.ref);
+			out.writeInt(this.outputId);
+			return; }
+		
+		case S2C | UPLOAD: {
+			this.status.writeExternal(out);
+			return; }
+		
+		case S2C | DOWNLOAD: {
+			out.writeInt(this.outputId);
+			FileInputStream input= null;
+			try {
+				final File file= (gSPathResolver != null) ? gSPathResolver.resolve(this.ref, this.remoteFilePath) : new File(this.remoteFilePath);
+				try {
+					input= new FileInputStream(file);
+					input.available();
+				}
+				catch (final IOException e) {
+					if (input != null) {
+						try {
+							input.close();
+							input= null;
+						}
+						catch (final IOException ignore) {}
+					}
+					if (!file.exists() || e instanceof FileNotFoundException) {
+						new RjsStatus(RjsStatus.ERROR, 0, "Failed to find file '"+ this.remoteFilePath + "'.").writeExternal(out);
+					}
+					else {
+						new RjsStatus(RjsStatus.ERROR, 0, "Failed to open file '"+ this.remoteFilePath + "'.").writeExternal(out);
+					}
+				}
+				if (input != null) {
+					RjsStatus.OK_STATUS.writeExternal(out);
+					long length= this.inputLength= file.length();
+					out.writeLong(length);
+					final byte[] buffer= new byte[DEFAULT_BUFFER_SIZE];
+					while (length > 0) {
+						final int n= input.read(buffer, 0, (int) Math.min(DEFAULT_BUFFER_SIZE, length));
+						if (n == -1) {
+							throw new IOException("Unexcepted end of file content.");
+						}
+						length-= n;
+						out.write(buffer, 0, n);
+					}
+				}
+			}
+			catch (final RjException e) {
+				this.status= new RjsStatus(RjsStatus.ERROR, 0, e.getMessage());
+				throw new IOException("Failed to resolve file path.");
+			}
+			finally {
+				if (input != null) {
+					try {
+						input.close();
+					}
+					catch (final IOException ignore) {}
+				}
+			}
+			return; }
+		
+		default:
+			throw new IllegalStateException();
+		}
+	}
+	
+	
+	@Override
+	public String toString() {
+		final StringBuilder sb= new StringBuilder(128);
+		sb.append("DataCmdItem ");
+		switch (this.options & OM_TYPE) {
+		case UPLOAD:
+			sb.append("UPLOAD");
+			break;
+		case DOWNLOAD:
+			sb.append("DOWNLOAD");
+			break;
+		default:
+			sb.append((this.options & OM_TYPE));
+			break;
+		}
+		sb.append("\n\t").append("direction= ");
+		switch (this.options & OM_2) {
+		case C2S:
+			sb.append("CLIENT-2-SERVER");
+			break;
+		case S2C:
+			sb.append("SERVER-2-CLIENT");
+			break;
+		default:
+			sb.append((this.options & OM_2));
+		}
+		sb.append("\n\tlength= ");
+		sb.append(this.inputLength);
+		if (this.status != null) {
+			sb.append("\n<STATUS>\n");
+			this.status.getCode();
+			sb.append("\n</STATUS>");
+		}
+		return sb.toString();
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/ComHandler.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/ComHandler.java
new file mode 100644
index 0000000..5628389
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/ComHandler.java
@@ -0,0 +1,26 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server;
+
+import java.io.IOException;
+import java.io.ObjectInput;
+
+
+public interface ComHandler {
+	
+	
+	public void processMainCmd(ObjectInput in) throws IOException;
+	
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/ConsoleMessageCmdItem.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/ConsoleMessageCmdItem.java
new file mode 100644
index 0000000..a4903bd
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/ConsoleMessageCmdItem.java
@@ -0,0 +1,105 @@
+/*=============================================================================#
+ # Copyright (c) 2008, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server;
+
+import java.io.IOException;
+
+import org.eclipse.statet.rj.data.RJIO;
+
+
+/**
+ * Command for main loop console messages.
+ */
+public final class ConsoleMessageCmdItem extends MainCmdItem {
+	
+	
+	private final String text;
+	
+	
+	public ConsoleMessageCmdItem(final String text) {
+		assert (text != null);
+		this.text= text;
+	}
+	
+	/**
+	 * Constructor for deserialization
+	 */
+	public ConsoleMessageCmdItem(final RJIO in) throws IOException, ClassNotFoundException {
+		this.text= in.readString();
+	}
+	
+	@Override
+	public void writeExternal(final RJIO out) throws IOException {
+		out.writeString(this.text);
+	}
+	
+	
+	@Override
+	public byte getCmdType() {
+		return T_MESSAGE_ITEM;
+	}
+	
+	@Override
+	public byte getOp() {
+		return 0;
+	}
+	
+	
+	@Override
+	public void setAnswer(final RjsStatus status) {
+		throw new UnsupportedOperationException();
+	}
+	
+	
+	@Override
+	public boolean isOK() {
+		return true;
+	}
+	
+	@Override
+	public RjsStatus getStatus() {
+		return null;
+	}
+	
+	@Override
+	public String getDataText() {
+		return this.text;
+	}
+	
+	
+	@Override
+	public boolean testEquals(final MainCmdItem other) {
+		if (!(other instanceof ConsoleMessageCmdItem)) {
+			return false;
+		}
+		final ConsoleMessageCmdItem otherItem= (ConsoleMessageCmdItem) other;
+		if (this.options != otherItem.options) {
+			return false;
+		}
+		return (this.text.equals(otherItem.getDataText()));
+	}
+	
+	@Override
+	public String toString() {
+		final StringBuilder sb= new StringBuilder(128);
+		sb.append("ConsoleMessageCmdItem");
+		sb.append("\n\t").append("options= 0x").append(Integer.toHexString(this.options));
+		sb.append("\n<TEXT>\n");
+		sb.append(this.text);
+		sb.append("\n</TEXT>");
+		return sb.toString();
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/ConsoleReadCmdItem.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/ConsoleReadCmdItem.java
new file mode 100644
index 0000000..c4ae25f
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/ConsoleReadCmdItem.java
@@ -0,0 +1,135 @@
+/*=============================================================================#
+ # Copyright (c) 2008, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server;
+
+import java.io.IOException;
+
+import org.eclipse.statet.rj.data.RJIO;
+
+
+/**
+ * Command for main loop console prompt/input.
+ */
+public final class ConsoleReadCmdItem extends MainCmdItem {
+	
+	
+	public static final int O_ADD_TO_HISTORY= 0;
+	
+	
+	private static final int OV_WITHTEXT=                  0x01000000;
+	
+	
+	private String text;
+	
+	
+	public ConsoleReadCmdItem(final int options, final String text) {
+		assert (text != null);
+		this.options= (options | (OV_WITHTEXT | OM_WAITFORCLIENT));
+		this.text= text;
+	}
+	
+	/**
+	 * Constructor for deserialization
+	 */
+	public ConsoleReadCmdItem(final RJIO in) throws IOException {
+		this.requestId= in.readInt();
+		this.options= in.readInt();
+		if ((this.options & OV_WITHTEXT) != 0) {
+			this.text= in.readString();
+		}
+	}
+	
+	@Override
+	public void writeExternal(final RJIO out) throws IOException {
+		out.writeInt(this.requestId);
+		out.writeInt(this.options);
+		if ((this.options & OV_WITHTEXT) != 0) {
+			out.writeString(this.text);
+		}
+	}
+	
+	
+	@Override
+	public byte getCmdType() {
+		return T_CONSOLE_READ_ITEM;
+	}
+	
+	@Override
+	public byte getOp() {
+		return 0;
+	}
+	
+	
+	@Override
+	public void setAnswer(final RjsStatus status) {
+		this.options= (this.options & OM_CLEARFORANSWER) | (status.getSeverity() << OS_STATUS);
+	}
+	
+	public void setAnswer(final String text) {
+		assert (text != null);
+		this.options= (this.options & OM_CLEARFORANSWER) | (OV_ANSWER | OV_WITHTEXT);
+		this.text= text;
+	}
+	
+	
+	@Override
+	public boolean isOK() {
+		return ((this.options & OM_STATUS) == RjsStatus.OK);
+	}
+	
+	@Override
+	public RjsStatus getStatus() {
+		return null;
+	}
+	
+	@Override
+	public String getDataText() {
+		return this.text;
+	}
+	
+	
+	@Override
+	public boolean testEquals(final MainCmdItem other) {
+		if (!(other instanceof ConsoleReadCmdItem)) {
+			return false;
+		}
+		final ConsoleReadCmdItem otherItem= (ConsoleReadCmdItem) other;
+		if (this.options != otherItem.options) {
+			return false;
+		}
+		if (((this.options & OV_WITHTEXT) != 0)
+				&& !this.text.equals(otherItem.getDataText())) {
+			return false;
+		}
+		return true;
+	}
+	
+	@Override
+	public String toString() {
+		final StringBuffer sb= new StringBuffer(128);
+		sb.append("ConsoleReadCmdItem");
+		sb.append("\n\t").append("options= 0x").append(Integer.toHexString(this.options));
+		if ((this.options & OV_WITHTEXT) != 0) {
+			sb.append("\n<TEXT>\n");
+			sb.append(this.text);
+			sb.append("\n</TEXT>");
+		}
+		else {
+			sb.append("\n<TEXT/>");
+		}
+		return sb.toString();
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/ConsoleWriteCmdItem.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/ConsoleWriteCmdItem.java
new file mode 100644
index 0000000..1b36ab4
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/ConsoleWriteCmdItem.java
@@ -0,0 +1,114 @@
+/*=============================================================================#
+ # Copyright (c) 2008, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server;
+
+import java.io.IOException;
+
+import org.eclipse.statet.rj.data.RJIO;
+
+
+/**
+ * Command for main loop console output.
+ */
+public final class ConsoleWriteCmdItem extends MainCmdItem {
+	
+	
+	public static final byte R_OUTPUT=                      1;
+	public static final byte R_ERROR=                       2;
+	public static final byte SYS_OUTPUT=                    5;
+	
+	
+	private final byte streamId;
+	
+	private final String text;
+	
+	
+	public ConsoleWriteCmdItem(final byte streamId, final String text) {
+		assert (text != null);
+		this.streamId= streamId;
+		this.text= text;
+	}
+	
+	/**
+	 * Constructor for deserialization
+	 */
+	public ConsoleWriteCmdItem(final RJIO in) throws IOException {
+		this.streamId= in.readByte();
+		this.text= in.readString();
+	}
+	
+	@Override
+	public void writeExternal(final RJIO out) throws IOException {
+		out.writeByte(this.streamId);
+		out.writeString(this.text);
+	}
+	
+	
+	@Override
+	public byte getCmdType() {
+		return T_CONSOLE_WRITE_ITEM;
+	}
+	
+	@Override
+	public byte getOp() {
+		return this.streamId;
+	}
+	
+	
+	@Override
+	public void setAnswer(final RjsStatus status) {
+		throw new UnsupportedOperationException();
+	}
+	
+	
+	@Override
+	public boolean isOK() {
+		return true;
+	}
+	
+	@Override
+	public RjsStatus getStatus() {
+		return null;
+	}
+	
+	@Override
+	public String getDataText() {
+		return this.text;
+	}
+	
+	
+	@Override
+	public boolean testEquals(final MainCmdItem other) {
+		if (!(other instanceof ConsoleWriteCmdItem)) {
+			return false;
+		}
+		final ConsoleWriteCmdItem otherItem= (ConsoleWriteCmdItem) other;
+		return (this.options == otherItem.options
+				&& this.streamId == otherItem.streamId
+				&& this.text.equals(otherItem.getDataText()) );
+	}
+	
+	@Override
+	public String toString() {
+		final StringBuilder sb= new StringBuilder(128);
+		sb.append("ConsoleWriteCmdItem (").append(this.streamId).append(")");
+		sb.append("\n\t").append("options= 0x").append(Integer.toHexString(this.options));
+		sb.append("\n<TEXT>\n");
+		sb.append(this.text);
+		sb.append("\n</TEXT>");
+		return sb.toString();
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/CtrlCmdItem.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/CtrlCmdItem.java
new file mode 100644
index 0000000..3b25b88
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/CtrlCmdItem.java
@@ -0,0 +1,108 @@
+/*=============================================================================#
+ # Copyright (c) 2008, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server;
+
+import java.io.Externalizable;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+
+import org.eclipse.statet.rj.data.RJIO;
+import org.eclipse.statet.rj.data.RJIOExternalizable;
+
+
+/**
+ * Client-to-Server list with {@link MainCmdItem}s.
+ */
+public final class CtrlCmdItem implements RjsComObject, RJIOExternalizable, Externalizable {
+	
+	
+	public static final int REQUEST_CANCEL= 1;
+	public static final int REQUEST_HOT_MODE= 2;
+	
+	
+	private int ctrl;
+	
+	
+	public CtrlCmdItem(final int ctrlId) {
+		this.ctrl= ctrlId;
+	}
+	
+	/**
+	 * Constructor for automatic deserialization
+	 */
+	public CtrlCmdItem() {
+	}
+	
+	/**
+	 * Constructor for automatic deserialization
+	 * @throws IOException 
+	 */
+	public CtrlCmdItem(final RJIO in) throws IOException {
+		this.ctrl= in.readInt();
+	}
+	
+	@Override
+	public void readExternal(final ObjectInput in) throws IOException {
+		this.ctrl= in.readInt();
+	}
+	
+	@Override
+	public void writeExternal(final RJIO out) throws IOException {
+		out.writeInt(this.ctrl);
+	}
+	
+	@Override
+	public void writeExternal(final ObjectOutput out) throws IOException {
+		out.writeInt(this.ctrl);
+	}
+	
+	
+	@Override
+	public int getComType() {
+		return RjsComObject.T_CTRL;
+	}
+	
+	public int getCtrlId() {
+		return this.ctrl;
+	}
+	
+	
+	public boolean testEquals(final CtrlCmdItem other) {
+		if (this.ctrl != other.ctrl) {
+			return false;
+		}
+		return true;
+	}
+	
+	@Override
+	public String toString() {
+		final StringBuilder sb= new StringBuilder(64);
+		sb.append("CtrlCmdItem ");
+		switch (this.ctrl) {
+		case REQUEST_CANCEL:
+			sb.append("REQUEST_CANCEL");
+			break;
+		case REQUEST_HOT_MODE:
+			sb.append("REQUEST_HOT_MODE");
+			break;
+		default:
+			sb.append(this.ctrl);
+			break;
+		}
+		return sb.toString();
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/DataCmdItem.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/DataCmdItem.java
new file mode 100644
index 0000000..c403637
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/DataCmdItem.java
@@ -0,0 +1,462 @@
+/*=============================================================================#
+ # Copyright (c) 2008, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server;
+
+import java.io.IOException;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.eclipse.statet.rj.data.RJIO;
+import org.eclipse.statet.rj.data.RObject;
+import org.eclipse.statet.rj.data.RObjectFactory;
+import org.eclipse.statet.rj.data.impl.DefaultRObjectFactory;
+
+
+/**
+ * Command item for main loop data exchange/evaluation
+ */
+public final class DataCmdItem extends MainCmdItem {
+	
+	
+	public static final class Operation {
+		
+		public static final byte NONE= 0;
+		public static final byte EXPR= 1;
+		public static final byte POINTER= 2;
+		public static final byte FCALL= 3;
+		public static final byte RDATA= 4;
+		
+		public final byte op;
+		
+		public final String name;
+		
+		public final byte source;
+		public final byte target;
+		public final boolean returnData;
+		
+		private final boolean reqSourceExpr;
+		private final boolean reqRData;
+		private final boolean reqTargetExpr;
+		
+		private Operation(final String name, final int op,
+				final byte source, final byte target, final boolean returnData) {
+			this.op= (byte) op;
+			this.name= name;
+			this.source= source;
+			this.target= target;
+			this.returnData= returnData;
+			
+			this.reqSourceExpr= (source == EXPR || source == POINTER || source == FCALL);
+			this.reqRData= (source == FCALL || source == RDATA);
+			this.reqTargetExpr= (target == EXPR || target == POINTER);
+		}
+		
+		
+		@Override
+		public String toString() {
+			return this.name;
+		}
+		
+	}
+	
+	
+	public static final Operation EVAL_EXPR_VOID= new Operation("EVAL_EXPR_VOID", 1, //$NON-NLS-1$
+			Operation.EXPR, Operation.NONE, false);
+	public static final Operation EVAL_FCALL_VOID= new Operation("EVAL_FCALL_VOID", 2, //$NON-NLS-1$
+			Operation.FCALL, Operation.NONE, false);
+	
+	public static final Operation EVAL_EXPR_DATA= new Operation("EVAL_EXPR_DATA", 3, //$NON-NLS-1$
+			Operation.EXPR, Operation.NONE, true);
+	public static final Operation EVAL_FCALL_DATA= new Operation("EVAL_FCALL_DATA", 4, //$NON-NLS-1$
+			Operation.FCALL, Operation.NONE, true);
+	public static final Operation RESOLVE_DATA= new Operation("RESOLVE_DATA", 5, // EVAL_REF_DATA //$NON-NLS-1$
+			Operation.POINTER, Operation.NONE, true);
+	
+	public static final Operation ASSIGN_DATA= new Operation("ASSIGN_DATA", 6, //$NON-NLS-1$
+			Operation.RDATA, Operation.EXPR, false);
+	public static final Operation ASSIGN_FCALL= new Operation("ASSIGN_FCALL", 7, //$NON-NLS-1$
+			Operation.FCALL, Operation.EXPR, false);
+	
+	public static final int FIND_DATA_OP= 8;
+	public static final Operation FIND_DATA= new Operation("FIND_DATA", FIND_DATA_OP, //$NON-NLS-1$
+			Operation.EXPR, Operation.NONE, true);
+	
+	public static final int EVAL_NAMESPACE_DATA_OP= 9;
+	public static final Operation EVAL_NAMESPACE_DATA= new Operation("EVAL_NAMESPACE_DATA", EVAL_NAMESPACE_DATA_OP, //$NON-NLS-1$
+			Operation.EXPR, Operation.NONE, false);
+	public static final int EVAL_NAMESPACE_EXPORTS_DATA_OP= 10;
+	public static final Operation EVAL_NAMESPACE_EXPORTS_DATA= new Operation("EVAL_NAMESPACE_EXPORTS_DATA", EVAL_NAMESPACE_EXPORTS_DATA_OP, //$NON-NLS-1$
+			Operation.EXPR, Operation.NONE, false);
+	
+	
+	private static final Operation[] OPERATIONS= new Operation[11];
+	
+	private static final void addOp(final Operation operation) {
+		if (OPERATIONS[operation.op] != null) {
+			throw new IllegalArgumentException();
+		}
+		OPERATIONS[operation.op]= operation;
+	}
+	
+	private static final Operation getOperation(final byte op) {
+		if (op <= 0 || op >= OPERATIONS.length) {
+			throw new UnsupportedOperationException("data op: " + op); //$NON-NLS-1$
+		}
+		return OPERATIONS[op];
+	}
+	
+	static {
+		addOp(EVAL_EXPR_VOID);
+		addOp(EVAL_FCALL_VOID);
+		addOp(EVAL_EXPR_DATA);
+		addOp(EVAL_FCALL_DATA);
+		addOp(RESOLVE_DATA);
+		addOp(ASSIGN_DATA);
+		addOp(ASSIGN_FCALL);
+		addOp(FIND_DATA);
+		addOp(EVAL_NAMESPACE_DATA);
+		addOp(EVAL_NAMESPACE_EXPORTS_DATA);
+	}
+	
+	
+	private static final int OV_WITHDATA=                  0x02000000;
+	private static final int OV_WITHRHO=                   0x04000000;
+	private static final int OV_WITHSTATUS=                0x08000000;
+	
+	
+	public static final String DEFAULT_FACTORY_ID= "default"; //$NON-NLS-1$
+	
+	
+	static RObjectFactory gDefaultFactory;
+	
+	static final Map<String, RObjectFactory> gFactories= new ConcurrentHashMap<>();
+	
+	private static final RObjectFactory getFactory(final String id) {
+		final RObjectFactory factory= gFactories.get(id);
+		if (factory != null) {
+			return factory;
+		}
+		return gDefaultFactory;
+	}
+	
+	static {
+		RjsComConfig.setDefaultRObjectFactory(DefaultRObjectFactory.INSTANCE);
+	}
+	
+	
+	private final Operation operation;
+	
+	private byte depth;
+	private String sourceExpr;
+	private String targetExpr;
+	private RObject rdata;
+	private RObject rho;
+	
+	private String factoryId;
+	
+	private RjsStatus status;
+	
+	
+	/**
+	 * Constructor for operations with returned data
+	 */
+	public DataCmdItem(final Operation op, final int options, final byte depth,
+			final String sourceExpr, final RObject data, final String targetExpr,
+			final RObject rho,
+			final String factoryId) {
+		assert (op.reqSourceExpr == (sourceExpr != null));
+		assert (op.reqRData == (data != null));
+		assert (op.reqTargetExpr == (targetExpr != null));
+		assert (factoryId == null || gFactories.containsKey(factoryId));
+		this.operation= op;
+		this.sourceExpr= sourceExpr;
+		this.targetExpr= targetExpr;
+		this.options= (OV_WAITFORCLIENT | (options & OM_CUSTOM));
+		if (data != null) {
+			this.rdata= data;
+			this.options |= OV_WITHDATA;
+		}
+		if (rho != null) {
+			this.rho= rho;
+			this.options |= OV_WITHRHO;
+		}
+		this.depth= depth;
+		this.factoryId= (factoryId != null) ? factoryId : DEFAULT_FACTORY_ID;
+	}
+	
+	/**
+	 * Constructor for operations without returned data:
+	 */
+	public DataCmdItem(final Operation op, final int options,
+			final String sourceExpr, final RObject data, final String targetExpr,
+			final RObject rho) {
+		assert (op.reqSourceExpr == (sourceExpr != null));
+		assert (op.reqRData == (data != null));
+		assert (op.reqTargetExpr == (targetExpr != null));
+		this.operation= op;
+		this.sourceExpr= sourceExpr;
+		this.targetExpr= targetExpr;
+		this.options= (OV_WAITFORCLIENT | (options & OM_CUSTOM));
+		if (data != null) {
+			this.rdata= data;
+			this.options |= OV_WITHDATA;
+		}
+		if (rho != null) {
+			this.rho= rho;
+			this.options |= OV_WITHRHO;
+		}
+		this.factoryId= "";
+	}
+	
+	
+	/**
+	 * Constructor for deserialization
+	 */
+	public DataCmdItem(final RJIO in) throws IOException {
+		this.requestId= in.readInt();
+		this.operation= getOperation(in.readByte());
+		this.options= in.readInt();
+		if ((this.options & OV_WITHSTATUS) != 0) {
+			this.status= new RjsStatus(in);
+			return;
+		}
+		this.depth= in.readByte();
+		this.factoryId= in.readString();
+		if ((this.options & OV_ANSWER) == 0) { // request
+			if (this.operation.reqSourceExpr) {
+				this.sourceExpr= in.readString();
+			}
+			if (this.operation.reqRData) {
+				in.flags= 0;
+				this.rdata= gDefaultFactory.readObject(in);
+			}
+			if (this.operation.reqTargetExpr) {
+				this.targetExpr= in.readString();
+			}
+			if ((this.options & OV_WITHRHO) != 0) {
+				in.flags= 0;
+				this.rho= gDefaultFactory.readObject(in);
+			}
+		}
+		else { // answer
+			if ((this.options & OV_WITHDATA) != 0) {
+				in.flags= (this.options & 0xff);
+				this.rdata= getFactory(this.factoryId).readObject(in);
+			}
+			if ((this.options & OV_WITHRHO) != 0) {
+				in.flags= RObjectFactory.F_ONLY_STRUCT;
+				this.rho= getFactory(this.factoryId).readObject(in);
+			}
+		}
+	}
+	
+	@Override
+	public void writeExternal(final RJIO out) throws IOException {
+		out.writeInt(this.requestId);
+		out.writeByte(this.operation.op);
+		out.writeInt(this.options);
+		if ((this.options & OV_WITHSTATUS) != 0) {
+			this.status.writeExternal(out);
+			return;
+		}
+		out.writeByte(this.depth);
+		out.writeString(this.factoryId);
+		if ((this.options & OV_ANSWER) == 0) { // request
+			if (this.operation.reqSourceExpr) {
+				out.writeString(this.sourceExpr);
+			}
+			if (this.operation.reqRData) {
+				out.flags= 0;
+				gDefaultFactory.writeObject(this.rdata, out);
+			}
+			if (this.operation.reqTargetExpr) {
+				out.writeString(this.targetExpr);
+			}
+			if ((this.options & OV_WITHRHO) != 0) {
+				out.flags= 0;
+				gDefaultFactory.writeObject(this.rho, out);
+			}
+		}
+		else { // anwser
+			if ((this.options & OV_WITHDATA) != 0) {
+				out.flags= (this.options & 0xff);
+				gDefaultFactory.writeObject(this.rdata, out);
+			}
+			if ((this.options & OV_WITHRHO) != 0) {
+				out.flags= RObjectFactory.F_ONLY_STRUCT;
+				gDefaultFactory.writeObject(this.rho, out);
+			}
+		}
+	}
+	
+	
+	@Override
+	public byte getCmdType() {
+		return T_DATA_ITEM;
+	}
+	
+	
+	@Override
+	public void setAnswer(final RjsStatus status) {
+		assert (status != null);
+		if (status == RjsStatus.OK_STATUS) {
+			this.options= (this.options & OM_CLEARFORANSWER) | OV_ANSWER;
+			this.status= null;
+			this.sourceExpr= null;
+			this.rdata= null;
+			this.targetExpr= null;
+			this.rho= null;
+		}
+		else {
+			this.options= ((this.options & OM_CLEARFORANSWER) | (OV_ANSWER | OV_WITHSTATUS));
+			this.status= status;
+			this.sourceExpr= null;
+			this.rdata= null;
+			this.targetExpr= null;
+			this.rho= null;
+		}
+	}
+	
+	public void setAnswer(final RObject rdata, final RObject rho) {
+		this.options= ((this.options & OM_CLEARFORANSWER) | OV_ANSWER);
+		if (rdata != null) {
+			this.options |= OV_WITHDATA;
+		}
+		if (rho != null) {
+			this.options |= OV_WITHRHO;
+		}
+		this.status= null;
+		this.sourceExpr= null;
+		this.rdata= rdata;
+		this.targetExpr= null;
+		this.rho= rho;
+	}
+	
+	
+	@Override
+	public byte getOp() {
+		return this.operation.op;
+	}
+	
+	public Operation getOperation() {
+		return this.operation;
+	}
+	
+	@Override
+	public boolean isOK() {
+		return (this.status == null || this.status.getSeverity() == RjsStatus.OK);
+	}
+	
+	@Override
+	public RjsStatus getStatus() {
+		return this.status;
+	}
+	
+	@Override
+	public String getDataText() {
+		return this.sourceExpr;
+	}
+	
+	public RObject getData() {
+		return this.rdata;
+	}
+	
+	public String getTargetExpr() {
+		return this.targetExpr;
+	}
+	
+	public RObject getRho() {
+		return this.rho;
+	}
+	
+	public byte getDepth() {
+		return this.depth;
+	}
+	
+	
+	@Override
+	public boolean testEquals(final MainCmdItem other) {
+		if (!(other instanceof DataCmdItem)) {
+			return false;
+		}
+		final DataCmdItem otherItem= (DataCmdItem) other;
+		if (getOp() != otherItem.getOp()) {
+			return false;
+		}
+		if (this.options != otherItem.options) {
+			return false;
+		}
+		if (!((this.sourceExpr != null) ?
+				this.sourceExpr.equals(otherItem.sourceExpr) :
+				null == otherItem.sourceExpr )) {
+			return false;
+		}
+		if (!((this.rdata != null) ?
+				this.rdata.equals(otherItem.rdata) :
+				null == otherItem.rdata )) {
+			return false;
+		}
+		if (!((this.targetExpr != null) ?
+				this.targetExpr.equals(otherItem.targetExpr) :
+				null == otherItem.targetExpr )) {
+			return false;
+		}
+		if (!((this.rho != null) ?
+				this.rho.equals(otherItem.rho) :
+				null == otherItem.rho )) {
+			return false;
+		}
+		return true;
+	}
+	
+	@Override
+	public String toString() {
+		final StringBuffer sb= new StringBuffer(100);
+		sb.append("DataCmdItem ");
+		sb.append(this.operation.name);
+		sb.append("\n\t").append("options= 0x").append(Integer.toHexString(this.options));
+		if (this.sourceExpr != null) {
+			sb.append("\n<SOURCE-EXPR>\n");
+			sb.append(this.sourceExpr);
+			sb.append("\n</SOURCE-EXPR>");
+		}
+		else {
+			sb.append("\n<SOURCE-EXPR/>");
+		}
+		if ((this.options & OV_WITHDATA) != 0) {
+			sb.append("\n<DATA>\n");
+			sb.append(this.rdata.toString());
+			sb.append("\n</DATA>");
+		}
+		else {
+			sb.append("\n<DATA/>");
+		}
+		if (this.targetExpr != null) {
+			sb.append("\n<TARGET-EXPR>\n");
+			sb.append(this.targetExpr);
+			sb.append("\n</TARGET-EXPR>");
+		}
+		else {
+			sb.append("\n<TARGET-EXPR/>");
+		}
+		if ((this.options & OV_WITHRHO) != 0) {
+			sb.append("\n<RHO>\n");
+			sb.append(this.rho.toString());
+			sb.append("\n</RHO>");
+		}
+		return sb.toString();
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/DbgCmdItem.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/DbgCmdItem.java
new file mode 100644
index 0000000..33a48ee
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/DbgCmdItem.java
@@ -0,0 +1,375 @@
+/*=============================================================================#
+ # Copyright (c) 2008, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server;
+
+import java.io.Externalizable;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+
+import org.eclipse.statet.rj.data.RJIO;
+import org.eclipse.statet.rj.data.RJIOExternalizable;
+import org.eclipse.statet.rj.server.dbg.CallStack;
+import org.eclipse.statet.rj.server.dbg.CtrlReport;
+import org.eclipse.statet.rj.server.dbg.DbgEnablement;
+import org.eclipse.statet.rj.server.dbg.DbgFilterState;
+import org.eclipse.statet.rj.server.dbg.DbgRequest;
+import org.eclipse.statet.rj.server.dbg.ElementTracepointInstallationRequest;
+import org.eclipse.statet.rj.server.dbg.FlagTracepointInstallationRequest;
+import org.eclipse.statet.rj.server.dbg.FrameContext;
+import org.eclipse.statet.rj.server.dbg.FrameContextDetailRequest;
+import org.eclipse.statet.rj.server.dbg.SetDebugReport;
+import org.eclipse.statet.rj.server.dbg.SetDebugRequest;
+import org.eclipse.statet.rj.server.dbg.TracepointEvent;
+import org.eclipse.statet.rj.server.dbg.TracepointInstallationReport;
+import org.eclipse.statet.rj.server.dbg.TracepointStatesUpdate;
+
+
+/**
+ * Command item for main loop dbg operations (="op")
+ */
+public final class DbgCmdItem extends MainCmdItem implements RjsComObject, Externalizable {
+	
+	// -- C2S sync
+	public static final byte OP_LOAD_FRAME_LIST=            0001;
+	public static final byte OP_LOAD_FRAME_CONTEXT=         0002;
+	public static final byte OP_SET_DEBUG=                  0003;
+	public static final byte OP_REQUEST_SUSPEND=            0004;
+//	public static final byte OP_CTRL_SUSPEND=               0010;
+	public static final byte OP_CTRL_RESUME=                0011;
+	public static final byte OP_CTRL_STEP_INTO=             0012;
+	public static final byte OP_CTRL_STEP_OVER=             0014;
+	public static final byte OP_CTRL_STEP_RETURN=           0016;
+	public static final byte OP_INSTALL_TP_FLAGS=           0020;
+	public static final byte OP_INSTALL_TP_POSITIONS=       0021;
+	
+	// -- C2S sync + async
+	public static final byte OP_SET_ENABLEMENT=             0031;
+	public static final byte OP_RESET_FILTER_STATE=         0032;
+	public static final byte OP_UPDATE_TP_STATES=           0034;
+	
+	public static final byte OP_C2S_S2C=                    0040;
+	
+	public static final byte OP_NOTIFY_TP_EVENT=            0x41;
+	
+	
+	private static final int OV_WITHDATA=                   0x01000000;
+	private static final int OV_WITHSTATUS=                 0x08000000;
+	
+	
+	public static interface CustomDataReader {
+		
+		Object read(byte type, boolean answer, RJIO io) throws IOException;
+		
+	}
+	
+	private static Object readData(final RJIO io, final byte type, final boolean answer) throws IOException {
+		if (!answer) {
+			switch (type) {
+			case OP_LOAD_FRAME_LIST:
+				return null;
+			case OP_LOAD_FRAME_CONTEXT:
+				return new FrameContextDetailRequest(io);
+			case OP_SET_DEBUG:
+				return new SetDebugRequest(io);
+			case OP_REQUEST_SUSPEND:
+				return null;
+			case OP_CTRL_RESUME:
+				return new DbgRequest.Resume(io);
+			case OP_CTRL_STEP_INTO:
+				return new DbgRequest.StepInto(io);
+			case OP_CTRL_STEP_OVER:
+				return new DbgRequest.StepOver(io);
+			case OP_CTRL_STEP_RETURN:
+				return new DbgRequest.StepReturn(io);
+			case OP_SET_ENABLEMENT:
+				return new DbgEnablement(io);
+			case OP_RESET_FILTER_STATE:
+				return new DbgFilterState(io);
+			case OP_INSTALL_TP_FLAGS:
+				return new FlagTracepointInstallationRequest(io);
+			case OP_INSTALL_TP_POSITIONS:
+				return new ElementTracepointInstallationRequest(io);
+			case OP_UPDATE_TP_STATES:
+				return new TracepointStatesUpdate(io);
+			case OP_NOTIFY_TP_EVENT:
+				return new TracepointEvent(io);
+			default:
+				break;
+			}
+			throw new IOException("Unsupported type= " + type); //$NON-NLS-1$
+		}
+		else {
+			switch (type) {
+			case OP_LOAD_FRAME_LIST:
+				return new CallStack(io);
+			case OP_LOAD_FRAME_CONTEXT:
+				return new FrameContext(io);
+			case OP_SET_DEBUG:
+				return new SetDebugReport(io);
+			case OP_REQUEST_SUSPEND:
+				break; // status
+			case OP_CTRL_RESUME:
+			case OP_CTRL_STEP_INTO:
+			case OP_CTRL_STEP_OVER:
+			case OP_CTRL_STEP_RETURN:
+				return new CtrlReport(io);
+			case OP_SET_ENABLEMENT:
+			case OP_RESET_FILTER_STATE:
+				break; // status
+			case OP_INSTALL_TP_FLAGS:
+			case OP_INSTALL_TP_POSITIONS:
+				return new TracepointInstallationReport(io);
+			case OP_UPDATE_TP_STATES:
+				break; // status
+			default:
+				break;
+			}
+			throw new IOException("Unsupported type= " + type); //$NON-NLS-1$
+		}
+	}
+	
+	
+	private byte op;
+	
+	private Object data;
+	
+	private RjsStatus status;
+	
+	
+	/**
+	 * Constructor for new commands
+	 */
+	public DbgCmdItem(final byte op, final int options,
+			final RJIOExternalizable data) {
+		this.op= op;
+		this.options= (options & OM_CUSTOM);
+		if (data != null) {
+			this.options |= OV_WITHDATA;
+		}
+		if (op < OP_NOTIFY_TP_EVENT) {
+			this.options |= OV_WAITFORCLIENT;
+		}
+		this.data= data;
+	}
+	
+	/**
+	 * Constructor for automatic deserialization
+	 */
+	public DbgCmdItem() {
+	}
+	
+	/**
+	 * Constructor for deserialization
+	 */
+	public DbgCmdItem(final RJIO io) throws IOException {
+		readExternal(io, null);
+	}
+	
+	/**
+	 * Constructor for deserialization
+	 */
+	public DbgCmdItem(final RJIO io, final CustomDataReader reader) throws IOException {
+		readExternal(io, reader);
+	}
+	
+	@Override
+	public void writeExternal(final RJIO io) throws IOException {
+		io.writeInt(this.options);
+		io.writeByte(this.op);
+		if ((this.options & OV_WITHSTATUS) != 0) {
+			this.status.writeExternal(io);
+		}
+		else if ((this.options & OV_WITHDATA) != 0) {
+			((RJIOExternalizable) this.data).writeExternal(io);
+		}
+	}
+	
+	@Override
+	public void writeExternal(final ObjectOutput out) throws IOException {
+		final RJIO io= RJIO.get(out);
+		final int check= io.writeCheck1();
+		writeExternal(io);
+		io.writeCheck2(check);
+		io.disconnect(out);
+	}
+	
+	private void readExternal(final RJIO io, final CustomDataReader reader) throws IOException {
+		this.options= io.readInt();
+		this.op= io.readByte();
+		if ((this.options & OV_WITHSTATUS) != 0) {
+			this.status= new RjsStatus(io);
+		}
+		else if ((this.options & OV_WITHDATA) != 0) {
+			final boolean answer= ((this.options & OV_ANSWER) != 0);
+			if (reader != null) {
+				this.data= reader.read(this.op, answer, io);
+				if (this.data == null) {
+					this.data= readData(io, this.op, answer);
+				}
+			}
+			else {
+				this.data= readData(io, this.op, answer);
+			}
+		}
+	}
+	
+	@Override
+	public void readExternal(final ObjectInput in) throws IOException {
+		final RJIO io= RJIO.get(in);
+		final int check= io.readCheck1();
+		readExternal(io, null);
+		io.readCheck2(check);
+		io.disconnect(in);
+	}
+	
+	
+	@Override
+	public int getComType() {
+		return T_DBG;
+	}
+	
+	@Override
+	public byte getCmdType() {
+		return T_DBG_ITEM;
+	}
+	
+	
+	@Override
+	public void setAnswer(final RjsStatus status) {
+		assert (status != null);
+		if (status == RjsStatus.OK_STATUS) {
+			this.options= (this.options & OM_CLEARFORANSWER) | OV_ANSWER;
+			this.status= null;
+			this.data= null;
+		}
+		else {
+			this.options= (this.options & OM_CLEARFORANSWER) | (OV_ANSWER | OV_WITHSTATUS);
+			this.status= status;
+			this.data= null;
+		}
+	}
+	
+	public void setAnswer(final RJIOExternalizable data) {
+		this.options= (this.options & OM_CLEARFORANSWER) | OV_ANSWER;
+		if (data != null) {
+			this.options |= OV_WITHDATA;
+		}
+		this.status= null;
+		this.data= data;
+	}
+	
+	
+	@Override
+	public byte getOp() {
+		return this.op;
+	}
+	
+	@Override
+	public boolean isOK() {
+		return (this.status == null || this.status.getSeverity() == RjsStatus.OK);
+	}
+	
+	@Override
+	public RjsStatus getStatus() {
+		return this.status;
+	}
+	
+	@Override
+	public String getDataText() {
+		return null;
+	}
+	
+	public Object getData() {
+		return this.data;
+	}
+	
+	
+	@Override
+	public boolean testEquals(final MainCmdItem other) {
+		if (!(other instanceof DbgCmdItem)) {
+			return false;
+		}
+		final DbgCmdItem otherItem= (DbgCmdItem) other;
+		if (getOp() != otherItem.getOp()) {
+			return false;
+		}
+		if (this.options != otherItem.options) {
+			return false;
+		}
+		return true;
+	}
+	
+	@Override
+	public String toString() {
+		final StringBuffer sb= new StringBuffer(100);
+		sb.append("DbgCmdItem "); //$NON-NLS-1$
+		switch (this.op) {
+		case OP_LOAD_FRAME_LIST:
+			sb.append("LOAD_FRAME_LIST"); //$NON-NLS-1$
+			break;
+		case OP_LOAD_FRAME_CONTEXT:
+			sb.append("LOAD_FRAME_CONTEXT"); //$NON-NLS-1$
+			break;
+		case OP_SET_DEBUG:
+			sb.append("SET_DEBUG"); //$NON-NLS-1$
+			break;
+		case OP_REQUEST_SUSPEND:
+			sb.append("REQUEST_SUSPEND"); //$NON-NLS-1$
+			break;
+		case OP_CTRL_RESUME:
+			sb.append("CTRL_RESUME"); //$NON-NLS-1$
+			break;
+		case OP_CTRL_STEP_INTO:
+			sb.append("CTRL_STEP_INTO"); //$NON-NLS-1$
+			break;
+		case OP_CTRL_STEP_OVER:
+			sb.append("CTRL_STEP_OVER"); //$NON-NLS-1$
+			break;
+		case OP_CTRL_STEP_RETURN:
+			sb.append("CTRL_STEP_RETURN"); //$NON-NLS-1$
+			break;
+		case OP_INSTALL_TP_FLAGS:
+			sb.append("INSTALL_TP_FLAGS"); //$NON-NLS-1$
+			break;
+		case OP_INSTALL_TP_POSITIONS:
+			sb.append("INSTALL_TP_POSITIONS"); //$NON-NLS-1$
+			break;
+		case OP_SET_ENABLEMENT:
+			sb.append("SET_ENABLEMENT"); //$NON-NLS-1$
+			break;
+		case OP_RESET_FILTER_STATE:
+			sb.append("RESET_FILTER_STATE"); //$NON-NLS-1$
+			break;
+		case OP_UPDATE_TP_STATES:
+			sb.append("UPDATE_TRACEPOINTS_STATES"); //$NON-NLS-1$
+			break;
+		case OP_NOTIFY_TP_EVENT:
+			sb.append("NOTIFY_TP_EVENT"); //$NON-NLS-1$
+			break;
+		default:
+			sb.append(this.op);
+			break;
+		}
+		sb.append("\n\t" + "options= 0x").append(Integer.toHexString(this.options)); //$NON-NLS-1$ //$NON-NLS-2$
+		if ((this.options & OV_WITHDATA) != 0) {
+			sb.append("\n<DATA>\n"); //$NON-NLS-1$
+			sb.append(this.data);
+			sb.append("\n</DATA>"); //$NON-NLS-1$
+		}
+		return sb.toString();
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/ExtUICmdItem.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/ExtUICmdItem.java
new file mode 100644
index 0000000..919c8b0
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/ExtUICmdItem.java
@@ -0,0 +1,172 @@
+/*=============================================================================#
+ # Copyright (c) 2008, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server;
+
+import java.io.IOException;
+
+import org.eclipse.statet.rj.data.RJIO;
+import org.eclipse.statet.rj.data.RList;
+
+
+/**
+ * Command item for main loop UI interaction.
+ */
+public final class ExtUICmdItem extends MainCmdItem {
+	
+	
+	private static final int OV_WITHMAP=                   0x01000000;
+	private static final int OV_WITHSTATUS=                0x08000000;
+	
+	
+	private String command;
+	private RList data;
+	
+	private RjsStatus status;
+	
+	
+	public ExtUICmdItem(final String command, final int options, final RList args, final boolean waitForClient) {
+		assert (command != null);
+		this.command= command;
+		this.options= (waitForClient) ?
+				(options | OM_WAITFORCLIENT) : (options);
+		if (args != null) {
+			this.options |= OV_WITHMAP;
+			this.data= args;
+		}
+	}
+	
+	/**
+	 * Constructor for deserialization
+	 */
+	public ExtUICmdItem(final RJIO io) throws IOException {
+		this.requestId= io.readInt();
+		this.command= io.readString();
+		this.options= io.readInt();
+		if ((this.options & OV_WITHSTATUS) != 0) {
+			this.status= new RjsStatus(io);
+			return;
+		}
+		if ((this.options & OV_WITHMAP) != 0) {
+			io.flags= 0;
+			this.data= (RList) DataCmdItem.gDefaultFactory.readObject(io);
+		}
+	}
+	
+	@Override
+	public void writeExternal(final RJIO out) throws IOException {
+		out.writeInt(this.requestId);
+		out.writeString(this.command);
+		out.writeInt(this.options);
+		if ((this.options & OV_WITHSTATUS) != 0) {
+			this.status.writeExternal(out);
+			return;
+		}
+		if ((this.options & OV_WITHMAP) != 0) {
+			out.flags= 0;
+			DataCmdItem.gDefaultFactory.writeObject(this.data, out);
+		}
+	}
+	
+	
+	@Override
+	public byte getCmdType() {
+		return T_EXTENDEDUI_ITEM;
+	}
+	
+	@Override
+	public byte getOp() {
+		return 0;
+	}
+	
+	@Override
+	public void setAnswer(final RjsStatus status) {
+		assert (status != null);
+		if (status == RjsStatus.OK_STATUS) {
+			this.options= (this.options & OM_CLEARFORANSWER) | OV_ANSWER;
+			this.status= null;
+		}
+		else {
+			this.options= (this.options & OM_CLEARFORANSWER) | (OV_ANSWER | OV_WITHSTATUS);
+			this.status= status;
+		}
+	}
+	
+	public void setAnswer(final RList answer) {
+		this.options= (this.options & OM_CLEARFORANSWER) | OV_ANSWER;
+		if (answer != null) {
+			this.options |= OV_WITHMAP;
+		}
+		this.status= null;
+		this.data= answer;
+	}
+	
+	
+	@Override
+	public boolean isOK() {
+		return (this.status == null || this.status.getSeverity() == RjsStatus.OK);
+	}
+	
+	@Override
+	public RjsStatus getStatus() {
+		return this.status;
+	}
+	
+	@Override
+	public String getDataText() {
+		return this.command;
+	}
+	
+	public RList getDataArgs() {
+		return this.data;
+	}
+	
+	
+	@Override
+	public boolean testEquals(final MainCmdItem other) {
+		if (!(other instanceof ExtUICmdItem)) {
+			return false;
+		}
+		final ExtUICmdItem otherItem= (ExtUICmdItem) other;
+		if (!getDataText().equals(otherItem.getDataText())) {
+			return false;
+		}
+		if (this.options != otherItem.options) {
+			return false;
+		}
+		if (((this.options & OV_WITHMAP) != 0)
+				&& !getDataArgs().equals(otherItem.getDataArgs())) {
+			return false;
+		}
+		return true;
+	}
+	
+	@Override
+	public String toString() {
+		final StringBuffer sb= new StringBuffer(100);
+		sb.append("ExtUICmdItem ");
+		sb.append(this.command);
+		sb.append("\n\t").append("options= 0x").append(Integer.toHexString(this.options));
+		if ((this.options & OV_WITHMAP) != 0) {
+			sb.append("\n<ARGS>\n");
+			sb.append(this.data.toString());
+			sb.append("\n</ARGS>");
+		}
+		else {
+			sb.append("\n<ARGS/>");
+		}
+		return sb.toString();
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/FxCallback.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/FxCallback.java
new file mode 100644
index 0000000..3037f7d
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/FxCallback.java
@@ -0,0 +1,60 @@
+/*=============================================================================#
+ # Copyright (c) 2008, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server;
+
+import java.io.Serializable;
+
+import javax.security.auth.callback.Callback;
+
+
+/**
+ * Callback for authentication using file permission
+ */
+public class FxCallback implements Callback, Serializable {
+	
+	
+	private static final long serialVersionUID= 3559656299612581181L;
+	
+	
+	private final String filename;
+	private byte[] content;
+	
+	
+	public FxCallback(final String filename, final byte[] pendingKey) {
+		this.filename= filename;
+		this.content= pendingKey;
+	}
+	
+	
+	public String getFilename() {
+		return this.filename;
+	}
+	
+	public byte[] createContent(final byte[] clientKey) {
+		if (clientKey == null) {
+			throw new NullPointerException();
+		}
+		final byte[] newContent= new byte[this.content.length+clientKey.length];
+		System.arraycopy(this.content, 0, newContent, 0, this.content.length);
+		System.arraycopy(clientKey, 0, newContent, this.content.length, clientKey.length);
+		this.content= clientKey;
+		return newContent;
+	}
+	
+	public byte[] getContent() {
+		return this.content;
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/GDCmdItem.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/GDCmdItem.java
new file mode 100644
index 0000000..c5379cd
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/GDCmdItem.java
@@ -0,0 +1,1310 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server;
+
+import java.io.IOException;
+import java.util.Arrays;
+
+import org.eclipse.statet.rj.data.RJIO;
+
+
+/**
+ * Command item for GD.
+ */
+public abstract class GDCmdItem extends MainCmdItem {
+	
+	
+	public static final byte SET_CLIP=                     0x01;
+	public static final byte SET_COLOR=                    0x02;
+	public static final byte SET_FILL=                     0x03;
+	public static final byte SET_LINE=                     0x04;
+	public static final byte SET_FONT=                     0x05;
+	
+	public static final byte DRAW_LINE=                    0x11;
+	public static final byte DRAW_RECTANGLE=               0x12;
+	public static final byte DRAW_POLYLINE=                0x13;
+	public static final byte DRAW_POLYGON=                 0x14;
+	public static final byte DRAW_PATH=                    0x15;
+	public static final byte DRAW_CIRCLE=                  0x16;
+	public static final byte DRAW_TEXT=                    0x17;
+	public static final byte DRAW_RASTER=                  0x18;
+	
+	public static final byte CAPTURE=                      0x1c;
+	
+	public static final byte C_NEW_PAGE=                   0x21;
+	public static final byte C_CLOSE_DEVICE=               0x22;
+	public static final byte C_GET_SIZE=                   0x23;
+	public static final byte C_SET_ACTIVE_OFF=             0x24;
+	public static final byte C_SET_ACTIVE_ON=              0x25;
+	public static final byte C_SET_MODE=                   0x26;
+	public static final byte C_GET_FONTMETRIC=             0x27;
+	public static final byte C_GET_STRINGWIDTH=            0x28;
+	
+	public static final byte U_LOCATOR=                    0x31;
+	
+	
+	private static final double[] NO_DATA= new double[0];
+	
+	
+	public static final class Answer extends GDCmdItem {
+		
+		
+		private static final int OM_WITHDATA=              0x07000000;
+		private static final int OV_WITHDOUBLE=            0x01000000;
+		private static final int OV_WITHBYTE=              0x02000000;
+		
+		private final Object data;
+		
+// use DoubleAnswer
+//		public Answer(final byte requestId, final int devId, final double[] data) {
+//			this.options= (data != null) ? (OV_WITHDOUBLE | OV_WAITFORCLIENT) : OV_WAITFORCLIENT;
+//			this.devId= devId;
+//			this.data= data;
+//			this.requestId= requestId;
+//		}
+		
+		public Answer(final byte requestId, final int devId, final byte[] data) {
+			this.options= (data != null) ? (OV_WITHBYTE | OV_WAITFORCLIENT) : OV_WAITFORCLIENT;
+			this.devId= devId;
+			this.data= data;
+			this.requestId= requestId;
+		}
+		
+		public Answer(final byte requestId, final int devId, final RjsStatus status) {
+			this.options= OV_WAITFORCLIENT | (status.getSeverity() << OS_STATUS);
+			this.devId= devId;
+			this.data= NO_DATA;
+			this.requestId= requestId;
+		}
+		
+		/**
+		 * Constructor for deserialization
+		 */
+		public Answer(final RJIO io) throws IOException, ClassNotFoundException {
+			this.options= io.readInt();
+			this.devId= io.readInt();
+			this.requestId= io.readByte();
+			switch (this.options & OM_WITHDATA) {
+			case OV_WITHDOUBLE: {
+				final double[] d= new double[io.readInt()];
+				io.readDoubleData(d, d.length);
+				this.data= d;
+				break; }
+			case OV_WITHBYTE: {
+				final byte[] b= new byte[io.readInt()];
+				io.readByteData(b, b.length);
+				this.data= b;
+				break; }
+			default:
+				this.data= null;
+				break;
+			}
+		}
+		
+		@Override
+		public void writeExternal(final RJIO io) throws IOException {
+			io.writeInt(this.options);
+			io.writeInt(this.devId);
+			io.writeByte(this.requestId);
+			switch (this.options & OM_WITHDATA) {
+			case OV_WITHDOUBLE: {
+				final double[] d= (double[]) this.data;
+				io.writeInt(d.length);
+				io.writeDoubleData(d, d.length);
+				break; }
+			case OV_WITHBYTE: {
+				final byte[] b= (byte[]) this.data;
+				io.writeInt(b.length);
+				io.writeByteData(b, b.length);
+				break; }
+			}
+		}
+		
+		
+		@Override
+		public double[] getDoubleData() {
+			return (double[]) this.data;
+		}
+		
+		@Override
+		public byte[] getByteData() {
+			return (byte[]) this.data;
+		}
+		
+		
+		@Override
+		public String toString() {
+			final StringBuffer sb= new StringBuffer(100);
+			sb.append("GDCmdItem (options=0x");
+			sb.append(Integer.toHexString(this.options));
+			sb.append(", device=");
+			sb.append(this.devId);
+			sb.append(", commandId=ANSWER");
+			sb.append(")");
+			sb.append("\n<GD-DATA>\n");
+			switch (this.options & OM_WITHDATA) {
+			case OV_WITHDOUBLE:
+				sb.append(Arrays.toString((double[]) this.data));
+			}
+			sb.append("\n</GD-DATA>");
+			return sb.toString();
+		}
+		
+	}
+	
+	public static final class DoubleAnswer extends GDCmdItem {
+		
+		
+		private final double[] data;
+		
+		
+		public DoubleAnswer(final byte requestId, final int devId, final double[] data) {
+			this.options= (data != null) ? (Answer.OV_WITHDOUBLE | OV_WAITFORCLIENT) : OV_WAITFORCLIENT;
+			this.devId= devId;
+			this.data= data;
+			this.requestId= requestId;
+		}
+		
+		
+		@Override
+		public void writeExternal(final RJIO io) throws IOException {
+			io.writeInt(this.options);
+			io.writeInt(this.devId);
+			io.writeByte(this.requestId);
+			if (this.data != null) {
+				final int length= this.data.length;
+				io.writeInt(length);
+				io.writeDoubleData(this.data, length);
+			}
+		}
+		
+		
+		@Override
+		public double[] getDoubleData() {
+			return this.data;
+		}
+		
+		
+		@Override
+		public String toString() {
+			final StringBuffer sb= new StringBuffer(100);
+			sb.append("GDCmdItem (options=0x");
+			sb.append(Integer.toHexString(this.options));
+			sb.append(", device=");
+			sb.append(this.devId);
+			sb.append(", commandId=ANSWER");
+			sb.append(")");
+			sb.append("\n<GD-DATA>\n");
+			sb.append(Arrays.toString(this.data));
+			sb.append("\n</GD-DATA>");
+			return sb.toString();
+		}
+		
+	}
+	
+	public static final class CInit extends GDCmdItem {
+		
+		
+		private final double w;
+		private final double h;
+		private final int canvasColor;
+		private final boolean active;
+		
+		
+		public CInit(final int devId, final double w, final double h, final int canvasColor,
+				final boolean activate, final byte slot) {
+			this.options= 0;
+			this.devId= devId;
+			this.w= w;
+			this.h= h;
+			this.canvasColor= canvasColor;
+			this.active= activate;
+			
+			this.slot= slot;
+		}
+		
+		@Override
+		public void writeExternal(final RJIO io) throws IOException {
+			io.writeInt(this.devId);
+			io.writeByte(C_NEW_PAGE);
+			io.writeDouble(this.w);
+			io.writeDouble(this.h);
+			io.writeInt(this.canvasColor);
+			io.writeBoolean(this.active);
+		}
+		
+		
+		@Override
+		public String toString() {
+			final StringBuffer sb= new StringBuffer();
+			sb.append("GDCmdItem (options=0x");
+			sb.append(Integer.toHexString(this.options));
+			sb.append(", device=");
+			sb.append(this.devId);
+			sb.append(", commandId=");
+			sb.append(C_NEW_PAGE);
+			sb.append(")\n<GD-DATA>\n");
+			sb.append("\n</GD-DATA>");
+			return sb.toString();
+		}
+		
+	}
+	
+	public static final class CCloseDevice extends GDCmdItem {
+		
+		
+		public CCloseDevice(final int devId, final byte slot) {
+			this.options= 0;
+			this.devId= devId;
+			
+			this.slot= slot;
+		}
+		
+		@Override
+		public void writeExternal(final RJIO io) throws IOException {
+			io.writeInt(this.devId);
+			io.writeByte(C_CLOSE_DEVICE);
+		}
+		
+		
+		@Override
+		public String toString() {
+			final StringBuffer sb= new StringBuffer();
+			sb.append("GDCmdItem (options=0x");
+			sb.append(Integer.toHexString(this.options));
+			sb.append(", device=");
+			sb.append(this.devId);
+			sb.append(", commandId=");
+			sb.append(C_CLOSE_DEVICE);
+			sb.append(")\n<GD-DATA />");
+			return sb.toString();
+		}
+		
+	}
+	
+	public static final class CGetSize extends GDCmdItem {
+		
+		
+		public CGetSize(final int devId, final byte slot) {
+			this.options= OV_WAITFORCLIENT;
+			this.devId= devId;
+			
+			this.slot= slot;
+		}
+		
+		@Override
+		public void writeExternal(final RJIO io) throws IOException {
+			io.writeInt((OV_WAITFORCLIENT | this.devId));
+			io.writeByte(C_GET_SIZE);
+			io.writeByte(this.requestId);
+		}
+		
+		
+		@Override
+		public void setAnswer(final RjsStatus status) {
+			this.options= (this.options & OM_CLEARFORANSWER) | (status.getSeverity() << OS_STATUS);
+		}
+		
+		
+		@Override
+		public String toString() {
+			final StringBuffer sb= new StringBuffer();
+			sb.append("GDCmdItem (options=0x");
+			sb.append(Integer.toHexString(this.options));
+			sb.append(", device=");
+			sb.append(this.devId);
+			sb.append(", commandId=");
+			sb.append(C_GET_SIZE);
+			sb.append(")\n<GD-DATA>\n");
+			sb.append("\n</GD-DATA>");
+			return sb.toString();
+		}
+		
+	}
+	
+	public static final class CSetActiveOff extends GDCmdItem {
+		
+		
+		public CSetActiveOff(final int devId, final byte slot) {
+			this.options= 0;
+			this.devId= devId;
+			
+			this.slot= slot;
+		}
+		
+		@Override
+		public void writeExternal(final RJIO io) throws IOException {
+			io.writeInt(this.devId);
+			io.writeByte(C_SET_ACTIVE_OFF);
+		}
+		
+		
+		@Override
+		public String toString() {
+			final StringBuffer sb= new StringBuffer();
+			sb.append("GDCmdItem (options=0x");
+			sb.append(Integer.toHexString(this.options));
+			sb.append(", device=");
+			sb.append(this.devId);
+			sb.append(", commandId=");
+			sb.append(C_SET_ACTIVE_OFF);
+			sb.append(")\n<GD-DATA />");
+			return sb.toString();
+		}
+		
+	}
+	
+	public static final class CSetActiveOn extends GDCmdItem {
+		
+		
+		public CSetActiveOn(final int devId, final byte slot) {
+			this.options= 0;
+			this.devId= devId;
+			
+			this.slot= slot;
+		}
+		
+		@Override
+		public void writeExternal(final RJIO io) throws IOException {
+			io.writeInt(this.devId);
+			io.writeByte(C_SET_ACTIVE_ON);
+		}
+		
+		
+		@Override
+		public String toString() {
+			final StringBuffer sb= new StringBuffer();
+			sb.append("GDCmdItem (options=0x");
+			sb.append(Integer.toHexString(this.options));
+			sb.append(", device=");
+			sb.append(this.devId);
+			sb.append(", commandId=");
+			sb.append(C_SET_ACTIVE_ON);
+			sb.append(")\n<GD-DATA />");
+			return sb.toString();
+		}
+		
+	}
+	
+	public static final class CSetMode extends GDCmdItem {
+		
+		
+		private final byte mode;
+		
+		
+		public CSetMode(final int devId, final int mode, final byte slot) {
+			this.options= 0;
+			this.devId= devId;
+			this.mode= (byte) mode;
+			
+			this.slot= slot;
+		}
+		
+		@Override
+		public void writeExternal(final RJIO io) throws IOException {
+			io.writeInt(this.devId);
+			io.writeByte(C_SET_MODE);
+			io.writeByte(this.mode);
+		}
+		
+		
+		@Override
+		public String toString() {
+			final StringBuffer sb= new StringBuffer();
+			sb.append("GDCmdItem (options=0x");
+			sb.append(Integer.toHexString(this.options));
+			sb.append(", device=");
+			sb.append(this.devId);
+			sb.append(", commandId=");
+			sb.append(C_SET_MODE);
+			sb.append(")<GD-DATA>\nmode= ");
+			sb.append(this.mode);
+			sb.append("\n</GD-DATA>");
+			return sb.toString();
+		}
+		
+	}
+	
+	public static final class CGetFontMetric extends GDCmdItem {
+		
+		
+		private final int c;
+		
+		
+		public CGetFontMetric(final int devId, final int c, final byte slot) {
+			this.options= OV_WAITFORCLIENT;
+			this.devId= devId;
+			this.c= c;
+			
+			this.slot= slot;
+		}
+		
+		@Override
+		public void writeExternal(final RJIO io) throws IOException {
+			io.writeInt((OV_WAITFORCLIENT | this.devId));
+			io.writeByte(C_GET_FONTMETRIC);
+			io.writeByte(this.requestId);
+			io.writeInt(this.c);
+		}
+		
+		
+		@Override
+		public void setAnswer(final RjsStatus status) {
+			this.options= (this.options & OM_CLEARFORANSWER) | (status.getSeverity() << OS_STATUS);
+		}
+		
+		
+		@Override
+		public String toString() {
+			final StringBuffer sb= new StringBuffer();
+			sb.append("GDCmdItem (options=0x");
+			sb.append(Integer.toHexString(this.options));
+			sb.append(", device=");
+			sb.append(this.devId);
+			sb.append(", commandId=");
+			sb.append(C_GET_FONTMETRIC);
+			sb.append(")\n<GD-DATA>\n");
+			sb.append("\n</GD-DATA>");
+			return sb.toString();
+		}
+		
+	}
+	
+	public static final class CGetStrWidth extends GDCmdItem {
+		
+		
+		private final String text;
+		
+		
+		public CGetStrWidth(final int devId, final String text, final byte slot) {
+			this.options= OV_WAITFORCLIENT;
+			this.devId= devId;
+			this.text= text;
+			
+			this.slot= slot;
+		}
+		
+		@Override
+		public void writeExternal(final RJIO io) throws IOException {
+			io.writeInt((OV_WAITFORCLIENT | this.devId));
+			io.writeByte(C_GET_STRINGWIDTH);
+			io.writeByte(this.requestId);
+			io.writeString(this.text);
+		}
+		
+		
+		@Override
+		public void setAnswer(final RjsStatus status) {
+			this.options= (this.options & OM_CLEARFORANSWER) | (status.getSeverity() << OS_STATUS);
+		}
+		
+		
+		@Override
+		public String toString() {
+			final StringBuffer sb= new StringBuffer();
+			sb.append("GDCmdItem (options=0x");
+			sb.append(Integer.toHexString(this.options));
+			sb.append(", device=");
+			sb.append(this.devId);
+			sb.append(", commandId=");
+			sb.append(C_GET_STRINGWIDTH);
+			sb.append(")\n<GD-DATA>\n");
+			sb.append("\n</GD-DATA>");
+			return sb.toString();
+		}
+		
+	}
+	
+	public static final class SetClip extends GDCmdItem {
+		
+		
+		private final double x0;
+		private final double y0;
+		private final double x1;
+		private final double y1;
+		
+		
+		public SetClip(final int devId, final double x0, final double y0, final double x1, final double y1,
+				final byte slot) {
+			this.options= 0;
+			this.devId= devId;
+			this.x0= x0;
+			this.y0= y0;
+			this.x1= x1;
+			this.y1= y1;
+			
+			this.slot= slot;
+		}
+		
+		@Override
+		public void writeExternal(final RJIO io) throws IOException {
+			io.writeInt(this.devId);
+			io.writeByte(SET_CLIP);
+			io.writeDouble(this.x0);
+			io.writeDouble(this.y0);
+			io.writeDouble(this.x1);
+			io.writeDouble(this.y1);
+		}
+		
+		
+		@Override
+		public String toString() {
+			final StringBuffer sb= new StringBuffer();
+			sb.append("GDCmdItem (options=0x");
+			sb.append(Integer.toHexString(this.options));
+			sb.append(", device=");
+			sb.append(this.devId);
+			sb.append(", commandId=");
+			sb.append(SET_CLIP);
+			sb.append(")\n<GD-DATA>\n");
+			sb.append("\n</GD-DATA>");
+			return sb.toString();
+		}
+		
+	}
+	
+	public static final class SetColor extends GDCmdItem {
+		
+		
+		private final int cc;
+		
+		
+		public SetColor(final int devId, final int cc, final byte slot) {
+			this.options= 0;
+			this.devId= devId;
+			this.cc= cc;
+			
+			this.slot= slot;
+		}
+		
+		@Override
+		public void writeExternal(final RJIO io) throws IOException {
+			io.writeInt(this.devId);
+			io.writeByte(SET_COLOR);
+			io.writeInt(this.cc);
+		}
+		
+		
+		@Override
+		public String toString() {
+			final StringBuffer sb= new StringBuffer();
+			sb.append("GDCmdItem (options=0x");
+			sb.append(Integer.toHexString(this.options));
+			sb.append(", device=");
+			sb.append(this.devId);
+			sb.append(", commandId=");
+			sb.append(SET_COLOR);
+			sb.append(")\n<GD-DATA>\n");
+			sb.append("\n</GD-DATA>");
+			return sb.toString();
+		}
+		
+	}
+	
+	public static final class SetFill extends GDCmdItem {
+		
+		
+		private final int cc;
+		
+		
+		public SetFill(final int devId, final int cc, final byte slot) {
+			this.options= 0;
+			this.devId= devId;
+			this.cc= cc;
+			
+			this.slot= slot;
+		}
+		
+		@Override
+		public void writeExternal(final RJIO io) throws IOException {
+			io.writeInt(this.devId);
+			io.writeByte(SET_FILL);
+			io.writeInt(this.cc);
+		}
+		
+		
+		@Override
+		public String toString() {
+			final StringBuffer sb= new StringBuffer();
+			sb.append("GDCmdItem (options=0x");
+			sb.append(Integer.toHexString(this.options));
+			sb.append(", device=");
+			sb.append(this.devId);
+			sb.append(", commandId=");
+			sb.append(SET_FILL);
+			sb.append(")\n<GD-DATA>\n");
+			sb.append("\n</GD-DATA>");
+			return sb.toString();
+		}
+		
+	}
+	
+	public static final class SetLine extends GDCmdItem {
+		
+		
+		private final int type;
+		private final float width;
+		private final byte cap;
+		private final byte join;
+		private final float joinMiterLimit;
+		
+		
+		public SetLine(final int devId, final int type, final float width,
+				final byte cap, final byte join, final float joinMiterLimit,
+				final byte slot) {
+			this.options= 0;
+			this.devId= devId;
+			this.type= type;
+			this.width= width;
+			this.cap= cap;
+			this.join= join;
+			this.joinMiterLimit= joinMiterLimit;
+			
+			this.slot= slot;
+		}
+		
+		@Override
+		public void writeExternal(final RJIO io) throws IOException {
+			io.writeInt(this.devId);
+			io.writeByte(SET_LINE);
+			io.writeInt(this.type);
+			io.writeFloat(this.width);
+			io.writeByte(this.cap);
+			io.writeByte(this.join);
+			io.writeFloat(this.joinMiterLimit);
+		}
+		
+		
+		@Override
+		public String toString() {
+			final StringBuffer sb= new StringBuffer();
+			sb.append("GDCmdItem (options=0x");
+			sb.append(Integer.toHexString(this.options));
+			sb.append(", device=");
+			sb.append(this.devId);
+			sb.append(", commandId=");
+			sb.append(SET_LINE);
+			sb.append(")\n<GD-DATA>\n");
+			sb.append("\n</GD-DATA>");
+			return sb.toString();
+		}
+		
+	}
+	
+	public static final class SetFont extends GDCmdItem {
+		
+		
+		private final String family;
+		private final int face;
+		private final float pointSize;
+		private final float lineHeight;
+		
+		
+		public SetFont(final int devId, final String family, final int face, final float pointSize,
+				final float lineHeight,
+				final byte slot) {
+			this.options= 0;
+			this.devId= devId;
+			this.family= family;
+			this.face= face;
+			this.pointSize= pointSize;
+			this.lineHeight= lineHeight;
+			
+			this.slot= slot;
+		}
+		
+		@Override
+		public void writeExternal(final RJIO io) throws IOException {
+			io.writeInt(this.devId);
+			io.writeByte(SET_FONT);
+			io.writeString(this.family);
+			io.writeInt(this.face);
+			io.writeFloat(this.pointSize);
+			io.writeFloat(this.lineHeight);
+		}
+		
+		
+		@Override
+		public String toString() {
+			final StringBuffer sb= new StringBuffer();
+			sb.append("GDCmdItem (options=0x");
+			sb.append(Integer.toHexString(this.options));
+			sb.append(", device=");
+			sb.append(this.devId);
+			sb.append(", commandId=");
+			sb.append(SET_FONT);
+			sb.append(")\n<GD-DATA>\n");
+			sb.append("\n</GD-DATA>");
+			return sb.toString();
+		}
+		
+	}
+	
+	public static final class DrawLine extends GDCmdItem {
+		
+		
+		private final double x0;
+		private final double y0;
+		private final double x1;
+		private final double y1;
+		
+		
+		public DrawLine(final int devId, final double x0, final double y0, final double x1, final double y1,
+				final byte slot) {
+			this.options= 0;
+			this.devId= devId;
+			this.x0= x0;
+			this.y0= y0;
+			this.x1= x1;
+			this.y1= y1;
+			
+			this.slot= slot;
+		}
+		
+		@Override
+		public void writeExternal(final RJIO io) throws IOException {
+			io.writeInt(this.devId);
+			io.writeByte(DRAW_LINE);
+			io.writeDouble(this.x0);
+			io.writeDouble(this.y0);
+			io.writeDouble(this.x1);
+			io.writeDouble(this.y1);
+		}
+		
+		
+		@Override
+		public String toString() {
+			final StringBuffer sb= new StringBuffer();
+			sb.append("GDCmdItem (options=0x");
+			sb.append(Integer.toHexString(this.options));
+			sb.append(", device=");
+			sb.append(this.devId);
+			sb.append(", commandId=");
+			sb.append(DRAW_LINE);
+			sb.append(")\n<GD-DATA>\n");
+			sb.append("\n</GD-DATA>");
+			return sb.toString();
+		}
+		
+	}
+	
+	public static final class DrawRect extends GDCmdItem {
+		
+		
+		private final double x0;
+		private final double y0;
+		private final double x1;
+		private final double y1;
+		
+		
+		public DrawRect(final int devId, final double x0, final double y0, final double x1, final double y1,
+				final byte slot) {
+			this.options= 0;
+			this.devId= devId;
+			this.x0= x0;
+			this.y0= y0;
+			this.x1= x1;
+			this.y1= y1;
+			
+			this.slot= slot;
+		}
+		
+		@Override
+		public void writeExternal(final RJIO io) throws IOException {
+			io.writeInt(this.devId);
+			io.writeByte(DRAW_RECTANGLE);
+			io.writeDouble(this.x0);
+			io.writeDouble(this.y0);
+			io.writeDouble(this.x1);
+			io.writeDouble(this.y1);
+		}
+		
+		
+		@Override
+		public String toString() {
+			final StringBuffer sb= new StringBuffer();
+			sb.append("GDCmdItem (options=0x");
+			sb.append(Integer.toHexString(this.options));
+			sb.append(", device=");
+			sb.append(this.devId);
+			sb.append(", commandId=");
+			sb.append(DRAW_RECTANGLE);
+			sb.append(")\n<GD-DATA>\n");
+			sb.append("\n</GD-DATA>");
+			return sb.toString();
+		}
+		
+	}
+	
+	public static final class DrawPolyline extends GDCmdItem {
+		
+		
+		private final double x[];
+		private final double y[];
+		
+		
+		public DrawPolyline(final int devId, final double x[], final double y[],
+				final byte slot) {
+			this.options= 0;
+			this.devId= devId;
+			this.x= x;
+			this.y= y;
+			
+			this.slot= slot;
+		}
+		
+		@Override
+		public void writeExternal(final RJIO io) throws IOException {
+			io.writeInt(this.devId);
+			io.writeByte(DRAW_POLYLINE);
+			final int length= this.x.length;
+			io.writeInt(length);
+			io.writeDoubleData(this.x, length);
+			io.writeDoubleData(this.y, length);
+		}
+		
+		
+		@Override
+		public String toString() {
+			final StringBuffer sb= new StringBuffer();
+			sb.append("GDCmdItem (options=0x");
+			sb.append(Integer.toHexString(this.options));
+			sb.append(", device=");
+			sb.append(this.devId);
+			sb.append(", commandId=");
+			sb.append(DRAW_POLYLINE);
+			sb.append(")\n<GD-DATA>\n");
+			sb.append("\n</GD-DATA>");
+			return sb.toString();
+		}
+		
+	}
+	
+	public static final class DrawPolygon extends GDCmdItem {
+		
+		
+		private final double x[];
+		private final double y[];
+		
+		
+		public DrawPolygon(final int devId, final double x[], final double y[],
+				final byte slot) {
+			this.options= 0;
+			this.devId= devId;
+			this.x= x;
+			this.y= y;
+			
+			this.slot= slot;
+		}
+		
+		@Override
+		public void writeExternal(final RJIO io) throws IOException {
+			io.writeInt(this.devId);
+			io.writeByte(DRAW_POLYGON);
+			final int length= this.x.length;
+			io.writeInt(length);
+			io.writeDoubleData(this.x, length);
+			io.writeDoubleData(this.y, length);
+		}
+		
+		
+		@Override
+		public String toString() {
+			final StringBuffer sb= new StringBuffer();
+			sb.append("GDCmdItem (options=0x");
+			sb.append(Integer.toHexString(this.options));
+			sb.append(", device=");
+			sb.append(this.devId);
+			sb.append(", commandId=");
+			sb.append(DRAW_POLYGON);
+			sb.append(")\n<GD-DATA>\n");
+			sb.append("\n</GD-DATA>");
+			return sb.toString();
+		}
+		
+	}
+	
+	public static final class DrawPath extends GDCmdItem {
+		
+		
+		private final int[] n;
+		private final double x[];
+		private final double y[];
+		private final int mode;
+		
+		
+		public DrawPath(final int devId, final int[] n, final double x[], final double y[],
+				final int mode, final byte slot) {
+			this.options= 0;
+			this.devId= devId;
+			this.n= n;
+			this.x= x;
+			this.y= y;
+			this.mode= mode;
+			
+			this.slot= slot;
+		}
+		
+		@Override
+		public void writeExternal(final RJIO io) throws IOException {
+			io.writeInt(this.devId);
+			io.writeByte(DRAW_PATH);
+			io.writeIntArray(this.n, this.n.length);
+			final int length= this.x.length;
+			io.writeInt(length);
+			io.writeDoubleData(this.x, length);
+			io.writeDoubleData(this.y, length);
+			io.writeInt(this.mode);
+		}
+		
+		
+		@Override
+		public String toString() {
+			final StringBuffer sb= new StringBuffer();
+			sb.append("GDCmdItem (options=0x");
+			sb.append(Integer.toHexString(this.options));
+			sb.append(", device=");
+			sb.append(this.devId);
+			sb.append(", commandId=");
+			sb.append(DRAW_PATH);
+			sb.append(")\n<GD-DATA>\n");
+			sb.append("\n</GD-DATA>");
+			return sb.toString();
+		}
+		
+	}
+	
+	public static final class DrawCircle extends GDCmdItem {
+		
+		
+		private final double x;
+		private final double y;
+		private final double r;
+		
+		
+		public DrawCircle(final int devId, final double x, final double y, final double r,
+				final byte slot) {
+			this.options= 0;
+			this.devId= devId;
+			this.x= x;
+			this.y= y;
+			this.r= r;
+			
+			this.slot= slot;
+		}
+		
+		@Override
+		public void writeExternal(final RJIO io) throws IOException {
+			io.writeInt(this.devId);
+			io.writeByte(DRAW_CIRCLE);
+			io.writeDouble(this.x);
+			io.writeDouble(this.y);
+			io.writeDouble(this.r);
+		}
+		
+		
+		@Override
+		public String toString() {
+			final StringBuffer sb= new StringBuffer();
+			sb.append("GDCmdItem (options=0x");
+			sb.append(Integer.toHexString(this.options));
+			sb.append(", device=");
+			sb.append(this.devId);
+			sb.append(", commandId=");
+			sb.append(DRAW_CIRCLE);
+			sb.append(")\n<GD-DATA>\n");
+			sb.append("\n</GD-DATA>");
+			return sb.toString();
+		}
+		
+	}
+	
+	public static final class DrawText extends GDCmdItem {
+		
+		
+		private final String text;
+		private final double x, y;
+		private final double rDeg;
+		private final double hAdj;
+		
+		
+		public DrawText(final int devId, final String text,
+				final double x, final double y, final double rDeg, final double hAdj, 
+				final byte slot) {
+			this.options= 0;
+			this.devId= devId;
+			
+			this.text= text;
+			this.x= x;
+			this.y= y;
+			this.rDeg= rDeg;
+			this.hAdj= hAdj;
+			
+			this.slot= slot;
+		}
+		
+		@Override
+		public void writeExternal(final RJIO io) throws IOException {
+			io.writeInt(this.devId);
+			io.writeByte(DRAW_TEXT);
+			io.writeString(this.text);
+			io.writeDouble(this.x);
+			io.writeDouble(this.y);
+			io.writeDouble(this.rDeg);
+			io.writeDouble(this.hAdj);
+		}
+		
+		
+		@Override
+		public String toString() {
+			final StringBuffer sb= new StringBuffer();
+			sb.append("GDCmdItem (options=0x");
+			sb.append(Integer.toHexString(this.options));
+			sb.append(", device=");
+			sb.append(this.devId);
+			sb.append(", commandId=");
+			sb.append(DRAW_TEXT);
+			sb.append(")\n<GD-DATA>\n");
+			sb.append("\n</GD-DATA>");
+			return sb.toString();
+		}
+		
+	}
+	
+	public static final class DrawRaster extends GDCmdItem {
+		
+		
+		private final byte[] imgData;
+		private final boolean imgAlpha;
+		private final int imgW, imgH;
+		private final double x, y;
+		private final double w, h;
+		private final double rDeg;
+		private final boolean interpolate;
+		
+		
+		public DrawRaster(final int devId,
+				final byte[] imgData, final boolean imgAlpha, final int imgW, final int imgH,
+				final double x, final double y, final double w, final double h,
+				final double rDeg, final boolean interpolate,
+				final byte slot) {
+			this.options= 0;
+			this.devId= devId;
+			
+			this.imgData= imgData;
+			this.imgAlpha= imgAlpha;
+			this.imgW= imgW;
+			this.imgH= imgH;
+			this.x= x;
+			this.y= y;
+			this.w= w;
+			this.h= h;
+			this.rDeg= rDeg;
+			this.interpolate= interpolate;
+			
+			this.slot= slot;
+		}
+		
+		@Override
+		public void writeExternal(final RJIO io) throws IOException {
+			io.writeInt(this.devId);
+			io.writeByte(DRAW_RASTER);
+			io.writeInt(this.imgData.length);
+			io.writeByteData(this.imgData, this.imgData.length);
+			io.writeBoolean(this.imgAlpha);
+			io.writeInt(this.imgW);
+			io.writeInt(this.imgH);
+			io.writeDouble(this.x);
+			io.writeDouble(this.y);
+			io.writeDouble(this.w);
+			io.writeDouble(this.h);
+			io.writeDouble(this.rDeg);
+			io.writeBoolean(this.interpolate);
+		}
+		
+		
+		@Override
+		public String toString() {
+			final StringBuffer sb= new StringBuffer();
+			sb.append("GDCmdItem (options=0x");
+			sb.append(Integer.toHexString(this.options));
+			sb.append(", device=");
+			sb.append(this.devId);
+			sb.append(", commandId=");
+			sb.append(DRAW_RASTER);
+			sb.append(")\n<GD-DATA>\n");
+			sb.append("\n</GD-DATA>");
+			return sb.toString();
+		}
+		
+	}
+	
+	public static final class Capture extends GDCmdItem {
+		
+		
+		private final int w, h;
+		
+		
+		public Capture(final int devId,
+				final int w, final int h,
+				final byte slot) {
+			this.options= OV_WAITFORCLIENT;
+			this.devId= devId;
+			
+			this.w= w;
+			this.h= h;
+			
+			this.slot= slot;
+		}
+		
+		@Override
+		public void writeExternal(final RJIO io) throws IOException {
+			io.writeInt(this.devId);
+			io.writeByte(CAPTURE);
+			io.writeByte(this.requestId);
+			io.writeInt(this.w);
+			io.writeInt(this.h);
+		}
+		
+		
+		@Override
+		public void setAnswer(final RjsStatus status) {
+			this.options= (this.options & OM_CLEARFORANSWER) | (status.getSeverity() << OS_STATUS);
+		}
+		
+		
+		@Override
+		public String toString() {
+			final StringBuffer sb= new StringBuffer();
+			sb.append("GDCmdItem (options=0x");
+			sb.append(Integer.toHexString(this.options));
+			sb.append(", device=");
+			sb.append(this.devId);
+			sb.append(", commandId=");
+			sb.append(CAPTURE);
+			sb.append(")\n<GD-DATA>\n");
+			sb.append("\n</GD-DATA>");
+			return sb.toString();
+		}
+		
+	}
+	
+	public static final class Locator extends GDCmdItem {
+		
+		
+		public Locator(final int devId,
+				final byte slot) {
+			this.options= OV_WAITFORCLIENT;
+			this.devId= devId;
+			
+			this.slot= slot;
+		}
+		
+		@Override
+		public void writeExternal(final RJIO io) throws IOException {
+			io.writeInt((OV_WAITFORCLIENT | this.devId));
+			io.writeByte(U_LOCATOR);
+			io.writeByte(this.requestId);
+		}
+		
+		
+		@Override
+		public String toString() {
+			final StringBuffer sb= new StringBuffer();
+			sb.append("GDCmdItem (options=0x");
+			sb.append(Integer.toHexString(this.options));
+			sb.append(", device=");
+			sb.append(this.devId);
+			sb.append(", commandId=");
+			sb.append(U_LOCATOR);
+			sb.append(")\n<GD-DATA>\n");
+			sb.append("\n</GD-DATA>");
+			return sb.toString();
+		}
+		
+	}
+	
+	
+	protected int devId;
+	
+	
+	/**
+	 * Constructor for automatic deserialization
+	 */
+	protected GDCmdItem() {
+	}
+	
+	
+	@Override
+	public final byte getCmdType() {
+		return T_GRAPH_ITEM;
+	}
+	
+	@Override
+	public byte getOp() {
+		return 0;
+	}
+	
+	@Override
+	public final boolean isOK() {
+		return ((this.options & OM_STATUS) == RjsStatus.OK);
+	}
+	
+	@Override
+	public final RjsStatus getStatus() {
+		return null;
+	}
+	
+	public final int getDeviceId() {
+		return this.devId;
+	}
+	
+	@Override
+	public void setAnswer(final RjsStatus status) {
+		throw new UnsupportedOperationException();
+	}
+	
+	
+	public double[] getDoubleData() {
+		throw new UnsupportedOperationException();
+	}
+	
+	public byte[] getByteData() {
+		throw new UnsupportedOperationException();
+	}
+	
+	
+	@Override
+	public final String getDataText() {
+		return null;
+	}
+	
+	
+	@Override
+	public boolean testEquals(final MainCmdItem other) {
+		if (!(other instanceof GDCmdItem)) {
+			return false;
+		}
+		final GDCmdItem otherItem= (GDCmdItem) other;
+		if (this.options != otherItem.options) {
+			return false;
+		}
+		if (getDeviceId() != otherItem.getDeviceId()) {
+			return false;
+		}
+		return true;
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/GraOpCmdItem.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/GraOpCmdItem.java
new file mode 100644
index 0000000..dc64d83
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/GraOpCmdItem.java
@@ -0,0 +1,201 @@
+/*=============================================================================#
+ # Copyright (c) 2008, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server;
+
+import java.io.IOException;
+
+import org.eclipse.statet.rj.data.RJIO;
+import org.eclipse.statet.rj.data.RJIOExternalizable;
+import org.eclipse.statet.rj.server.gr.Coord;
+import org.eclipse.statet.rj.server.gr.GraOp;
+
+
+/**
+ * Command item for main loop graphic operations (="op")
+ */
+public final class GraOpCmdItem extends MainCmdItem implements GraOp {
+	
+	
+	private static final int OV_WITHDATA=                  0x01000000;
+	private static final int OV_WITHSTATUS=                0x08000000;
+	
+	
+	private final int devId;
+	private final byte op;
+	
+	private RJIOExternalizable data;
+	
+	
+	/**
+	 * Constructor for new commands
+	 */
+	public GraOpCmdItem(final int devId, final byte op) {
+		this.devId= devId;
+		this.op= op;
+	}
+	
+	/**
+	 * Constructor for new commands
+	 */
+	public GraOpCmdItem(final int devId, final byte op, final RJIOExternalizable data) {
+		this.devId= devId;
+		this.op= op;
+		if (data != null) {
+			this.data= data;
+			this.options |= OV_WITHDATA;
+		}
+	}
+	
+	/**
+	 * Constructor for deserialization
+	 */
+	public GraOpCmdItem(final RJIO in) throws IOException {
+		this.requestId= in.readInt();
+		this.options= in.readInt();
+		this.devId= in.readInt();
+		this.op= in.readByte();
+		if ((this.options & OV_WITHSTATUS) != 0) {
+			this.data= new RjsStatus(in);
+		}
+		else if ((this.options & OV_WITHDATA) != 0) {
+			switch (this.op) {
+			case OP_CONVERT_DEV2USER:
+				this.data= new Coord(in);
+				break;
+			default:
+				break;
+			}
+		}
+	}
+	
+	@Override
+	public void writeExternal(final RJIO out) throws IOException {
+		out.writeInt(this.requestId);
+		out.writeInt(this.options);
+		out.writeInt(this.devId);
+		out.writeByte(this.op);
+		if ((this.options & (OV_WITHSTATUS | OV_WITHDATA)) != 0) {
+			this.data.writeExternal(out);
+		}
+	}
+	
+	
+	@Override
+	public byte getCmdType() {
+		return T_GRAPHICS_OP_ITEM;
+	}
+	
+	
+	@Override
+	public void setAnswer(final RjsStatus status) {
+		assert (status != null);
+		if (status.getSeverity() == RjsStatus.OK) {
+			this.options= (this.options & OM_CLEARFORANSWER) | OV_ANSWER;
+			this.data= null;
+		}
+		else {
+			this.options= (this.options & OM_CLEARFORANSWER) | (OV_ANSWER | OV_WITHSTATUS);
+			this.data= status;
+		}
+	}
+	
+	public void setAnswer(final RJIOExternalizable data) {
+		this.options= (this.options & OM_CLEARFORANSWER) | OV_ANSWER;
+		if (data != null) {
+			this.options |= OV_WITHDATA;
+		}
+		this.data= data;
+	}
+	
+	
+	public int getDevId() {
+		return this.devId;
+	}
+	
+	@Override
+	public byte getOp() {
+		return this.op;
+	}
+	
+	@Override
+	public boolean isOK() {
+		return ((this.options & OV_WITHSTATUS) == 0 || this.data == null);
+	}
+	
+	@Override
+	public RjsStatus getStatus() {
+		if ((this.options & OV_ANSWER) != 0) {
+			return ((this.options & OV_WITHSTATUS) == 0) ? RjsStatus.OK_STATUS : (RjsStatus) this.data;
+		}
+		return null;
+	}
+	
+	@Override
+	public String getDataText() {
+		return null;
+	}
+	
+	public Object getData() {
+		return this.data;
+	}
+	
+	
+	@Override
+	public boolean testEquals(final MainCmdItem other) {
+		if (!(other instanceof GraOpCmdItem)) {
+			return false;
+		}
+		final GraOpCmdItem otherItem= (GraOpCmdItem) other;
+		if (this.devId != otherItem.devId) {
+			return false;
+		}
+		if (this.op != otherItem.op) {
+			return false;
+		}
+		if (this.options != otherItem.options) {
+			return false;
+		}
+		return true;
+	}
+	
+	@Override
+	public String toString() {
+		final StringBuilder sb= new StringBuilder(128);
+		sb.append("GDOpCmdItem ");
+		switch (this.op) {
+		case OP_CLOSE:
+			sb.append("CLOSE");
+			break;
+		default:
+			sb.append(this.op);
+			break;
+		}
+		sb.append("\n\t").append("options= 0x").append(Integer.toHexString(this.options));
+		if ((this.options & OV_WITHSTATUS) != 0) {
+			sb.append("\nwith status: ");
+			sb.append((this.data == null) ? RjsStatus.OK_STATUS : this.data);
+		}
+		else if ((this.options & OV_WITHDATA) != 0) {
+			sb.append("\n<DATA>\n");
+			sb.append(this.data);
+			sb.append("\n</DATA>");
+		}
+		else {
+			sb.append("\n<DATA/>");
+		}
+		return sb.toString();
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/MainCmdC2SList.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/MainCmdC2SList.java
new file mode 100644
index 0000000..d649bde
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/MainCmdC2SList.java
@@ -0,0 +1,220 @@
+/*=============================================================================#
+ # Copyright (c) 2008, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server;
+
+import java.io.Externalizable;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+
+import org.eclipse.statet.rj.data.RJIO;
+
+
+/**
+ * Client-to-Server list with {@link MainCmdItem}s.
+ */
+public final class MainCmdC2SList implements RjsComObject, Externalizable {
+	
+	
+	private final RJIO privateIO;
+	
+	private MainCmdItem first;
+	
+	
+	public MainCmdC2SList(final RJIO io) {
+		this.privateIO= io;
+	}
+	
+	/**
+	 * Constructor for automatic deserialization
+	 */
+	public MainCmdC2SList() {
+		this.privateIO= null;
+		this.first= null;
+	}
+	
+	@Override
+	public void writeExternal(final ObjectOutput out) throws IOException {
+		final RJIO io;
+		if (this.privateIO != null) {
+			io= this.privateIO;
+			io.connect(out);
+		}
+		else {
+			io= RJIO.get(out);
+		}
+		final int check= io.writeCheck1();
+		
+		MainCmdItem item= this.first;
+		if (item != null) {
+			do {
+				out.writeByte(item.getCmdType());
+				item.writeExternal(io);
+			} while ((item= item.next) != null);
+		}
+		out.writeByte(MainCmdItem.T_NONE);
+		
+		io.writeCheck2(check);
+		io.disconnect(out);
+	}
+	
+	@Override
+	public void readExternal(final ObjectInput in) throws IOException, ClassNotFoundException {
+		final RJIO io= RJIO.get(in);
+		final int check= io.readCheck1();
+		
+		{	// first
+			final byte type= in.readByte();
+			switch (type) {
+			case MainCmdItem.T_NONE:
+				this.first= null;
+				io.readCheck2(check);
+				io.disconnect(in);
+				return;
+			case MainCmdItem.T_CONSOLE_READ_ITEM:
+				this.first= new ConsoleReadCmdItem(io);
+				break;
+			case MainCmdItem.T_CONSOLE_WRITE_ITEM:
+				this.first= new ConsoleWriteCmdItem(io);
+				break;
+			case MainCmdItem.T_MESSAGE_ITEM:
+				this.first= new ConsoleMessageCmdItem(io);
+				break;
+			case MainCmdItem.T_EXTENDEDUI_ITEM:
+				this.first= new ExtUICmdItem(io);
+				break;
+			case MainCmdItem.T_GRAPH_ITEM:
+				this.first= new GDCmdItem.Answer(io);
+				break;
+			case MainCmdItem.T_MAIN_CTRL_ITEM:
+				this.first= new MainCtrlCmdItem(io);
+				break;
+			case MainCmdItem.T_DATA_ITEM:
+				this.first= new DataCmdItem(io);
+				break;
+			case MainCmdItem.T_GRAPHICS_OP_ITEM:
+				this.first= new GraOpCmdItem(io);
+				break;
+			case MainCmdItem.T_DBG_ITEM:
+				this.first= new DbgCmdItem(io);
+				break;
+			default:
+				io.disconnect(in);
+				throw new ClassNotFoundException("Unknown cmdtype id: "+type);
+			}
+		}
+		
+		MainCmdItem item= this.first;
+		while (true) {
+			final byte type= in.readByte();
+			switch (type) {
+			case MainCmdItem.T_NONE:
+				io.readCheck2(check);
+				io.disconnect(in);
+				return;
+			case MainCmdItem.T_CONSOLE_READ_ITEM:
+				item= item.next= new ConsoleReadCmdItem(io);
+				continue;
+			case MainCmdItem.T_CONSOLE_WRITE_ITEM:
+				item= item.next= new ConsoleWriteCmdItem(io);
+				continue;
+			case MainCmdItem.T_MESSAGE_ITEM:
+				item= item.next= new ConsoleMessageCmdItem(io);
+				continue;
+			case MainCmdItem.T_EXTENDEDUI_ITEM:
+				item= item.next= new ExtUICmdItem(io);
+				continue;
+			case MainCmdItem.T_GRAPH_ITEM:
+				item= item.next= new GDCmdItem.Answer(io);
+				continue;
+			case MainCmdItem.T_MAIN_CTRL_ITEM:
+				this.first= new MainCtrlCmdItem(io);
+				break;
+			case MainCmdItem.T_DATA_ITEM:
+				item= item.next= new DataCmdItem(io);
+				continue;
+			case MainCmdItem.T_GRAPHICS_OP_ITEM:
+				item= item.next= new GraOpCmdItem(io);
+				continue;
+			case MainCmdItem.T_DBG_ITEM:
+				item= item.next= new DbgCmdItem(io);
+				continue;
+			default:
+				io.disconnect(in);
+				throw new ClassNotFoundException("Unknown cmdtype id: "+type);
+			}
+		}
+	}
+	
+	
+	public void clear() {
+		this.first= null;
+	}
+	
+	public void setObjects(final MainCmdItem first) {
+		this.first= first;
+	}
+	
+	
+	@Override
+	public int getComType() {
+		return RjsComObject.T_MAIN_LIST;
+	}
+	
+	public MainCmdItem getItems() {
+		return this.first;
+	}
+	
+	public boolean testEquals(final MainCmdC2SList other) {
+		MainCmdItem thisItem= this.first;
+		MainCmdItem otherItem= other.first;
+		while (thisItem != null && otherItem != null) {
+			if (!thisItem.equals(otherItem)) {
+				return false;
+			}
+			thisItem= thisItem.next;
+			otherItem= otherItem.next;
+		}
+		if (thisItem != null || otherItem != null) {
+			return false;
+		}
+		return true;
+	}
+	
+	@Override
+	public String toString() {
+		final StringBuilder sb= new StringBuilder(100);
+		sb.append("MainCmdC2SList (");
+		sb.append("):");
+		if (this.first == null) {
+			sb.append("\n<ITEM />");
+		}
+		else {
+			MainCmdItem item= this.first;
+			int i= 0;
+			while (item != null) {
+				sb.append("\n<ITEM i=\"");
+				sb.append(i);
+				sb.append("\">\n");
+				sb.append(item.toString());
+				sb.append("\n</ITEM>");
+				item= item.next;
+				i++;
+			}
+		}
+		return sb.toString();
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/MainCmdItem.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/MainCmdItem.java
new file mode 100644
index 0000000..11bd36b
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/MainCmdItem.java
@@ -0,0 +1,138 @@
+/*=============================================================================#
+ # Copyright (c) 2008, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server;
+
+import java.io.IOException;
+
+import org.eclipse.statet.rj.data.RJIO;
+import org.eclipse.statet.rj.data.RJIOExternalizable;
+
+
+public abstract class MainCmdItem implements RJIOExternalizable {
+	
+	
+	public static final byte T_NONE= 0;
+	
+	/**
+	 * {@link ConsoleReadCmdItem}
+	 */
+	public static final byte T_CONSOLE_READ_ITEM=          0x01;
+	
+	/**
+	 * {@link ConsoleWriteCmdItem}
+	 */
+	public static final byte T_CONSOLE_WRITE_ITEM=         0x02;
+	
+	
+	/**
+	 * {@link ConsoleMessageCmdItem}
+	 */
+	public static final byte T_MESSAGE_ITEM=               0x04;
+	
+	/**
+	 * {@link ExtUICmdItem}
+	 */
+	public static final byte T_EXTENDEDUI_ITEM=            0x05;
+	
+	/**
+	 * {@link GDCmdItem}
+	 */
+	public static final byte T_GRAPH_ITEM=                 0x07;
+	
+	/**
+	 * T_id <  => initiated by server
+	 * T_id >  => initiated by client
+	 */
+	public static final byte T_S2C_C2S= 9;
+	
+	/**
+	 * {@link MainCtrlCmdItem}
+	 */
+	public static final byte T_MAIN_CTRL_ITEM=              0x10;
+	
+	/**
+	 * {@link DataCmdItem}
+	 */
+	public static final byte T_DATA_ITEM=                  0x11;
+	
+	/**
+	 * {@link GraOpCmdItem}
+	 */
+	public static final byte T_GRAPHICS_OP_ITEM=           0x12;
+	
+	/**
+	 * {@link DbgCmdItem}
+	 */
+	public static final byte T_DBG_ITEM=                   0x14;
+	
+	
+	/**
+	 * Inside server only
+	 */
+	public static final byte T_SRV_ITEM=                   0x20;
+	
+	
+	protected static final int OM_STATUS=                  0x00f00000; // 0xf << OS_STATUS
+	protected static final int OS_STATUS=                  20;
+	
+	protected static final int OM_WITH=                    0x0f000000;
+	
+	public static final int OV_ANSWER=                     0x40000000;
+	protected static final int OM_ANSWER=                  OV_ANSWER;
+	public static final int OV_WAITFORCLIENT=              0x80000000;
+	protected static final int OM_WAITFORCLIENT=           OV_WAITFORCLIENT;
+	protected static final int OC_WAITFORCLIENT=           ~(OM_WAITFORCLIENT);
+	
+	public static final int OM_CUSTOM=                     0x0000ffff;
+	
+	protected static final int OM_CLEARFORANSWER=          ~(OM_STATUS | OM_WITH);
+	
+	
+	protected int options;
+	
+	public MainCmdItem next;
+	
+	public int requestId;
+	public byte slot;
+	
+	
+	public abstract byte getCmdType();
+	
+	public abstract byte getOp();
+	
+	public final boolean waitForClient() {
+		return ((this.options & OM_WAITFORCLIENT) != 0);
+	}
+	
+	public final boolean isAnswer() {
+		return ((this.options & OM_ANSWER) != 0);
+	}
+	
+	public final int getCmdOption() {
+		return ((this.options & OM_CUSTOM));
+	}
+	
+	public abstract void setAnswer(RjsStatus status);
+	
+	public abstract boolean isOK();
+	public abstract RjsStatus getStatus();
+	public abstract String getDataText();
+	
+	@Override
+	public abstract void writeExternal(RJIO io) throws IOException;
+	
+	public abstract boolean testEquals(MainCmdItem other);
+	
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/MainCmdS2CList.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/MainCmdS2CList.java
new file mode 100644
index 0000000..47980a9
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/MainCmdS2CList.java
@@ -0,0 +1,250 @@
+/*=============================================================================#
+ # Copyright (c) 2008, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server;
+
+import java.io.Externalizable;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+
+import org.eclipse.statet.rj.data.RJIO;
+
+
+/**
+ * Server-to-Client list with {@link MainCmdItem}s.
+ */
+public final class MainCmdS2CList implements RjsComObject, Externalizable {
+	
+	
+	static final AutoIdMap<ComHandler> gComHandlers= new AutoIdMap<>();
+	
+	
+	private int id;
+	
+	private boolean isBusy;
+	
+	private MainCmdItem first;
+	
+	
+	public MainCmdS2CList(final MainCmdItem first, final boolean isBusy) {
+		this.isBusy= isBusy;
+		this.first= first;
+	}
+	
+	/**
+	 * Constructor for automatic deserialization
+	 */
+	public MainCmdS2CList() {
+		this.isBusy= false;
+		this.first= null;
+	}
+	
+	@Override
+	public void writeExternal(final ObjectOutput out) throws IOException {
+		out.writeShort(this.id);
+		
+		out.writeBoolean(this.isBusy);
+		
+		final RJIO io= RJIO.get(out);
+		final int check= io.writeCheck1();
+		
+		MainCmdItem item= this.first;
+		if (item != null) {
+			do {
+				out.writeByte(item.getCmdType());
+				item.writeExternal(io);
+			} while ((item= item.next) != null);
+		}
+		out.writeByte(MainCmdItem.T_NONE);
+		
+		io.writeCheck2(check);
+		io.disconnect(out);
+	}
+	
+	@Override
+	public void readExternal(final ObjectInput in) throws IOException, ClassNotFoundException {
+		this.id= in.readUnsignedShort();
+		if (this.id != 0) {
+			gComHandlers.get(this.id).processMainCmd(in);
+			return;
+		}
+		
+		this.isBusy= in.readBoolean();
+		
+		final RJIO io= RJIO.get(in);
+		final int check= io.readCheck1();
+		
+		{	// first
+			final byte type= in.readByte();
+			switch (type) {
+			case MainCmdItem.T_NONE:
+				this.first= null;
+				io.readCheck2(check);
+				io.disconnect(in);
+				return;
+			case MainCmdItem.T_CONSOLE_READ_ITEM:
+				this.first= new ConsoleReadCmdItem(io);
+				break;
+			case MainCmdItem.T_CONSOLE_WRITE_ITEM:
+				this.first= new ConsoleWriteCmdItem(io);
+				break;
+			case MainCmdItem.T_MESSAGE_ITEM:
+				this.first= new ConsoleMessageCmdItem(io);
+				break;
+			case MainCmdItem.T_EXTENDEDUI_ITEM:
+				this.first= new ExtUICmdItem(io);
+				break;
+			case MainCmdItem.T_MAIN_CTRL_ITEM:
+				this.first= new MainCtrlCmdItem(io);
+				break;
+			case MainCmdItem.T_DATA_ITEM:
+				this.first= new DataCmdItem(io);
+				break;
+			case MainCmdItem.T_GRAPHICS_OP_ITEM:
+				this.first= new GraOpCmdItem(io);
+				break;
+			case MainCmdItem.T_DBG_ITEM:
+				this.first= new DbgCmdItem(io);
+				break;
+			default:
+				throw new ClassNotFoundException("Unknown cmdtype id: "+type);
+			}
+		}
+		
+		MainCmdItem item= this.first;
+		while (true) {
+			final byte type= in.readByte();
+			switch (type) {
+			case MainCmdItem.T_NONE:
+				io.readCheck2(check);
+				io.disconnect(in);
+				return;
+			case MainCmdItem.T_CONSOLE_READ_ITEM:
+				item= item.next= new ConsoleReadCmdItem(io);
+				continue;
+			case MainCmdItem.T_CONSOLE_WRITE_ITEM:
+				item= item.next= new ConsoleWriteCmdItem(io);
+				continue;
+			case MainCmdItem.T_MESSAGE_ITEM:
+				item= item.next= new ConsoleMessageCmdItem(io);
+				continue;
+			case MainCmdItem.T_EXTENDEDUI_ITEM:
+				item= item.next= new ExtUICmdItem(io);
+				continue;
+			case MainCmdItem.T_MAIN_CTRL_ITEM:
+				this.first= new MainCtrlCmdItem(io);
+				break;
+			case MainCmdItem.T_DATA_ITEM:
+				item= item.next= new DataCmdItem(io);
+				continue;
+			case MainCmdItem.T_GRAPHICS_OP_ITEM:
+				item= item.next= new GraOpCmdItem(io);
+				continue;
+			case MainCmdItem.T_DBG_ITEM:
+				item= item.next= new DbgCmdItem(io);
+				continue;
+			default:
+				io.disconnect(in);
+				throw new ClassNotFoundException("Unknown cmdtype id: "+type);
+			}
+		}
+	}
+	
+	
+	public void clear() {
+		MainCmdItem item= this.first;
+		while (item != null) {
+			final MainCmdItem tmp= item;
+			item= item.next;
+			tmp.next= null;
+		}
+		this.first= null;
+	}
+	
+	public boolean isEmpty() {
+		return (this.first == null);
+	}
+	
+	public void setId(final int id) {
+		this.id= (short) id;
+	}
+	
+	public void setBusy(final boolean isBusy) {
+		this.isBusy= isBusy;
+	}
+	
+	public void setObjects(final MainCmdItem first) {
+		this.first= first;
+	}
+	
+	
+	@Override
+	public int getComType() {
+		return RjsComObject.T_MAIN_LIST;
+	}
+	
+	public MainCmdItem getItems() {
+		return this.first;
+	}
+	
+	public boolean isBusy() {
+		return this.isBusy;
+	}
+	
+	
+	public boolean testEquals(final MainCmdS2CList other) {
+		if (this.isBusy != other.isBusy()) {
+			return false;
+		}
+		
+		MainCmdItem thisItem= this.first;
+		MainCmdItem otherItem= other.first;
+		while (thisItem != null && otherItem != null) {
+			if (!thisItem.equals(otherItem)) {
+				return false;
+			}
+			thisItem= thisItem.next;
+			otherItem= otherItem.next;
+		}
+		if (thisItem != null || otherItem != null) {
+			return false;
+		}
+		return true;
+	}
+	
+	@Override
+	public String toString() {
+		final StringBuilder sb= new StringBuilder(128);
+		sb.append("MainCmdS2CList (isBusy=");
+		sb.append(this.isBusy);
+		sb.append(')');
+		if (this.first != null) {
+			sb.append(':');
+		}
+		MainCmdItem item= this.first;
+		int i= 0;
+		while (item != null) {
+			sb.append("\n<ITEM i=\"");
+			sb.append(i);
+			sb.append("\">\n");
+			sb.append(item.toString());
+			sb.append("\n</ITEM>");
+			item= item.next;
+			i++;
+		}
+		return sb.toString();
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/MainCtrlCmdItem.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/MainCtrlCmdItem.java
new file mode 100644
index 0000000..99a9c13
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/MainCtrlCmdItem.java
@@ -0,0 +1,115 @@
+/*=============================================================================#
+ # Copyright (c) 2008, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server;
+
+import java.io.IOException;
+
+import org.eclipse.statet.rj.data.RJIO;
+
+
+/**
+ * Command for main loop console prompt/input.
+ */
+public final class MainCtrlCmdItem extends MainCmdItem {
+	
+	
+	public static final byte OP_FINISH_TASK= 02;
+	
+	
+	private final byte op;
+	
+	
+	public MainCtrlCmdItem(final byte op, final int options) {
+		this.op= op;
+		this.options= (options | (OM_WAITFORCLIENT));
+	}
+	
+	/**
+	 * Constructor for deserialization
+	 */
+	public MainCtrlCmdItem(final RJIO in) throws IOException {
+		this.requestId= in.readInt();
+		this.options= in.readInt();
+		this.op= in.readByte();
+	}
+	
+	@Override
+	public void writeExternal(final RJIO out) throws IOException {
+		out.writeInt(this.requestId);
+		out.writeInt(this.options);
+		out.writeByte(this.op);
+	}
+	
+	
+	@Override
+	public byte getCmdType() {
+		return T_MAIN_CTRL_ITEM;
+	}
+	
+	@Override
+	public byte getOp() {
+		return this.op;
+	}
+	
+	
+	@Override
+	public void setAnswer(final RjsStatus status) {
+		this.options= (this.options & OM_CLEARFORANSWER) | (status.getSeverity() << OS_STATUS);
+	}
+	
+	
+	@Override
+	public boolean isOK() {
+		return ((this.options & OM_STATUS) == RjsStatus.OK);
+	}
+	
+	@Override
+	public RjsStatus getStatus() {
+		return null;
+	}
+	
+	@Override
+	public String getDataText() {
+		return null;
+	}
+	
+	
+	@Override
+	public boolean testEquals(final MainCmdItem other) {
+		if (!(other instanceof MainCtrlCmdItem)) {
+			return false;
+		}
+		final MainCtrlCmdItem otherItem= (MainCtrlCmdItem) other;
+		return (getOp() == otherItem.getOp()
+				&& this.options == otherItem.options );
+	}
+	
+	@Override
+	public String toString() {
+		final StringBuffer sb= new StringBuffer(128);
+		sb.append("MainCtrlCmdItem ");
+		switch (this.op) {
+		case OP_FINISH_TASK:
+			sb.append("FINISH_TASK");
+			break;
+		default:
+			sb.append(this.op);
+			break;
+		}
+		sb.append("\n\t").append("options= 0x").append(Integer.toHexString(this.options));
+		return sb.toString();
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/Operation.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/Operation.java
new file mode 100644
index 0000000..7ddd98c
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/Operation.java
@@ -0,0 +1,35 @@
+/*=============================================================================#
+ # Copyright (c) 2014, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server;
+
+
+/**
+ * Operation
+ */
+public interface Operation {
+	
+	
+	interface SyncOp extends Operation {
+		
+	}
+	
+	interface AsyncOp extends Operation {
+		
+	}
+	
+	
+	byte getOp();
+	
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/REngine.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/REngine.java
new file mode 100644
index 0000000..4fafd40
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/REngine.java
@@ -0,0 +1,78 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server;
+
+import java.rmi.Remote;
+import java.rmi.RemoteException;
+import java.util.Map;
+
+
+/**
+ * Interface to the R console / REPL
+ */
+public interface REngine extends Remote {
+	
+	/**
+	 * Returns the public server reference
+	 * Usually you got this server by the public server reference
+	 * 
+	 * @return 
+	 * @throws RemoteException
+	 */
+	Server getPublic() throws RemoteException;
+	
+	/**
+	 * Returns a collection of platform data.
+	 * Current default items:
+	 * <ul>
+	 *     <li><code>os.type</code> - {@link String}</li>
+	 *     <li><code>file.sep</code> - {@link String}</li>
+	 *     <li><code>path.sep</code> - {@link String}</li>
+	 *     <li><code>version.string</code> - {@link String}</li>
+	 * </ul>
+	 * 
+	 * @return the map with all available data
+	 * @throws RemoteException
+	 */
+	Map<String, Object> getPlatformData() throws RemoteException;
+	
+	/**
+	 * Sets RJ server properties
+	 * 
+	 * @param properties map with properties to update
+	 * @throws RemoteException
+	 */
+	void setProperties(Map<String, ? extends Object> properties) throws RemoteException;
+	
+	/**
+	 * Disconnects the client from the server
+	 * The client can reconnect using {@link #connect(long)}.
+	 * 
+	 * @throws RemoteException
+	 */
+	void disconnect() throws RemoteException;
+	
+	RjsComObject runMainLoop(RjsComObject com) throws RemoteException;
+	RjsComObject runAsync(RjsComObject com) throws RemoteException;
+	
+	/**
+	 * Tests if the connection to R is closed
+	 * 
+	 * @return <code>true</code> if engine is still valid, otherwise <code>false</code>
+	 * @throws RemoteException
+	 */
+	boolean isClosed() throws RemoteException;
+	
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/RJ.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/RJ.java
new file mode 100644
index 0000000..4519631
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/RJ.java
@@ -0,0 +1,120 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import org.eclipse.statet.rj.server.gr.RjsGraphicManager;
+
+
+/**
+ * Interface from R to Java side of the RJ server
+ */
+public class RJ {
+	
+	
+	private static RJ instance;
+	
+	protected byte currentSlot;
+	
+	private final Object clientPropertiesLock= new Object();
+	private Map<String, Object>[] clientPropertiesMaps= new Map[2];
+	
+	
+	public final static RJ getInstance() {
+		return instance;
+	}
+	
+	
+	protected RJ() {
+		if (instance != null) {
+			throw new IllegalStateException();
+		}
+		instance= this;
+	}
+	
+	
+	public void onRExit() {
+		instance= null;
+	}
+	
+	public byte getCurrentSlot() {
+		return this.currentSlot;
+	}
+	
+	public RjsGraphicManager getGraphicManager() {
+		return null;
+	}
+	
+	protected void setClientProperty(final byte slot, final String key, final Object value) {
+		Map<String, Object> map;
+		synchronized (this.clientPropertiesLock) {
+			if (slot >= this.clientPropertiesMaps.length) {
+				final Map<String, Object>[] newMaps= new Map[this.clientPropertiesMaps.length];
+				System.arraycopy(this.clientPropertiesMaps, 0, newMaps, 0, slot+1);
+				this.clientPropertiesMaps= newMaps;
+			}
+			map= this.clientPropertiesMaps[slot];
+			if (map == null) {
+				this.clientPropertiesMaps[slot]= new HashMap<>();
+			}
+		}
+		map.put(key, value);
+	}
+	
+	protected void setClientProperties(final byte slot, final Map<String, ? extends Object> properties) {
+		Map<String, Object> map;
+		synchronized (this.clientPropertiesLock) {
+			if (slot >= this.clientPropertiesMaps.length) {
+				final Map<String, Object>[] newMaps= new Map[this.clientPropertiesMaps.length];
+				System.arraycopy(this.clientPropertiesMaps, 0, newMaps, 0, slot+1);
+				this.clientPropertiesMaps= newMaps;
+			}
+			map= this.clientPropertiesMaps[slot];
+			if (map == null) {
+				this.clientPropertiesMaps[slot]= map= new HashMap<>();
+			}
+		}
+		for (final Entry<String, ? extends Object> entry : properties.entrySet()) {
+			if (entry.getValue() != null) {
+				map.put(entry.getKey(), entry.getValue());
+			}
+			else {
+				map.remove(entry.getKey());
+			}
+		}
+	}
+	
+	public Object getClientProperty(final byte slot, final String key) {
+		final Map<String, Object>[] clients= this.clientPropertiesMaps;
+		if (slot >= clients.length) {
+			return null;
+		}
+		final Map<String, Object> map= clients[slot];
+		if (map == null) {
+			return null;
+		}
+		synchronized (map) {
+			return map.get(key);
+		}
+	}
+	
+	public MainCmdItem sendMainCmd(final MainCmdItem cmd) {
+		throw new UnsupportedOperationException();
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/RjsComConfig.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/RjsComConfig.java
new file mode 100644
index 0000000..036ea5b
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/RjsComConfig.java
@@ -0,0 +1,237 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server;
+
+import java.io.Externalizable;
+import java.io.File;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import java.net.InetAddress;
+import java.net.Socket;
+import java.net.UnknownHostException;
+import java.rmi.Remote;
+import java.rmi.server.RMIClientSocketFactory;
+import java.rmi.server.RMISocketFactory;
+import java.security.AccessControlException;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.eclipse.statet.rj.RjException;
+import org.eclipse.statet.rj.data.RObjectFactory;
+
+
+public class RjsComConfig {
+	
+	
+	public static final String RJ_COM_S2C_ID_PROPERTY_ID= "rj.com.s2c.id";
+	
+	public static final String RJ_DATA_STRUCTS_LISTS_MAX_LENGTH_PROPERTY_ID= "rj.data.structs.lists.max_length";
+	public static final String RJ_DATA_STRUCTS_ENVS_MAX_LENGTH_PROPERTY_ID= "rj.data.structs.envs.max_length";
+	
+	
+	private static final Map<String, Object> PROPERTIES= new ConcurrentHashMap<>();
+	
+	
+	public static interface PathResolver {
+		File resolve(Remote client, String path) throws RjException;
+	}
+	
+	
+	public static void setServerPathResolver(final RjsComConfig.PathResolver resolver) {
+		BinExchange.gSPathResolver= resolver;
+	}
+	
+	
+	public static int registerClientComHandler(final ComHandler handler) {
+		if (handler == null) {
+			throw new NullPointerException();
+		}
+		final int id= MainCmdS2CList.gComHandlers.put(handler);
+		if (id < 0xffff) {
+			return id;
+		}
+		MainCmdS2CList.gComHandlers.remove(id);
+		throw new UnsupportedOperationException("Too much open clients");
+	}
+	
+	public static void unregisterClientComHandler(final int id) {
+		MainCmdS2CList.gComHandlers.remove(id);
+	}
+	
+	
+	/**
+	 * Registers an additional RObject factory
+	 * 
+	 * Factory registration is valid for the current VM.
+	 */
+	public static final void registerRObjectFactory(final String id, final RObjectFactory factory) {
+		if (id == null || factory == null) {
+			throw new NullPointerException();
+		}
+		if (id.equals(DataCmdItem.DEFAULT_FACTORY_ID)) {
+			throw new IllegalArgumentException();
+		}
+		DataCmdItem.gFactories.put(id, factory);
+	}
+	
+	/**
+	 * Sets the default RObject factory
+	 * 
+	 * Factory registration is valid for the current VM.
+	 */
+	public static final void setDefaultRObjectFactory(final RObjectFactory factory) {
+		if (factory == null) {
+			throw new NullPointerException();
+		}
+		DataCmdItem.gDefaultFactory= factory;
+		DataCmdItem.gFactories.put(DataCmdItem.DEFAULT_FACTORY_ID, factory);
+	}
+	
+	public static final void setProperty(final String key, final Object value) {
+		PROPERTIES.put(key, value);
+	}
+	
+	public static final Object getProperty(final String key) {
+		return PROPERTIES.get(key);
+	}
+	
+	
+	private static final ThreadLocal<RMIClientSocketFactory> gRMIClientSocketFactoriesInit= new ThreadLocal<>();
+	private static final ConcurrentHashMap<String, RMIClientSocketFactory> gRMIClientSocketFactories= new ConcurrentHashMap<>();
+	
+	
+	private static RMIClientSocketFactory getSystemRMIClientSocketFactory() {
+		RMIClientSocketFactory factory= RMISocketFactory.getSocketFactory();
+		if (factory == null) {
+			factory= RMISocketFactory.getDefaultSocketFactory();
+		}
+		return factory;
+	}
+	
+	private static final class RjRMIClientSocketFactory implements RMIClientSocketFactory, Externalizable {
+		
+		
+		private static final long serialVersionUID= -2470426070934072117L;
+		
+		private static String getLocalHostName() {
+			try {
+				return InetAddress.getLocalHost().getCanonicalHostName();
+			}
+			catch (final UnknownHostException e) {}
+			catch (final ArrayIndexOutOfBoundsException e) { /* JVM bug */ }
+			return "unknown";
+		}
+		
+		
+		private String id;
+		private RMIClientSocketFactory resolvedFactory;
+		
+		
+		public RjRMIClientSocketFactory() {
+		}
+		
+		public RjRMIClientSocketFactory(final String init) {
+			final StringBuilder sb= new StringBuilder(init);
+			sb.append(getLocalHostName());
+			sb.append('/').append(System.nanoTime()).append('/').append(Math.random());
+			this.id= sb.toString();
+		}
+		
+		
+		@Override
+		public void writeExternal(final ObjectOutput out) throws IOException {
+			out.writeUTF(this.id);
+		}
+		@Override
+		public void readExternal(final ObjectInput in) throws IOException, ClassNotFoundException {
+			this.id= in.readUTF();
+		}
+		
+		
+		@Override
+		public Socket createSocket(final String host, final int port) throws IOException {
+			RMIClientSocketFactory factory= null;
+			factory= gRMIClientSocketFactoriesInit.get();
+			if (factory != null) {
+				this.resolvedFactory= factory;
+				gRMIClientSocketFactories.put(this.id, factory);
+			}
+			else {
+				factory= this.resolvedFactory;
+				if (factory == null) {
+					factory= gRMIClientSocketFactories.get(this.id);
+					if (factory != null) {
+						this.resolvedFactory= factory;
+					}
+					else {
+						factory= getSystemRMIClientSocketFactory();
+					}
+				}
+			}
+			return factory.createSocket(host, port);
+		}
+		
+		
+		@Override
+		public int hashCode() {
+			return this.id.hashCode();
+		}
+		
+		@Override
+		public boolean equals(final Object obj) {
+			return (this == obj
+					|| (obj instanceof RjRMIClientSocketFactory
+							&& this.id.equals(((RjRMIClientSocketFactory) obj).id) ));
+		}
+		
+	}
+	
+	private final static boolean RMISERVER_CLIENTSOCKET_FACTORY_ENABLED;
+	
+	private static RMIClientSocketFactory RMISERVER_CLIENTSOCKET_FACTORY;
+	
+	static {
+		{	boolean enabled= true;
+			try {
+				if ("true".equalsIgnoreCase(System.getProperty("org.eclipse.statet.rj.rmi.disableSocketFactory"))) {
+					enabled= false;
+				}
+			}
+			catch (final AccessControlException e) { // in RMI registry
+			}
+			RMISERVER_CLIENTSOCKET_FACTORY_ENABLED= enabled;
+		}
+	}
+	
+	public static synchronized final RMIClientSocketFactory getRMIServerClientSocketFactory() {
+		if (RMISERVER_CLIENTSOCKET_FACTORY_ENABLED && RMISERVER_CLIENTSOCKET_FACTORY == null) {
+			RMISERVER_CLIENTSOCKET_FACTORY= new RjRMIClientSocketFactory("S/");
+		}
+		return RMISERVER_CLIENTSOCKET_FACTORY;
+	}
+	
+	public static final void setRMIClientSocketFactory(RMIClientSocketFactory factory) {
+		if (factory == null) {
+			factory= getSystemRMIClientSocketFactory();
+		}
+		gRMIClientSocketFactoriesInit.set(factory);
+	}
+	
+	public static final void clearRMIClientSocketFactory() {
+		gRMIClientSocketFactoriesInit.set(null);
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/RjsComObject.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/RjsComObject.java
new file mode 100644
index 0000000..1c1d891
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/RjsComObject.java
@@ -0,0 +1,67 @@
+/*=============================================================================#
+ # Copyright (c) 2008, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server;
+
+
+/**
+ * Interface for all communication exchange objects.
+ */
+public interface RjsComObject {
+	
+	/**
+	 * {@link RjsStatus}
+	 */
+	public static final int T_STATUS=               1;
+	
+	/**
+	 * {@link RjsPing}
+	 */
+	public static final int T_PING=                 2;
+	
+	/**
+	 * {@link MainCmdS2CList}
+	 */
+	public static final int T_MAIN_LIST=            3;
+	
+	/**
+	 * {@link BinExchange}
+	 */
+	public static final int T_FILE_EXCHANGE=        4;
+	
+	/**
+	 * {@link CtrlCmdItem}
+	 */
+	public static final int T_CTRL=                 5;
+	
+	/**
+	 * {@link DbgCmdItem}
+	 */
+	public static final int T_DBG=                  6;
+	
+	
+	// Same value as in IStatus
+	public static final int V_OK=               RjsStatus.OK;
+	public static final int V_INFO=             RjsStatus.INFO;
+	public static final int V_WARNING=          RjsStatus.WARNING;
+	public static final int V_ERROR=            RjsStatus.ERROR;
+	public static final int V_CANCEL=           RjsStatus.CANCEL;
+	
+	public static final int V_FALSE=            0x0;
+	public static final int V_TRUE=             0x1;
+	
+	
+	public int getComType();
+	
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/RjsException.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/RjsException.java
new file mode 100644
index 0000000..48a7dcc
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/RjsException.java
@@ -0,0 +1,45 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server;
+
+
+/**
+ * Exception indicating that RJ operation failed
+ */
+public class RjsException extends Exception {
+	
+	
+	private static final long serialVersionUID= 4433450430400305890L;
+	
+	
+	private final int code;
+	
+	
+	public RjsException(final int code, final String message) {
+		super(message);
+		this.code= code;
+	}
+	
+	public RjsException(final int code, final String message, final Throwable cause) {
+		super(message, cause);
+		this.code= code;
+	}
+	
+	
+	public RjsStatus getStatus() {
+		return new RjsStatus(RjsStatus.ERROR, this.code, getMessage());
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/RjsPing.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/RjsPing.java
new file mode 100644
index 0000000..0828321
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/RjsPing.java
@@ -0,0 +1,67 @@
+/*=============================================================================#
+ # Copyright (c) 2008, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server;
+
+import java.io.Externalizable;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+
+
+/**
+ * Command for simple ping. Should be answered directly with a {@link RjsStatus}.
+ */
+public final class RjsPing implements RjsComObject, Externalizable {
+	
+	
+	public static final RjsPing INSTANCE= new RjsPing();
+	
+	
+	public RjsPing() {
+	}
+	
+	
+	@Override
+	public void writeExternal(final ObjectOutput out) throws IOException {
+	}
+	
+	@Override
+	public void readExternal(final ObjectInput in) throws IOException, ClassNotFoundException {
+	}
+	
+	
+	@Override
+	public int getComType() {
+		return RjsComObject.T_PING;
+	}
+	
+	
+	@Override
+	public int hashCode() {
+		return 1;
+	}
+	
+	@Override
+	public boolean equals(final Object obj) {
+		return (obj instanceof RjsPing);
+	}
+	
+	
+	@Override
+	public String toString() {
+		return "RjsPing";
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/RjsStatus.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/RjsStatus.java
new file mode 100644
index 0000000..d479db2
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/RjsStatus.java
@@ -0,0 +1,207 @@
+/*=============================================================================#
+ # Copyright (c) 2008, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server;
+
+import java.io.Externalizable;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+
+import org.eclipse.statet.rj.data.RJIO;
+import org.eclipse.statet.rj.data.RJIOExternalizable;
+
+
+public final class RjsStatus implements RjsComObject, Externalizable, RJIOExternalizable {
+	
+	
+	public static final int OK=               0x0;
+	public static final int INFO=             0x1;
+	public static final int WARNING=          0x2;
+	public static final int ERROR=            0x4;
+	public static final int CANCEL=           0x8;
+	
+	
+	public static final RjsStatus OK_STATUS= new RjsStatus(OK, 0);
+	
+	public static final RjsStatus CANCEL_STATUS= new RjsStatus(CANCEL, 0);
+	
+	
+	private int severity;
+	private int code;
+	private String text;
+	
+	
+	/**
+	 * Constructor to create a status object without a message
+	 */
+	public RjsStatus(final int severity, final int code) {
+		this.severity= severity;
+		this.code= code;
+		this.text= null;
+	}
+	
+	/**
+	 * Constructor to create a status object with a message
+	 */
+	public RjsStatus(final int severity, final int code, final String s) {
+		this.severity= severity;
+		this.code= code;
+		this.text= (s != null && s.length() > 0) ? s : null;
+	}
+	
+	/**
+	 * Constructor for automatic deserialization
+	 */
+	public RjsStatus() {
+	}
+	
+	/**
+	 * Constructor for deserialization
+	 */
+	public RjsStatus(final ObjectInput in) throws IOException {
+		readExternal(in);
+	}
+	
+	public RjsStatus(final RJIO io) throws IOException {
+		if (io.readBoolean()) {
+			this.severity= io.readByte();
+			this.code= io.readInt();
+			this.text= io.readString();
+		}
+		else {
+			this.severity= io.readByte();
+			this.code= io.readInt();
+			this.text= null;
+		}
+	}
+	
+	@Override
+	public void writeExternal(final RJIO io) throws IOException {
+		if (this.text != null) {
+			io.writeBoolean(true);
+			io.writeByte(this.severity);
+			io.writeInt(this.code);
+			io.writeString(this.text);
+		}
+		else {
+			io.writeBoolean(false);
+			io.writeByte(this.severity);
+			io.writeInt(this.code);
+		}
+	}
+	
+	@Override
+	public void readExternal(final ObjectInput in) throws IOException {
+		if (in.readBoolean()) {
+			this.severity= in.readByte();
+			this.code= in.readInt();
+			this.text= in.readUTF();
+		}
+		else {
+			this.severity= in.readByte();
+			this.code= in.readInt();
+			this.text= null;
+		}
+	}
+	
+	@Override
+	public void writeExternal(final ObjectOutput out) throws IOException {
+		if (this.text != null) {
+			out.writeBoolean(true);
+			out.writeByte(this.severity);
+			out.writeInt(this.code);
+			out.writeUTF(this.text);
+		}
+		else {
+			out.writeBoolean(false);
+			out.writeByte(this.severity);
+			out.writeInt(this.code);
+		}
+	}
+	
+	
+	@Override
+	public int getComType() {
+		return RjsComObject.T_STATUS;
+	}
+	
+	public int getSeverity() {
+		return this.severity;
+	}
+	
+	public int getCode() {
+		return this.code;
+	}
+	
+	public String getMessage() {
+		return (this.text != null) ? this.text : "";
+	}
+	
+	
+	@Override
+	public int hashCode() {
+		return this.severity+this.code;
+	}
+	
+	@Override
+	public boolean equals(final Object obj) {
+		if (!(obj instanceof RjsStatus)) {
+			return false;
+		}
+		final RjsStatus other= (RjsStatus) obj;
+		return (this.code == other.getCode() && this.severity == other.getSeverity()
+				&& ((this.text != null) ? this.text.equals(other.text) : (null == other.text)) );
+	}
+	
+	
+	@Override
+	public String toString() {
+		final StringBuffer sb= new StringBuffer(100);
+		sb.append("RjsStatus (severity=");
+		switch (this.severity) {
+		case OK:
+			sb.append("OK");
+			break;
+		case INFO:
+			sb.append("INFO");
+			break;
+		case WARNING:
+			sb.append("WARNING");
+			break;
+		case ERROR:
+			sb.append("ERROR");
+			break;
+		case CANCEL:
+			sb.append("CANCEL");
+			break;
+		default:
+			sb.append(this.severity);
+			break;
+		}
+		sb.append(", code=0x");
+		sb.append(Integer.toHexString(this.code));
+		sb.append(")");
+		if (this.text != null) {
+			sb.append("\n<TEXT>\n");
+			sb.append(this.text);
+			sb.append("\n</TEXT>");
+		}
+		else {
+			sb.append("\n<TEXT />");
+		}
+		return sb.toString();
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/Server.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/Server.java
new file mode 100644
index 0000000..af50226
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/Server.java
@@ -0,0 +1,120 @@
+/*=============================================================================#
+ # Copyright (c) 2008, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server;
+
+import java.rmi.Remote;
+import java.rmi.RemoteException;
+import java.util.Map;
+
+import javax.security.auth.login.LoginException;
+
+
+/**
+ * Interface of the R server visible for the remote clients.
+ * 
+ */
+public interface Server extends Remote {
+	
+	/**
+	 * Status code indicating, that the R engine is not yet started.
+	 */
+	public static final int S_NOT_STARTED= 	0x00011;
+	
+	/**
+	 * Status code indicating, that the R engine is started and a/the client is connected.
+	 */
+	public static final int S_CONNECTED= 		0x00014;
+	
+	/**
+	 * Status code indicating, that the R engine is started and the client is connected but
+	 * not active during the last minutes.
+	 */
+	public static final int S_CONNECTED_STALE= 0x00016;
+	
+	/**
+	 * Status code indicating, that the R engine is started and the client was disconnected.
+	 */
+	public static final int S_DISCONNECTED= 	0x00018;
+	
+	/**
+	 * Status code indicating, that R engine is started and the client-server connection was lost.
+	 */
+	public static final int S_LOST= 			0x00019;
+	
+	/**
+	 * Status code indicating, that the server was stopped.
+	 */
+	public static final int S_STOPPED= 		0x0001a;
+	
+	public static final String C_CONSOLE_START= "console.start";
+	
+	public static final String C_CONSOLE_CONNECT= "console.connect";
+	
+	public static final String C_RSERVI_NODECONTROL= "rservi.nodecontrol";
+	
+	
+	/**
+	 * Triple of API version of the this server
+	 * 
+	 * @return the version number
+	 * @throws RemoteException
+	 */
+	int[] getVersion() throws RemoteException;
+	
+	/**
+	 * The current server information
+	 * 
+	 * The information represents the state this method is call
+	 * and is not updated. To check for updates the method must be
+	 * called again. 
+	 * 
+	 * @return a server information object
+	 * @throws RemoteException
+	 */
+	ServerInfo getInfo() throws RemoteException;
+	
+	/**
+	 * Current state of this server. One of the constants with S_ prefix.
+	 * 
+	 * @return current state
+	 * @throws RemoteException
+	 */
+	int getState() throws RemoteException;
+	
+	
+	/**
+	 * Creates and returns the ServerLogin with all information necessary
+	 * to login ({@link #execute(String, Map, ServerLogin)})
+	 * to run the specified command 
+	 * 
+	 * @param the execute command constant the login will be for
+	 * @return the server login for the command
+	 * @throws RemoteException
+	 */
+	ServerLogin createLogin(String command) throws RemoteException;
+	
+	
+	/**
+	 * Universal method to executes a server command
+	 * 
+	 * @param command a command, default are available as constants with C_ prefix. 
+	 * @param login the login creditals a answer of {@link #createConsoleLogin()}
+	 * @return the return value of the command, see command description
+	 * @throws LoginException if login failed
+	 * @throws RemoteException
+	 */
+	Object execute(String command, Map<String, ? extends Object> args, ServerLogin login) throws LoginException, RemoteException;
+	
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/ServerInfo.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/ServerInfo.java
new file mode 100644
index 0000000..b12c9f4
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/ServerInfo.java
@@ -0,0 +1,75 @@
+/*=============================================================================#
+ # Copyright (c) 2008, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server;
+
+import java.io.Serializable;
+
+
+public class ServerInfo implements Serializable {
+	
+	
+	private static final long serialVersionUID= -5411479269748201535L;
+	
+	public static final String USER_OWNER= "owner";
+	public static final String USER_CONSOLE= "console";
+	public static final String USER_RSERVI= "rservi";
+	
+	
+	private final String name;
+	private final String[] userTypes;
+	private final String[] userNames;
+	private final String directory;
+	private final long timestamp;
+	private final int state;
+	
+	
+	public ServerInfo(final String name, final String directory, final long timestamp,
+			final String[] userTypes, final String[] userNames,
+			final int state) {
+		this.name= name;
+		this.userTypes= userTypes;
+		this.userNames= userNames;
+		this.directory= directory;
+		this.timestamp= timestamp;
+		this.state= state;
+	}
+	
+	
+	public String getName() {
+		return this.name;
+	}
+	
+	public String getUsername(final String type) {
+		for (int i= 0; i < this.userTypes.length; i++) {
+			if (this.userTypes[i].equals(type)) {
+				return this.userNames[i];
+			}
+		}
+		return null;
+	}
+	
+	public String getDirectory() {
+		return this.directory;
+	}
+	
+	public long getTimestamp() {
+		return this.timestamp;
+	}
+	
+	public int getState() {
+		return this.state;
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/ServerLogin.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/ServerLogin.java
new file mode 100644
index 0000000..7b95942
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/ServerLogin.java
@@ -0,0 +1,184 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server;
+
+import java.io.Serializable;
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.charset.Charset;
+import java.security.Key;
+import java.util.Arrays;
+
+import javax.crypto.Cipher;
+import javax.security.auth.callback.Callback;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.callback.PasswordCallback;
+
+import org.eclipse.statet.rj.RjException;
+import org.eclipse.statet.rj.server.srvext.ServerAuthMethod;
+
+
+public final class ServerLogin implements Serializable {
+	
+	
+	private static final long serialVersionUID= -596748668244272719L;
+	
+	
+	private long id;
+	
+	private Key pubkey;
+	
+	private Callback[] callbacks;
+	
+	
+	public ServerLogin() {
+	}
+	
+	public ServerLogin(final long id, final Key pubkey, final Callback[] callbacks) {
+		this.id= id;
+		this.pubkey= pubkey;
+		this.callbacks= callbacks;
+	}
+	
+	
+	public long getId() {
+		return this.id;
+	}
+	
+	/**
+	 * The callback items which should be handled by the client.
+	 * 
+	 * @return an array with all callback objects
+	 * @see CallbackHandler
+	 */
+	public Callback[] getCallbacks() {
+		return this.callbacks;
+	}
+	
+	/**
+	 * Must be called by the client to create login data for authentification
+	 * when connecting to server via {@link Server#start(ServerLogin, String[])}
+	 * or {@link Server#connect(ServerLogin)}.
+	 * 
+	 * @return the login data prepared to send to the server
+	 * @throws RjException when creating login data failed
+	 */
+	public ServerLogin createAnswer() throws RjException {
+		try {
+			Callback[] copy;
+			if (this.callbacks != null) {
+				copy= new Callback[this.callbacks.length];
+				System.arraycopy(this.callbacks, 0, copy, 0, this.callbacks.length);
+				if (this.pubkey != null) {
+					process(copy, Cipher.ENCRYPT_MODE, this.pubkey);
+				}
+			}
+			else {
+				copy= null;
+			}
+			return new ServerLogin(this.id, null, copy);
+		}
+		catch (final Exception e) {
+			throw new RjException("An error occurred when creating login data.", e);
+		}
+	}
+	
+	/**
+	 * Is called by server to decrypt data. By default it is called in
+	 * {@link ServerAuthMethod#performLogin(ServerLogin)}.
+	 * 
+	 * @param privateKey the key to decrypt the data
+	 * @throws RjException when processing login data failed
+	 */
+	public void readAnswer(final Key privateKey) throws RjException {
+		try {
+			if (privateKey != null) {
+				process(this.callbacks, Cipher.DECRYPT_MODE, privateKey);
+			}
+		}
+		catch (final Exception e) {
+			throw new RjException("An error occurred when processing login data.", e);
+		}
+	}
+	
+	private void process(final Callback[] callbacks, final int mode, final Key key) throws Exception {
+		final Cipher with= Cipher.getInstance("RSA");
+		with.init(mode, key);
+		final Charset charset= Charset.forName("UTF-8");
+		
+		for (int i= 0; i < callbacks.length; i++) {
+			if (callbacks[i] instanceof PasswordCallback) {
+				final PasswordCallback c= (PasswordCallback) callbacks[i];
+				final char[] orgPassword= c.getPassword();
+				if (orgPassword != null) {
+					final byte[] orgBytes;
+					if (mode == Cipher.ENCRYPT_MODE) {
+						orgBytes= charset.encode(CharBuffer.wrap(orgPassword)).array();
+					}
+					else {
+						orgBytes= new byte[orgPassword.length];
+						for (int j= 0; j < orgBytes.length; j++) {
+							orgBytes[j]= (byte) orgPassword[j];
+						}
+					}
+					final byte[] encBytes= with.doFinal(orgBytes);
+					final char[] encPassword;
+					if (mode == Cipher.ENCRYPT_MODE) {
+						encPassword= new char[encBytes.length];
+						for (int j= 0; j < encPassword.length; j++) {
+							encPassword[j]= (char) encBytes[j];
+						}
+					}
+					else {
+						encPassword= charset.decode(ByteBuffer.wrap(encBytes)).array();
+					}
+					
+					if (mode == Cipher.ENCRYPT_MODE) {
+						final PasswordCallback copy= new PasswordCallback(c.getPrompt(), c.isEchoOn());
+						copy.setPassword(encPassword);
+						callbacks[i]= copy;
+					}
+					else {
+						c.clearPassword();
+						c.setPassword(encPassword);
+					}
+					
+					Arrays.fill(orgBytes, (byte) 0);
+					Arrays.fill(orgPassword, (char) 0);
+					Arrays.fill(encBytes, (byte) 0);
+					Arrays.fill(encPassword, (char) 0);
+				}
+				continue;
+			}
+		}
+	}
+	
+	/**
+	 * Clear data, especially the password.
+	 */
+	public void clearData() {
+		this.pubkey= null;
+		if (this.callbacks != null) {
+			for (int i= 0; i < this.callbacks.length; i++) {
+				if (this.callbacks[i] instanceof PasswordCallback) {
+					((PasswordCallback) this.callbacks[i]).clearPassword();
+				}
+				this.callbacks[i]= null;
+			}
+			this.callbacks= null;
+		}
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/CallStack.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/CallStack.java
new file mode 100644
index 0000000..4c71804
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/CallStack.java
@@ -0,0 +1,146 @@
+/*=============================================================================#
+ # Copyright (c) 2011, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server.dbg;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.statet.rj.data.RJIO;
+import org.eclipse.statet.rj.data.RJIOExternalizable;
+
+
+public class CallStack implements RJIOExternalizable {
+	
+	
+	public static final int FLAG_TOPFRAME=                  0x00001000;
+	
+	public static final int FLAG_NOSTEPPING=                0x00000100;
+	
+	public static final int FLAG_SOURCE=                    0x00000010;
+	public static final int FLAG_COMMAND=                   0x00000020;
+	
+	
+	private final List<? extends Frame> frames;
+	
+	
+	public CallStack(final List<? extends Frame> list, final boolean setDefaultFlags) {
+		this.frames= list;
+		if (setDefaultFlags) {
+			setDefaultFlags();
+		}
+	}
+	
+	public CallStack(final RJIO io) throws IOException {
+		final int l= io.readInt();
+		final ArrayList<Frame> list= new ArrayList<>(l);
+		for (int i= 0; i < l; i++) {
+			final Frame frame= new Frame(i, io.readString());
+			frame.handle= io.readLong();
+			frame.fileName= io.readString();
+			frame.fileTimestamp= io.readLong();
+			frame.exprSrcref= io.readIntArray();
+			frame.flags= io.readInt();
+			list.add(frame);
+		}
+		this.frames= list;
+	}
+	
+	@Override
+	public void writeExternal(final RJIO io) throws IOException {
+		final int l= this.frames.size();
+		io.writeInt(l);
+		for (int i= 0; i < l; i++) {
+			final Frame frame= this.frames.get(i);
+			io.writeString(frame.getCall());
+			io.writeLong(frame.handle);
+			io.writeString(frame.fileName);
+			io.writeLong(frame.fileTimestamp);
+			io.writeIntArray(frame.exprSrcref, (frame.exprSrcref != null) ? 6 : -1);
+			io.writeInt(frame.flags);
+		}
+	}
+	
+	protected void setDefaultFlags() {
+		final int n= this.frames.size();
+		for (int i= 0; i < n; i++) {
+			final Frame frame0= this.frames.get(i);
+			if (frame0.getCall() != null) {
+				if (frame0.getCall().startsWith("source(")) { //$NON-NLS-1$
+					Frame frame1;
+					Frame frame2;
+					if (i+1 < n && (frame1= this.frames.get(i+1)).getCall() != null
+							&& frame1.getCall().startsWith("eval.with.vis(") ) { //$NON-NLS-1$
+						frame0.addFlags((FLAG_SOURCE | 0));
+						frame1.addFlags((FLAG_SOURCE | 1));
+						i++;
+						if (i+1 < n && (frame2= this.frames.get(i+1)).getCall() != null
+								&& frame2.getCall().startsWith("eval.with.vis(") ) { //$NON-NLS-1$
+							frame2.addFlags((FLAG_SOURCE | 2));
+							i++;
+						}
+					}
+					else if (i+2 < n && (frame1= this.frames.get(i+1)).getCall() != null
+							&& frame1.getCall().startsWith("withVisible(") //$NON-NLS-1$
+							&& (frame2= this.frames.get(i+2)).getCall() != null
+							&& frame2.getCall().startsWith("eval(") ) { //$NON-NLS-1$
+						frame0.addFlags((FLAG_SOURCE | 0));
+						frame1.addFlags((FLAG_SOURCE | 1));
+						frame2.addFlags((FLAG_SOURCE | 2));
+						i+= 2;
+						if (i+1 < n && (frame2= this.frames.get(i+1)).getCall() != null
+								&& frame2.getCall().startsWith("eval(") ) { //$NON-NLS-1$
+							frame2.addFlags((FLAG_SOURCE | 3));
+							i++;
+						}
+					}
+				}
+				else if (frame0.getCall().startsWith("rj:::.statet.evalCommand(") //$NON-NLS-1$
+						|| frame0.getCall().startsWith(".statet.evalCommand(") ) { //$NON-NLS-1$
+					frame0.addFlags((FLAG_COMMAND | 0));
+					final Frame frame1;
+					if (i+1 < n && (frame1= this.frames.get(i+1)).getCall() != null
+							&& frame1.getCall().startsWith("eval(") ) { //$NON-NLS-1$
+						frame1.addFlags((FLAG_COMMAND | 1));
+						i++;
+						final Frame frame2;
+						if (i+1 < n && (frame2= this.frames.get(i+1)).getCall() != null
+								&& frame2.getCall().startsWith("eval(") ) { //$NON-NLS-1$
+							frame2.addFlags((FLAG_COMMAND | 2));
+							i++;
+						}
+					}
+				}
+			}
+		}
+		
+		this.frames.get(n-1).addFlags(FLAG_TOPFRAME);
+	}
+	
+	public List<? extends Frame> getFrames() {
+		return this.frames;
+	}
+	
+	public Frame findFrame(final long handle) {
+		for (int i= 0; i < this.frames.size(); i++) {
+			final Frame frame= this.frames.get(i);
+			if (frame.getHandle() == handle) {
+				return frame;
+			}
+		}
+		return null;
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/CtrlReport.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/CtrlReport.java
new file mode 100644
index 0000000..cd24356
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/CtrlReport.java
@@ -0,0 +1,84 @@
+/*=============================================================================#
+ # Copyright (c) 2011, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server.dbg;
+
+import java.io.IOException;
+
+import org.eclipse.statet.rj.data.RJIO;
+import org.eclipse.statet.rj.data.RJIOExternalizable;
+
+
+public class CtrlReport implements RJIOExternalizable {
+	
+	
+	private final static int REQUEST_EXECUTED=              0x01000000;
+	
+	private final static int ENGINE_EXECUTING=              0;
+	private final static int ENGINE_SUSPENDED=              0x02000000;
+	
+	private final static int RESET_PROMPT=                  0x00100000;
+	
+	
+	public static CtrlReport createRequestExecuted(final byte type) {
+		switch (type) {
+		case DbgRequest.RESUME:
+		case DbgRequest.STEP_INTO:
+		case DbgRequest.STEP_OVER:
+		case DbgRequest.STEP_RETURN:
+			return new CtrlReport(type | REQUEST_EXECUTED | ENGINE_EXECUTING);
+		default:
+			throw new IllegalArgumentException("type= " + type); //$NON-NLS-1$
+		}
+	}
+	
+	public static CtrlReport createRequestNotApplicable(final boolean isEngineSuspended) {
+		return new CtrlReport((isEngineSuspended) ? ENGINE_SUSPENDED : ENGINE_EXECUTING);
+	}
+	
+	public static CtrlReport createRequestNotSupported(final boolean isEngineSuspended) {
+		return new CtrlReport((isEngineSuspended) ? ENGINE_SUSPENDED : ENGINE_EXECUTING);
+	}
+	
+	
+	private final int code;
+	
+	
+	private CtrlReport(final int code) {
+		this.code= code;
+	}
+	
+	public CtrlReport(final RJIO io) throws IOException {
+		this.code= io.readInt();
+	}
+	
+	@Override
+	public void writeExternal(final RJIO io) throws IOException {
+		io.writeInt(this.code);
+	}
+	
+	
+	public byte getOp() {
+		return (byte) (this.code & 0xff);
+	}
+	
+	public boolean isRequestExecuted() {
+		return ((this.code & REQUEST_EXECUTED) != 0);
+	}
+	
+	public boolean isEngineSuspended() {
+		return ((this.code & ENGINE_SUSPENDED) != 0);
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/DbgEnablement.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/DbgEnablement.java
new file mode 100644
index 0000000..dd2665f
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/DbgEnablement.java
@@ -0,0 +1,50 @@
+/*=============================================================================#
+ # Copyright (c) 2011, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server.dbg;
+
+import java.io.IOException;
+
+import org.eclipse.statet.rj.data.RJIO;
+import org.eclipse.statet.rj.data.RJIOExternalizable;
+
+
+public class DbgEnablement implements RJIOExternalizable {
+	
+	
+	private static final int ENABLE_BREAKPOINTS=           0x00000001;
+	
+	
+	private final int properties;
+	
+	
+	public DbgEnablement(final boolean breakpointsEnabled) {
+		this.properties= (breakpointsEnabled) ? ENABLE_BREAKPOINTS : 0;
+	}
+	
+	public DbgEnablement(final RJIO io) throws IOException {
+		this.properties= io.readInt();
+	}
+	
+	@Override
+	public void writeExternal(final RJIO io) throws IOException {
+		io.writeInt(this.properties);
+	}
+	
+	
+	public boolean getBreakpointsEnabled() {
+		return ((this.properties & ENABLE_BREAKPOINTS) != 0);
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/DbgFilterState.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/DbgFilterState.java
new file mode 100644
index 0000000..43e11e2
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/DbgFilterState.java
@@ -0,0 +1,47 @@
+/*=============================================================================#
+ # Copyright (c) 2011, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server.dbg;
+
+import java.io.IOException;
+
+import org.eclipse.statet.rj.data.RJIO;
+import org.eclipse.statet.rj.data.RJIOExternalizable;
+
+
+public class DbgFilterState implements RJIOExternalizable {
+	
+	
+	private final int stepFilterState;
+	
+	
+	public DbgFilterState(final boolean stepFilterEnabled) {
+		this.stepFilterState= (stepFilterEnabled) ? 0x1 : 0x0;
+	}
+	
+	public DbgFilterState(final RJIO io) throws IOException {
+		this.stepFilterState= io.readInt();
+	}
+	
+	@Override
+	public void writeExternal(final RJIO io) throws IOException {
+		io.writeInt(this.stepFilterState);
+	}
+	
+	
+	public boolean stepFilterEnabled() {
+		return ((this.stepFilterState & 0x1) != 0);
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/DbgListener.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/DbgListener.java
new file mode 100644
index 0000000..17e8cbb
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/DbgListener.java
@@ -0,0 +1,23 @@
+/*=============================================================================#
+ # Copyright (c) 2011, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server.dbg;
+
+
+public interface DbgListener {
+	
+	
+	void handle(TracepointEvent event);
+	
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/DbgRequest.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/DbgRequest.java
new file mode 100644
index 0000000..316219a
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/DbgRequest.java
@@ -0,0 +1,155 @@
+/*=============================================================================#
+ # Copyright (c) 2014, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server.dbg;
+
+import java.io.IOException;
+
+import org.eclipse.statet.rj.data.RJIO;
+import org.eclipse.statet.rj.data.RJIOExternalizable;
+import org.eclipse.statet.rj.server.DbgCmdItem;
+import org.eclipse.statet.rj.server.Operation;
+
+
+public abstract class DbgRequest implements Operation, RJIOExternalizable {
+	
+	
+	public static final byte RESUME=                        DbgCmdItem.OP_CTRL_RESUME;
+	public static final byte STEP_INTO=                     DbgCmdItem.OP_CTRL_STEP_INTO;
+	public static final byte STEP_OVER=                     DbgCmdItem.OP_CTRL_STEP_OVER;
+	public static final byte STEP_RETURN=                   DbgCmdItem.OP_CTRL_STEP_RETURN;
+	
+	
+	private static final int FRAME_POSITION=                00000001;
+	private static final int FRAME_HANDLE=                  00000002;
+	
+	
+	public static class Resume extends DbgRequest implements SyncOp {
+		
+		
+		public Resume() {
+		}
+		
+		public Resume(final RJIO in) throws IOException {
+		}
+		
+		@Override
+		public void writeExternal(final RJIO out) throws IOException {
+		}
+		
+		
+		@Override
+		public byte getOp() {
+			return RESUME;
+		}
+		
+	}
+	
+	public static class StepOver extends DbgRequest implements SyncOp {
+		
+		
+		public StepOver() {
+		}
+		
+		public StepOver(final RJIO in) throws IOException {
+		}
+		
+		@Override
+		public void writeExternal(final RJIO out) throws IOException {
+		}
+		
+		
+		@Override
+		public byte getOp() {
+			return STEP_OVER;
+		}
+		
+	}
+	
+	public static class StepInto extends DbgRequest implements SyncOp {
+		
+		
+		public StepInto() {
+		}
+		
+		public StepInto(final RJIO in) throws IOException {
+		}
+		
+		@Override
+		public void writeExternal(final RJIO out) throws IOException {
+		}
+		
+		
+		@Override
+		public byte getOp() {
+			return STEP_INTO;
+		}
+		
+	}
+	
+	public static class StepReturn extends DbgRequest implements SyncOp {
+		
+		
+		private final int detail;
+		
+		private final RJIOExternalizable target;
+		
+		
+		public StepReturn(final FrameRef target) {
+			if (target instanceof FrameRef.ByPosition) {
+				this.detail= FRAME_POSITION;
+			}
+			else if (target instanceof FrameRef.ByHandle) {
+				this.detail= FRAME_HANDLE;
+			}
+			else {
+				throw new IllegalArgumentException("target"); //$NON-NLS-1$
+			}
+			this.target= target;
+		}
+		
+		public StepReturn(final RJIO in) throws IOException {
+			this.detail= in.readInt();
+			switch (this.detail & 0xf) {
+			case FRAME_POSITION:
+				this.target= new FrameRef.ByPosition(in);
+				break;
+			case FRAME_HANDLE:
+				this.target= new FrameRef.ByHandle(in);
+				break;
+			default:
+				throw new IOException();
+			}
+		}
+		
+		@Override
+		public void writeExternal(final RJIO out) throws IOException {
+			out.writeInt(this.detail);
+			this.target.writeExternal(out);
+		}
+		
+		
+		@Override
+		public byte getOp() {
+			return STEP_RETURN;
+		}
+		
+		public Object getTarget() {
+			return this.target;
+		}
+		
+	}
+	
+	
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/ElementTracepointInstallationRequest.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/ElementTracepointInstallationRequest.java
new file mode 100644
index 0000000..76b5189
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/ElementTracepointInstallationRequest.java
@@ -0,0 +1,58 @@
+/*=============================================================================#
+ # Copyright (c) 2011, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server.dbg;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.statet.rj.data.RJIO;
+
+
+public class ElementTracepointInstallationRequest extends TracepointInstallationRequest {
+	
+	
+	private final List<? extends ElementTracepointPositions> requests;
+	
+	
+	public ElementTracepointInstallationRequest(
+			final List<? extends ElementTracepointPositions> checkedList) {
+		this.requests= checkedList;
+	}
+	
+	public ElementTracepointInstallationRequest(final RJIO io) throws IOException {
+		final int l= io.readInt();
+		final List<ElementTracepointPositions> list= new ArrayList<>(l);
+		for (int i= 0; i < l; i++) {
+			list.add(new ElementTracepointPositions(io));
+		}
+		this.requests= list;
+	}
+	
+	@Override
+	public void writeExternal(final RJIO io) throws IOException {
+		final int l= this.requests.size();
+		io.writeInt(l);
+		for (int i= 0; i < l; i++) {
+			this.requests.get(i).writeExternal(io);
+		}
+	}
+	
+	
+	public List<? extends ElementTracepointPositions> getRequests() {
+		return this.requests;
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/ElementTracepointPositions.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/ElementTracepointPositions.java
new file mode 100644
index 0000000..727b69b
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/ElementTracepointPositions.java
@@ -0,0 +1,102 @@
+/*=============================================================================#
+ # Copyright (c) 2011, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server.dbg;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.statet.rj.data.RJIO;
+import org.eclipse.statet.rj.data.RJIOExternalizable;
+
+
+public class ElementTracepointPositions implements RJIOExternalizable {
+	
+	
+	private final SrcfileData fileInfo;
+	
+	private final String elementId;
+	private final int[] elementSrcref;
+	
+	private final List<TracepointPosition> positions;
+	
+	
+	public ElementTracepointPositions(final SrcfileData fileInfo,
+			final String elementId, final int[] elementSrcref) {
+		if (fileInfo == null) {
+			throw new NullPointerException("fileInfo"); //$NON-NLS-1$
+		}
+		if (elementId == null) {
+			throw new NullPointerException("elementId"); //$NON-NLS-1$
+		}
+		this.fileInfo= fileInfo;
+		this.elementId= elementId;
+		this.elementSrcref= elementSrcref;
+		this.positions= new ArrayList<>(4);
+	}
+	
+	public ElementTracepointPositions(final RJIO io) throws IOException {
+		this.fileInfo= new SrcfileData(io);
+		this.elementId= io.readString();
+		this.elementSrcref= io.readIntArray();
+		final int l= io.readInt();
+		this.positions= new ArrayList<>(l);
+		for (int i= 0; i < l; i++) {
+			this.positions.add(new TracepointPosition(io));
+		}
+	}
+	
+	@Override
+	public void writeExternal(final RJIO io) throws IOException {
+		this.fileInfo.writeExternal(io);
+		io.writeString(this.elementId);
+		io.writeIntArray(this.elementSrcref, (this.elementSrcref != null) ? 6 : -1);
+		final int l= this.positions.size();
+		io.writeInt(l);
+		for (int i= 0; i < l; i++) {
+			this.positions.get(i).writeExternal(io);
+		}
+	}
+	
+	
+	public SrcfileData getSrcfile() {
+		return this.fileInfo;
+	}
+	
+	public String getElementId() {
+		return this.elementId;
+	}
+	
+	public int[] getElementSrcref() {
+		return this.elementSrcref;
+	}
+	
+	public List<? extends TracepointPosition> getPositions() {
+		return this.positions;
+	}
+	
+	
+	@Override
+	public String toString() {
+		final StringBuilder sb= new StringBuilder("ElementTracepointPositions"); //$NON-NLS-1$
+		sb.append(" for ").append(this.elementId); //$NON-NLS-1$
+		sb.append("\n").append("list (count= ").append(this.positions.size()).append("):"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		for (int i= 0; i < this.positions.size(); i++) {
+			sb.append("\n").append(this.positions.get(i).toString()); //$NON-NLS-1$
+		}
+		return sb.toString();
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/FlagTracepointInstallationRequest.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/FlagTracepointInstallationRequest.java
new file mode 100644
index 0000000..302cf70
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/FlagTracepointInstallationRequest.java
@@ -0,0 +1,60 @@
+/*=============================================================================#
+ # Copyright (c) 2016, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server.dbg;
+
+import java.io.IOException;
+
+import org.eclipse.statet.rj.data.RJIO;
+
+
+public class FlagTracepointInstallationRequest extends TracepointInstallationRequest {
+	
+	
+	private final byte[] types;
+	private final int[] flags;
+	
+	
+	public FlagTracepointInstallationRequest(final byte[] types, final int[] flags) {
+		if (types.length != flags.length) {
+			throw new IllegalArgumentException("types.length != flags.length");
+		}
+		this.types= types;
+		this.flags= flags;
+	}
+	
+	public FlagTracepointInstallationRequest(final RJIO in) throws IOException {
+		final int l= in.readInt();
+		this.types= in.readByteData(new byte[l], l);
+		this.flags= in.readIntData(new int[l], l);
+	}
+	
+	@Override
+	public void writeExternal(final RJIO out) throws IOException {
+		final int l= this.types.length;
+		out.writeInt(l);
+		out.writeByteData(this.types, l);
+		out.writeIntData(this.flags, l);
+	}
+	
+	
+	public byte[] getTypes() {
+		return this.types;
+	}
+	
+	public int[] getFlags() {
+		return this.flags;
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/Frame.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/Frame.java
new file mode 100644
index 0000000..564ace6
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/Frame.java
@@ -0,0 +1,93 @@
+/*=============================================================================#
+ # Copyright (c) 2014, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server.dbg;
+
+
+public class Frame {
+	
+	
+	private final int position;
+	private final String call;
+	
+	protected long handle;
+	
+	protected String fileName;
+	protected long fileTimestamp;
+	
+	protected int[] exprSrcref;
+	
+	protected int flags;
+	
+	
+	public Frame(final int position, final String call, final long handle,
+			final String fileName, final long fileTimestamp, final int[] exprSrcref) {
+		this.position= position;
+		this.call= call;
+		this.handle= handle;
+		this.fileName= fileName;
+		this.fileTimestamp= fileTimestamp;
+		this.exprSrcref= exprSrcref;
+	}
+	
+	protected Frame(final int position, final String call) {
+		this.position= position;
+		this.call= call;
+	}
+	
+	
+	public int getPosition() {
+		return this.position;
+	}
+	
+	public String getCall() {
+		return this.call;
+	}
+	
+	public long getHandle() {
+		return this.handle;
+	}
+	
+	public String getFileName() {
+		return this.fileName;
+	}
+	
+	public long getFileTimestamp() {
+		return this.fileTimestamp;
+	}
+	
+	public int[] getExprSrcref() {
+		return this.exprSrcref;
+	}
+	
+	
+	public int getFlags() {
+		return this.flags;
+	}
+	
+	public void addFlags(final int flags) {
+		this.flags |= flags;
+	}
+	
+	/** top frame */
+	public boolean isTopFrame() {
+		return ((this.flags & CallStack.FLAG_TOPFRAME) != 0);
+	}
+	
+	/** frame of top level command */
+	public boolean isTopLevelCommand() {
+		return (this.position == 3 && (this.flags & 0xff) == (CallStack.FLAG_COMMAND | 2));
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/FrameContext.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/FrameContext.java
new file mode 100644
index 0000000..d1cd78b
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/FrameContext.java
@@ -0,0 +1,156 @@
+/*=============================================================================#
+ # Copyright (c) 2011, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server.dbg;
+
+import java.io.IOException;
+
+import org.eclipse.statet.rj.data.RJIO;
+import org.eclipse.statet.rj.data.RJIOExternalizable;
+
+
+public class FrameContext implements RJIOExternalizable {
+	
+	
+	public static final int SOURCETYPE_1_LINES= 1;
+	public static final int SOURCETYPE_1_FILE= 2;
+	public static final int SOURCETYPE_2_LINES= 3;
+	public static final int SOURCETYPE_3_DEPARSE= 4;
+	
+	
+	private final int position;
+	private final String call;
+	
+	protected String fileName;
+	protected long fileTimestamp;
+	protected String fileEncoding;
+	protected String filePath;
+	
+	protected int sourceType;
+	protected String sourceCode;
+	protected int[] sourceSrcref;
+	
+	protected int[] firstSrcref;
+	protected int[] lastSrcref;
+	protected int[] exprSrcref;
+	
+	
+	public FrameContext(final int position, final String call,
+			final String fileName, final long fileTimestamp, final String fileEncoding,
+			final String filePath, final int sourceType, final String sourceCode, final int[] sourceSrcref,
+			final int[] firstSrcref, final int[] lastSrcref, final int[] exprSrcref) {
+		this.position= position;
+		this.call= call;
+		
+		this.fileName= fileName;
+		this.fileTimestamp= fileTimestamp;
+		this.fileEncoding= fileEncoding;
+		this.filePath= filePath;
+		
+		this.sourceType= sourceType;
+		this.sourceCode= sourceCode;
+		this.sourceSrcref= sourceSrcref;
+		
+		this.firstSrcref= firstSrcref;
+		this.lastSrcref= lastSrcref;
+		this.exprSrcref= exprSrcref;
+	}
+	
+	public FrameContext(final RJIO io) throws IOException {
+		this.position= io.readInt();
+		this.call= io.readString();
+		
+		this.fileName= io.readString();
+		this.fileTimestamp= io.readLong();
+		this.fileEncoding= io.readString();
+		this.filePath= io.readString();
+		
+		this.sourceType= io.readInt();
+		this.sourceCode= io.readString();
+		this.sourceSrcref= io.readIntArray();
+		
+		this.firstSrcref= io.readIntArray();
+		this.lastSrcref= io.readIntArray();
+		this.exprSrcref= io.readIntArray();
+	}
+	
+	@Override
+	public void writeExternal(final RJIO io) throws IOException {
+		io.writeInt(this.position);
+		io.writeString(this.call);
+		
+		io.writeString(this.fileName);
+		io.writeLong(this.fileTimestamp);
+		io.writeString(this.fileEncoding);
+		io.writeString(this.filePath);
+		
+		io.writeInt(this.sourceType);
+		io.writeString(this.sourceCode);
+		io.writeIntArray(this.sourceSrcref, (this.sourceSrcref != null) ? 6 : -1);
+		
+		io.writeIntArray(this.firstSrcref, (this.firstSrcref != null) ? 6 : -1);
+		io.writeIntArray(this.lastSrcref, (this.lastSrcref != null) ? 6 : -1);
+		io.writeIntArray(this.exprSrcref, (this.exprSrcref != null) ? 6 : -1);
+	}
+	
+	
+	public int getPosition() {
+		return this.position;
+	}
+	
+	public String getCall() {
+		return this.call;
+	}
+	
+	public String getFileName() {
+		return this.fileName;
+	}
+	
+	public long getFileTimestamp() {
+		return this.fileTimestamp;
+	}
+	
+	public String getFileEncoding() {
+		return this.fileEncoding;
+	}
+	
+	public String getFilePath() {
+		return this.filePath;
+	}
+	
+	public int getSourceType() {
+		return this.sourceType;
+	}
+	
+	public String getSourceCode() {
+		return this.sourceCode;
+	}
+	
+	public int[] getSourceSrcref() {
+		return this.sourceSrcref;
+	}
+	
+	public int[] getFirstSrcref() {
+		return this.firstSrcref;
+	}
+	
+	public int[] getLastSrcref() {
+		return this.lastSrcref;
+	}
+	
+	public int[] getExprSrcref() {
+		return this.exprSrcref;
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/FrameContextDetailRequest.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/FrameContextDetailRequest.java
new file mode 100644
index 0000000..733a51e
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/FrameContextDetailRequest.java
@@ -0,0 +1,47 @@
+/*=============================================================================#
+ # Copyright (c) 2011, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server.dbg;
+
+import java.io.IOException;
+
+import org.eclipse.statet.rj.data.RJIO;
+import org.eclipse.statet.rj.data.RJIOExternalizable;
+
+
+public class FrameContextDetailRequest implements RJIOExternalizable {
+	
+	
+	private final int position;
+	
+	
+	public FrameContextDetailRequest(final int position) {
+		this.position= position;
+	}
+	
+	public FrameContextDetailRequest(final RJIO io) throws IOException {
+		this.position= io.readInt();
+	}
+	
+	@Override
+	public void writeExternal(final RJIO io) throws IOException {
+		io.writeInt(this.position);
+	}
+	
+	
+	public int getPosition() {
+		return this.position;
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/FrameRef.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/FrameRef.java
new file mode 100644
index 0000000..49e7709
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/FrameRef.java
@@ -0,0 +1,80 @@
+/*=============================================================================#
+ # Copyright (c) 2014, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server.dbg;
+
+import java.io.IOException;
+
+import org.eclipse.statet.rj.data.RJIO;
+import org.eclipse.statet.rj.data.RJIOExternalizable;
+
+
+/**
+ * References a frame of the callstack.
+ */
+public abstract class FrameRef implements RJIOExternalizable {
+	
+	
+	public static final class ByPosition extends FrameRef {
+		
+		
+		private final int position;
+		
+		
+		public ByPosition(final int position) {
+			this.position= position;
+		}
+		
+		public ByPosition(final RJIO in) throws IOException {
+			this.position= in.readInt();
+		}
+		
+		@Override
+		public void writeExternal(final RJIO out) throws IOException {
+			out.writeInt(this.position);
+		}
+		
+		
+		public int getPosition() {
+			return this.position;
+		}
+		
+	}
+	
+	public static final class ByHandle extends FrameRef {
+		
+		
+		private final long handle;
+		
+		
+		public ByHandle(final long handle) {
+			this.handle= handle;
+		}
+		
+		public ByHandle(final RJIO in) throws IOException {
+			this.handle= in.readLong();
+		}
+		
+		@Override
+		public void writeExternal(final RJIO out) throws IOException {
+			out.writeLong(this.handle);
+		}
+		
+		
+		public long getHandle() {
+			return this.handle;
+		}
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/SetDebugReport.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/SetDebugReport.java
new file mode 100644
index 0000000..cc5d5ca
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/SetDebugReport.java
@@ -0,0 +1,49 @@
+/*=============================================================================#
+ # Copyright (c) 2011, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server.dbg;
+
+import java.io.IOException;
+
+import org.eclipse.statet.rj.data.RJIO;
+import org.eclipse.statet.rj.data.RJIOExternalizable;
+
+
+public class SetDebugReport implements RJIOExternalizable {
+	
+	
+	private static final int CHANGED=                      0x000000001;
+	
+	
+	private final int resultCode;
+	
+	
+	public SetDebugReport(final boolean changed) {
+		this.resultCode= (changed) ? CHANGED : 0;
+	}
+	
+	public SetDebugReport(final RJIO io) throws IOException {
+		this.resultCode= io.readInt();
+	}
+	@Override
+	public void writeExternal(final RJIO io) throws IOException {
+		io.writeInt(this.resultCode);
+	}
+	
+	
+	public boolean isChanged() {
+		return ((this.resultCode & CHANGED) != 0);
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/SetDebugRequest.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/SetDebugRequest.java
new file mode 100644
index 0000000..5ff2cac
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/SetDebugRequest.java
@@ -0,0 +1,124 @@
+/*=============================================================================#
+ # Copyright (c) 2011, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server.dbg;
+
+import java.io.IOException;
+
+import org.eclipse.statet.rj.data.RJIO;
+import org.eclipse.statet.rj.data.RJIOExternalizable;
+
+
+public class SetDebugRequest implements RJIOExternalizable {
+	
+	public static final int FRAME=                          1 << 0;
+	public static final int FUNCTION=                       1 << 1;
+	
+	private static final int ENABLED=                       1 << 0 << 24;
+	
+	private static final int TEMP=                          1 << 8;
+	
+	
+	private final long frameId;
+	private final String fName;
+	
+	private final int properties;
+	
+	
+	public SetDebugRequest(final long frameId, final boolean enable, final boolean temp) {
+		this.frameId= frameId;
+		this.fName= null;
+		int props= FRAME;
+		if (enable) {
+			props |= ENABLED;
+		}
+		if (temp) {
+			props |= TEMP;
+		}
+		this.properties= props;
+	}
+	
+	public SetDebugRequest(final int position, final String fName, final boolean enable, final boolean temp) {
+		this.frameId= position;
+		this.fName= fName;
+		int props= FUNCTION;
+		if (enable) {
+			props |= ENABLED;
+		}
+		if (temp) {
+			props |= TEMP;
+		}
+		this.properties= props;
+	}
+	
+	public SetDebugRequest(final RJIO io) throws IOException {
+		this.properties= io.readInt();
+		switch (this.properties & 0xf) {
+		case FRAME:
+			this.frameId= io.readLong();
+			this.fName= null;
+			break;
+		case FUNCTION:
+			this.frameId= io.readInt();
+			this.fName= io.readString();
+			break;
+		default:
+			this.frameId= 0;
+			this.fName= null;
+			break;
+		}
+	}
+	
+	@Override
+	public void writeExternal(final RJIO io) throws IOException {
+		io.writeInt(this.properties);
+		switch (this.properties & 0xf) {
+		case FRAME:
+			io.writeLong(this.frameId);
+			break;
+		case FUNCTION:
+			io.writeInt((int) this.frameId);
+			io.writeString(this.fName);
+			break;
+		default:
+			break;
+		}
+	}
+	
+	
+	public int getType() {
+		return (this.properties & 0xf);
+	}
+	
+	public long getHandle() {
+		return this.frameId;
+	}
+	
+	public int getPosition() {
+		return (int) this.frameId;
+	}
+	
+	public String getName() {
+		return this.fName;
+	}
+	
+	public boolean isTemp() {
+		return ((this.properties & TEMP) != 0);
+	}
+	
+	public int getDebug() {
+		return ((this.properties & 0xff000000) >>> 24);
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/SrcfileData.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/SrcfileData.java
new file mode 100644
index 0000000..8b8c33c
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/SrcfileData.java
@@ -0,0 +1,111 @@
+/*=============================================================================#
+ # Copyright (c) 2011, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server.dbg;
+
+import java.io.IOException;
+import java.util.Objects;
+
+import org.eclipse.statet.rj.data.RJIO;
+import org.eclipse.statet.rj.data.RJIOExternalizable;
+
+
+public class SrcfileData implements RJIOExternalizable {
+	
+	
+	private final String path;
+	private final String name;
+	private final long timestamp;
+	
+	
+	public SrcfileData(final String path, final String name, final long timestamp) {
+		this.path= path;
+		this.name= name;
+		this.timestamp= timestamp;
+	}
+	
+	public SrcfileData(final RJIO io) throws IOException {
+		this.path= io.readString();
+		this.name= io.readString();
+		this.timestamp= io.readLong();
+	}
+	
+	@Override
+	public void writeExternal(final RJIO io) throws IOException {
+		io.writeString(this.path);
+		io.writeString(this.name);
+		io.writeLong(this.timestamp);
+	}
+	
+	
+	/**
+	 * Returns the file path in the application (e.g. path in Eclipse workspace)
+	 * @return the path or <code>null</code>
+	 */
+	public String getPath() {
+		return this.path;
+	}
+	
+	/**
+	 * Returns the complete standardized file path usually compatible with 'filename' properties in
+	 * R.
+	 * @return the path or <code>null</code>
+	 */
+	public String getName() {
+		return this.name;
+	}
+	
+	/**
+	 * Returns the modification timestamp of the file compatible with 'timestamp' properties in R 
+	 * (seconds, not milliseconds).
+	 * 
+	 * @return the timestamp or <code>0</code>
+	 */
+	public long getTimestamp() {
+		return this.timestamp;
+	}
+	
+	
+	@Override
+	public int hashCode() {
+		return Objects.hashCode(this.path) * 17
+				^ Objects.hashCode(this.name)
+				^ (int)(this.timestamp ^ (this.timestamp >>> 32));
+	}
+	
+	@Override
+	public boolean equals(final Object obj) {
+		if (this == obj) {
+			return true;
+		}
+		if (obj instanceof SrcfileData) {
+			final SrcfileData other= (SrcfileData) obj;
+			return (Objects.equals(this.path, other.path)
+					&& Objects.equals(this.name, other.name)
+					&& this.timestamp == other.timestamp );
+		}
+		return super.equals(obj);
+	}
+	
+	
+	@Override
+	public String toString() {
+		final StringBuilder sb= new StringBuilder("SrcfileData"); //$NON-NLS-1$
+		sb.append("\n\t" + "path= ").append(this.path); //$NON-NLS-1$ //$NON-NLS-2$
+		sb.append("\n\t" + "name= ").append(this.name); //$NON-NLS-1$ //$NON-NLS-2$
+		sb.append("\n\t" + "timestamp= ").append(this.timestamp); //$NON-NLS-1$ //$NON-NLS-2$
+		return sb.toString();
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/Srcref.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/Srcref.java
new file mode 100644
index 0000000..bdaf9ed
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/Srcref.java
@@ -0,0 +1,153 @@
+/*=============================================================================#
+ # Copyright (c) 2011, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server.dbg;
+
+
+public class Srcref {
+	
+	
+	public static final int BEGIN_LINE= 0;
+	public static final int BEGIN_COLUMN= 4;
+	public static final int BEGIN_BYTE= 1;
+	
+	public static final int END_LINE= 2;
+	public static final int END_COLUMN= 5;
+	public static final int END_BYTE= 3;
+	
+	public static final int NA= Integer.MIN_VALUE;
+	
+	
+	public static int[] diff(final int[] base, final int[] rel) {
+		final int[] diff= new int[6];
+		
+		if (base[BEGIN_LINE] > 0 && rel[BEGIN_LINE] > 0) {
+			diff[BEGIN_LINE]= 1 + rel[BEGIN_LINE] - base[BEGIN_LINE];
+			if (diff[BEGIN_LINE] <= 0) {
+				return null;
+			}
+		}
+		else {
+			diff[BEGIN_LINE]= NA;
+		}
+		if (diff[BEGIN_LINE] == 1) {
+			if (base[BEGIN_COLUMN] > 0 && rel[BEGIN_COLUMN] > 0) {
+				diff[BEGIN_COLUMN]= 1 + rel[BEGIN_COLUMN] - base[BEGIN_COLUMN];
+				if (diff[BEGIN_COLUMN] <= 0) {
+					return null;
+				}
+			}
+			else {
+				diff[BEGIN_COLUMN]= NA;
+			}
+			if (base[BEGIN_BYTE] > 0 && rel[BEGIN_BYTE] > 0) {
+				diff[BEGIN_BYTE]= 1 + rel[BEGIN_BYTE] - base[BEGIN_BYTE];
+				if (diff[BEGIN_BYTE] <= 0) {
+					diff[BEGIN_BYTE]= NA;
+				}
+			}
+			else {
+				diff[BEGIN_BYTE]= NA;
+			}
+		}
+		
+		if (base[BEGIN_LINE] > 0 && rel[END_LINE] > 0) {
+			diff[END_LINE]= 1 + rel[END_LINE] - base[BEGIN_LINE];
+			if (diff[END_LINE] <= 0) {
+				return null;
+			}
+		}
+		else {
+			diff[END_LINE]= NA;
+		}
+		if (diff[END_LINE] == 1) {
+			if (base[BEGIN_COLUMN] > 0 && rel[END_COLUMN] > 0) {
+				diff[END_COLUMN]= 1 + rel[END_COLUMN] - base[BEGIN_COLUMN];
+				if (diff[END_COLUMN] <= 0) {
+					return null;
+				}
+			}
+			else {
+				diff[END_COLUMN]= NA;
+			}
+			if (base[BEGIN_BYTE] > 0 && rel[END_BYTE] > 0) {
+				diff[END_BYTE]= 1 + rel[END_BYTE] - base[BEGIN_BYTE];
+				if (diff[END_BYTE] <= 0) {
+					diff[END_BYTE]= NA;
+				}
+			}
+			else {
+				diff[END_BYTE]= NA;
+			}
+		}
+		
+		return diff;
+	}
+	
+	public static int addLine(final int base, final int diff) {
+		if (base > 0 && diff > 0) {
+			return base + diff - 1;
+		}
+		else {
+			return NA;
+		}
+	}
+	
+	public static int[] add(final int[] base, final int[] diff) {
+		final int[] sum= new int[6];
+		
+		sum[BEGIN_LINE]= addLine(base[BEGIN_LINE], diff[BEGIN_LINE]);
+		if (diff[BEGIN_LINE] == 1) {
+			if (base[BEGIN_COLUMN] > 0 && diff[BEGIN_COLUMN] > 0) {
+				sum[BEGIN_COLUMN]= base[BEGIN_COLUMN] + diff[BEGIN_COLUMN] - 1;
+			}
+			else {
+				sum[BEGIN_COLUMN]= NA;
+			}
+			if (base[BEGIN_BYTE] > 0 && diff[BEGIN_BYTE] > 0) {
+				sum[BEGIN_BYTE]= base[BEGIN_BYTE] + diff[BEGIN_BYTE] - 1;
+			}
+			else {
+				sum[BEGIN_BYTE]= NA;
+			}
+		}
+		else {
+			sum[BEGIN_COLUMN]= base[BEGIN_COLUMN];
+			sum[BEGIN_BYTE]= base[BEGIN_BYTE];
+		}
+		
+		sum[END_LINE]= addLine(base[BEGIN_LINE], diff[END_LINE]);
+		if (diff[END_LINE] == 1) {
+			if (base[BEGIN_COLUMN] > 0 && diff[END_COLUMN] > 0) {
+				sum[END_COLUMN]= base[BEGIN_COLUMN] + diff[END_COLUMN] - 1;
+			}
+			else {
+				sum[END_COLUMN]= NA;
+			}
+			if (base[BEGIN_BYTE] > 0 && diff[END_BYTE] > 0) {
+				sum[END_BYTE]= base[BEGIN_BYTE] + diff[END_BYTE] - 1;
+			}
+			else {
+				sum[END_BYTE]= NA;
+			}
+		}
+		else {
+			sum[END_COLUMN]= base[END_COLUMN];
+			sum[END_BYTE]= base[END_BYTE];
+		}
+		
+		return sum;
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/Tracepoint.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/Tracepoint.java
new file mode 100644
index 0000000..0552680
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/Tracepoint.java
@@ -0,0 +1,36 @@
+/*=============================================================================#
+ # Copyright (c) 2011, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server.dbg;
+
+
+public interface Tracepoint {
+	
+	/** all breakpoint types */
+	byte TYPE_BREAKPOINT=                                   0x0_0000_000F;
+	/** function breakpoint */
+	byte TYPE_FB=                                           0x0_0000_0001;
+	/** line breakpoint */
+	byte TYPE_LB=                                           0x0_0000_0002;
+	/** toplevel line breakpoint */
+	byte TYPE_TB=                                           0x0_0000_0003;
+	/** exception breakpoint */
+	byte TYPE_EB=                                           0x0_0000_0005;
+	
+	int TYPE_DELETED=                                       0x0_0100_0000;
+	
+	
+	int getType();
+	
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/TracepointEvent.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/TracepointEvent.java
new file mode 100644
index 0000000..65abac1
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/TracepointEvent.java
@@ -0,0 +1,99 @@
+/*=============================================================================#
+ # Copyright (c) 2011, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server.dbg;
+
+import java.io.IOException;
+
+import org.eclipse.statet.rj.data.RJIO;
+import org.eclipse.statet.rj.data.RJIOExternalizable;
+
+
+public class TracepointEvent implements Tracepoint, RJIOExternalizable {
+	
+	
+	public static final byte KIND_ABOUT_TO_HIT=            0x01;
+	
+	
+	private final byte kind;
+	
+	private final int type;
+	
+	private final String filePath;
+	private final long id;
+	
+	private final String label;
+	private final int flags;
+	private final String message;
+	
+	
+	public TracepointEvent(final byte kind, final int type, final String filePath, final long id,
+			final String label, final int flags, final String message) {
+		this.kind= kind;
+		this.type= type;
+		this.filePath= filePath;
+		this.id= id;
+		this.label= label;
+		this.flags= flags;
+		this.message= message;
+	}
+	
+	public TracepointEvent(final RJIO io) throws IOException {
+		this.kind= io.readByte();
+		this.type= io.readInt();
+		this.filePath= io.readString();
+		this.id= io.readLong();
+		this.label= io.readString();
+		this.flags= io.readInt();
+		this.message= io.readString();
+	}
+	
+	@Override
+	public void writeExternal(final RJIO io) throws IOException {
+		io.writeByte(this.kind);
+		io.writeInt(this.type);
+		io.writeString(this.filePath);
+		io.writeLong(this.id);
+		io.writeString(this.label);
+		io.writeInt(this.flags);
+		io.writeString(this.message);
+	}
+	
+	
+	public byte getKind() {
+		return this.kind;
+	}
+	
+	@Override
+	public int getType() {
+		return this.type;
+	}
+	
+	public String getFilePath() {
+		return this.filePath;
+	}
+	
+	public long getId() {
+		return this.id;
+	}
+	
+	public String getLabel() {
+		return this.label;
+	}
+	
+	public int getFlags() {
+		return this.flags;
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/TracepointInstallationReport.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/TracepointInstallationReport.java
new file mode 100644
index 0000000..109a091
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/TracepointInstallationReport.java
@@ -0,0 +1,53 @@
+/*=============================================================================#
+ # Copyright (c) 2011, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server.dbg;
+
+import java.io.IOException;
+
+import org.eclipse.statet.rj.data.RJIO;
+import org.eclipse.statet.rj.data.RJIOExternalizable;
+
+
+public class TracepointInstallationReport implements RJIOExternalizable {
+	
+	
+	public static final int NOTFOUND= 1;
+	public static final int FOUND_UNCHANGED= 2;
+	public static final int FOUND_UNSET= 3;
+	public static final int FOUND_SET= 4;
+	
+	
+	private final int[] results;
+	
+	
+	public TracepointInstallationReport(final int[] resultCodes) {
+		this.results= resultCodes;
+	}
+	
+	public TracepointInstallationReport(final RJIO io) throws IOException {
+		this.results= io.readIntArray();
+	}
+	
+	@Override
+	public void writeExternal(final RJIO io) throws IOException {
+		io.writeIntArray(this.results, this.results.length);
+	}
+	
+	
+	public int[] getInstallationResults() {
+		return this.results;
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/TracepointInstallationRequest.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/TracepointInstallationRequest.java
new file mode 100644
index 0000000..f1b384e
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/TracepointInstallationRequest.java
@@ -0,0 +1,23 @@
+/*=============================================================================#
+ # Copyright (c) 2016, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server.dbg;
+
+import org.eclipse.statet.rj.data.RJIOExternalizable;
+
+
+public abstract class TracepointInstallationRequest implements RJIOExternalizable {
+	
+	
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/TracepointPosition.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/TracepointPosition.java
new file mode 100644
index 0000000..9ce6cba
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/TracepointPosition.java
@@ -0,0 +1,129 @@
+/*=============================================================================#
+ # Copyright (c) 2011, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server.dbg;
+
+import java.io.IOException;
+import java.util.Arrays;
+
+import org.eclipse.statet.rj.data.RJIO;
+import org.eclipse.statet.rj.data.RJIOExternalizable;
+
+
+public class TracepointPosition implements Tracepoint, Comparable<TracepointPosition>,
+		RJIOExternalizable {
+	
+	
+	private final int type;
+	
+	private final long id;
+	
+	protected int[] exprIndex;
+	protected int[] exprSrcref;
+	
+	
+	public TracepointPosition(final int type, final long id,
+			final int[] index, final int[] srcref) {
+		this.type= type;
+		this.id= id;
+		this.exprIndex= index;
+		this.exprSrcref= srcref;
+	}
+	
+	TracepointPosition(final RJIO io) throws IOException {
+		this.type= io.readInt();
+		this.id= io.readLong();
+		this.exprIndex= io.readIntArray();
+		this.exprSrcref= io.readIntArray();
+	}
+	
+	@Override
+	public void writeExternal(final RJIO io) throws IOException {
+		io.writeInt(this.type);
+		io.writeLong(this.id);
+		io.writeIntArray(this.exprIndex, this.exprIndex.length);
+		io.writeIntArray(this.exprSrcref, (this.exprSrcref != null) ? 6 : -1);
+	}
+	
+	
+	@Override
+	public int getType() {
+		return this.type;
+	}
+	
+	public long getId() {
+		return this.id;
+	}
+	
+	public int[] getIndex() {
+		return this.exprIndex;
+	}
+	
+	public int[] getSrcref() {
+		return this.exprSrcref;
+	}
+	
+	
+	@Override
+	public int compareTo(final TracepointPosition other) {
+		for (int i= 0; i < this.exprIndex.length; i++) {
+			if (i < other.exprIndex.length) {
+				final int diff= this.exprIndex[i] - other.exprIndex[i];
+				if (diff != 0) {
+					return diff;
+				}
+				else {
+					continue;
+				}
+			}
+			return 1; // this deeper
+		}
+		if (this.exprIndex.length != other.exprIndex.length) {
+			return -1; // other deeper
+		}
+		return this.type - other.type;
+	}
+	
+	@Override
+	public int hashCode() {
+		int h= this.type;
+		for (int i= 0; i < this.exprIndex.length; i++) {
+			h= this.exprIndex[i] * 128 * (i + 1) ^ 2;
+		}
+		return h;
+	}
+	
+	@Override
+	public boolean equals(final Object obj) {
+		if (obj == this) {
+			return true;
+		}
+		if (!(obj instanceof TracepointPosition)) {
+			return false;
+		}
+		final TracepointPosition other= (TracepointPosition) obj;
+		return (this.type == other.type
+				&& Arrays.equals(this.exprIndex, other.exprIndex) );
+	}
+	
+	@Override
+	public String toString() {
+		final StringBuilder sb= new StringBuilder("TracepointPosition"); //$NON-NLS-1$
+		sb.append(" (type= ").append(this.type).append(")"); //$NON-NLS-1$ //$NON-NLS-2$
+		sb.append("\n\t" + "exprIndex= ").append(Arrays.toString(this.exprIndex)); //$NON-NLS-1$ //$NON-NLS-2$
+		sb.append("\n\t" + "exprSrcref= ").append(Arrays.toString(this.exprSrcref)); //$NON-NLS-1$ //$NON-NLS-2$
+		return sb.toString();
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/TracepointState.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/TracepointState.java
new file mode 100644
index 0000000..a2705a0
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/TracepointState.java
@@ -0,0 +1,286 @@
+/*=============================================================================#
+ # Copyright (c) 2011, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server.dbg;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.statet.rj.data.RJIO;
+import org.eclipse.statet.rj.data.RJIOExternalizable;
+
+
+public class TracepointState implements Tracepoint, Comparable<TracepointState>, RJIOExternalizable {
+	
+	
+	static final List<TracepointState> readList(final RJIO io) throws IOException {
+		final int l= io.readInt();
+		final List<TracepointState> list= new ArrayList<>(l);
+		String filePath= null;
+		String elementId= null;
+		for (int i= 0; i < l; i++) {
+			final TracepointState state= new TracepointState();
+			list.add(state);
+			state.type= io.readInt();
+			state.id= io.readLong();
+			state.filePath= io.readString();
+			if (state.filePath != null) {
+				filePath= state.filePath;
+			}
+			else {
+				state.filePath= filePath;
+			}
+			if (state.type == TYPE_DELETED) {
+				continue;
+			}
+			state.elementId= io.readString();
+			if (state.elementId != null) {
+				elementId= state.elementId;
+			}
+			else {
+				state.elementId= elementId;
+			}
+			state.index= io.readIntArray();
+			state.elementLabel= io.readString();
+			state.flags= io.readInt();
+			state.expr= io.readString();
+		}
+		return list;
+	}
+	
+	static final void writeList(final List<TracepointState> list, final RJIO io) throws IOException {
+		final int l= list.size();
+		io.writeInt(l);
+		String filePath= null;
+		String elementId= null;
+		for (int i= 0; i < l; i++) {
+			final TracepointState state= list.get(i);
+			io.writeInt(state.type);
+			io.writeLong(state.id);
+			if (state.filePath.equals(filePath)) {
+				io.writeString(null);
+			}
+			else {
+				filePath= state.filePath;
+				io.writeString(filePath);
+			}
+			if (state.type == TYPE_DELETED) {
+				continue;
+			}
+			if (state.elementId.equals(elementId)) {
+				io.writeString(null);
+			}
+			else {
+				elementId= state.elementId;
+				io.writeString(elementId);
+			}
+			io.writeIntArray(state.index, state.index.length);
+			io.writeString(state.elementLabel);
+			io.writeInt(state.flags);
+			io.writeString(state.expr);
+		}
+	}
+	
+	
+	public static final int FLAG_ENABLED=                  0x00000001;
+	
+	public static final int FLAG_MB_ENTRY=                 0x00010000;
+	public static final int FLAG_MB_EXIT=                  0x00020000;
+	
+	public static final int FLAG_EXPR_INVALID=             0x01000000;
+	public static final int FLAG_EXPR_EVAL_FAILED=         0x02000000;
+	
+	public static final String EB_FILEPATH= "exception"; //$NON-NLS-1$
+	
+	
+	private static final int[] NO_IDX= new int[0];
+	
+	
+	private int type;
+	
+	private String filePath;
+	private long id;
+	
+	private String elementId;
+	private int[] index;
+	
+	protected String elementLabel;
+	protected int flags;
+	protected String expr;
+	
+	
+	public TracepointState(final int type,
+			final String filePath, final long id, final String elementId, final int[] index,
+			final String elementLabel, final int flags, final String expr) {
+		if (filePath == null || elementId == null || index == null) {
+			throw new NullPointerException();
+		}
+		this.type= type;
+		this.filePath= filePath;
+		this.id= id;
+		this.elementId= elementId;
+		this.index= index;
+		this.elementLabel= elementLabel;
+		this.flags= flags;
+		this.expr= expr;
+	}
+	
+	public TracepointState(final int type,
+			final String filePath, final long id, final String elementId,
+			final String elementLabel, final int flags, final String expr) {
+		if (filePath == null || elementId == null) {
+			throw new NullPointerException();
+		}
+		this.type= type;
+		this.filePath= filePath;
+		this.id= id;
+		this.elementId= elementId;
+		this.index= NO_IDX;
+		this.elementLabel= elementLabel;
+		this.flags= flags;
+		this.expr= expr;
+	}
+	
+	public TracepointState(final int type,
+			final String filePath, final long id) {
+		if (type != TYPE_DELETED) {
+			throw new IllegalArgumentException("type= " + type); //$NON-NLS-1$
+		}
+		this.type= type;
+		this.filePath= filePath;
+		this.id= id;
+	}
+	
+	private TracepointState() {
+	}
+	
+	public TracepointState(final RJIO io) throws IOException {
+		this.type= io.readInt();
+		this.id= io.readLong();
+		this.filePath= io.readString();
+		if (this.type == TYPE_DELETED) {
+			return;
+		}
+		this.elementId= io.readString();
+		this.index= io.readIntArray();
+		this.elementLabel= io.readString();
+		this.flags= io.readInt();
+		this.expr= io.readString();
+	}
+	
+	@Override
+	public void writeExternal(final RJIO io) throws IOException {
+		io.writeInt(this.type);
+		io.writeLong(this.id);
+		io.writeString(this.filePath);
+		if (this.type == TYPE_DELETED) {
+			return;
+		}
+		io.writeString(this.elementId);
+		io.writeIntArray(this.index, this.index.length);
+		io.writeString(this.elementLabel);
+		io.writeInt(this.flags);
+		io.writeString(this.expr);
+	}
+	
+	@Override
+	public TracepointState clone() {
+		return new TracepointState(this.type,
+				this.filePath, this.id, this.elementId, this.index,
+				this.elementLabel, this.flags, this.expr );
+	}
+	
+	
+	@Override
+	public int getType() {
+		return this.type;
+	}
+	
+	public String getFilePath() {
+		return this.filePath;
+	}
+	
+	public long getId() {
+		return this.id;
+	}
+	
+	public String getElementId() {
+		return this.elementId;
+	}
+	
+	public int[] getIndex() {
+		return this.index;
+	}
+	
+	public boolean isEnabled() {
+		return ((this.flags & FLAG_ENABLED) != 0);
+	}
+	
+	public String getElementLabel() {
+		return this.elementLabel;
+	}
+	
+	public int getFlags() {
+		return this.flags;
+	}
+	
+	public String getExpr() {
+		return this.expr;
+	}
+	
+	
+	@Override
+	public int compareTo(final TracepointState other) {
+		{	final int diff= this.filePath.compareTo(other.filePath);
+			if (diff != 0) {
+				return diff;
+			}
+		}
+		if (this.elementId != null) {
+			if (other.elementId != null) {
+				final int diff= this.elementId.compareTo(other.elementId);
+				if (diff != 0) {
+					return diff;
+				}
+			}
+			else {
+				return 0x1000;
+			}
+		}
+		else if (other.elementId != null) {
+			return -0x1000;
+		}
+		return (this.id < other.id) ? -0x1 : 0x1;
+	}
+	
+	@Override
+	public int hashCode() {
+		return (int) (this.filePath.hashCode() * this.id);
+	}
+	
+	@Override
+	public boolean equals(final Object obj) {
+		if (this == obj) {
+			return true;
+		}
+		if (!(obj instanceof TracepointState)) {
+			return false;
+		}
+		final TracepointState other= (TracepointState) obj;
+		return (this.id == other.id
+				&& this.filePath.equals(other.filePath) );
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/TracepointStatesUpdate.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/TracepointStatesUpdate.java
new file mode 100644
index 0000000..b9842c8
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/TracepointStatesUpdate.java
@@ -0,0 +1,61 @@
+/*=============================================================================#
+ # Copyright (c) 2011, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server.dbg;
+
+import java.io.IOException;
+import java.util.List;
+
+import org.eclipse.statet.rj.data.RJIO;
+import org.eclipse.statet.rj.data.RJIOExternalizable;
+
+
+public class TracepointStatesUpdate implements RJIOExternalizable {
+	
+	
+	private final static int RESET=                         0x00000001;
+	
+	
+	private final List<TracepointState> states;
+	
+	private final int properties;
+	
+	
+	public TracepointStatesUpdate(final List<TracepointState> states,
+			final boolean reset) {
+		this.states= states;
+		this.properties= (reset) ? RESET : 0;
+	}
+	
+	public TracepointStatesUpdate(final RJIO io) throws IOException {
+		this.properties= io.readInt();
+		this.states= TracepointState.readList(io);
+	}
+	
+	@Override
+	public void writeExternal(final RJIO io) throws IOException {
+		io.writeInt(this.properties);
+		TracepointState.writeList(this.states, io);
+	}
+	
+	
+	public boolean getReset() {
+		return ((this.properties & RESET) != 0);
+	}
+	
+	public List<TracepointState> getStates() {
+		return this.states;
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/gr/Coord.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/gr/Coord.java
new file mode 100644
index 0000000..db08267
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/gr/Coord.java
@@ -0,0 +1,67 @@
+/*=============================================================================#
+ # Copyright (c) 2011, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server.gr;
+
+import java.io.IOException;
+
+import org.eclipse.statet.rj.data.RJIO;
+import org.eclipse.statet.rj.data.RJIOExternalizable;
+
+
+/**
+ * Single R graphic coordinate
+ */
+public class Coord implements RJIOExternalizable {
+	
+	
+	private double x;
+	private double y;
+	
+	
+	public Coord(final double x, final double y) {
+		this.x= x;
+		this.y= y;
+	}
+	
+	public Coord(final RJIO in) throws IOException {
+		this.x= in.readDouble();
+		this.y= in.readDouble();
+	}
+	
+	
+	@Override
+	public void writeExternal(final RJIO out) throws IOException {
+		out.writeDouble(this.x);
+		out.writeDouble(this.y);
+	}
+	
+	
+	public void setX(final double x) {
+		this.x= x;
+	}
+	
+	public void setY(final double y) {
+		this.y= y;
+	}
+	
+	public double getX() {
+		return this.x;
+	}
+	
+	public double getY() {
+		return this.y;
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/gr/GraOp.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/gr/GraOp.java
new file mode 100644
index 0000000..bc3c99a
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/gr/GraOp.java
@@ -0,0 +1,32 @@
+/*=============================================================================#
+ # Copyright (c) 2011, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server.gr;
+
+
+/**
+ * Graphic operations
+ */
+public interface GraOp {
+	
+	
+	// -- C2S sync
+	byte OP_CLOSE=                     0x01;
+	
+	byte OP_REQUEST_RESIZE=            0x08;
+	
+	byte OP_CONVERT_DEV2USER=          0x10;
+	byte OP_CONVERT_USER2DEV=          0x11;
+	
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/gr/RjsGraphic.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/gr/RjsGraphic.java
new file mode 100644
index 0000000..29f402d
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/gr/RjsGraphic.java
@@ -0,0 +1,243 @@
+/*=============================================================================#
+ # Copyright (c) 2011, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server.gr;
+
+import org.eclipse.statet.rj.server.GDCmdItem;
+import org.eclipse.statet.rj.server.MainCmdItem;
+import org.eclipse.statet.rj.server.RJ;
+
+
+public final class RjsGraphic {
+	
+	
+	public static final int STATE_CLOSED= -1;
+	public static final int STATE_OPENED= 1;
+	public static final int STATE_PAGED= 2;
+	
+	
+	private final RJ rj;
+	private final RjsGraphicManager manager;
+	
+	private final byte slot;
+	
+	private int devId;
+	int state;
+	
+	private int cachedStrWidthChar;
+	private double[] cachedStrWidthCharResult;
+	private String cachedStrWidthStr;
+	private double[] cachedStrWidthStrResult;
+	
+	
+	public RjsGraphic() {
+		this.rj= RJ.getInstance();
+		this.manager= this.rj.getGraphicManager();
+		this.slot= this.rj.getCurrentSlot();
+	}
+	
+	
+	public byte getSlot() {
+		return this.slot;
+	}
+	
+	public int getDevId() {
+		return this.devId;
+	}
+	
+	public int getState() {
+		return this.state;
+	}
+	
+	
+	public void initPage(final int devId, final int state, final double width, final double height,
+			final int canvasColor, final boolean isActive) {
+		if (this.devId != devId || this.state < STATE_OPENED) {
+			this.devId= devId;
+			this.manager.registerGraphic(this);
+		}
+		this.state= state;
+		
+		this.cachedStrWidthChar= -1;
+		this.cachedStrWidthStr= null;
+		
+		this.rj.sendMainCmd(new GDCmdItem.CInit(
+				this.devId, width, height, canvasColor, isActive, this.slot ));
+	}
+	
+	public void close() {
+		this.state= STATE_CLOSED;
+		this.manager.unregisterGraphic(this);
+		this.rj.sendMainCmd(new GDCmdItem.CCloseDevice(
+				this.devId, this.slot ));
+	}
+	
+	public void setMode(final int mode) {
+		if (this.state > 0) {
+			this.rj.sendMainCmd(new GDCmdItem.CSetMode(
+					this.devId, mode, this.slot ));
+		}
+	}
+	
+	public void activate() {
+		if (this.state > 0) {
+			this.manager.activate(this);
+		}
+	}
+	
+	public void deactivate() {
+		if (this.state > 0) {
+			this.manager.deactivate(this);
+		}
+	}
+	
+	public boolean newPageConfirm() {
+		return false;
+	}
+	
+	public double[] newPagePPI() {
+		return (double[]) this.rj.getClientProperty(this.slot, "display.ppi");
+	}
+	
+	public double[] newPageSize() {
+		final MainCmdItem answer= this.rj.sendMainCmd(new GDCmdItem.CGetSize(
+				this.devId, this.slot ));
+		return (answer instanceof GDCmdItem && answer.isOK() ) ?
+				((GDCmdItem) answer).getDoubleData() : null;
+	}
+	
+	
+	public void setColor(final int color) {
+		this.rj.sendMainCmd(new GDCmdItem.SetColor(
+				this.devId, color, this.slot ));
+	}
+	
+	public void setFill(final int color) {
+		this.rj.sendMainCmd(new GDCmdItem.SetFill(
+				this.devId, color, this.slot ));
+	}
+	
+	public void setLine(final int lty, final float lwd,
+			final byte cap, final byte join, final float joinMiterLimit) {
+		this.rj.sendMainCmd(new GDCmdItem.SetLine(
+				this.devId, lty, lwd, cap, join, joinMiterLimit, this.slot ));
+	}
+	
+	public void setClip(final double x0, final double x1, final double y0, final double y1) {
+		this.rj.sendMainCmd(new GDCmdItem.SetClip(
+				this.devId, x0, y0, x1, y1, this.slot ));
+	}
+	
+	public void drawLine(final double x0, final double y0, final double x1, final double y1) {
+		this.rj.sendMainCmd(new GDCmdItem.DrawLine(
+				this.devId, x0, y0, x1, y1, this.slot ));
+	}
+	
+	public void drawRect(final double x0, final double y0, final double x1, final double y1) {
+		this.rj.sendMainCmd(new GDCmdItem.DrawRect(
+				this.devId, x0, y0, x1, y1, this.slot ));
+	}
+	
+	public void drawPolyline(final double[] x, final double[] y) {
+		this.rj.sendMainCmd(new GDCmdItem.DrawPolyline(
+				this.devId, x, y, this.slot ));
+	}
+	
+	public void drawPolygon(final double[] x, final double[] y) {
+		this.rj.sendMainCmd(new GDCmdItem.DrawPolygon(
+				this.devId, x, y, this.slot ));
+	}
+	
+	public void drawPath(final int[] n, final double[] x, final double[] y, final int mode) {
+		this.rj.sendMainCmd(new GDCmdItem.DrawPath(
+				this.devId, n, x, y, mode, this.slot ));
+	}
+	
+	public void drawCircle(final double x, final double y, final double r) {
+		this.rj.sendMainCmd(new GDCmdItem.DrawCircle(
+				this.devId, x, y, r, this.slot ));
+	}
+	
+	
+	public void setFont(final String family, final int face, final float pointSize,
+			final float lineheight) {
+		this.rj.sendMainCmd(new GDCmdItem.SetFont(
+				this.devId, family, face, pointSize, lineheight, this.slot ));
+		
+		this.cachedStrWidthChar= -1;
+		this.cachedStrWidthStr= null;
+	}
+	
+	public double[] getStrWidth(final String str) {
+		if (str.length() == 1) {
+			final int ch= str.charAt(0);
+			if (ch == this.cachedStrWidthChar) {
+				return this.cachedStrWidthCharResult;
+			}
+			final MainCmdItem answer= this.rj.sendMainCmd(new GDCmdItem.CGetStrWidth(
+					this.devId, str, this.slot ));
+			this.cachedStrWidthCharResult= (answer instanceof GDCmdItem && answer.isOK() ) ?
+					((GDCmdItem) answer).getDoubleData() : null;
+			this.cachedStrWidthChar= ch;
+			return this.cachedStrWidthCharResult;
+		}
+		else {
+			if (str.equals(this.cachedStrWidthStr)) {
+				return this.cachedStrWidthStrResult;
+			}
+			final MainCmdItem answer= this.rj.sendMainCmd(new GDCmdItem.CGetStrWidth(
+					this.devId, str, this.slot ));
+			this.cachedStrWidthStrResult= (answer instanceof GDCmdItem && answer.isOK() ) ?
+					((GDCmdItem) answer).getDoubleData() : null;
+			this.cachedStrWidthStr= str;
+			return this.cachedStrWidthStrResult;
+		}
+	}
+	
+	public double[] getMetricInfo(final int ch) {
+		final MainCmdItem answer= this.rj.sendMainCmd(new GDCmdItem.CGetFontMetric(
+				this.devId, ch, this.slot ));
+		return (answer instanceof GDCmdItem && answer.isOK() ) ?
+				((GDCmdItem) answer).getDoubleData() : null;
+	}
+	
+	public void drawText(final String str, final double x, final double y, final double rDeg, final double hAdj) {
+		this.rj.sendMainCmd(new GDCmdItem.DrawText(
+				this.devId, str, x, y, rDeg, hAdj, this.slot ));
+	}
+	
+	
+	public void drawRaster(final byte[] imgData, final boolean imgAlpha, final int imgW, final int imgH,
+			final double x, final double y, final double w, final double h,
+			final double rDeg, final boolean interpolate) {
+		this.rj.sendMainCmd(new GDCmdItem.DrawRaster(this.devId, imgData, imgAlpha, imgW, imgH, x, y, w, h,
+				rDeg, interpolate, this.slot ));
+	}
+	
+	public byte[] capture(final int[] dim) {
+		final MainCmdItem answer= this.rj.sendMainCmd(new GDCmdItem.Capture(this.devId,
+				dim[0], dim[1], this.slot ));
+		return (answer instanceof GDCmdItem && answer.isOK() ) ?
+				((GDCmdItem) answer).getByteData() : null;
+	}
+	
+	
+	public double[] execLocator() {
+		final MainCmdItem answer= this.rj.sendMainCmd(new GDCmdItem.Locator(
+				this.devId, this.slot ));
+		return (answer instanceof GDCmdItem && answer.isOK() ) ?
+				((GDCmdItem) answer).getDoubleData() : null;
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/gr/RjsGraphicManager.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/gr/RjsGraphicManager.java
new file mode 100644
index 0000000..b167f5a
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/gr/RjsGraphicManager.java
@@ -0,0 +1,134 @@
+/*=============================================================================#
+ # Copyright (c) 2013, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server.gr;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
+import org.eclipse.statet.rj.server.GDCmdItem;
+import org.eclipse.statet.rj.server.RJ;
+
+
+public class RjsGraphicManager {
+	
+	
+	private static final Comparator<RjsGraphic> GRAPHIC_COMPARATOR= new Comparator<RjsGraphic>() {
+		
+		@Override
+		public int compare(final RjsGraphic o1, final RjsGraphic o2) {
+			return o1.getDevId() - o2.getDevId();
+		}
+		
+	};
+	
+	
+	private final List<RjsGraphic> graphicList= new ArrayList<>();
+	
+	private RjsGraphic activeGraphic;
+	
+	private int inOperation;
+	private RjsGraphic inOperationActiveGraphic;
+	
+	private final RJ rj;
+	
+	
+	public RjsGraphicManager(final RJ rj) {
+		this.rj= rj;
+	}
+	
+	
+	void registerGraphic(final RjsGraphic graphic) {
+		final int idx= Collections.binarySearch(this.graphicList, graphic, GRAPHIC_COMPARATOR);
+		if (idx >= 0) {
+			this.graphicList.set(idx, graphic);
+		}
+		else {
+			this.graphicList.add(-(idx+1), graphic);
+		}
+	}
+	
+	void unregisterGraphic(final RjsGraphic graphic) {
+		if (this.activeGraphic == graphic) {
+			this.activeGraphic= null;
+		}
+		if (this.inOperationActiveGraphic == graphic) {
+			this.inOperationActiveGraphic= null;
+		}
+		this.graphicList.remove(graphic);
+	}
+	
+	void activate(final RjsGraphic graphic) {
+		this.activeGraphic= graphic;
+		if (this.inOperation == 0) {
+			this.rj.sendMainCmd(new GDCmdItem.CSetActiveOn(
+					graphic.getDevId(), graphic.getSlot() ));
+		}
+	}
+	
+	void deactivate(final RjsGraphic graphic) {
+		if (this.activeGraphic == graphic) {
+			this.activeGraphic= null;
+		}
+		if (this.inOperation == 0) {
+			this.rj.sendMainCmd(new GDCmdItem.CSetActiveOff(
+					graphic.getDevId(), graphic.getSlot() ));
+		}
+	}
+	
+	
+	public RjsGraphic getGraphic(final int devId) {
+		for (int i= 0; i < this.graphicList.size(); i++) {
+			final RjsGraphic graphic= this.graphicList.get(i);
+			if (graphic.getDevId() < devId) {
+				continue;
+			}
+			else if (graphic.getDevId() > devId) {
+				break;
+			}
+			else {
+				return graphic;
+			}
+		}
+		return null;
+	}
+	
+	
+	protected void beginOperation() {
+		if (this.inOperation == 0) {
+			this.inOperationActiveGraphic= this.activeGraphic;
+		}
+		this.inOperation++;
+	}
+	
+	protected void endOperation() {
+		this.inOperation--;
+		if (this.inOperation == 0) {
+			if (this.inOperationActiveGraphic != this.activeGraphic) {
+				if (this.inOperationActiveGraphic != null) {
+					this.rj.sendMainCmd(new GDCmdItem.CSetActiveOff(
+							this.inOperationActiveGraphic.getDevId(), this.inOperationActiveGraphic.getSlot() ));
+				}
+				if (this.activeGraphic != null) {
+					this.rj.sendMainCmd(new GDCmdItem.CSetActiveOn(
+							this.activeGraphic.getDevId(), this.activeGraphic.getSlot() ));
+				}
+			}
+			this.inOperationActiveGraphic= null;
+		}
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/srv/CliUtil.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/srv/CliUtil.java
new file mode 100644
index 0000000..b16d89b
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/srv/CliUtil.java
@@ -0,0 +1,135 @@
+/*=============================================================================#
+ # Copyright (c) 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server.srv;
+
+import java.io.File;
+import java.io.PrintStream;
+import java.util.HashMap;
+import java.util.Map;
+
+
+public class CliUtil {
+	
+	
+	public static final int EXIT_ARGS_MISSING= ServerControl.EXIT_ARGS | 1;
+	public static final int EXIT_ARGS_INVALID= ServerControl.EXIT_ARGS | 2;
+	
+	
+	private final String command;
+	
+	private final String name;
+	
+	private final Map<String, String> options;
+	
+	
+	public CliUtil(final String[] args) {
+		int idx= 0;
+		if (args.length <= idx || args[idx].startsWith("-")) {
+			invalidArgs("Missing server command");
+		}
+		this.command= args[idx++]; 
+		if (!isValidCommand(this.command)) {
+			invalidArgs("Invalid server command '" + this.command + "'");
+		}
+		
+		if (isNameCommand(this.command) && args.length <= idx) {
+			invalidArgs("Missing server name");
+		}
+		this.name= args[idx++];
+		
+		this.options= new HashMap<>();
+		while (idx < args.length) {
+			final String arg= args[idx++];
+			if (arg.length() == 0 || arg.charAt(0) != '-') {
+				continue;
+			}
+			final int split= arg.indexOf('=');
+			if (split > 1) {
+				this.options.put(arg.substring(1, split), arg.substring(split + 1));
+			}
+			else if (split < 0) {
+				this.options.put(arg.substring(1), null);
+			}
+		}
+		
+		checkGlobalOptions();
+	}
+	
+	
+	protected boolean isValidCommand(final String command) {
+		return (command.equals("start") || command.equals("clean"));
+	}
+	
+	protected boolean isNameCommand(final String command) {
+		return true;
+	}
+	
+	protected void checkGlobalOptions() {
+		if (Boolean.parseBoolean(System.getProperty("org.eclipse.statet.rj.verbose"))
+				|| Boolean.parseBoolean(System.getProperty("org.eclipse.statet.rj.debug")) ) {
+			this.options.put("verbose", "true");
+		}
+		if (this.options.containsKey("log")) {
+			try {
+				final String fileName= this.options.get("log");
+				final File file= new File((fileName != null) ? fileName : "out.log");
+				final PrintStream stream= new PrintStream(file);
+				stream.println("(RServi) R node log");
+				stream.flush();
+				System.setOut(stream);
+				System.setErr(stream);
+			}
+			catch (final Throwable e) {
+				e.printStackTrace();
+				RMIServerControl.exit(ServerControl.EXIT_INIT_LOGGING_ERROR);
+			}
+		}
+	}
+	
+	
+	public String getCommand() {
+		return this.command;
+	}
+	
+	public String getName() {
+		return this.name;
+	}
+	
+	public Map<String, String> getOptions() {
+		return this.options;
+	}
+	
+	
+	public void invalidArgs(final String message) {
+		System.err.println(message);
+		printHelp();
+		RMIServerControl.exit(EXIT_ARGS_INVALID);
+	}
+	
+	public void printHelp() {
+		System.out.println("= Usage of RJserver command line control ================");
+		System.out.println("commands:");
+		System.out.println("  start <name>    adds server to RMIregistry");
+		System.out.println("  clean <name>    stops server/remove from RMIregistry");
+		System.out.println("name:             unique name in RMIregistry");
+		System.out.println("options:");
+		System.out.println("  -verbose        verbose logging");
+		System.out.println("  -server         class name of server implementation");
+		System.out.println("  -plugins=<..>   list of plugins");
+		System.out.println("  -auth=<..>      authetification method");
+	}
+	
+	
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/srv/RMIAddress.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/srv/RMIAddress.java
new file mode 100644
index 0000000..b9455f0
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/srv/RMIAddress.java
@@ -0,0 +1,309 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server.srv;
+
+import java.net.InetAddress;
+import java.net.MalformedURLException;
+import java.net.UnknownHostException;
+import java.rmi.registry.Registry;
+
+
+/**
+ * Address for RMI naming
+ */
+class RMIAddress {
+	
+	
+	public static final InetAddress LOOPBACK;
+	
+	public static void validate(final String address) throws MalformedURLException {
+		try {
+			new RMIAddress(address, false);
+		}
+		catch (final UnknownHostException e) {
+		}
+	}
+	
+	
+	private static String checkChars(final String s) throws MalformedURLException {
+		for (int i= 0; i < s.length(); i++) {
+			final char c= s.charAt(i);
+			if (c == '?' || c == '#' || c == '[' || c == ']' || c == '@'
+					|| c == '!' || c == '$' || c == '&' || c == '\'' || c == '(' || c == ')'
+					|| c == '*' || c == '+' || c == ',' || c == ';' || c == '='
+					|| c == '"' || c == '\\') {
+				throw new MalformedURLException("Character '"+c+"' is not allowed.");
+			}
+		}
+		return s;
+	}
+	
+	private static int checkPort(final String port) throws MalformedURLException {
+		final int portNum;
+		try {
+			portNum= (port != null) ? Integer.parseInt(port) : Registry.REGISTRY_PORT;
+		}
+		catch (final NumberFormatException e) {
+			throw new MalformedURLException("Invalid port, " + e.getMessage());
+		}
+		return checkPort(portNum);
+	}
+	
+	private static int checkPort(final int portNum) throws MalformedURLException {
+		if (portNum < 0 || portNum > 65535) {
+			throw new MalformedURLException("Invalid port, " + "Value must be in range 0-65535");
+		}
+		return portNum;
+	}
+	
+	private static String build(final String host, final int portNum, final String name) {
+		final StringBuilder sb= new StringBuilder("//"); //$NON-NLS-1$
+		if (host != null) {
+			sb.append(host);
+		}
+		sb.append(':');
+		if (portNum >= 0) {
+			sb.append(Integer.toString(portNum));
+		}
+		sb.append('/');
+		if (name != null) {
+			sb.append(name);
+		}
+		return sb.toString();
+	}
+	
+	
+	static {
+		InetAddress loopbackAddress;
+		try {
+			loopbackAddress= InetAddress.getByAddress("localhost", new byte[] { 127, 0, 0, 1 }); //$NON-NLS-1$
+		}
+		catch (final UnknownHostException e) {
+			loopbackAddress= null;
+			e.printStackTrace();
+		}
+		LOOPBACK= loopbackAddress;
+	}
+	
+	
+	private final String host;
+	private InetAddress hostAddress;
+	private final String port;
+	private final int portNum;
+	private final boolean ssl;
+	private final String path;
+	
+	private String address;
+	private String ser;
+	
+	
+	public RMIAddress(final String address) throws UnknownHostException, MalformedURLException {
+		this(address, true);
+	}
+	
+	public RMIAddress(final String host, final int portNum, final String name) throws UnknownHostException, MalformedURLException {
+		this(build(host, portNum, name), true);
+	}
+	
+	public RMIAddress(final InetAddress address, final int port, final String name)
+			throws MalformedURLException {
+		this(address.getHostAddress(), address, Integer.toString(port), checkPort(port), false,
+				(name != null) ? checkChars(name) : "");
+	}
+	
+	public RMIAddress(final InetAddress address, final int port, final boolean ssl, final String name)
+			throws MalformedURLException {
+		this(address.getHostAddress(), address, Integer.toString(port), checkPort(port), ssl,
+				(name != null) ? checkChars(name) : "");
+	}
+	
+	public RMIAddress(final RMIAddress registry, final String name) throws MalformedURLException {
+		this(registry.host, registry.hostAddress, registry.port, registry.portNum, registry.ssl,
+				(name != null) ? checkChars(name) : "");
+	}
+	
+	private RMIAddress(String address, final boolean resolve) throws UnknownHostException, MalformedURLException {
+		address= checkChars(address);
+		
+		if (address.startsWith("ssl:")) { //$NON-NLS-1$
+			address= address.substring(4);
+			this.ssl= true;
+		}
+		else {
+			this.ssl= false;
+		}
+		if (address.startsWith("rmi:")) { //$NON-NLS-1$
+			address= address.substring(4);
+		}
+		if (!address.startsWith("//")) { //$NON-NLS-1$
+			address= "//"+address; //$NON-NLS-1$
+		}
+		
+		final int idxPort= address.indexOf(':', 2);
+		final int idxPath= address.indexOf('/', 2);
+		if (idxPort > 0) {
+			if (idxPath <= idxPort) {
+				throw new IllegalArgumentException();
+			}
+			this.host= (2 < idxPort) ? address.substring(2, idxPort) : null;
+			this.port= (idxPort+1 < idxPath) ? address.substring(idxPort+1, idxPath) : null;
+			this.path= address.substring(idxPath+1);
+		}
+		else if (idxPath > 0){
+			this.host= (2 < idxPath) ? address.substring(2, idxPath) : null;
+			this.port= null;
+			this.path= address.substring(idxPath+1);
+		}
+		else {
+			this.host= null;
+			this.port= null;
+			this.path= address.substring(2);
+		}
+		try {
+			this.portNum= checkPort(this.port);
+		}
+		catch (final NumberFormatException e) {
+			throw new MalformedURLException("Invalid port, " + e.getLocalizedMessage());
+		}
+		if (resolve) {
+			this.hostAddress= (this.host != null) ? InetAddress.getByName(this.host) : LOOPBACK;
+		}
+	}
+	
+	private RMIAddress(final String host, final InetAddress hostAddress, final String port,
+			final int portNum, final boolean ssl, final String path) {
+		this.host= host;
+		this.hostAddress= hostAddress;
+		this.port= port;
+		this.portNum= portNum;
+		this.ssl= ssl;
+		this.path= path;
+	}
+	
+	
+	/**
+	 * @return the host as specified when creating the address
+	 */
+	public String getHost() {
+		return (this.host != null) ? this.host : this.hostAddress.getHostAddress();
+	}
+	
+	public InetAddress getHostAddress() {
+		return this.hostAddress;
+	}
+	
+	public boolean isLocalHost() {
+		if (this.hostAddress.isLoopbackAddress()) {
+			return true;
+		}
+		try {
+			final InetAddress localhost= InetAddress.getLocalHost();
+			if (this.hostAddress.equals(localhost)) {
+				return true;
+			}
+		}
+		catch (final UnknownHostException e) {}
+		catch (final ArrayIndexOutOfBoundsException e) { /* JVM bug */ }
+		
+		return false;
+	}
+	
+	/**
+	 * @return the port
+	 */
+	public String getPort() {
+		return this.port;
+	}
+	
+	public int getPortNum() {
+		return this.portNum;
+	}
+	
+	/**
+	 * @return the name
+	 */
+	public String getName() {
+		return this.path;
+	}
+	
+	/**
+	 * Standard string presentation to use for rmi
+	 * @return
+	 */
+	public String getAddress() {
+		if (this.address == null) {
+			final StringBuilder sb= new StringBuilder(32);
+			sb.append("rmi://"); //$NON-NLS-1$
+			if (this.host != null) {
+				sb.append(this.host);
+			}
+			if (this.portNum != Registry.REGISTRY_PORT) {
+				sb.append(':');
+				sb.append(this.port);
+			}
+			sb.append('/');
+			sb.append(this.path);
+			this.address= sb.toString();
+		}
+		return this.address;
+	}
+	
+	public RMIAddress getRegistryAddress() {
+		return new RMIAddress(this.host, this.hostAddress, this.port, this.portNum, this.ssl, "");
+	}
+	
+	/**
+	 * 
+	 * @return if SSL is enabled
+	 * 
+	 * @since 1.4
+	 */
+	public boolean isSSL() {
+		return this.ssl;
+	}
+	
+	
+	@Override
+	public String toString() {
+		if (this.ser == null) {
+			final String address= getAddress();
+			if (this.ssl) {
+				this.ser= "ssl:" + address;
+			}
+			else {
+				this.ser= address;
+			}
+		}
+		return this.ser;
+	}
+	
+	@Override
+	public int hashCode() {
+		return toString().hashCode();
+	}
+	
+	@Override
+	public boolean equals(final Object obj) {
+		if (!(obj instanceof RMIAddress)) {
+			return false;
+		}
+		final RMIAddress other= (RMIAddress) obj;
+		return (this.hostAddress.equals(other.hostAddress)
+				&& this.portNum == other.portNum
+				&& this.ssl == other.ssl
+				&& this.path.equals(other.path) );
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/srv/RMIServerControl.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/srv/RMIServerControl.java
new file mode 100644
index 0000000..3c33c5d
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/srv/RMIServerControl.java
@@ -0,0 +1,410 @@
+/*=============================================================================#
+ # Copyright (c) 2008, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server.srv;
+
+import java.io.StreamCorruptedException;
+import java.lang.reflect.Constructor;
+import java.net.MalformedURLException;
+import java.net.UnknownHostException;
+import java.rmi.AlreadyBoundException;
+import java.rmi.NoSuchObjectException;
+import java.rmi.NotBoundException;
+import java.rmi.Remote;
+import java.rmi.RemoteException;
+import java.rmi.UnmarshalException;
+import java.rmi.registry.LocateRegistry;
+import java.rmi.registry.Registry;
+import java.rmi.server.RMIClientSocketFactory;
+import java.rmi.server.RMIServerSocketFactory;
+import java.rmi.server.UnicastRemoteObject;
+import java.text.MessageFormat;
+import java.util.Map;
+import java.util.logging.Level;
+import java.util.logging.LogRecord;
+
+import javax.rmi.ssl.SslRMIClientSocketFactory;
+import javax.rmi.ssl.SslRMIServerSocketFactory;
+
+import org.eclipse.statet.rj.RjException;
+import org.eclipse.statet.rj.RjInvalidConfigurationException;
+import org.eclipse.statet.rj.server.RjsComConfig;
+import org.eclipse.statet.rj.server.Server;
+import org.eclipse.statet.rj.server.srv.engine.SrvEngineServer;
+import org.eclipse.statet.rj.server.srvext.ServerAuthMethod;
+import org.eclipse.statet.rj.server.srvext.ServerRuntimePlugin;
+import org.eclipse.statet.rj.server.util.ServerUtils;
+
+
+public class RMIServerControl extends ServerControl {
+	
+	
+	public static final int EXIT_REGISTRY_PROBLEM= 150;
+	public static final int EXIT_REGISTRY_INVALID_ADDRESS= 151;
+	public static final int EXIT_REGISTRY_CONNECTING_ERROR= 151;
+	public static final int EXIT_REGISTRY_SERVER_STILL_ACTIVE= 152;
+	public static final int EXIT_REGISTRY_ALREADY_BOUND= 153;
+	public static final int EXIT_REGISTRY_CLEAN_FAILED= 155;
+	public static final int EXIT_REGISTRY_BIND_FAILED= 156;
+	public static final int EXIT_START_RENGINE_ERROR= 161;
+	
+	
+	protected final String logPrefix;
+	
+	private final RMIAddress rmiAddress;
+	
+	private Server mainServer;
+	private boolean isPublished;
+	
+	
+	public RMIServerControl(final String name, final Map<String, String> options) {
+		super(options);
+		final int lastSegment= name.lastIndexOf('/');
+		this.logPrefix= "[Control:"+((lastSegment >= 0) ? name.substring(lastSegment+1) : name)+"]";
+		
+		{	RMIAddress address= null;
+			Exception error= null;
+			try {
+				address= new RMIAddress(name);
+			}
+			catch (final MalformedURLException e) {
+				error= e;
+			}
+			catch (final UnknownHostException e) {
+				error= e;
+			}
+			if (address == null) {
+				final LogRecord record= new LogRecord(Level.SEVERE,
+						"{0} the server address ''{1}'' is invalid.");
+				record.setParameters(new Object[] { this.logPrefix, name });
+				record.setThrown(error);
+				LOGGER.log(record);
+				
+				exit(EXIT_REGISTRY_INVALID_ADDRESS);
+			}
+			this.rmiAddress= address;
+		}
+		
+		if (options != null) {
+			if (options.containsKey("verbose")) {
+				initVerbose();
+			}
+		}
+	}
+	
+	
+	public SrvEngineServer initServer() {
+		LOGGER.log(Level.INFO, "{0} Initializing R engine server...", this.logPrefix);
+		try {
+			final String serverType= getOptions().get("server"); //$NON-NLS-1$
+			if (serverType == null) {
+				final ServerAuthMethod auth= createServerAuth(getOptions().remove("auth")); //$NON-NLS-1$
+				return new SrvEngineServer(this, auth);
+			}
+			else {
+				final Class<SrvEngineServer> serverClass= (Class<SrvEngineServer>) Class.forName(serverType);
+				final Constructor<SrvEngineServer> constructor= serverClass.getConstructor(RMIServerControl.class);
+				return constructor.newInstance(this);
+			}
+		}
+		catch (final Exception e) {
+			final LogRecord record= new LogRecord(Level.SEVERE,
+					"{0} Failed to initialize R engine server.");
+			record.setParameters(new Object[] { this.logPrefix });
+			record.setThrown(e);
+			LOGGER.log(record);
+			
+			exit(EXIT_INIT_RENGINE_ERROR);
+			throw new RuntimeException();
+		}
+	}
+	
+	protected Registry getRegistry() throws RemoteException {
+		RMIClientSocketFactory csf= null;
+		if (this.rmiAddress.isSSL()) {
+			csf= new SslRMIClientSocketFactory();
+		}
+		return LocateRegistry.getRegistry(this.rmiAddress.getHost(), this.rmiAddress.getPortNum(), csf);
+	}
+	
+	public String getName() {
+		return this.rmiAddress.getName();
+	}
+	
+	public Remote exportObject(final Remote obj) throws RemoteException {
+		RMIClientSocketFactory csf= RjsComConfig.getRMIServerClientSocketFactory();
+		RMIServerSocketFactory ssf= null;
+		if (this.rmiAddress.isSSL()) {
+			csf= new SslRMIClientSocketFactory();
+			ssf= new SslRMIServerSocketFactory(null, null, true);
+		}
+		return UnicastRemoteObject.exportObject(obj, 0, csf, ssf);
+	}
+	
+	
+	protected void publishServer(final SrvEngineServer server) {
+		try {
+			System.setSecurityManager(new SecurityManager());
+			final Registry registry= getRegistry();
+			Server stub= (Server) exportObject(server);
+			this.mainServer= server;
+			try {
+				registry.bind(getName(), stub);
+			}
+			catch (final AlreadyBoundException boundException) {
+				if (server.getConfigUnbindOnStartup() && unbindDead() == 0) {
+					registry.bind(getName(), stub);
+				}
+				else {
+					throw boundException;
+				}
+			}
+			catch (final RemoteException remoteException) {
+				if (remoteException.getCause() instanceof UnmarshalException
+						&& remoteException.getCause().getCause() instanceof StreamCorruptedException
+						&& RjsComConfig.getRMIServerClientSocketFactory() != null) {
+					stub= null;
+					try {
+						UnicastRemoteObject.unexportObject(server, true);
+						stub= (Server) UnicastRemoteObject.exportObject(server, 0, null, null);
+					}
+					catch (final Exception testException) {}
+					if (stub != null) {
+						final LogRecord record= new LogRecord(Level.SEVERE,
+								"{0} caught StreamCorruptedException \nretrying without socket factory to reveal other potential problems.");
+						record.setParameters(new Object[] { this.logPrefix });
+						record.setThrown(remoteException);
+						LOGGER.log(record);
+						registry.bind(getName(), stub);
+						registry.unbind(getName());
+						throw new RjException("No error without socket factory, use the Java property 'org.eclipse.statet.rj.rmi.disableSocketFactory' to disable the factory.");
+					}
+				}
+				throw remoteException;
+			}
+			Runtime.getRuntime().addShutdownHook(new Thread() {
+				@Override
+				public void run() {
+					checkCleanup();
+				}
+			});
+			this.isPublished= true;
+			LOGGER.log(Level.INFO, "{0} server is added to registry - ready.", this.logPrefix);
+			
+			return;
+		}
+		catch (final Exception e) {
+			final LogRecord record= new LogRecord(Level.SEVERE,
+					"{0} init server failed.");
+			record.setParameters(new Object[] { this.logPrefix });
+			record.setThrown(e);
+			LOGGER.log(record);
+			
+			if (e instanceof AlreadyBoundException) {
+				exit(EXIT_REGISTRY_ALREADY_BOUND);
+			}
+			
+			checkCleanup();
+			exit(EXIT_REGISTRY_BIND_FAILED);
+		}
+	}
+	
+	/**
+	 * @return <code>true</code> if it was removed, otherwise <code>false</code>
+	 */
+	protected int unbindDead() {
+		Remote remote;
+		try {
+			final Registry registry= getRegistry();
+			remote= registry.lookup(getName());
+		}
+		catch (final NotBoundException lookupException) {
+			return 0;
+		}
+		catch (final RemoteException lookupException) {
+			return EXIT_REGISTRY_CONNECTING_ERROR;
+		}
+		if (!(remote instanceof Server)) {
+			return 2;
+		}
+		try {
+			((Server) remote).getInfo();
+			return EXIT_REGISTRY_SERVER_STILL_ACTIVE;
+		}
+		catch (final RemoteException deadException) {
+			try {
+				final Registry registry= getRegistry();
+				registry.unbind(getName());
+				LOGGER.log(Level.INFO,
+						"{0} dead server removed from registry.",
+						this.logPrefix);
+				return 0;
+			}
+			catch (final Exception unbindException) {
+				return EXIT_REGISTRY_CLEAN_FAILED;
+			}
+		}
+	}
+	
+	public void checkCleanup() {
+		if (this.mainServer == null) {
+			return;
+		}
+		LOGGER.log(Level.INFO, "{0} cleaning up server resources...", this.logPrefix);
+		try {
+			final Registry registry= getRegistry();
+			registry.unbind(getName());
+		}
+		catch (final NotBoundException e) {
+			// ok
+		}
+		catch (final Exception e) {
+			final LogRecord record= new LogRecord(this.isPublished ? Level.SEVERE : Level.INFO,
+					"{0} cleaning up server resources failed.");
+			record.setParameters(new Object[] { this.logPrefix });
+			record.setThrown(e);
+			LOGGER.log(record);
+		}
+		try {
+			UnicastRemoteObject.unexportObject(this.mainServer, true);
+		}
+		catch (final NoSuchObjectException e) {
+			// ok
+		}
+		this.mainServer= null;
+		System.gc();
+	}
+	
+	public ServerAuthMethod createServerAuth(final String config) throws RjException {
+		// auth
+		final String authType;
+		final String authConfig;
+		try {
+			final String[] auth= ServerUtils.getArgSubValue(config);
+			if (auth[0].length() == 0) {
+				throw new RjInvalidConfigurationException("Missing 'auth' configuration");
+			}
+			else if (auth[0].equals("none")) {
+				authType= "org.eclipse.statet.rj.server.srvext.auth.NoAuthMethod";
+			}
+			else if (auth[0].equals("name-pass")) {
+				authType= "org.eclipse.statet.rj.server.srvext.auth.SimpleNamePassAuthMethod";
+			}
+			else if (auth[0].equals("fx")) {
+				authType= "org.eclipse.statet.rj.server.srvext.auth.FxAuthMethod";
+			}
+			else if (auth[0].equals("local-shaj")) {
+				authType= "org.eclipse.statet.rj.server.srvext.auth.LocalShajAuthMethod";
+			}
+			else {
+				authType= auth[0];
+			}
+			authConfig= auth[1];
+		}
+		catch (final Exception e) {
+			final LogRecord record= new LogRecord(Level.SEVERE,
+					"{0} init authentication method failed.");
+			record.setParameters(new Object[] { this.logPrefix });
+			record.setThrown(e);
+			LOGGER.log(record);
+			throw new RjInvalidConfigurationException("Init authentication method failed.", e);
+		}
+		try {
+			final Class<ServerAuthMethod> authClazz= (Class<ServerAuthMethod>) Class.forName(authType);
+			final ServerAuthMethod authMethod= authClazz.newInstance();
+			authMethod.init(authConfig);
+			return authMethod;
+		}
+		catch (final Exception e) {
+			final LogRecord record= new LogRecord(Level.SEVERE,
+					"{0} init authentication method ''{1}'' failed.");
+			record.setParameters(new Object[] { this.logPrefix, authType });
+			record.setThrown(e);
+			LOGGER.log(record);
+			throw new RjException(MessageFormat.format("Init authentication method failed ''{0}''.", authType), e);
+		}
+	}
+	
+	
+	public void start(final SrvEngineServer server) {
+		try {
+			server.start(new ServerRuntimePlugin() {
+				
+				@Override
+				public String getSymbolicName() {
+					return "rmi";
+				}
+				
+				@Override
+				public void rjIdle() throws Exception {
+				}
+				
+				@Override
+				public void rjStop(final int state) throws Exception {
+					if (state == 0) {
+						try {
+							Thread.sleep(1000);
+						}
+						catch (final InterruptedException e) {
+						}
+					}
+					checkCleanup();
+				};
+				
+			});
+		}
+		catch (final Exception e) {
+			final LogRecord record= new LogRecord(Level.SEVERE,
+					"{0} Starting R engine server failed.");
+			record.setParameters(new Object[] { this.logPrefix });
+			record.setThrown(e);
+			LOGGER.log(record);
+			
+			exit(EXIT_INIT_RENGINE_ERROR | 8);
+		}
+		
+		publishServer(server);
+	}
+	
+	public void clean() {
+		final int dead= unbindDead();
+		if (dead == 0) {
+			exit(0);
+			return;
+		}
+		if (dead == EXIT_REGISTRY_SERVER_STILL_ACTIVE && !getOptions().containsKey("force")) {
+			exit(EXIT_REGISTRY_SERVER_STILL_ACTIVE);
+		}
+		try {
+			final Registry registry= getRegistry();
+			registry.unbind(getName());
+			LOGGER.log(Level.INFO,
+					"{0} server removed from registry.",
+					this.logPrefix);
+		}
+		catch (final NotBoundException e) {
+			exit(0);
+		}
+		catch (final RemoteException e) {
+			final LogRecord record= new LogRecord(Level.SEVERE,
+					"{0} removing server from registry failed.");
+			record.setParameters(new Object[] { this.logPrefix });
+			record.setThrown(e);
+			LOGGER.log(record);
+			
+			exit(EXIT_REGISTRY_CONNECTING_ERROR);
+		}
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/srv/ServerControl.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/srv/ServerControl.java
new file mode 100644
index 0000000..623e6fa
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/srv/ServerControl.java
@@ -0,0 +1,111 @@
+/*=============================================================================#
+ # Copyright (c) 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server.srv;
+
+import java.util.Map;
+import java.util.logging.ConsoleHandler;
+import java.util.logging.Handler;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import org.eclipse.statet.rj.server.util.ServerUtils;
+
+
+public abstract class ServerControl {
+	
+	
+	public static final int EXIT_ARGS=                      130;
+	
+	public static final int EXIT_INIT=                      140;
+	
+	public static final int EXIT_INIT_LOGGING_ERROR=        EXIT_INIT | 1;
+	public static final int EXIT_INIT_AUTHMETHOD_ERROR=     EXIT_INIT | 3;
+	public static final int EXIT_INIT_RENGINE_ERROR=        EXIT_INIT | 5;
+	
+	
+	private static boolean VERBOSE= false;
+	private static boolean VERBOSE_ON_ERROR= true;
+	
+	public static void initVerbose() {
+		if (VERBOSE) {
+			return;
+		}
+		VERBOSE= true;
+		
+		LOGGER.setLevel(Level.ALL); // default is Level.INFO
+//		System.setProperty("java.rmi.server.logCalls", "true");
+//		RemoteServer.setLog(System.err);
+		ClassLoader.getSystemClassLoader().setDefaultAssertionStatus(true);
+		
+		Logger logger= LOGGER;
+		SEARCH_CONSOLE: while (logger != null) {
+			for (final Handler handler : logger.getHandlers()) {
+				if (handler instanceof ConsoleHandler) {
+					handler.setLevel(Level.ALL);
+					break SEARCH_CONSOLE;
+				}
+			}
+			if (!logger.getUseParentHandlers()) {
+				break SEARCH_CONSOLE;
+			}
+			logger= logger.getParent();
+		}
+		
+		final StringBuilder sb= new StringBuilder(256);
+		
+		LOGGER.log(Level.CONFIG, "verbose mode enabled.");
+		
+		sb.setLength(0);
+		sb.append("java properties:");
+		ServerUtils.prettyPrint(System.getProperties(), sb);
+		LOGGER.log(Level.CONFIG, sb.toString());
+		
+		sb.setLength(0);
+		sb.append("env variables:");
+		ServerUtils.prettyPrint(System.getenv(), sb);
+		LOGGER.log(Level.CONFIG, sb.toString());
+	}
+	
+	public static void exit(final int status) {
+		try {
+			if (status != 0 && VERBOSE_ON_ERROR) {
+				initVerbose();
+			}
+			System.err.flush();
+			System.out.flush();
+		}
+		finally {
+			System.exit(status);
+		}
+	}
+	
+	
+	protected static final Logger LOGGER= Logger.getLogger("org.eclipse.statet.rj.server");
+	
+	
+	
+	private final Map<String, String> options;
+	
+	
+	public ServerControl(final Map<String, String> options) {
+		this.options= options;
+	}
+	
+	
+	public Map<String, String> getOptions() {
+		return this.options;
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/srv/engine/REngineImpl.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/srv/engine/REngineImpl.java
new file mode 100644
index 0000000..1afe71f
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/srv/engine/REngineImpl.java
@@ -0,0 +1,76 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server.srv.engine;
+
+import java.rmi.RemoteException;
+import java.util.Map;
+
+import org.eclipse.statet.rj.server.REngine;
+import org.eclipse.statet.rj.server.RjsComObject;
+import org.eclipse.statet.rj.server.Server;
+import org.eclipse.statet.rj.server.srvext.Client;
+
+
+public final class REngineImpl implements REngine {
+	
+	
+	private final Server publicServer;
+	private final SrvEngine srvEngine;
+	private final Client client;
+	
+	
+	public REngineImpl(final Server publicServer, final SrvEngine srvEngine, final Client client) {
+		this.publicServer= publicServer;
+		this.srvEngine= srvEngine;
+		this.client= client;
+	}
+	
+	
+	@Override
+	public Server getPublic() throws RemoteException {
+		return this.publicServer;
+	}
+	
+	@Override
+	public Map<String, Object> getPlatformData() {
+		return this.srvEngine.getPlatformData();
+	}
+	
+	@Override
+	public void setProperties(final Map<String, ? extends Object> properties) throws RemoteException {
+		this.srvEngine.setProperties(this.client, properties);
+	}
+	
+	@Override
+	public void disconnect() throws RemoteException {
+		this.srvEngine.disconnect(this.client);
+	}
+	
+	@Override
+	public RjsComObject runAsync(final RjsComObject com) throws RemoteException {
+		return this.srvEngine.runAsync(this.client, com);
+	}
+	
+	@Override
+	public RjsComObject runMainLoop(final RjsComObject com) throws RemoteException {
+		return this.srvEngine.runMainLoop(this.client, com);
+	}
+	
+	@Override
+	public boolean isClosed() throws RemoteException {
+		return (this.srvEngine.getCurrentClient() != this.client);
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/srv/engine/SrvEngine.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/srv/engine/SrvEngine.java
new file mode 100644
index 0000000..d3deef1
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/srv/engine/SrvEngine.java
@@ -0,0 +1,45 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server.srv.engine;
+
+import java.rmi.RemoteException;
+import java.util.Map;
+
+import org.eclipse.statet.rj.server.RjsComObject;
+import org.eclipse.statet.rj.server.Server;
+import org.eclipse.statet.rj.server.srv.RMIServerControl;
+import org.eclipse.statet.rj.server.srvext.Client;
+
+
+public interface SrvEngine {
+	
+	
+	void init(RMIServerControl control, Server publicServer, Map<String, Object> more) throws Exception;
+	
+	int[] getVersion();
+	
+	int getState();
+	Client getCurrentClient();
+	Map<String, Object> getPlatformData();
+	
+	Object start(Client client, Map<String, ? extends Object> properties) throws RemoteException;
+	Object connect(Client client, Map<String, ? extends Object> properties) throws RemoteException;
+	void disconnect(Client client) throws RemoteException;
+	void setProperties(Client client, Map<String, ? extends Object> properties) throws RemoteException;
+	
+	RjsComObject runMainLoop(Client client, RjsComObject com) throws RemoteException;
+	RjsComObject runAsync(Client client, RjsComObject com) throws RemoteException;
+	
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/srv/engine/SrvEnginePluginExtension.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/srv/engine/SrvEnginePluginExtension.java
new file mode 100644
index 0000000..c8a4344
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/srv/engine/SrvEnginePluginExtension.java
@@ -0,0 +1,31 @@
+/*=============================================================================#
+ # Copyright (c) 2008, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server.srv.engine;
+
+import org.eclipse.statet.rj.server.Server;
+import org.eclipse.statet.rj.server.srvext.ServerRuntimePlugin;
+
+
+/**
+ * Interface for {@link Server} for local (none-exported) methods
+ */
+public interface SrvEnginePluginExtension {
+	
+	
+	public void addPlugin(ServerRuntimePlugin plugin);
+	
+	public void removePlugin(ServerRuntimePlugin plugin);
+	
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/srv/engine/SrvEngineServer.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/srv/engine/SrvEngineServer.java
new file mode 100644
index 0000000..7b26d51
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/srv/engine/SrvEngineServer.java
@@ -0,0 +1,293 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server.srv.engine;
+
+import static org.eclipse.statet.rj.server.util.ServerUtils.MISSING_ANSWER_STATUS;
+
+import java.io.File;
+import java.rmi.Remote;
+import java.rmi.RemoteException;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.security.auth.login.LoginException;
+
+import org.eclipse.statet.rj.RjException;
+import org.eclipse.statet.rj.data.RObject;
+import org.eclipse.statet.rj.server.DataCmdItem;
+import org.eclipse.statet.rj.server.MainCmdC2SList;
+import org.eclipse.statet.rj.server.MainCmdItem;
+import org.eclipse.statet.rj.server.MainCmdS2CList;
+import org.eclipse.statet.rj.server.RjsComConfig;
+import org.eclipse.statet.rj.server.RjsComObject;
+import org.eclipse.statet.rj.server.RjsException;
+import org.eclipse.statet.rj.server.RjsStatus;
+import org.eclipse.statet.rj.server.Server;
+import org.eclipse.statet.rj.server.ServerInfo;
+import org.eclipse.statet.rj.server.ServerLogin;
+import org.eclipse.statet.rj.server.srv.RMIServerControl;
+import org.eclipse.statet.rj.server.srvext.Client;
+import org.eclipse.statet.rj.server.srvext.ServerAuthMethod;
+import org.eclipse.statet.rj.server.srvext.ServerRuntimePlugin;
+
+
+public class SrvEngineServer implements Server, RjsComConfig.PathResolver {
+	
+	
+	private static final List<Remote> clients= new CopyOnWriteArrayList<>();
+	
+	public static void removeClient(final Remote remote) {
+		clients.add(remote);
+	}
+	public static void addClient(final Remote remote) {
+		clients.add(remote);
+	}
+	public static boolean isValid(final Remote remote) {
+		return clients.contains(remote);
+	}
+	
+	
+	protected static final Logger LOGGER= Logger.getLogger("org.eclipse.statet.rj.server");
+	
+	protected final RMIServerControl control;
+	protected SrvEngine srvEngine;
+	
+	private final String[] userTypes;
+	private String[] userNames;
+	protected String workingDirectory;
+	protected long timestamp;
+	
+	protected ServerAuthMethod authMethod;
+	
+	protected final Client serverClient= new Client("rservi", "dummy", (byte) 1);
+	private final MainCmdC2SList serverC2SList= new MainCmdC2SList();
+	
+	
+	public SrvEngineServer(final RMIServerControl control, final ServerAuthMethod authMethod) {
+		if (control == null) {
+			throw new NullPointerException();
+		}
+		
+		this.control= control;
+		
+		this.userTypes= createUserTypes();
+		this.userNames= new String[this.userTypes.length];
+		setUserName(ServerInfo.USER_OWNER, System.getProperty("user.name"));
+		
+		this.workingDirectory= System.getProperty("user.dir");
+		
+		this.authMethod= authMethod;
+	}
+	
+	
+	protected String[] createUserTypes() {
+		return new String[] { ServerInfo.USER_OWNER, ServerInfo.USER_CONSOLE };
+	}
+	
+	protected void setUserName(final String type, final String name) {
+		for (int i= 0; i < this.userTypes.length; i++) {
+			if (this.userTypes[i].equals(type)) {
+				if ((this.userNames[i] != null) ? !this.userNames[i].equals(name) : name != null) {
+					final String[] newNames= new String[this.userTypes.length];
+					System.arraycopy(this.userNames, 0, newNames, 0, this.userTypes.length);
+					newNames[i]= name;
+					this.userNames= newNames;
+				}
+				return;
+			}
+		}
+	}
+	
+	
+	public boolean getConfigUnbindOnStartup() {
+		return true;
+	}
+	
+	public void setEngine(final SrvEngine engine) {
+		if (this.srvEngine != null) {
+			throw new IllegalStateException();
+		}
+		
+		this.srvEngine= engine;
+	}
+	
+	public void start(final ServerRuntimePlugin runtimePlugin) throws Exception {
+		if (this.srvEngine instanceof SrvEnginePluginExtension) {
+			((SrvEnginePluginExtension) this.srvEngine).addPlugin(runtimePlugin);
+		}
+	}
+	
+	
+	@Override
+	public int getState() throws RemoteException {
+		return this.srvEngine.getState();
+	}
+	
+	@Override
+	public int[] getVersion() throws RemoteException {
+		final int[] internalVersion= this.srvEngine.getVersion();
+		final int[] version= new int[internalVersion.length];
+		System.arraycopy(internalVersion, 0, version, 0, internalVersion.length);
+		return version;
+	}
+	
+	@Override
+	public ServerInfo getInfo() throws RemoteException {
+		return new ServerInfo(this.control.getName(), this.workingDirectory, this.timestamp,
+				this.userTypes, this.userNames,
+				this.srvEngine.getState());
+	}
+	
+	
+	protected ServerAuthMethod getAuthMethod(final String command) {
+		if (command.startsWith("console.")) {
+			return this.authMethod;
+		}
+		throw new UnsupportedOperationException();
+	}
+	
+	@Override
+	public final ServerLogin createLogin(final String command) throws RemoteException {
+		final ServerAuthMethod authMethod= getAuthMethod(command);
+		try {
+			return authMethod.createLogin();
+		}
+		catch (final RjException e) {
+			final String message= "Initializing login failed.";
+			LOGGER.log(Level.SEVERE, message, e);
+			throw new RemoteException(message, e);
+		}
+	}
+	
+	protected Client connectClient(final String command, final ServerLogin login) throws RemoteException, LoginException {
+		final ServerAuthMethod authMethod= getAuthMethod(command);
+		try {
+			return authMethod.performLogin(login);
+		}
+		catch (final RjException e) {
+			final String message= "Performing login failed.";
+			LOGGER.log(Level.SEVERE, message, e);
+			throw new RemoteException(message, e);
+		}
+	}
+	
+	@Override
+	public Object execute(final String command, final Map<String, ? extends Object> properties, final ServerLogin login) throws RemoteException, LoginException {
+		try {
+			if (command.equals(C_CONSOLE_START)) {
+				final Client client= connectClient(command, login);
+				final Object r= this.srvEngine.start(client, properties);
+				final Object startupTime= properties.get("rj.session.startup.time");
+				if (startupTime instanceof Long) {
+					this.timestamp= ((Long) startupTime).longValue();
+				}
+				return r;
+			}
+			if (command.equals(C_CONSOLE_CONNECT)) {
+				final Client client= connectClient(command, login);
+				final Object r= this.srvEngine.connect(client, properties);
+				return r;
+			}
+			return null;
+		}
+		finally {
+			final Client client= this.srvEngine.getCurrentClient();
+			setUserName(ServerInfo.USER_CONSOLE, ((client != null) ? client.getUsername() : null));
+		}
+	}
+	
+	
+	protected RObject runServerLoopCommand(RjsComObject sendCom, final DataCmdItem sendItem) throws RjException {
+		if (sendCom != null) {
+			throw new UnsupportedOperationException("sendComd");
+		}
+		DataCmdItem answer= null;
+		try {
+			this.serverC2SList.setObjects(sendItem);
+			sendCom= this.serverC2SList;
+			
+			WAIT_FOR_ANSWER: while (true) {
+				final RjsComObject receivedCom= runMainLoop(sendCom, null);
+				sendCom= null;
+				
+				COM_TYPE: switch (receivedCom.getComType()) {
+				case RjsComObject.T_PING:
+					sendCom= RjsStatus.OK_STATUS;
+					break COM_TYPE;
+				case RjsComObject.T_STATUS:
+					final RjsStatus status= (RjsStatus) receivedCom;
+					switch (status.getSeverity()) {
+					case RjsStatus.OK:
+						break COM_TYPE;
+					case RjsStatus.INFO:
+						break COM_TYPE;
+					case RjsStatus.ERROR:
+						if (status.getCode() == RjsStatus.ERROR) {
+							break WAIT_FOR_ANSWER;
+						}
+						throw new RjsException(status.getCode(), status.getMessage());
+					default:
+						break COM_TYPE;
+					}
+				case RjsComObject.T_MAIN_LIST:
+					final MainCmdS2CList list= (MainCmdS2CList) receivedCom;
+					MainCmdItem item= list.getItems();
+					while (item != null) {
+						if (item == sendItem) {
+							answer= sendItem;
+							break COM_TYPE;
+						}
+						item= item.next;
+					}
+					break COM_TYPE;
+				}
+			}
+			this.serverC2SList.clear();
+			if (answer == null || !answer.isOK()) {
+				final RjsStatus status= (answer != null) ? answer.getStatus() : MISSING_ANSWER_STATUS;
+				throw new RjException("R commands failed: "+status.getMessage()+".");
+			}
+			return answer.getData();
+		}
+		catch (final Exception e) {
+			if (e instanceof RjException) {
+				throw (RjException) e;
+			}
+			throw new RjException("An error when executing R command.", e);
+		}
+	}
+	
+	protected RjsComObject runMainLoop(final RjsComObject com, final Object caller) throws RemoteException {
+		return this.srvEngine.runMainLoop(this.serverClient, com);
+	}
+	
+	@Override
+	public File resolve(final Remote ref, final String path) throws RjException {
+		final File file= new File(path);
+		if (!SrvEngineServer.isValid(ref)) {
+			throw new RjException("Invalid access.");
+		}
+		if (file.isAbsolute()) {
+			return file;
+		}
+		final RObject rwd= runServerLoopCommand(null, new DataCmdItem(DataCmdItem.EVAL_EXPR_DATA, 0,
+				(byte) -1, "getwd()", null, null, null, null ));
+		return new File(rwd.getData().getChar(0), file.getPath());
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/srvext/Client.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/srvext/Client.java
new file mode 100644
index 0000000..916e774
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/srvext/Client.java
@@ -0,0 +1,37 @@
+/*=============================================================================#
+ # Copyright (c) 2008, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server.srvext;
+
+
+public final class Client {
+	
+	
+	private final String username;
+	final String clientId;
+	
+	public final byte slot;
+	
+	
+	public Client(final String username, final String clientId, final byte slot) {
+		this.username= username;
+		this.clientId= clientId;
+		this.slot= slot;
+	}
+	
+	public String getUsername() {
+		return this.username;
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/srvext/ServerAuthMethod.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/srvext/ServerAuthMethod.java
new file mode 100644
index 0000000..929b87d
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/srvext/ServerAuthMethod.java
@@ -0,0 +1,274 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server.srvext;
+
+import java.rmi.server.RemoteServer;
+import java.rmi.server.ServerNotActiveException;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.SecureRandom;
+import java.util.Locale;
+import java.util.Random;
+import java.util.logging.Level;
+import java.util.logging.LogRecord;
+import java.util.logging.Logger;
+
+import javax.security.auth.callback.Callback;
+import javax.security.auth.callback.ChoiceCallback;
+import javax.security.auth.callback.ConfirmationCallback;
+import javax.security.auth.callback.LanguageCallback;
+import javax.security.auth.callback.NameCallback;
+import javax.security.auth.callback.PasswordCallback;
+import javax.security.auth.callback.TextInputCallback;
+import javax.security.auth.callback.TextOutputCallback;
+import javax.security.auth.callback.UnsupportedCallbackException;
+import javax.security.auth.login.FailedLoginException;
+import javax.security.auth.login.LoginException;
+
+import org.eclipse.statet.rj.RjException;
+import org.eclipse.statet.rj.RjInitFailedException;
+import org.eclipse.statet.rj.server.ServerLogin;
+
+
+/**
+ * Abstract class for authentication methods.
+ * 
+ * An authentication method must extend this class and implement the
+ * abstract methods:
+ * <li>{@link #doInit(String)}</li>
+ * <li>{@link #doCreateLogin()}</li>
+ * <li>{@link #doPerformLogin(Callback[])}</li>
+ */
+public abstract class ServerAuthMethod {
+	
+	
+	protected static void copyAnswer(final Callback[] from, final Callback[] to) throws UnsupportedCallbackException {
+		assert (from.length == to.length);
+		for (int i= 0; i < from.length; i++) {
+			if (from[i] instanceof TextOutputCallback) {
+				continue;
+			}
+			if (from[i] instanceof NameCallback) {
+				((NameCallback) to[i]).setName(((NameCallback) from[i]).getName());
+				continue;
+			}
+			if (from[i] instanceof PasswordCallback) {
+				((PasswordCallback) to[i]).setPassword(((PasswordCallback) from[i]).getPassword());
+				((PasswordCallback) from[i]).clearPassword();
+				continue;
+			}
+			if (from[i] instanceof TextInputCallback) {
+				((TextInputCallback) to[i]).setText(((TextInputCallback) from[i]).getText());
+				continue;
+			}
+			if (from[i] instanceof ChoiceCallback) {
+				final int[] selectedIndexes= ((ChoiceCallback) from[i]).getSelectedIndexes();
+				if (((ChoiceCallback) from[i]).allowMultipleSelections()) {
+					((ChoiceCallback) to[i]).setSelectedIndexes(selectedIndexes);
+				}
+				else if (selectedIndexes.length == 1) {
+					((ChoiceCallback) to[i]).setSelectedIndex(selectedIndexes[0]);
+				}
+				continue;
+			}
+			if (from[i] instanceof ConfirmationCallback) {
+				((ConfirmationCallback) to[i]).setSelectedIndex(((ConfirmationCallback) from[i]).getSelectedIndex());
+				continue;
+			}
+			if (from[i] instanceof LanguageCallback) {
+				((LanguageCallback) to[i]).setLocale(Locale.getDefault());
+				continue;
+			}
+			throw new UnsupportedCallbackException(to[i]);
+		}
+	}
+	
+	
+	private static final Logger LOGGER= Logger.getLogger("org.eclipse.statet.rj.server.auth");
+	private final String logPrefix;
+	
+	
+	private final String id;
+	
+	private Random randomGenerator;
+	
+	private final boolean usePubkeyExchange;
+	private KeyPairGenerator keyPairGenerator;
+	
+	private String pendingLoginClient;
+	private long pendingLoginId;
+	private KeyPair pendingLoginKeyPair;
+	
+	private String expliciteClient;
+	
+	
+	/**
+	 * 
+	 * @param usePubkeyExchange enables default encryption of secret data (password)
+	 */
+	protected ServerAuthMethod(final String id, final boolean usePubkeyExchange) {
+		this.usePubkeyExchange= usePubkeyExchange;
+		this.id= id;
+		this.logPrefix= "[Auth:"+id+"]";
+	}
+	
+	
+	public void setExpliciteClient(final String client) {
+		this.expliciteClient= client;
+	}
+	
+	private String getCallingClient() throws ServerNotActiveException {
+		if (this.expliciteClient != null) {
+			return this.expliciteClient;
+		}
+		return RemoteServer.getClientHost();
+	}
+	
+	public boolean isValid(final Client client) {
+		try {
+			return (getCallingClient().equals(client.clientId));
+		}
+		catch (final ServerNotActiveException e) {
+			return false;
+		}
+	}
+	
+	public final void init(final String arg) throws RjException {
+		try {
+			if (this.usePubkeyExchange) {
+				this.keyPairGenerator= KeyPairGenerator.getInstance("RSA");
+				this.keyPairGenerator.initialize(2048);
+			}
+			
+			this.randomGenerator= new SecureRandom();
+			
+			doInit(arg);
+		}
+		catch (final Exception e) {
+			final RjException rje= (e instanceof RjException) ? (RjException) e :
+					new RjInitFailedException("An error occurred when initializing authentication method '"+this.id+"'.", e);
+			throw rje;
+		}
+	}
+	
+	protected final Random getRandom() {
+		return this.randomGenerator;
+	}
+	
+	/**
+	 * Is called when the server is started
+	 * 
+	 * @param arg configuration argument
+	 * 
+	 * @throws RjException
+	 */
+	protected abstract void doInit(String arg) throws RjException;
+	
+	public final ServerLogin createLogin() throws RjException {
+		try {
+			final String client= getCallingClient();
+			final boolean same= client.equals(this.pendingLoginClient);
+			this.pendingLoginClient= client;
+			
+			LOGGER.log(Level.INFO, "{0} creating new login ({1}).",
+					new Object[] { this.logPrefix, client });
+			
+			long nextId;
+			do {
+				nextId= this.randomGenerator.nextLong();
+			} while (nextId == this.pendingLoginId);
+			this.pendingLoginId= nextId;
+			if (this.usePubkeyExchange) {
+				if (this.pendingLoginKeyPair == null || !same) {
+					this.pendingLoginKeyPair= this.keyPairGenerator.generateKeyPair();
+				}
+			}
+			
+			return createNewLogin(doCreateLogin());
+		}
+		catch (final Exception e) {
+			final RjException rje= (e instanceof RjException) ? (RjException) e :
+					new RjException("An unexpected error occurred when preparing login process.", e);
+			throw rje;
+		}
+	}
+	
+	/**
+	 * Is called when client initiates a login process.
+	 * 
+	 * @return login callbacks to handle by the client
+	 * 
+	 * @throws RjException
+	 */
+	protected abstract Callback[] doCreateLogin() throws RjException;
+	
+	private ServerLogin createNewLogin(final Callback[] callbacks) {
+		if (this.usePubkeyExchange) {
+			return new ServerLogin(this.pendingLoginId, this.pendingLoginKeyPair.getPublic(), callbacks);
+		}
+		else {
+			return new ServerLogin(this.pendingLoginId, null, callbacks);
+		}
+	}
+	
+	public final Client performLogin(final ServerLogin login) throws RjException, LoginException {
+		String client= null;
+		try {
+			client= getCallingClient();
+			if (login.getId() != this.pendingLoginId ||
+					!client.equals(this.pendingLoginClient)) {
+				throw new FailedLoginException("Login process was interrupted by another client.");
+			}
+			
+			login.readAnswer(this.usePubkeyExchange ? this.pendingLoginKeyPair.getPrivate() : null);
+			this.pendingLoginKeyPair= null;
+			final String name= doPerformLogin(login.getCallbacks());
+			
+			LOGGER.log(Level.INFO, "{0} performing login completed successfull: {1} ({2}).",
+					new Object[] { this.logPrefix, name, client });
+			return new Client(name, getCallingClient(), (byte) 0);
+		}
+		catch (final Exception e) {
+			if (e instanceof LoginException) {
+				final LogRecord log= new LogRecord(Level.INFO, "{0} performing login failed ({1}).");
+				log.setParameters(new Object[] { this.logPrefix, client });
+				log.setThrown(e);
+				LOGGER.log(log);
+				throw (LoginException) e;
+			}
+			if (e instanceof RjException) {
+				throw (RjException) e;
+			}
+			throw new RjException("An unexpected error occurred when validating the login credential.", e);
+		}
+		finally {
+			System.gc();
+		}
+	}
+	
+	/**
+	 * This method is called when the client sends the login data
+	 * 
+	 * @param callbacks the callbacks handled by the client (note, the callbacks are not
+	 *     the same instances returned by {@link #createLogin()}, but clones)
+	 * 
+	 * @return login id like username
+	 * 
+	 * @throws LoginException if login failed (but can usually fixed by other login data)
+	 * @throws RjException
+	 */
+	protected abstract String doPerformLogin(Callback[] callbacks) throws LoginException, RjException;
+	
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/srvext/ServerRuntimePlugin.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/srvext/ServerRuntimePlugin.java
new file mode 100644
index 0000000..adbb209
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/srvext/ServerRuntimePlugin.java
@@ -0,0 +1,27 @@
+/*=============================================================================#
+ # Copyright (c) 2008, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server.srvext;
+
+
+public interface ServerRuntimePlugin {
+	
+	
+	public String getSymbolicName();
+	
+	public void rjIdle() throws Exception;
+	
+	public void rjStop(int state) throws Exception;
+	
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/srvext/auth/FxAuthMethod.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/srvext/auth/FxAuthMethod.java
new file mode 100644
index 0000000..8796611
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/srvext/auth/FxAuthMethod.java
@@ -0,0 +1,128 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server.srvext.auth;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.nio.ByteBuffer;
+import java.nio.channels.FileChannel;
+import java.util.Arrays;
+
+import javax.security.auth.callback.Callback;
+import javax.security.auth.callback.NameCallback;
+import javax.security.auth.login.FailedLoginException;
+import javax.security.auth.login.LoginException;
+
+import org.eclipse.statet.rj.RjException;
+import org.eclipse.statet.rj.server.FxCallback;
+import org.eclipse.statet.rj.server.srvext.ServerAuthMethod;
+import org.eclipse.statet.rj.server.util.ServerUtils;
+
+
+/**
+ * Authentication method 'none'
+ * without any authentication mechanism.
+ */
+public class FxAuthMethod extends ServerAuthMethod {
+	
+	
+	private File file;
+	private FileInputStream fileInputStream;
+	
+	private final byte[] pendingKey= new byte[1024];
+	private FileChannel fileChannel;
+	
+	
+	public FxAuthMethod() {
+		super("fx", false);
+	}
+	
+	
+	@Override
+	public void doInit(final String arg) throws RjException {
+		final String configType;
+		final String configValue;
+		{	final String[] args= ServerUtils.getArgConfigValue(arg);
+			configType= args[0];
+			configValue= args[1];
+		}
+		if (configType.equals("file")) {
+			if (configValue == null || configValue.length() == 0) {
+				throw new RjException("Missing lock file name.", null);
+			}
+			this.file= new File(configValue);
+			
+			try {
+				if (!this.file.exists()) {
+					this.file.createNewFile();
+				}
+				this.fileChannel= new RandomAccessFile(this.file, "rws").getChannel();
+				this.fileChannel.truncate(512);
+			}
+			catch (final IOException e) {
+				throw new RjException("Cannot read lock file.", e);
+			}
+		}
+		else {
+			throw new RjException("Unsupported configuration type '"+configType+"'.", null);
+		}
+	}
+	
+	@Override
+	protected Callback[] doCreateLogin() throws RjException {
+		getRandom().nextBytes(this.pendingKey);
+		try {
+			this.fileChannel.position(this.fileChannel.size());
+		}
+		catch (final IOException e) {
+			throw new RjException("Cannot read lock file.", e);
+		}
+		
+		return new Callback[] {
+				new NameCallback("Username"),
+				new FxCallback(this.file.getPath(), this.pendingKey),
+		};
+	}
+	
+	@Override
+	protected String doPerformLogin(final Callback[] callbacks) throws LoginException, RjException {
+		final String userName= ((NameCallback) callbacks[0]).getName();
+		final byte[] clientKey= ((FxCallback) callbacks[1]).getContent();
+		if (clientKey.length < 1024) {
+			throw new RjException("Unsufficient client key");
+		}
+		try {
+			if (compare(this.pendingKey) && compare(clientKey)) {
+				return userName;
+			}
+		}
+		catch (final IOException e) {
+			throw new RjException("Cannot read lock file.", e);
+		}
+		throw new FailedLoginException();
+	}
+	
+	private boolean compare(final byte[] key) throws IOException {
+		final byte[] check= new byte[key.length];
+		final int n= this.fileChannel.read(ByteBuffer.wrap(check));
+		if (n != key.length) {
+			return false;
+		}
+		return Arrays.equals(key, check);
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/srvext/auth/JaasAuthMethod.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/srvext/auth/JaasAuthMethod.java
new file mode 100644
index 0000000..804dbb1
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/srvext/auth/JaasAuthMethod.java
@@ -0,0 +1,213 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server.srvext.auth;
+
+import java.io.IOException;
+import java.util.HashMap;
+
+import javax.security.auth.Subject;
+import javax.security.auth.callback.Callback;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.callback.UnsupportedCallbackException;
+import javax.security.auth.login.AppConfigurationEntry;
+import javax.security.auth.login.Configuration;
+import javax.security.auth.login.LoginContext;
+import javax.security.auth.login.LoginException;
+
+import org.eclipse.statet.rj.RjException;
+import org.eclipse.statet.rj.server.srvext.ServerAuthMethod;
+
+
+/**
+ * Draft for a JAAS auth method. 
+ * Missing role/principal handling.
+ */
+public abstract class JaasAuthMethod extends ServerAuthMethod implements CallbackHandler, Runnable {
+	
+	
+	private static String JAAS_NAME= "org.eclipse.statet.rj.server";
+	
+	
+	private class JaasConfig extends Configuration {
+		
+		
+		private final AppConfigurationEntry entry;
+		
+		
+		JaasConfig(final String clazz) {
+			this.entry= new AppConfigurationEntry(clazz, AppConfigurationEntry.LoginModuleControlFlag.REQUIRED, new HashMap());
+		}
+		
+		
+		@Override
+		public AppConfigurationEntry[] getAppConfigurationEntry(final String name) {
+			return null;
+		}
+		
+		@Override
+		public void refresh() {
+		}
+		
+	}
+	
+	
+	private static final int STARTED= 1;
+	private static final int CALLBACK= 2;
+	private static final int PERFORM= 3;
+	private static final int LOGGED_IN= 4;
+	
+	private static final int CANCEL= -1;
+	private static final int FAILED= -2;
+	
+	
+	private Configuration configuration;
+	private LoginContext context;
+	
+	private Callback[] pendingLoginCallback;
+	private int pendingLogin;
+	private String pendingLoginMsg;
+	
+	private final Thread loginThread;
+	
+	
+	protected JaasAuthMethod(final String id) {
+		super(id, true);
+		this.loginThread= new Thread(this);
+	}
+	
+	
+	@Override
+	public void doInit(final String arg) throws RjException {
+		this.configuration= Configuration.getConfiguration();
+		if (this.configuration.getAppConfigurationEntry(JAAS_NAME) == null) {
+			this.configuration= new JaasConfig(arg);
+		}
+		try {
+			this.context= new LoginContext(JAAS_NAME, new Subject(), this, this.configuration);
+		}
+		catch (final LoginException e) {
+			e.printStackTrace();
+		}
+	}
+	
+	@Override
+	protected Callback[] doCreateLogin() throws RjException {
+		cancel();
+		this.loginThread.start();
+		synchronized (this) {
+			while (this.pendingLogin >= 0 && this.pendingLogin < CALLBACK) {
+				notifyAll();
+				try {
+					wait();
+				}
+				catch (final InterruptedException e) {}
+			}
+		}
+		if (this.pendingLogin == FAILED) {
+			throw new SecurityException("failed to init login", null);
+		}
+		return this.pendingLoginCallback;
+	}
+	
+	@Override
+	protected String doPerformLogin(final Callback[] callbacks) throws LoginException, RjException {
+		this.pendingLoginCallback= callbacks;
+		this.pendingLogin= PERFORM;
+		synchronized (this) {
+			while (this.loginThread.isAlive()) {
+				notifyAll();
+				try {
+					wait();
+				}
+				catch (final InterruptedException e) {}
+			}
+		}
+		if (this.pendingLogin != LOGGED_IN) {
+			if (this.pendingLoginMsg != null) {
+				throw new LoginException(this.pendingLoginMsg);
+			}
+			else {
+				throw new SecurityException("", null);
+			}
+		}
+		return null;
+	}
+	
+	private void cancel() {
+		this.pendingLoginCallback= null;
+		this.pendingLoginMsg= null;
+		this.pendingLogin= CANCEL;
+		synchronized (this) {
+			while (this.loginThread.isAlive()) {
+				notifyAll();
+				try {
+					wait();
+				}
+				catch (final InterruptedException e) {}
+			}
+		}
+		this.pendingLogin= 0;
+	}
+	
+	@Override
+	public void run() {
+		this.pendingLogin= STARTED;
+		try {
+			this.context.login();
+			this.pendingLogin= LOGGED_IN;
+			this.context.logout();
+		}
+		catch (final LoginException e) {
+			this.pendingLogin= FAILED;
+			this.pendingLoginMsg= e.getLocalizedMessage();
+		}
+		catch (final Throwable e) {
+			this.pendingLogin= FAILED;
+		}
+		finally {
+			synchronized (this) {
+				notifyAll();
+			}
+		}
+	}
+	
+	@Override
+	public void handle(final Callback[] callbacks) throws IOException, UnsupportedCallbackException {
+		if (this.pendingLogin == STARTED) {
+			this.pendingLogin= CALLBACK;
+			this.pendingLoginCallback= callbacks;
+			
+			synchronized (this) {
+				while (this.pendingLogin == CALLBACK) {
+					notifyAll();
+					try {
+						wait();
+					}
+					catch (final InterruptedException e) {}
+				}
+			}
+			
+			if (this.pendingLogin != PERFORM) {
+				throw new IOException();
+			}
+			copyAnswer(this.pendingLoginCallback, callbacks);
+		}
+		else if (callbacks.length > 0){
+			this.pendingLogin= FAILED;
+			throw new UnsupportedCallbackException(callbacks[0]);
+		}
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/srvext/auth/LocalShajAuthMethod.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/srvext/auth/LocalShajAuthMethod.java
new file mode 100644
index 0000000..d23fc2b
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/srvext/auth/LocalShajAuthMethod.java
@@ -0,0 +1,82 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server.srvext.auth;
+
+import javax.security.auth.callback.Callback;
+import javax.security.auth.callback.NameCallback;
+import javax.security.auth.callback.PasswordCallback;
+import javax.security.auth.login.FailedLoginException;
+import javax.security.auth.login.LoginException;
+
+import com.cenqua.shaj.Shaj;
+
+import org.eclipse.statet.rj.RjException;
+import org.eclipse.statet.rj.server.srvext.ServerAuthMethod;
+
+
+/**
+ * Authentication method 'local-shaj'
+ * to authenticate against local user account.
+ */
+public class LocalShajAuthMethod extends ServerAuthMethod {
+	
+	
+	private String[] users;
+	
+	
+	public LocalShajAuthMethod() {
+		super("local-shaj", true);
+	}
+	
+	
+	@Override
+	public void doInit(final String arg) throws RjException {
+		if (!Shaj.init()) {
+			throw new RjException("Initializing authentication failed:\n" +
+					"Initializing 'shaj'-library failed");
+		}
+		this.users = new String[] { System.getProperty("user.name") };
+	}
+	
+	@Override
+	protected Callback[] doCreateLogin() throws RjException {
+		return new Callback[] {
+				new NameCallback("Username"),
+				new PasswordCallback("Password", false),
+		};
+	}
+	
+	@Override
+	protected String doPerformLogin(final Callback[] callbacks) throws LoginException, RjException {
+		final String loginName = ((NameCallback) callbacks[0]).getName();
+		if (isValidUser(loginName)) {
+			final char[] loginPassword = ((PasswordCallback) callbacks[1]).getPassword();
+			if (Shaj.checkPassword(null, loginName, new String(loginPassword))) {
+				return loginName;
+			}
+		}
+		throw new FailedLoginException("Invalid username or password");
+	}
+	
+	private boolean isValidUser(final String user) {
+		for (final String s : this.users) {
+			if (s.equals(user)) {
+				return true;
+			}
+		}
+		return false;
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/srvext/auth/NoAuthMethod.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/srvext/auth/NoAuthMethod.java
new file mode 100644
index 0000000..1eef829
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/srvext/auth/NoAuthMethod.java
@@ -0,0 +1,59 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server.srvext.auth;
+
+import javax.security.auth.callback.Callback;
+import javax.security.auth.login.LoginException;
+
+import org.eclipse.statet.rj.RjException;
+import org.eclipse.statet.rj.server.srvext.ServerAuthMethod;
+
+
+/**
+ * Authentication method 'none'
+ * without any authentication mechanism.
+ */
+public class NoAuthMethod extends ServerAuthMethod {
+	
+	
+	public NoAuthMethod() {
+		super("none", false);
+	}
+	
+	public NoAuthMethod(final String client) {
+		super("none", false);
+		setExpliciteClient(client);
+		try {
+			init("");
+		}
+		catch (final RjException e) {}
+	}
+	
+	
+	@Override
+	public void doInit(final String arg) throws RjException {
+	}
+	
+	@Override
+	protected Callback[] doCreateLogin() throws RjException {
+		return null;
+	}
+	
+	@Override
+	protected String doPerformLogin(final Callback[] callbacks) throws LoginException, RjException {
+		return "-";
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/srvext/auth/SimpleNamePassAuthMethod.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/srvext/auth/SimpleNamePassAuthMethod.java
new file mode 100644
index 0000000..e922c42
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/srvext/auth/SimpleNamePassAuthMethod.java
@@ -0,0 +1,139 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server.srvext.auth;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.nio.CharBuffer;
+import java.nio.charset.Charset;
+import java.security.MessageDigest;
+import java.security.SecureRandom;
+import java.util.Arrays;
+import java.util.Map.Entry;
+import java.util.Properties;
+import java.util.Set;
+
+import javax.security.auth.callback.Callback;
+import javax.security.auth.callback.NameCallback;
+import javax.security.auth.callback.PasswordCallback;
+import javax.security.auth.login.FailedLoginException;
+import javax.security.auth.login.LoginException;
+
+import org.eclipse.statet.rj.RjException;
+import org.eclipse.statet.rj.server.srvext.ServerAuthMethod;
+import org.eclipse.statet.rj.server.util.ServerUtils;
+
+
+/**
+ * Authentication method 'name-pass'
+ * to authenticate against a given name password pair.
+ */
+public class SimpleNamePassAuthMethod extends ServerAuthMethod {
+	
+	
+	private Properties users;
+	
+	private byte[] digestSash;
+	private MessageDigest digestService;
+	private Charset digestCharset;
+	
+	
+	public SimpleNamePassAuthMethod() {
+		super("name-pass", true);
+	}
+	
+	
+	@Override
+	public void doInit(final String arg) throws RjException {
+		final String configType;
+		final String configValue;
+		{	final String[] args= ServerUtils.getArgConfigValue(arg);
+			configType= args[0];
+			configValue= args[1];
+		}
+		try {
+			this.digestSash= new byte[8];
+			final SecureRandom random= SecureRandom.getInstance("SHA1PRNG");
+			random.nextBytes(this.digestSash);
+			this.digestService= MessageDigest.getInstance("SHA-512");
+			this.digestCharset= Charset.forName("UTF-8");
+		}
+		catch (final Exception e) {
+			throw new RjException("", e);
+		}
+		
+		if (configType.equals("file")) {
+			if (configValue == null || configValue.length() == 0) {
+				throw new RjException("Missing password file name.", null);
+			}
+			final File file= new File(configValue);
+			this.users= new Properties();
+			try {
+				this.users.load(new FileInputStream(file));
+			}
+			catch (final IOException e) {
+				throw new RjException("Reading password file failed.", null);
+			}
+		}
+		else {
+			throw new RjException("Unsupported configuration type '"+configType+"'.", null);
+		}
+		this.digestService.update(this.digestSash);
+		final Set<Entry<Object,Object>> entrySet= this.users.entrySet();
+		for (final Entry<Object, Object> entry : entrySet) {
+			final byte[] password= this.digestService.digest(this.digestCharset.encode(
+					(String) entry.getValue()).array());
+			entry.setValue(password);
+		}
+		System.gc();
+	}
+	
+	@Override
+	protected Callback[] doCreateLogin() throws RjException {
+		return new Callback[] {
+				new NameCallback("Loginname"),
+				new PasswordCallback("Password", false),
+		};
+	}
+	
+	@Override
+	protected String doPerformLogin(final Callback[] callbacks) throws LoginException, RjException {
+		final String loginName= ((NameCallback) callbacks[0]).getName();
+		final Object object= this.users.get(loginName);
+		if (object instanceof byte[]) {
+			final byte[] loginPassword= getPass((PasswordCallback) callbacks[1]);
+			if (Arrays.equals((byte[]) object, loginPassword)) {
+				return loginName;
+			}
+		}
+		throw new FailedLoginException("Invalid loginname or password");
+	}
+	
+	private byte[] getPass(final PasswordCallback callback) {
+		final char[] loginPassword= callback.getPassword();
+		final byte[] loginBytes;
+		if (loginPassword == null) {
+			return new byte[0];
+		}
+		this.digestService.update(this.digestSash);
+		loginBytes= this.digestService.digest(this.digestCharset.encode(
+				CharBuffer.wrap(loginPassword)).array());
+		callback.clearPassword();
+		Arrays.fill(loginPassword, (char) 0);
+		return loginBytes;
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/util/LocalREnv.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/util/LocalREnv.java
new file mode 100644
index 0000000..9329ad9
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/util/LocalREnv.java
@@ -0,0 +1,286 @@
+/*=============================================================================#
+ # Copyright (c) 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server.util;
+
+import java.io.File;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.function.Function;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import java.util.regex.Pattern;
+
+import org.eclipse.statet.rj.RjInvalidConfigurationException;
+
+
+public class LocalREnv {
+	
+	
+	public static final int OS_WIN= 1;
+	public static final int OS_NIX= 2;
+	public static final int OS_MAC= 3;
+	
+	
+	private static final Logger LOGGER= Logger.getLogger("org.eclipse.statet.rj.server"); //$NON-NLS-1$
+	
+	private static final int OS_TYPE;
+	static {
+		final String osname= System.getProperty("os.name").toLowerCase(); //$NON-NLS-1$
+		if (osname.contains("win")) { //$NON-NLS-1$
+			OS_TYPE= OS_WIN;
+		}
+		else if (osname.contains("mac")) { //$NON-NLS-1$
+			OS_TYPE= OS_MAC;
+		}
+		else {
+			OS_TYPE= OS_NIX;
+		}
+	}
+	
+	private static final Pattern PATH_SPLITTER= Pattern.compile(Pattern.quote(File.pathSeparator));
+	
+	private static final String DEFAULT_HOME_TEMPLATE= "${R_HOME}"; //$NON-NLS-1$
+	
+	private static final List<String> DEFAULT_PATHS_TEMPLATES= Arrays.asList(
+			"${R_LIBS}", //$NON-NLS-1$
+			"${R_LIBS_USER}", //$NON-NLS-1$
+			"${R_LIBS_SITE}" , //$NON-NLS-1$
+			"${R_HOME}/library" ); //$NON-NLS-1$
+	
+	
+	private static void add(final List<Path> paths, final Path pathToAdd) {
+		if (pathToAdd != null && !paths.contains(pathToAdd)) {
+			paths.add(pathToAdd);
+		}
+	}
+	
+	private static void addAll(final List<Path> paths, final List<Path> pathsToAdd) {
+		if (pathsToAdd != null) {
+			pathsToAdd.forEach((path) -> add(paths, path));
+		}
+	}
+	
+	
+	/**
+	 * R home path.
+	 */
+	private final Path rHomePath;
+	
+	/**
+	 * R library path (list with directories containing R packages).
+	 */
+	private final List<Path> rLibPaths;
+	
+	
+	public LocalREnv(final String rHomeTemplate, final List<String> rLibPathsTemplates,
+			Function<String, String> varResolver)
+			throws RjInvalidConfigurationException {
+		if (rHomeTemplate == null) {
+			throw new NullPointerException("rHomeTemplate"); //$NON-NLS-1$
+		}
+		if (rLibPathsTemplates == null) {
+			throw new NullPointerException("rLibPathsTemplates"); //$NON-NLS-1$
+		}
+		if (varResolver == null) {
+			varResolver= System::getenv;
+		}
+		this.rHomePath= checkPath(resolveTemplate(rHomeTemplate, varResolver));
+		this.rLibPaths= resolveRLibPaths(rLibPathsTemplates, varResolver);
+		
+		checkSpec();
+	}
+	
+	public LocalREnv() throws RjInvalidConfigurationException {
+		this(DEFAULT_HOME_TEMPLATE, DEFAULT_PATHS_TEMPLATES, null);
+	}
+	
+	public LocalREnv(final Function<String, String> varResolver)
+			throws RjInvalidConfigurationException {
+		this(DEFAULT_HOME_TEMPLATE, DEFAULT_PATHS_TEMPLATES, varResolver);
+	}
+	
+	
+	public LocalREnv(final String rHome, final List<String> rLibPaths)
+			throws RjInvalidConfigurationException {
+		if (rHome == null) {
+			throw new NullPointerException("rHome"); //$NON-NLS-1$
+		}
+		if (rLibPaths == null) {
+			throw new NullPointerException("rLibPaths"); //$NON-NLS-1$
+		}
+		this.rHomePath= checkPath(rHome);
+		this.rLibPaths= resolveRLibPaths(rLibPaths, null);
+		
+		checkSpec();
+	}
+	
+	public LocalREnv(final Path rHomePath, final List<Path> rLibPaths)
+			throws RjInvalidConfigurationException {
+		if (rHomePath == null) {
+			throw new NullPointerException("rHome"); //$NON-NLS-1$
+		}
+		if (rLibPaths == null) {
+			throw new NullPointerException("rLibPaths"); //$NON-NLS-1$
+		}
+		this.rHomePath= rHomePath;
+		this.rLibPaths= rLibPaths;
+		
+		checkSpec();
+	}
+	
+	
+	protected List<Path> resolveRLibPaths(final List<String> rLibPathsTemplates,
+			final Function<String, String> varResolver) {
+		final List<Path> paths= new ArrayList<>();
+		for (final String template : rLibPathsTemplates) {
+			final String value= (varResolver != null) ?
+					resolveTemplate(template, varResolver) :
+					template;
+			try {
+				addAll(paths, checkPathList(value));
+			}
+			catch (final Exception e) {
+				LOGGER.log(Level.WARNING, "An error occurred when adding '" + template + "' to R library paths.", e);
+			}
+		}
+		
+		return paths;
+	}
+	
+	protected String resolveTemplate(final String s, final Function<String, String> varResolver) {
+		if (s != null && s.indexOf('$') >= 0) {
+			final StringBuilder sb= new StringBuilder();
+			int startIdx= 0;
+			int endIdx= 0;
+			while (true) {
+				startIdx= s.indexOf("${", endIdx);
+				if (startIdx >= 0) {
+					sb.append(s, endIdx, startIdx);
+					startIdx+= 2;
+					endIdx= s.indexOf('}', startIdx);
+					if (endIdx >= 0) {
+						final String value= varResolver.apply(s.substring(startIdx, endIdx));
+						if (value != null) {
+							sb.append(value);
+							endIdx++;
+							continue;
+						}
+					}
+					break;
+				}
+				else {
+					sb.append(s, endIdx, s.length());
+					return sb.toString();
+				}
+			}
+		}
+		return null;
+	}
+	
+	protected void checkSpec() throws RjInvalidConfigurationException {
+		if (LOGGER.isLoggable(Level.CONFIG)) {
+			final StringBuilder sb= new StringBuilder();
+			sb.append("RJClassLoader - R home path= "); //$NON-NLS-1$
+			if (this.rHomePath != null) {
+				sb.append(this.rHomePath);
+			}
+			else {
+				sb.append("<missing>"); //$NON-NLS-1$
+			}
+			sb.append("RJClassLoader - R library paths= "); //$NON-NLS-1$
+			if (this.rLibPaths != null) {
+				if (this.rLibPaths.isEmpty()) {
+					sb.append("<empty>"); //$NON-NLS-1$
+				}
+				else {
+					ServerUtils.prettyPrint(this.rLibPaths, sb);
+				}
+			}
+			else {
+				sb.append("<missing>"); //$NON-NLS-1$
+			}
+			LOGGER.log(Level.CONFIG, sb.toString());
+		}
+		
+		if (this.rHomePath == null) {
+			throw new RjInvalidConfigurationException("Spec of R home path is missing."); //$NON-NLS-1$
+		}
+		if (this.rLibPaths.isEmpty()) {
+			throw new RjInvalidConfigurationException("Spec of R library paths is empty"); //$NON-NLS-1$
+		}
+	}
+	
+	
+	public Path checkPath(String path) {
+		if (path != null) {
+			path= path.trim();
+			if (!path.isEmpty()) {
+				return Paths.get(path).normalize();
+			}
+		}
+		return null;
+	}
+	
+	public List<Path> checkPathList(String pathList) {
+		if (pathList != null) {
+			pathList= pathList.trim();
+			if (!pathList.isEmpty()) {
+				final String[] split= PATH_SPLITTER.split(pathList);
+				final ArrayList<Path> list= new ArrayList<>(split.length);
+				for (int i= 0; i < split.length; i++) {
+					final Path path= checkPath(split[i]);
+					if (path != null) {
+						list.add(path);
+					}
+				}
+				return list;
+			}
+		}
+		return null;
+	}
+	
+	
+	public int getOSType() {
+		return OS_TYPE;
+	}
+	
+	public Path getRHomePath() {
+		return this.rHomePath;
+	}
+	
+	public List<Path> getRLibPaths() {
+		return Collections.unmodifiableList(this.rLibPaths);
+	}
+	
+	
+	public Path searchRPkg(final String name) {
+		for (final Path path : this.rLibPaths) {
+			try {
+				final Path packagePath= path.resolve(name);
+				if (Files.isRegularFile(packagePath.resolve("DESCRIPTION"))) {
+					return packagePath;
+				}
+			}
+			catch (final Exception e) {}
+		}
+		return null;
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/util/RJContext.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/util/RJContext.java
new file mode 100644
index 0000000..132775b
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/util/RJContext.java
@@ -0,0 +1,266 @@
+/*=============================================================================#
+ # Copyright (c) 2013, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server.util;
+
+import static org.eclipse.statet.rj.server.util.ServerUtils.RJ_SERVER_ID;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Properties;
+import java.util.regex.Pattern;
+
+import org.eclipse.statet.rj.RjInvalidConfigurationException;
+
+
+public class RJContext {
+	
+	
+	protected static abstract class PathEntry implements Comparable<PathEntry> {
+		
+		final String name;
+		
+		public PathEntry(final String child) {
+			this.name= child;
+		}
+		
+		@Override
+		public int compareTo(final PathEntry o) {
+			return this.name.compareTo((o).name);
+		}
+		
+		public abstract String getPath();
+		
+		@Override
+		public abstract String toString();
+		
+	}
+	
+	protected static class FilePathEntry extends PathEntry {
+		
+		final File dir;
+		
+		public FilePathEntry(final File dir, final String name) {
+			super(name);
+			this.dir= dir;
+		}
+		
+		@Override
+		public String getPath() {
+			final File file= new File(this.dir, this.name);
+			if (file.isDirectory()) {
+				final File binFile= new File(file, "bin");
+				if (binFile.exists() && binFile.isDirectory()) {
+					return binFile.getPath();
+				}
+			}
+			return file.getPath();
+		}
+		
+		@Override
+		public String toString() {
+			return '\'' + this.name + "' in '" + this.dir + '\'';
+		}
+		
+	}
+	
+	
+	private String libPath;
+	
+	
+	public RJContext(final String libPath) {
+		this.libPath= libPath;
+	}
+	
+	protected RJContext() {
+	}
+	
+	
+	public List<String> searchRJLibs(final List<String> libIds)
+			throws RjInvalidConfigurationException {
+		final List<PathEntry> candidates= getRJLibCandidates();
+		
+		final ArrayList<String> resolved= new ArrayList<>(libIds.size());
+		StringBuilder sb= null;
+		
+		Collections.sort(candidates);
+		for (final String libId : libIds) {
+			final PathEntry entry= searchLib(candidates, libId);
+			if (entry == null) {
+				if (sb == null) {
+					sb= new StringBuilder("Missing RJ library ");
+				}
+				else {
+					sb.append(", ");
+				}
+				sb.append('\'');
+				sb.append(libId);
+				sb.append('\'');
+			}
+			else {
+				resolved.add(entry.getPath());
+			}
+		}
+		if (sb != null) {
+			sb.append('.');
+			throw new RjInvalidConfigurationException(sb.toString());
+		}
+		return resolved;
+	}
+	
+	protected String[] getLibDirPaths() throws RjInvalidConfigurationException {
+		String path= System.getProperty("org.eclipse.statet.rj.path");
+		if (path == null) {
+			path= this.libPath; 
+		}
+		if (path == null || path.isEmpty()) {
+			throw new RjInvalidConfigurationException("Missing or invalid RJ library location.");
+		}
+		return path.split(Pattern.quote(File.pathSeparator));
+	}
+	
+	protected List<PathEntry> getRJLibCandidates() throws RjInvalidConfigurationException {
+		final String[] paths= getLibDirPaths();
+		
+		final List<PathEntry> files= new ArrayList<>(paths.length*10);
+		for (int i= 0; i < paths.length; i++) {
+			if (paths[i].length() > 0) {
+				File dir= new File(paths[i]);
+				try {
+					dir= dir.getCanonicalFile();
+				}
+				catch (final IOException e) {}
+				final String[] list= dir.list();
+				if (list != null) {
+					for (final String child : list) {
+						files.add(new FilePathEntry(dir, child));
+					}
+				}
+			}
+		}
+		
+		return files;
+	}
+	
+	protected PathEntry searchLib(final List<PathEntry> files, final String libId) {
+		PathEntry found= null;
+		for (final PathEntry entry : files) {
+			if (entry.name.startsWith(libId)) {
+				// without version
+				if (entry.name.length() == libId.length() // equals
+						|| (entry.name.length() == libId.length() + 4 && entry.name.endsWith(".jar")) ) {
+					return entry;
+				}
+				// with version suffix
+				if (entry.name.length() > libId.length()) {
+					if (entry.name.charAt(libId.length()) == '_') {
+						found= entry;
+					}
+				}
+			}
+		}
+		return found;
+	}
+	
+	
+	public String getServerPolicyFilePath() throws RjInvalidConfigurationException {
+		String serverLib= searchRJLibs(Collections.singletonList(RJ_SERVER_ID)).get(0);
+		final File libFile= new File(serverLib);
+		if (libFile.isDirectory()) {
+			File file= new File(libFile, "localhost.policy");
+			if (libFile.getName().equals("bin") && !file.exists()) {
+				file= new File(libFile.getParentFile(), "localhost.policy");
+			}
+			return file.toURI().toString();
+		}
+		// expect jar file
+		serverLib= libFile.toURI().toString();
+		return "jar:" + serverLib + "!/localhost.policy";
+	}
+	
+	
+	protected String getPropertiesDirPath() {
+		return System.getProperty("user.dir");
+	}
+	
+	protected InputStream getInputStream(final String path) throws IOException {
+		final File file= new File(path);
+		if (!file.exists()) {
+			return null;
+		}
+		return new FileInputStream(file);
+	}
+	
+	protected OutputStream getOutputStream(final String path) throws IOException {
+		final File file= new File(path);
+		return new FileOutputStream(file, false);
+	}
+	
+	public Properties loadProperties(final String name) throws IOException {
+		if (name == null) {
+			throw new NullPointerException("name");
+		}
+		final String path= getPropertiesDirPath() + "/" + name + ".properties";
+		final InputStream in= getInputStream(path);
+		if (in == null) {
+			return null;
+		}
+		
+		final Properties properties= new Properties();
+		try {
+			properties.load(in);
+		}
+		finally {
+			if (in != null) {
+				try {
+					in.close();
+				}
+				catch (final IOException e) {}
+			}
+		}
+		
+		return properties;
+	}
+	
+	public void saveProperties(final String name, final Properties properties) throws IOException {
+		if (name == null) {
+			throw new NullPointerException("name");
+		}
+		if (properties == null) {
+			throw new NullPointerException("properties");
+		}
+		final String path= getPropertiesDirPath() + "/" + name + ".properties";
+		final OutputStream out= getOutputStream(path);
+		
+		try {
+			properties.store(out, null);
+		}
+		finally {
+			if (out != null) {
+				try {
+					out.close();
+				}
+				catch (final IOException e) {}
+			}
+		}
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/util/ServerUtils.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/util/ServerUtils.java
new file mode 100644
index 0000000..4cf12b4
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/util/ServerUtils.java
@@ -0,0 +1,231 @@
+/*=============================================================================#
+ # Copyright (c) 2011, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server.util;
+
+import java.io.File;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+import org.eclipse.statet.rj.server.RjsStatus;
+
+
+/**
+ * Server utilities.
+ */
+public class ServerUtils {
+	
+	
+	public static final String RJ_DATA_ID= "org.eclipse.statet.rj.data";
+	public static final String RJ_SERVER_ID= "org.eclipse.statet.rj.server";
+	
+	public static final int[] RJ_VERSION= new int[] { 2, 1, 0 };
+	
+	public static final RjsStatus MISSING_ANSWER_STATUS= new RjsStatus(RjsStatus.ERROR, 121, "Server error (missing answer).");
+	
+	
+	/**
+	 * Split at next ':'
+	 * @param arg the argument to split
+	 * @return String array of length 2
+	 */
+	public static String[] getArgSubValue(final String arg) {
+		final String[] args= new String[2];
+		if (arg != null && arg.length() > 0) {
+			final int idx= arg.indexOf(':');
+			if (idx >= 0) {
+				args[0]= arg.substring(0, idx);
+				args[1]= arg.substring(idx+1);
+			}
+			else {
+				args[0]= arg;
+			}
+		}
+		else {
+			args[0]= "";
+		}
+		return args;
+	}
+	
+	/**
+	 * Split at next '='
+	 * @param arg the argument to split
+	 * @return String array of length 2
+	 */
+	public static String[] getArgConfigValue(final String arg) {
+		final String[] args= new String[2];
+		if (arg != null && arg.length() > 0) {
+			final int idx= arg.indexOf('=');
+			if (idx >= 0) {
+				args[0]= arg.substring(0, idx);
+				args[1]= arg.substring(idx+1);
+			}
+			else {
+				args[0]= arg;
+			}
+		}
+		else {
+			args[0]= "";
+		}
+		return args;
+	}
+	
+	/**
+	 * Split at ','
+	 * @param arg the argument to split
+	 * @return List with String
+	 */
+	public static List<String> getArgValueList(final String arg) {
+		if (arg != null && arg.length() > 0) {
+			return Arrays.asList(arg.split(","));
+		}
+		else {
+			return Collections.emptyList();
+		}
+	}
+	
+	public static void prettyPrint(final Map map, final StringBuilder sb) {
+		final String sep= System.getProperty("line.separator")+"\t";
+		final Set<Entry<?, ?>> entrySet= map.entrySet();
+		for (final Entry<?, ?> entry : entrySet) {
+			sb.append(sep);
+			sb.append(entry.getKey());
+			sb.append('=');
+			final Object value= entry.getValue();
+			if (value != null) {
+				sb.append(value);
+			}
+		}
+	}
+	
+	public static void prettyPrint(final Collection<?> list, final StringBuilder sb) {
+		final String sep= System.getProperty("line.separator")+"\t";
+		for (final Object value : list) {
+			sb.append(sep);
+			if (value != null) {
+				sb.append(value);
+			}
+		}
+	}
+	
+	public static void prettyPrintVersion(final int[] version, final StringBuilder sb) {
+		if (version == null || version.length == 0) {
+			sb.append("<missing>");
+		}
+		else {
+			sb.append(version[0]);
+			for (int i= 1; i < version.length; i++) {
+				sb.append('.');
+				sb.append(version[i]);
+			}
+		}
+	}
+	
+	
+	public static String concatPathVar(final Collection<String> entries) {
+		if (entries.isEmpty()) {
+			return "";
+		}
+		final StringBuilder sb= new StringBuilder();
+		for (final String entry : entries) {
+			sb.append(entry);
+			sb.append(File.pathSeparatorChar);
+		}
+		return sb.substring(0, sb.length()-1);
+	}
+	
+	private static String encodeCodebaseEntry(String path) {
+		if (path == null || path.isEmpty()) {
+			return null;
+		}
+		URI uri= null;
+		try {
+			if (path.startsWith("file:")) {
+				path= path.substring(5);
+				uri= new URI("file", null, path, null);
+			}
+			else {
+				if (File.separatorChar == '\\') {
+					path= path.replace('\\', '/');
+				}
+				if (path.charAt(0) != '/') {
+					path= '/' + path;
+				}
+				uri= new URI("file", null, path, null);
+			}
+			return uri.toString();
+		}
+		catch (final URISyntaxException e) {
+			throw new IllegalArgumentException("Invalid entry for codebase", e);
+		}
+	}
+	
+	/**
+	 * Concats the specified entries to a valid codebase property value.
+	 * The entries have to be path in the local file system. It is recommend to specify the entries
+	 * as URL with the schema 'file'.
+	 */
+	public static String concatCodebase(final Collection<String> entries) {
+		if (entries.isEmpty()) {
+			return "";
+		}
+		final StringBuilder sb= new StringBuilder();
+		for (final String entry : entries) {
+			final String path= encodeCodebaseEntry(entry);
+			if (path != null) {
+				sb.append(path);
+				sb.append(' ');
+			}
+		}
+		return sb.substring(0, sb.length()-1);
+	}
+	
+	public static boolean delDir(final File dir) {
+		final String[] children= dir.list();
+		for (final String child : children) {
+			final File file= new File(dir, child);
+			if (file.isDirectory()) {
+				delDir(file);
+			}
+			else {
+				file.delete();
+			}
+		}
+		return dir.delete();
+	}
+	
+	public static void cleanDir(final File dir, final String exclude) {
+		final String[] children= dir.list();
+		for (final String child : children) {
+			if (child.equals(exclude)) {
+				continue;
+			}
+			final File file= new File(dir, child);
+			if (file.isDirectory()) {
+				delDir(file);
+			}
+			else {
+				file.delete();
+			}
+		}
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.server/srcEExtensions/org/eclipse/statet/rj/server/e/srvext/SWTPlugin.java b/core/org.eclipse.statet.rj.server/srcEExtensions/org/eclipse/statet/rj/server/e/srvext/SWTPlugin.java
new file mode 100644
index 0000000..ab49038
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/srcEExtensions/org/eclipse/statet/rj/server/e/srvext/SWTPlugin.java
@@ -0,0 +1,57 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server.e.srvext;
+
+import org.eclipse.swt.widgets.Display;
+
+import org.eclipse.statet.rj.server.srvext.ServerRuntimePlugin;
+
+
+/**
+ * Creates a display for native widgets ('native' depends on SWT in classpath).
+ */
+public class SWTPlugin implements ServerRuntimePlugin {
+	
+	
+	private Display display;
+	
+	
+	public SWTPlugin() {
+	}
+	
+	
+	@Override
+	public String getSymbolicName() {
+		return "swt";
+	}
+	
+	@Override
+	public void rjIdle() throws Exception {
+		if (this.display == null) {
+			Display.setAppName("R");
+			this.display= new Display();
+		}
+		this.display.readAndDispatch();
+	}
+	
+	@Override
+	public void rjStop(final int regular) throws Exception {
+		if (this.display != null) {
+			this.display.dispose();
+			this.display= null;
+		}
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.server/srcEExtensions/org/eclipse/statet/rj/server/osgi/ERJContext.java b/core/org.eclipse.statet.rj.server/srcEExtensions/org/eclipse/statet/rj/server/osgi/ERJContext.java
new file mode 100644
index 0000000..ad1cbe1
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/srcEExtensions/org/eclipse/statet/rj/server/osgi/ERJContext.java
@@ -0,0 +1,150 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server.osgi;
+
+import static org.eclipse.statet.rj.server.util.ServerUtils.RJ_SERVER_ID;
+
+import java.io.IOException;
+import java.net.URL;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.osgi.framework.Bundle;
+
+import org.eclipse.core.runtime.FileLocator;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.Status;
+
+import org.eclipse.statet.jcommons.collections.ImCollections;
+
+import org.eclipse.statet.rj.RjInvalidConfigurationException;
+import org.eclipse.statet.rj.server.util.RJContext;
+
+
+/**
+ * Server utilities when using the Eclipse Platform.
+ */
+public class ERJContext extends RJContext {
+	
+	
+	private static void handle(final IStatus status) {
+		Platform.getLog(Platform.getBundle(RJ_SERVER_ID)).log(status);
+	}
+	
+	
+	public ERJContext() {
+	}
+	
+	
+	/**
+	 * Searches the specified RJ libraries in the Eclipse Platform installations
+	 * <p>
+	 * Uses always the os/arch currently running.</p>
+	 * 
+	 * @param libIds the bundle ids of the libraries
+	 * @return the file paths of the found libraries
+	 */
+	@Override
+	public List<String> searchRJLibs(final List<String> libIds) {
+		final Set<String> resolved= new LinkedHashSet<>();
+		for (final String libId : libIds) {
+			final Bundle pluginBundle= Platform.getBundle(libId);
+			if (pluginBundle != null) {
+				addPath(pluginBundle, resolved);
+				final Bundle[] fragments= Platform.getFragments(pluginBundle);
+				if (fragments != null) {
+					for (final Bundle fragmentBundle : fragments) {
+						addPath(fragmentBundle, resolved);
+					}
+				}
+			}
+		}
+		return ImCollections.toList(resolved);
+	}
+	
+	private void addPath(final Bundle bundle, final Set<String> classpath) {
+//		String location= bundle.getLocation();
+//		if (location.startsWith("initial@")) {
+//			location= location.substring(8);
+//		}
+//		if (location.startsWith("reference:file:")) { //$NON-NLS-1$
+//			location= location.substring(15);
+//			IPath path= new Path(location);
+//			if (!path.isAbsolute()) {
+//				path= new Path(Platform.getInstallLocation().getURL().getFile()).append(path);
+//			}
+//			String checked= path.lastSegment();
+//			if (checked.contains("motif")) { //$NON-NLS-1$
+//				checked= checked.replaceAll("motif", "gtk"); //$NON-NLS-1$ //$NON-NLS-2$
+//			}
+//			if (checked.contains("gtk")) { //$NON-NLS-1$
+//				if (is64 && !checked.contains("64")) { //$NON-NLS-1$
+//					checked= checked.replaceAll("x86", "x86_64"); //$NON-NLS-1$ //$NON-NLS-2$
+//				}
+//				if (!is64 && checked.contains("64")) { //$NON-NLS-1$
+//					checked= checked.replaceAll("x86_64", "x86"); //$NON-NLS-1$ //$NON-NLS-2$
+//				}
+//			}
+//			final String s= path.removeLastSegments(1).append(checked).makeAbsolute().toOSString();
+//			if (location.endsWith("/")) { // //$NON-NLS-1$
+//				if (Platform.inDevelopmentMode()) {
+//					classpath.add(s+File.separatorChar+"bin"+File.separatorChar); //$NON-NLS-1$
+//				}
+//				classpath.add(s+File.separatorChar);
+//			}
+//			else {
+//				classpath.add(s);
+//			}
+//			return;
+//		}
+		try {
+			String s= FileLocator.resolve(bundle.getEntry("/")).toExternalForm();
+			if (s.startsWith("jar:") && s.endsWith("!/")) {
+				s= s.substring(4, s.length()-2);
+			}
+			if (s.startsWith("file:")) {
+				s= s.substring(5);
+			}
+			if (Platform.inDevelopmentMode() && s.endsWith("/")) {
+				classpath.add(s+"bin/");
+			}
+			classpath.add(s);
+			return;
+		}
+		catch (final Exception e) {}
+		handle(new Status(IStatus.WARNING, RJ_SERVER_ID, 
+				"Unknown location for plug-in: '"+bundle.getBundleId()+"'. May cause fail to startup RJ (RMI/JRI)")); //$NON-NLS-1$ //$NON-NLS-2$
+	}
+	
+	@Override
+	public String getServerPolicyFilePath() throws RjInvalidConfigurationException {
+		try {
+			final Bundle bundle= Platform.getBundle(RJ_SERVER_ID);
+			if (bundle == null) {
+				throw new RjInvalidConfigurationException("RJ Server bundle ('"+RJ_SERVER_ID+"') is missing.");
+			}
+			final URL intern= bundle.getEntry("/localhost.policy"); 
+			final URL java= FileLocator.resolve(intern);
+			final String path= java.toExternalForm();
+			return path;
+		}
+		catch (final IOException e) {
+			throw new RjInvalidConfigurationException("Failed to resolve path to 'localhost.policy'.", e);
+		}
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.services.core/.classpath b/core/org.eclipse.statet.rj.services.core/.classpath
new file mode 100644
index 0000000..020ba8c
--- /dev/null
+++ b/core/org.eclipse.statet.rj.services.core/.classpath
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8">
+		<attributes>
+			<attribute name="owner.project.facets" value="java"/>
+		</attributes>
+	</classpathentry>
+	<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+	<classpathentry kind="src" path="src"/>
+	<classpathentry kind="src" path="srcREnv"/>
+	<classpathentry kind="src" path="srcGraphic"/>
+	<classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/core/org.eclipse.statet.rj.services.core/.gitignore b/core/org.eclipse.statet.rj.services.core/.gitignore
new file mode 100644
index 0000000..5e56e04
--- /dev/null
+++ b/core/org.eclipse.statet.rj.services.core/.gitignore
@@ -0,0 +1 @@
+/bin
diff --git a/core/org.eclipse.statet.rj.services.core/.project b/core/org.eclipse.statet.rj.services.core/.project
new file mode 100644
index 0000000..394d5aa
--- /dev/null
+++ b/core/org.eclipse.statet.rj.services.core/.project
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>org.eclipse.statet.rj.services.core</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.wst.common.project.facet.core.builder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.jdt.core.javabuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.pde.ManifestBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.pde.SchemaBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.pde.api.tools.apiAnalysisBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.pde.PluginNature</nature>
+		<nature>org.eclipse.jdt.core.javanature</nature>
+		<nature>org.eclipse.pde.api.tools.apiAnalysisNature</nature>
+		<nature>org.eclipse.wst.common.modulecore.ModuleCoreNature</nature>
+		<nature>org.eclipse.wst.common.project.facet.core.nature</nature>
+	</natures>
+</projectDescription>
diff --git a/core/org.eclipse.statet.rj.services.core/.settings/org.eclipse.core.resources.prefs b/core/org.eclipse.statet.rj.services.core/.settings/org.eclipse.core.resources.prefs
new file mode 100644
index 0000000..99f26c0
--- /dev/null
+++ b/core/org.eclipse.statet.rj.services.core/.settings/org.eclipse.core.resources.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+encoding/<project>=UTF-8
diff --git a/core/org.eclipse.statet.rj.services.core/.settings/org.eclipse.core.runtime.prefs b/core/org.eclipse.statet.rj.services.core/.settings/org.eclipse.core.runtime.prefs
new file mode 100644
index 0000000..5a0ad22
--- /dev/null
+++ b/core/org.eclipse.statet.rj.services.core/.settings/org.eclipse.core.runtime.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+line.separator=\n
diff --git a/core/org.eclipse.statet.rj.services.core/.settings/org.eclipse.jdt.core.prefs b/core/org.eclipse.statet.rj.services.core/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000..ccb1eaa
--- /dev/null
+++ b/core/org.eclipse.statet.rj.services.core/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,325 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.codeComplete.argumentPrefixes=
+org.eclipse.jdt.core.codeComplete.argumentSuffixes=
+org.eclipse.jdt.core.codeComplete.fieldPrefixes=
+org.eclipse.jdt.core.codeComplete.fieldSuffixes=
+org.eclipse.jdt.core.codeComplete.localPrefixes=
+org.eclipse.jdt.core.codeComplete.localSuffixes=
+org.eclipse.jdt.core.codeComplete.staticFieldPrefixes=
+org.eclipse.jdt.core.codeComplete.staticFieldSuffixes=
+org.eclipse.jdt.core.codeComplete.staticFinalFieldPrefixes=
+org.eclipse.jdt.core.codeComplete.staticFinalFieldSuffixes=
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=1.8
+org.eclipse.jdt.core.compiler.debug.lineNumber=generate
+org.eclipse.jdt.core.compiler.debug.localVariable=generate
+org.eclipse.jdt.core.compiler.debug.sourceFile=generate
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.source=1.8
+org.eclipse.jdt.core.formatter.align_fields_grouping_blank_lines=2147483647
+org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_assignment=0
+org.eclipse.jdt.core.formatter.alignment_for_binary_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_compact_if=16
+org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=80
+org.eclipse.jdt.core.formatter.alignment_for_enum_constants=0
+org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16
+org.eclipse.jdt.core.formatter.alignment_for_expressions_in_for_loop_header=0
+org.eclipse.jdt.core.formatter.alignment_for_method_declaration=0
+org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16
+org.eclipse.jdt.core.formatter.alignment_for_parameterized_type_references=0
+org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_resources_in_try=85
+org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=16
+org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_type_arguments=0
+org.eclipse.jdt.core.formatter.alignment_for_type_parameters=0
+org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch=16
+org.eclipse.jdt.core.formatter.blank_lines_after_imports=2
+org.eclipse.jdt.core.formatter.blank_lines_after_package=1
+org.eclipse.jdt.core.formatter.blank_lines_before_field=0
+org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=1
+org.eclipse.jdt.core.formatter.blank_lines_before_imports=1
+org.eclipse.jdt.core.formatter.blank_lines_before_member_type=1
+org.eclipse.jdt.core.formatter.blank_lines_before_method=1
+org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=2
+org.eclipse.jdt.core.formatter.blank_lines_before_package=1
+org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=1
+org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=1
+org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_block=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_lambda_body=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=false
+org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=false
+org.eclipse.jdt.core.formatter.comment.format_block_comments=true
+org.eclipse.jdt.core.formatter.comment.format_header=false
+org.eclipse.jdt.core.formatter.comment.format_html=true
+org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=true
+org.eclipse.jdt.core.formatter.comment.format_line_comments=true
+org.eclipse.jdt.core.formatter.comment.format_source_code=true
+org.eclipse.jdt.core.formatter.comment.indent_parameter_description=false
+org.eclipse.jdt.core.formatter.comment.indent_root_tags=true
+org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert
+org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=do not insert
+org.eclipse.jdt.core.formatter.comment.line_length=100
+org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries=false
+org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries=true
+org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments=false
+org.eclipse.jdt.core.formatter.compact_else_if=true
+org.eclipse.jdt.core.formatter.continuation_indentation=2
+org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=2
+org.eclipse.jdt.core.formatter.disabling_tag=@formatter\:off
+org.eclipse.jdt.core.formatter.enabling_tag=@formatter\:on
+org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false
+org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true
+org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true
+org.eclipse.jdt.core.formatter.indent_empty_lines=true
+org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true
+org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true
+org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true
+org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=false
+org.eclipse.jdt.core.formatter.indentation.size=4
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_enum_constant=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_label=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_type_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert
+org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert
+org.eclipse.jdt.core.formatter.insert_space_after_lambda_arrow=insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources=insert
+org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert
+org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=insert
+org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert
+org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw=insert
+org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.join_lines_in_comments=true
+org.eclipse.jdt.core.formatter.join_wrapped_lines=true
+org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=false
+org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false
+org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=false
+org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false
+org.eclipse.jdt.core.formatter.lineSplit=100
+org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false
+org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=false
+org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0
+org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=1
+org.eclipse.jdt.core.formatter.parentheses_positions_in_annotation=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_catch_clause=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_enum_constant_declaration=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_for_statment=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_if_while_statement=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_lambda_declaration=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_method_delcaration=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_method_invocation=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_switch_statement=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_try_clause=common_lines
+org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=true
+org.eclipse.jdt.core.formatter.tabulation.char=tab
+org.eclipse.jdt.core.formatter.tabulation.size=4
+org.eclipse.jdt.core.formatter.use_on_off_tags=false
+org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false
+org.eclipse.jdt.core.formatter.wrap_before_assignment_operator=false
+org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true
+org.eclipse.jdt.core.formatter.wrap_before_conditional_operator=false
+org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch=true
+org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true
+org.eclipse.jdt.core.javaFormatter=org.eclipse.jdt.core.defaultJavaFormatter
diff --git a/core/org.eclipse.statet.rj.services.core/.settings/org.eclipse.jdt.ui.prefs b/core/org.eclipse.statet.rj.services.core/.settings/org.eclipse.jdt.ui.prefs
new file mode 100644
index 0000000..e62a4f5
--- /dev/null
+++ b/core/org.eclipse.statet.rj.services.core/.settings/org.eclipse.jdt.ui.prefs
@@ -0,0 +1,131 @@
+cleanup.add_default_serial_version_id=true
+cleanup.add_generated_serial_version_id=false
+cleanup.add_missing_annotations=true
+cleanup.add_missing_deprecated_annotations=true
+cleanup.add_missing_methods=false
+cleanup.add_missing_nls_tags=false
+cleanup.add_missing_override_annotations=true
+cleanup.add_missing_override_annotations_interface_methods=true
+cleanup.add_serial_version_id=false
+cleanup.always_use_blocks=true
+cleanup.always_use_parentheses_in_expressions=true
+cleanup.always_use_this_for_non_static_field_access=true
+cleanup.always_use_this_for_non_static_method_access=false
+cleanup.convert_functional_interfaces=false
+cleanup.convert_to_enhanced_for_loop=false
+cleanup.correct_indentation=false
+cleanup.format_source_code=false
+cleanup.format_source_code_changes_only=false
+cleanup.insert_inferred_type_arguments=false
+cleanup.make_local_variable_final=true
+cleanup.make_parameters_final=true
+cleanup.make_private_fields_final=true
+cleanup.make_type_abstract_if_missing_method=false
+cleanup.make_variable_declarations_final=true
+cleanup.never_use_blocks=false
+cleanup.never_use_parentheses_in_expressions=false
+cleanup.organize_imports=true
+cleanup.qualify_static_field_accesses_with_declaring_class=false
+cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true
+cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=false
+cleanup.qualify_static_member_accesses_with_declaring_class=true
+cleanup.qualify_static_method_accesses_with_declaring_class=false
+cleanup.remove_private_constructors=true
+cleanup.remove_redundant_type_arguments=true
+cleanup.remove_trailing_whitespaces=false
+cleanup.remove_trailing_whitespaces_all=true
+cleanup.remove_trailing_whitespaces_ignore_empty=false
+cleanup.remove_unnecessary_casts=true
+cleanup.remove_unnecessary_nls_tags=true
+cleanup.remove_unused_imports=true
+cleanup.remove_unused_local_variables=false
+cleanup.remove_unused_private_fields=true
+cleanup.remove_unused_private_members=false
+cleanup.remove_unused_private_methods=true
+cleanup.remove_unused_private_types=true
+cleanup.sort_members=false
+cleanup.sort_members_all=false
+cleanup.use_anonymous_class_creation=false
+cleanup.use_blocks=true
+cleanup.use_blocks_only_for_return_and_throw=false
+cleanup.use_lambda=true
+cleanup.use_parentheses_in_expressions=false
+cleanup.use_this_for_non_static_field_access=true
+cleanup.use_this_for_non_static_field_access_only_if_necessary=false
+cleanup.use_this_for_non_static_method_access=true
+cleanup.use_this_for_non_static_method_access_only_if_necessary=true
+cleanup.use_type_arguments=false
+cleanup_profile=_StatET
+cleanup_settings_version=2
+eclipse.preferences.version=1
+editor_save_participant_org.eclipse.jdt.ui.postsavelistener.cleanup=true
+formatter_profile=_StatET
+formatter_settings_version=12
+org.eclipse.jdt.ui.exception.name=e
+org.eclipse.jdt.ui.gettersetter.use.is=true
+org.eclipse.jdt.ui.ignorelowercasenames=true
+org.eclipse.jdt.ui.importorder=\#;java;javax;com.ibm.icu;org.osgi;org.eclipse;;org.eclipse.statet.jcommons;org.eclipse.statet.ecommons;org.eclipse.statet;
+org.eclipse.jdt.ui.javadoc=true
+org.eclipse.jdt.ui.keywordthis=true
+org.eclipse.jdt.ui.ondemandthreshold=99
+org.eclipse.jdt.ui.overrideannotation=true
+org.eclipse.jdt.ui.staticondemandthreshold=99
+org.eclipse.jdt.ui.text.custom_code_templates=<?xml version\="1.0" encoding\="UTF-8" standalone\="no"?><templates><template autoinsert\="true" context\="gettercomment_context" deleted\="false" description\="Comment for getter method" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.gettercomment" name\="gettercomment">/**\n * @return the ${bare_field_name}\n */</template><template autoinsert\="true" context\="settercomment_context" deleted\="false" description\="Comment for setter method" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.settercomment" name\="settercomment">/**\n * @param ${param} the ${bare_field_name} to set\n */</template><template autoinsert\="true" context\="constructorcomment_context" deleted\="false" description\="Comment for created constructors" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.constructorcomment" name\="constructorcomment">/**\n * ${tags}\n */</template><template autoinsert\="false" context\="filecomment_context" deleted\="false" description\="Comment for created Java files" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.filecomment" name\="filecomment">/*\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\#\n \# Copyright (c) ${year} ${user} and others.\n # \n # This program and the accompanying materials are made available under the\n # terms of the Eclipse Public License 2.0 which is available at\n # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n # which is available at https://www.apache.org/licenses/LICENSE-2.0.\n # \n # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n # \n \# Contributors\:\n \#     ${user} - initial API and implementation\n \#\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=*/</template><template autoinsert\="false" context\="typecomment_context" deleted\="false" description\="Comment for created types" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.typecomment" name\="typecomment">/**\n * \n * ${tags}\n */</template><template autoinsert\="true" context\="fieldcomment_context" deleted\="false" description\="Comment for fields" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.fieldcomment" name\="fieldcomment">/**\n * \n */</template><template autoinsert\="true" context\="methodcomment_context" deleted\="false" description\="Comment for non-overriding methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.methodcomment" name\="methodcomment">/**\n * ${tags}\n */</template><template autoinsert\="false" context\="overridecomment_context" deleted\="false" description\="Comment for overriding methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.overridecomment" name\="overridecomment"/><template autoinsert\="true" context\="delegatecomment_context" deleted\="false" description\="Comment for delegate methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.delegatecomment" name\="delegatecomment">/**\n * ${tags}\n * ${see_to_target}\n */</template><template autoinsert\="false" context\="newtype_context" deleted\="false" description\="Newly created files" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.newtype" name\="newtype">${filecomment}\n\n${package_declaration}\n\n${typecomment}\n${type_declaration}</template><template autoinsert\="true" context\="classbody_context" deleted\="false" description\="Code in new class type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.classbody" name\="classbody">\n</template><template autoinsert\="true" context\="interfacebody_context" deleted\="false" description\="Code in new interface type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.interfacebody" name\="interfacebody">\n</template><template autoinsert\="true" context\="enumbody_context" deleted\="false" description\="Code in new enum type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.enumbody" name\="enumbody">\n</template><template autoinsert\="true" context\="annotationbody_context" deleted\="false" description\="Code in new annotation type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.annotationbody" name\="annotationbody">\n</template><template autoinsert\="true" context\="catchblock_context" deleted\="false" description\="Code in new catch blocks" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.catchblock" name\="catchblock">// ${todo} Auto-generated catch block\n${exception_var}.printStackTrace();</template><template autoinsert\="true" context\="methodbody_context" deleted\="false" description\="Code in created method stubs" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.methodbody" name\="methodbody">// ${todo} Auto-generated method stub\n${body_statement}</template><template autoinsert\="true" context\="constructorbody_context" deleted\="false" description\="Code in created constructor stubs" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.constructorbody" name\="constructorbody">${body_statement}\n// ${todo} Auto-generated constructor stub</template><template autoinsert\="true" context\="getterbody_context" deleted\="false" description\="Code in created getters" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.getterbody" name\="getterbody">return ${field};</template><template autoinsert\="true" context\="setterbody_context" deleted\="false" description\="Code in created setters" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.setterbody" name\="setterbody">${field} \= ${param};</template></templates>
+sp_cleanup.add_default_serial_version_id=true
+sp_cleanup.add_generated_serial_version_id=false
+sp_cleanup.add_missing_annotations=true
+sp_cleanup.add_missing_deprecated_annotations=true
+sp_cleanup.add_missing_methods=false
+sp_cleanup.add_missing_nls_tags=false
+sp_cleanup.add_missing_override_annotations=true
+sp_cleanup.add_missing_override_annotations_interface_methods=true
+sp_cleanup.add_serial_version_id=false
+sp_cleanup.always_use_blocks=true
+sp_cleanup.always_use_parentheses_in_expressions=true
+sp_cleanup.always_use_this_for_non_static_field_access=true
+sp_cleanup.always_use_this_for_non_static_method_access=false
+sp_cleanup.convert_functional_interfaces=false
+sp_cleanup.convert_to_enhanced_for_loop=false
+sp_cleanup.correct_indentation=false
+sp_cleanup.format_source_code=false
+sp_cleanup.format_source_code_changes_only=false
+sp_cleanup.insert_inferred_type_arguments=false
+sp_cleanup.make_local_variable_final=true
+sp_cleanup.make_parameters_final=true
+sp_cleanup.make_private_fields_final=true
+sp_cleanup.make_type_abstract_if_missing_method=false
+sp_cleanup.make_variable_declarations_final=false
+sp_cleanup.never_use_blocks=false
+sp_cleanup.never_use_parentheses_in_expressions=false
+sp_cleanup.on_save_use_additional_actions=true
+sp_cleanup.organize_imports=true
+sp_cleanup.qualify_static_field_accesses_with_declaring_class=false
+sp_cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true
+sp_cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=false
+sp_cleanup.qualify_static_member_accesses_with_declaring_class=true
+sp_cleanup.qualify_static_method_accesses_with_declaring_class=false
+sp_cleanup.remove_private_constructors=true
+sp_cleanup.remove_redundant_type_arguments=true
+sp_cleanup.remove_trailing_whitespaces=false
+sp_cleanup.remove_trailing_whitespaces_all=false
+sp_cleanup.remove_trailing_whitespaces_ignore_empty=true
+sp_cleanup.remove_unnecessary_casts=true
+sp_cleanup.remove_unnecessary_nls_tags=false
+sp_cleanup.remove_unused_imports=false
+sp_cleanup.remove_unused_local_variables=false
+sp_cleanup.remove_unused_private_fields=false
+sp_cleanup.remove_unused_private_members=false
+sp_cleanup.remove_unused_private_methods=false
+sp_cleanup.remove_unused_private_types=true
+sp_cleanup.sort_members=false
+sp_cleanup.sort_members_all=false
+sp_cleanup.use_anonymous_class_creation=false
+sp_cleanup.use_blocks=true
+sp_cleanup.use_blocks_only_for_return_and_throw=false
+sp_cleanup.use_lambda=false
+sp_cleanup.use_parentheses_in_expressions=false
+sp_cleanup.use_this_for_non_static_field_access=true
+sp_cleanup.use_this_for_non_static_field_access_only_if_necessary=false
+sp_cleanup.use_this_for_non_static_method_access=true
+sp_cleanup.use_this_for_non_static_method_access_only_if_necessary=true
+sp_cleanup.use_type_arguments=false
diff --git a/core/org.eclipse.statet.rj.services.core/.settings/org.eclipse.wst.common.component b/core/org.eclipse.statet.rj.services.core/.settings/org.eclipse.wst.common.component
new file mode 100644
index 0000000..8428fc2
--- /dev/null
+++ b/core/org.eclipse.statet.rj.services.core/.settings/org.eclipse.wst.common.component
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project-modules id="moduleCoreId" project-version="1.5.0">
+    <wb-module deploy-name="org.eclipse.statet.rj.services.core">
+        <wb-resource deploy-path="/" source-path="/src"/>
+        <wb-resource deploy-path="/" source-path="/srcGraphic"/>
+    </wb-module>
+</project-modules>
diff --git a/core/org.eclipse.statet.rj.services.core/.settings/org.eclipse.wst.common.project.facet.core.xml b/core/org.eclipse.statet.rj.services.core/.settings/org.eclipse.wst.common.project.facet.core.xml
new file mode 100644
index 0000000..a1f5f3c
--- /dev/null
+++ b/core/org.eclipse.statet.rj.services.core/.settings/org.eclipse.wst.common.project.facet.core.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<faceted-project>
+  <fixed facet="java"/>
+  <fixed facet="jst.utility"/>
+  <installed facet="java" version="1.8"/>
+  <installed facet="jst.utility" version="1.0"/>
+</faceted-project>
diff --git a/core/org.eclipse.statet.rj.services.core/META-INF/MANIFEST.MF b/core/org.eclipse.statet.rj.services.core/META-INF/MANIFEST.MF
new file mode 100644
index 0000000..b71336a
--- /dev/null
+++ b/core/org.eclipse.statet.rj.services.core/META-INF/MANIFEST.MF
@@ -0,0 +1,16 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-SymbolicName: org.eclipse.statet.rj.services.core;singleton:=true
+Bundle-Version: 2.1.0.qualifier
+Bundle-Vendor: Eclipse.org
+Bundle-Name: StatET RJ - R Services API and Tools - Core
+Bundle-RequiredExecutionEnvironment: JavaSE-1.8
+Require-Bundle: org.eclipse.statet.rj.data;bundle-version="[2.1.0,2.2.0)";visibility:=reexport
+Import-Package: org.osgi.framework;version="1.8.0",
+ org.eclipse.core.runtime
+Export-Package: org.eclipse.statet.rj.graphic.core;version="1.0.0",
+ org.eclipse.statet.rj.graphic.core.util;version="1.0.0",
+ org.eclipse.statet.rj.renv.core;version="2.1.0",
+ org.eclipse.statet.rj.services;version="1.0.0",
+ org.eclipse.statet.rj.services.util;version="2.1.0",
+ org.eclipse.statet.rj.services.util.dataaccess;version="2.1.0"
diff --git a/core/org.eclipse.statet.rj.services.core/about.html b/core/org.eclipse.statet.rj.services.core/about.html
new file mode 100644
index 0000000..e71ae66
--- /dev/null
+++ b/core/org.eclipse.statet.rj.services.core/about.html
@@ -0,0 +1,37 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+		"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+<title>About</title>
+</head>
+<body lang="EN-US">
+<h2>About This Content</h2>
+
+<p>December 1, 2017</p>
+<h3>License</h3>
+
+<p>
+	The Eclipse Foundation makes available all content in this plug-in
+	(&quot;Content&quot;). Unless otherwise indicated below, the Content
+	is provided to you under the terms and conditions of the Eclipse
+	Public License Version 2.0 (&quot;EPL&quot;), or the Apache License,
+	Version 2.0 (AL). A copy of the EPL is available at <a href="https://www.eclipse.org/legal/epl-2.0">https://www.eclipse.org/legal/epl-2.0</a>.
+	For purposes of the EPL, &quot;Program&quot; will mean the Content.
+	A copy of the AL is available at <a href="https://www.apache.org/licenses/LICENSE-2.0">https://www.apache.org/licenses/LICENSE-2.0</a>.
+</p>
+
+<p>
+	If you did not receive this Content directly from the Eclipse
+	Foundation, the Content is being redistributed by another party
+	(&quot;Redistributor&quot;) and different terms and conditions may
+	apply to your use of any object code in the Content. Check the
+	Redistributor's license that was provided with the Content. If no such
+	license exists, contact the Redistributor. Unless otherwise indicated
+	below, the terms and conditions of the EPL or AL still apply to any
+	source code in the Content and such source code may be obtained at <a
+	href="https://www.eclipse.org/">https://www.eclipse.org</a>.
+</p>
+
+</body>
+</html>
diff --git a/core/org.eclipse.statet.rj.services.core/build.properties b/core/org.eclipse.statet.rj.services.core/build.properties
new file mode 100644
index 0000000..fe1609f
--- /dev/null
+++ b/core/org.eclipse.statet.rj.services.core/build.properties
@@ -0,0 +1,10 @@
+source..= src/,\
+          srcREnv/,\
+          srcGraphic/
+output..= bin/
+javacDefaultEncoding..= UTF-8
+
+bin.includes= META-INF/,\
+              .,\
+              about.html
+src.includes= .settings/org.eclipse.core.resources.prefs
diff --git a/core/org.eclipse.statet.rj.services.core/src/org/eclipse/statet/rj/services/FQRObjectRef.java b/core/org.eclipse.statet.rj.services.core/src/org/eclipse/statet/rj/services/FQRObjectRef.java
new file mode 100644
index 0000000..86a6235
--- /dev/null
+++ b/core/org.eclipse.statet.rj.services.core/src/org/eclipse/statet/rj/services/FQRObjectRef.java
@@ -0,0 +1,49 @@
+/*=============================================================================#
+ # Copyright (c) 2016, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.services;
+
+import org.eclipse.statet.rj.data.RObject;
+
+
+/**
+ * Fully qualified reference to an R object.
+ * 
+ * @since 2.1 (provisional)
+ */
+public interface FQRObjectRef {
+	
+	
+	/**
+	 * Handle to the R instance.
+	 * 
+	 * @return handle to R.
+	 */
+	Object getRHandle();
+	
+	/**
+	 * The environment in R, specified by a call or reference.
+	 * 
+	 * @return a reference to the environment
+	 */
+	RObject getEnv();
+	
+	/**
+	 * Name, relative to the environment, specified by a symbol or call.
+	 * 
+	 * @return the name
+	 */
+	RObject getName();
+	
+}
diff --git a/core/org.eclipse.statet.rj.services.core/src/org/eclipse/statet/rj/services/FunctionCall.java b/core/org.eclipse.statet.rj.services.core/src/org/eclipse/statet/rj/services/FunctionCall.java
new file mode 100644
index 0000000..6008e09
--- /dev/null
+++ b/core/org.eclipse.statet.rj.services.core/src/org/eclipse/statet/rj/services/FunctionCall.java
@@ -0,0 +1,340 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.services;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+
+import org.eclipse.statet.rj.data.RObject;
+import org.eclipse.statet.rj.data.RStore;
+
+
+/**
+ * A function call provides a comfortable way to build and execute
+ * R function call.
+ * 
+ * <p>A function call builder for a given function can be created by 
+ * {@link RService#createFunctionCall(String)}.</p>
+ * 
+ * <p>The builder mainly provides methods to add arguments and to
+ * finally evaluate the resulting function call in R.</p>
+ * 
+ * <p>Arguments are added by the <code>#add...()</code> methods. The
+ * order they are added is exactly the order they are send to R. There
+ * are add methods for a symbol referring to data existing in R, 
+ * for given R data objects and for single data values which are
+ * transformed automatically from java primitives into R data objects.
+ * All methods are available in a variant with and without a parameter 
+ * for the R argument name. An unnamed argument can be specified by
+ * using the variant without the argument name parameter or by specifying
+ * the name as <code>null</code>.</p>
+ * 
+ * <p>The common guidelines in {@link RService} (like concurrency) are effective
+ * for all evaluation methods in this interface.</p>
+ */
+public interface FunctionCall {
+	
+	
+	/**
+	 * Adds an argument with the given R expression as value.
+	 * 
+	 * <p>The expression is parsed and lazily evaluated as known from function calls in R source
+	 * code.</p>
+	 * 
+	 * @param arg the name of the argument or <code>null</code> for unnamed
+	 * @param expression a single valid expression
+	 * @return a reference to this object
+	 * 
+	 * @see #addChar(String, String) to add a string/character value directly
+	 */
+	FunctionCall add(String arg, String expression);
+	
+	/**
+	 * Adds a unnamed argument with the given R expression as value.
+	 * 
+	 * <p>The expression is parsed and lazily evaluated as known from function calls in R source
+	 * code.</p>
+	 * 
+	 * @param expression a single valid expression
+	 * @return a reference to this object
+	 * 
+	 * @see #addChar(String) to add a string/character value directly
+	 */
+	FunctionCall add(String expression);
+	
+	/**
+	 * Adds a argument with the given R data object as value.
+	 * 
+	 * @param arg the name of the argument or <code>null</code> for unnamed
+	 * @param data an R data object
+	 * @return a reference to this object
+	 */
+	FunctionCall add(String arg, RObject data);
+	
+	/**
+	 * Adds an unnamed argument with the given R data object as value.
+	 * 
+	 * @param arg the name of the argument
+	 * @param data an R data object
+	 * @return a reference to this object
+	 */
+	FunctionCall add(RObject data);
+	
+	
+	/**
+	 * Adds an argument with the given boolean/logical as value.
+	 * 
+	 * <p>The Java boolean value is transformed into an R data object 
+	 * of type {@link RStore#LOGICAL logical}.</p>
+	 * 
+	 * @param arg the name of the argument or <code>null</code> for unnamed
+	 * @param logical the value of the argument
+	 * @return a reference to this object
+	 */
+	FunctionCall addLogi(String arg, boolean logical);
+	
+	/**
+	 * Adds an unnamed argument with the given boolean/logical as value.
+	 * 
+	 * <p>The Java boolean value is transformed into an R data object 
+	 * of type {@link RStore#LOGICAL logical}.</p>
+	 * 
+	 * @param logical the value of the argument
+	 * @return a reference to this object
+	 */
+	FunctionCall addLogi(boolean logical);
+	
+	/**
+	 * Adds an argument with the given integer as value.
+	 * 
+	 * <p>The Java integer value is transformed into an R data object 
+	 * of type {@link RStore#INTEGER integer}.</p>
+	 * 
+	 * @param arg the name of the argument or <code>null</code> for unnamed
+	 * @param integer the value of the argument
+	 * @return a reference to this object
+	 */
+	FunctionCall addInt(String arg, int integer);
+	
+	/**
+	 * Adds an unnamed argument with the given integer as value.
+	 * 
+	 * <p>The Java integer value is transformed into an R data object 
+	 * of type {@link RStore#INTEGER integer}.</p>
+	 * 
+	 * @param integer the value of the argument
+	 * @return a reference to this object
+	 */
+	FunctionCall addInt(int integer);
+	
+	/**
+	 * Adds an argument with the given double/numeric as value.
+	 * 
+	 * <p>The Java double value is transformed into an R data object 
+	 * of type {@link RStore#NUMERIC numeric}, also called real.</p>
+	 * 
+	 * @param arg the name of the argument or <code>null</code> for unnamed
+	 * @param numeric the value of the argument
+	 * @return a reference to this object
+	 */
+	FunctionCall addNum(String arg, double numeric);
+	
+	/**
+	 * Adds an unnamed argument with the given double/numeric as value.
+	 * 
+	 * <p>The Java double value is transformed into an R data object 
+	 * of type {@link RStore#NUMERIC numeric}, also called real.</p>
+	 * 
+	 * @param arg the name of the argument
+	 * @param numeric the value of the argument
+	 * @return a reference to this object
+	 */
+	FunctionCall addNum(double numeric);
+	
+	/**
+	 * Adds an argument with the given string/character as value.
+	 * 
+	 * <p>The Java String value is transformed into an R data object 
+	 * of type {@link RStore#CHARACTER character}.</p>
+	 * 
+	 * @param arg the name of the argument or <code>null</code> for unnamed
+	 * @param character the value of the argument
+	 * @return a reference to this object
+	 */
+	FunctionCall addCplx(String arg, double real, double imaginary);
+	
+	/**
+	 * Adds an unnamed argument with the given string/character as value.
+	 * 
+	 * <p>The Java String value is transformed into an R data object 
+	 * of type {@link RStore#CHARACTER character}.</p>
+	 * 
+	 * @param character the value of the argument
+	 * @return a reference to this object
+	 */
+	FunctionCall addCplx(double real, double imaginary);
+	
+	/**
+	 * Adds an argument with the given string/character as value.
+	 * 
+	 * <p>The Java String value is transformed into an R data object 
+	 * of type {@link RStore#CHARACTER character}.</p>
+	 * 
+	 * @param arg the name of the argument or <code>null</code> for unnamed
+	 * @param character the value of the argument
+	 * @return a reference to this object
+	 */
+	FunctionCall addChar(String arg, String character);
+	
+	/**
+	 * Adds an unnamed argument with the given string/character as value.
+	 * 
+	 * <p>The Java String value is transformed into an R data object 
+	 * of type {@link RStore#CHARACTER character}.</p>
+	 * 
+	 * @param character the value of the argument
+	 * @return a reference to this object
+	 */
+	FunctionCall addChar(String character);
+	
+	/**
+	 * Adds an argument with the given NULL as value.
+	 * 
+	 * <p>The Java String value is transformed into an R data 
+	 * {@link RObject#NULL NULL} object.</p>
+	 * 
+	 * @param arg the name of the argument or <code>null</code> for unnamed
+	 * @return a reference to this object
+	 */
+	FunctionCall addNull(String arg);
+	
+	/**
+	 * Adds an unnamed argument with the given NULL as value.
+	 * 
+	 * <p>The Java String value is transformed into an R data 
+	 * {@link RObject#NULL NULL} object.</p>
+	 * 
+	 * @return a reference to this object
+	 */
+	FunctionCall addNull();
+	
+	
+	/**
+	 * Performs the evaluation of this function call in R without returning a value.
+	 * The method returns after the evaluation is finished.
+	 * 
+	 * <p>The evaluation is performed in the global environment of R.</p>
+	 * 
+	 * @param monitor a progress monitor to catch cancellation and provide progress feedback.
+	 * @throws CoreException if the operation was canceled or failed; the status
+	 *     of the exception contains detail about the cause
+	 */
+	void evalVoid(IProgressMonitor monitor) throws CoreException;
+	
+	/**
+	 * Performs the evaluation of this function call in R without returning a value.
+	 * The method returns after the evaluation is finished.
+	 * 
+	 * <p>This method allows advanced configuration for the evaluation.</p>
+	 * 
+	 * @param envir the environment where to perform the evaluation; specified by an reference
+	 *     or language object, or <code>null</code> for the global environment
+	 * @param monitor a progress monitor to catch cancellation and provide progress feedback.
+	 * @throws CoreException if the operation was canceled or failed; the status
+	 *     of the exception contains detail about the cause
+	 * 
+	 * @since de.walware.rj.services 2.1
+	 */
+	void evalVoid(RObject envir, IProgressMonitor monitor) throws CoreException;
+	
+	/**
+	 * Performs the evaluation of the this function call in R and returns its value as R data object.
+	 * The method returns after the evaluation is finished.
+	 * 
+	 * <p>This is a short version of {@link #evalData(String, int, int, IProgressMonitor)}
+	 * sufficient for most purpose. The returned R data objects are created by the default factory
+	 * with no limit in the object tree depth.</p>
+	 * 
+	 * <p>The evaluation is performed in the global environment of R.</p>
+	 * 
+	 * @param monitor a progress monitor to catch cancellation and provide progress feedback
+	 * @return the evaluated value as R data object
+	 * @throws CoreException if the operation was canceled or failed; the status
+	 *     of the exception contains detail about the cause
+	 */
+	RObject evalData(IProgressMonitor monitor) throws CoreException;
+	
+	/**
+	 * Performs the evaluation of the this function call in R and returns its value as R data object.
+	 * The method returns after the evaluation is finished.
+	 * 
+	 * <p>This method allows advanced configuration for the returned R data object.</p>
+	 * 
+	 * <p>The evaluation is performed in the global environment of R.</p>
+	 * 
+	 * @param factoryId the id of the factory to use when creating the RObject in this VM.
+	 * @param options 0
+	 * @param depth object tree depth for the created return value
+	 * @param monitor a progress monitor to catch cancellation and provide progress feedback
+	 * @return the evaluated value as R data object
+	 * @throws CoreException if the operation was canceled or failed; the status
+	 *     of the exception contains detail about the cause
+	 */
+	RObject evalData(String factoryId, int options, int depth,
+			IProgressMonitor monitor) throws CoreException;
+	
+	/**
+	 * Performs the evaluation of the this function call in R and returns its value as R data object.
+	 * The method returns after the evaluation is finished.
+	 * 
+	 * <p>This method allows advanced configuration for the evaluation and the returned R data
+	 * object.</p>
+	 * 
+	 * @param envir the environment where to perform the evaluation; specified by an reference
+	 *     or language object, or <code>null</code> for the global environment
+	 * @param factoryId the id of the factory to use when creating the RObject in this VM.
+	 * @param options 0
+	 * @param depth object tree depth for the created return value
+	 * @param monitor a progress monitor to catch cancellation and provide progress feedback
+	 * @return the evaluated value as R data object
+	 * @throws CoreException if the operation was canceled or failed; the status
+	 *     of the exception contains detail about the cause
+	 * 
+	 * @since de.walware.rj.services 2.1
+	 */
+	RObject evalData(RObject envir, String factoryId, int options, int depth,
+			IProgressMonitor monitor) throws CoreException;
+	
+	/**
+	 * Performs the evaluation of the this function call in R and assign its return value to
+	 * the specified expression.
+	 * 
+	 * <p>The target have to be a valid target expression for a R <code>&lt;-</code> assignment 
+	 * operation.  A single symbol like <code>x</code> or <code>`x-y`</code>, a path in an object 
+	 * tree like <code>xlist$item1</code> or <code>xobj@slotName</code> is valid as well as
+	 * special function calls which supports assignments like <code>dim(x)</code>.</p>
+	 * 
+	 * <p>The evaluation and assignment is performed in the global environment of R.</p>
+	 * 
+	 * @param target a single valid expression to assign the result to
+	 * @param monitor a progress monitor to catch cancellation and provide progress feedback
+	 * @throws CoreException if the operation was canceled or failed; the status
+	 *     of the exception contains detail about the cause
+	 * 
+	 * @since de.walware.rj.services 2.0
+	 */
+	void evalAssign(String target, IProgressMonitor monitor) throws CoreException;
+	
+}
diff --git a/core/org.eclipse.statet.rj.services.core/src/org/eclipse/statet/rj/services/RGraphicCreator.java b/core/org.eclipse.statet.rj.services.core/src/org/eclipse/statet/rj/services/RGraphicCreator.java
new file mode 100644
index 0000000..f7c3fdc
--- /dev/null
+++ b/core/org.eclipse.statet.rj.services.core/src/org/eclipse/statet/rj/services/RGraphicCreator.java
@@ -0,0 +1,47 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.services;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+
+import org.eclipse.statet.rj.graphic.core.RGraphic;
+
+
+/**
+ * Controls the creation of {@link RGraphic}.
+ * 
+ * The creator can be access by {@link RService#createRGraphicCreator(int)}.
+ * A creator can be used multiple times for different graphics. Properties
+ * are reused and not reseted.
+ * 
+ * @noimplement This interface is not intended to be implemented by clients.
+ * @since de.walware.rj.services 0.5
+ */
+public interface RGraphicCreator {
+	
+	/**
+	 * Sets the size in pixel of the graphic to create.
+	 * 
+	 * @param width width in pixel
+	 * @param height height in pixel
+	 */
+	void setSize(double width, double height);
+	
+	RGraphic create(String expression, IProgressMonitor monitor) throws CoreException;
+	
+	RGraphic create(FunctionCall fcall, IProgressMonitor monitor) throws CoreException;
+	
+}
diff --git a/core/org.eclipse.statet.rj.services.core/src/org/eclipse/statet/rj/services/RJServices.java b/core/org.eclipse.statet.rj.services.core/src/org/eclipse/statet/rj/services/RJServices.java
new file mode 100644
index 0000000..6987a75
--- /dev/null
+++ b/core/org.eclipse.statet.rj.services.core/src/org/eclipse/statet/rj/services/RJServices.java
@@ -0,0 +1,28 @@
+/*=============================================================================#
+ # Copyright (c) 2016, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.services;
+
+
+public class RJServices {
+	
+	
+	public static final String BUNDLE_ID= "org.eclipse.statet.rj.services"; //$NON-NLS-1$
+	
+	
+	private RJServices() {
+	}
+	
+	
+}
diff --git a/core/org.eclipse.statet.rj.services.core/src/org/eclipse/statet/rj/services/RPlatform.java b/core/org.eclipse.statet.rj.services.core/src/org/eclipse/statet/rj/services/RPlatform.java
new file mode 100644
index 0000000..917ad20
--- /dev/null
+++ b/core/org.eclipse.statet.rj.services.core/src/org/eclipse/statet/rj/services/RPlatform.java
@@ -0,0 +1,155 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.services;
+
+import java.io.Externalizable;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+
+import org.osgi.framework.Version;
+
+
+/**
+ * Information about the platform R is running on
+ * and the running R version.
+ * 
+ * The properties usually doesn't change for a single RService
+ * instance.
+ */
+public final class RPlatform implements Externalizable {
+	
+	/**
+	 * OS type constant for windows operation systems
+	 */
+	public static final String OS_WINDOWS= "windows";
+	
+	/**
+	 * OS type constant for unix operation systems
+	 */
+	public static final String OS_UNIX= "unix";
+	
+	
+	private String osType;
+	
+	private String fileSep;
+	private String pathSep;
+	
+	private String versionString;
+	private transient Version version;
+	
+	private String osName;
+	private String osArch;
+	private String osVersion;
+	
+	
+	public RPlatform() {
+	}
+	
+	public RPlatform(final String osType, final String fileSep, final String pathSep,
+			final String version,
+			final String osName, final String osArch, final String osVersion) {
+		this.osType= osType;
+		this.fileSep= fileSep;
+		this.pathSep= pathSep;
+		this.versionString= version;
+		
+		this.osName= osName;
+		this.osArch= osArch;
+		this.osVersion= osVersion;
+	}
+	
+	
+	@Override
+	public void readExternal(final ObjectInput in) throws IOException, ClassNotFoundException {
+		this.osType= in.readUTF();
+		this.fileSep= in.readUTF();
+		this.pathSep= in.readUTF();
+		this.versionString= in.readUTF();
+		
+		this.osName= in.readUTF();
+		this.osArch= in.readUTF();
+		this.osVersion= in.readUTF();
+	}
+	
+	@Override
+	public void writeExternal(final ObjectOutput out) throws IOException {
+		out.writeUTF(this.osType);
+		out.writeUTF(this.fileSep);
+		out.writeUTF(this.pathSep);
+		out.writeUTF(this.versionString);
+		
+		out.writeUTF(this.osName);
+		out.writeUTF(this.osArch);
+		out.writeUTF(this.osVersion);
+	}
+	
+	
+	/**
+	 * The OS type as defined in R <code>.Platform$OS.type</code>
+	 * 
+	 * @see #OS_WINDOWS
+	 * @see #OS_UNIX
+	 * 
+	 * @return the os type constant
+	 */
+	public String getOsType() {
+		return this.osType;
+	}
+	
+	public String getFileSep() {
+		return this.fileSep;
+	}
+	
+	public String getPathSep() {
+		return this.pathSep;
+	}
+	
+	public Version getRVersion() {
+		if (this.version == null) {
+			this.version= new Version(this.versionString);
+		}
+		return this.version;
+	}
+	
+	
+	/**
+	 * The OS name as defined by the Java property <code>os.name</code>
+	 * 
+	 * @return the OS name string
+	 */
+	public String getOSName() {
+		return this.osName;
+	}
+	
+	/**
+	 * The OS architecture as defined by the Java property <code>os.arch</code>
+	 * 
+	 * @return the OS architecture string
+	 */
+	public String getOSArch() {
+		return this.osArch;
+	}
+	
+	/**
+	 * The OS version as defined by the Java property <code>os.version</code>
+	 * 
+	 * @return the OS version string
+	 */
+	public String getOSVersion() {
+		return this.osVersion;
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.services.core/src/org/eclipse/statet/rj/services/RService.java b/core/org.eclipse.statet.rj.services.core/src/org/eclipse/statet/rj/services/RService.java
new file mode 100644
index 0000000..edc4e69
--- /dev/null
+++ b/core/org.eclipse.statet.rj.services.core/src/org/eclipse/statet/rj/services/RService.java
@@ -0,0 +1,350 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.services;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+
+import org.eclipse.statet.rj.data.RObject;
+import org.eclipse.statet.rj.data.RReference;
+import org.eclipse.statet.rj.graphic.core.RGraphic;
+
+
+/**
+ * A interface with methods to evaluate and exchange data with R.
+ * <p>
+ * It depends on the application how to get access to the RService.
+ * In StatET it is passed as adapter argument in 
+ * {@link org.eclipse.statet.ecommons.ts.core.IToolRunnable#run(org.eclipse.statet.ecommons.ts.core.IToolService, IProgressMonitor) IToolRunnable#run(...)},
+ * if the R console supports the featureset {@link org.eclipse.statet.r.core.tool.RTool#R_DATA_FEATURESET_ID RTool#R_DATA_FEATURESET_ID}.
+ * In applications using R in the background by the RServi library, 
+ * the {@link org.eclipse.statet.rj.servi.RServi RServi} object provides the RService methods.</p>
+ * <p>
+ * If the application has also an console, the operations of an RService
+ * usually doesn't appears in the console. Even not recommended, it is possible
+ * to call special R functions like print which output is written to the console.
+ * It should absolutely avoided to use functions like <code>readline</code> which requires 
+ * interaction with the console.</p>
+ * <p>
+ * The methods of an RService should not be called concurrently by different
+ * threads. The RService consumer have to make sure that the function calls
+ * are synchronized, if multiple thread have access to the same instance.
+ * Implementations of RService interface can perform checks too, but the consumer 
+ * must not rely on that.</p>
+ * <p>
+ * Especially for longer evaluations, it is recommended that the application implements
+ * this synchronization in a way that the GUI is not blocked.
+ * In StatET both is guaranteed by a queue and a single execution thread for runnables.</p>
+ * <p>
+ * All data exchange methods are copy operations. So changes on R data objects in Java
+ * are not reflected in R and the other way round.</p>
+ * <p>
+ * In general it is not necessary to surround R expressions with try-catch or similar construction
+ * except the error object is expected as return value.</p>
+ * 
+ * @since de.walware.rj.services 0.4
+ */
+public interface RService {
+	
+	
+	/**
+	 * Value for depth parameters indicating that the depth is not limited.
+	 * 
+	 * @since de.walware.rj.services 0.5
+	 */
+	int DEPTH_INFINITE= -1;
+	
+	/**
+	 * Value for depth parameters indicating to create only the specified object itself.
+	 * 
+	 * @since de.walware.rj.services 0.5
+	 */
+	int DEPTH_ONE= 1;
+	
+	/**
+	 * Value for depth parameters indicating to create only a reference to the specified object.
+	 * 
+	 * @since de.walware.rj.services 1.1
+	 */
+	int DEPTH_REFERENCE= 0;
+	
+	
+	/**
+	 * Option flag indication to load environments directly instead of the reference only.
+	 * 
+	 * @since de.walware.rj.services 2.1
+	 **/
+	int LOAD_ENVIR=                                         1 << 4;
+	
+	/**
+	 * Option flag indicating to eval all promises directly.
+	 * 
+	 * @since de.walware.rj.services 2.1
+	 **/
+	int LOAD_PROMISE=                                       1 << 5;
+	
+	
+	RPlatform getPlatform();
+	
+	/**
+	 * Performs the evaluation of the given expression in R without returning a value.
+	 * The method returns after the evaluation is finished.
+	 * 
+	 * <p>The evaluation is performed in the global environment of R.</p>
+	 * 
+	 * @param expression a single valid R expression to evaluate
+	 * @param monitor a progress monitor to catch cancellation and provide progress feedback.
+	 * @throws CoreException if the operation was canceled or failed; the status
+	 *     of the exception contains detail about the cause
+	 */
+	void evalVoid(String expression, IProgressMonitor monitor) throws CoreException;
+	
+	/**
+	 * Performs the evaluation of the given expression in R without returning a value.
+	 * The method returns after the evaluation is finished.
+	 * 
+	 * <p>This method allows advanced configuration for the evaluation.</p>
+	 * 
+	 * @param expression a single valid R expression to evaluate
+	 * @param envir the environment where to perform the evaluation; specified by an reference
+	 *     or language object, or <code>null</code> for the global environment
+	 * @param monitor a progress monitor to catch cancellation and provide progress feedback.
+	 * @throws CoreException if the operation was canceled or failed; the status
+	 *     of the exception contains detail about the cause
+	 * 
+	 * @since de.walware.rj.services 2.1
+	 */
+	void evalVoid(String expression, RObject envir, IProgressMonitor monitor) throws CoreException;
+	
+	/**
+	 * Performs the evaluation of the given expression in R and returns its value as R data object.
+	 * The method returns after the evaluation is finished.
+	 * 
+	 * <p>This is a short version of {@link #evalData(String, String, int, int, IProgressMonitor)}
+	 * sufficient for most purpose. The returned R data objects are created by the default factory
+	 * with no limit in the object tree depth.</p>
+	 * 
+	 * <p>The evaluation is performed in the global environment of R.</p>
+	 * 
+	 * @param expression a single valid R expression to evaluate
+	 * @param monitor a progress monitor to catch cancellation and provide progress feedback
+	 * @return the evaluated value as R data object
+	 * @throws CoreException if the operation was canceled or failed; the status
+	 *     of the exception contains detail about the cause
+	 */
+	RObject evalData(String expression, IProgressMonitor monitor) throws CoreException;
+	
+	/**
+	 * Performs the evaluation of the given expression in R and returns its value. The method returns
+	 * after the evaluation is finished.
+	 * 
+	 * <p>This method allows advanced configuration for the returned R data object.</p>
+	 * 
+	 * <p>The evaluation is performed in the global environment of R.</p>
+	 * 
+	 * @param expression a single valid R expression to evaluate
+	 * @param factoryId the id of the factory to use when creating the RObject in this VM.
+	 * @param options 0
+	 * @param depth object tree depth for the created return value
+	 * @param monitor a progress monitor to catch cancellation and provide progress feedback
+	 * @return the evaluated value as R data object
+	 * @throws CoreException if the operation was canceled or failed; the status
+	 *     of the exception contains detail about the cause
+	 * 
+	 * @see #DEPTH_INFINITE
+	 * @see #DEPTH_ONE
+	 */
+	RObject evalData(String expression, String factoryId, int options, int depth,
+			IProgressMonitor monitor) throws CoreException;
+	
+	/**
+	 * Performs the evaluation of the given expression in R and returns its value. The method
+	 * returns after the evaluation is finished.
+	 * 
+	 * <p>This method allows advanced configuration for the evaluation and the returned R data
+	 * object.</p>
+	 * 
+	 * @param expression a single valid R expression to evaluate
+	 * @param envir the environment where to perform the evaluation; specified by an reference
+	 *     or language object, or <code>null</code> for the global environment
+	 * @param factoryId the id of the factory to use when creating the RObject in this VM.
+	 * @param options 0
+	 * @param depth object tree depth for the created return value
+	 * @param monitor a progress monitor to catch cancellation and provide progress feedback
+	 * @return the evaluated value as R data object
+	 * @throws CoreException if the operation was canceled or failed; the status
+	 *     of the exception contains detail about the cause
+	 * 
+	 * @since de.walware.rj.services 2.1
+	 * 
+	 * @see #DEPTH_INFINITE
+	 * @see #DEPTH_ONE
+	 */
+	RObject evalData(String expression, RObject envir, String factoryId, int options, int depth,
+			IProgressMonitor monitor) throws CoreException;
+	
+	RObject evalData(RReference reference, IProgressMonitor monitor) throws CoreException;
+	RObject evalData(RReference reference, String factoryId, int options, int depth,
+			IProgressMonitor monitor) throws CoreException;
+	
+	/**
+	 * Performs the assignment of the given R data object to an expression in R. The method returns
+	 * after the assignment is finished.
+	 * 
+	 * <p>The target have to be a valid target expression for a R <code>&lt;-</code> assignment 
+	 * operation.  A single symbol like <code>x</code> or <code>`x-y`</code>, a path in an object 
+	 * tree like <code>xlist$item1</code> or <code>xobj@slotName</code> is valid as well as
+	 * special function calls which supports assignments like <code>dim(x)</code>.</p>
+	 * 
+	 * <p>The assignment is performed in the global environment of R.</p>
+	 * 
+	 * @param target a single valid expression to assign the data to
+	 * @param data a valid R data object to assign to the expression
+	 * @param monitor a progress monitor to catch cancellation and provide progress feedback
+	 * @return the evaluated value as R data object
+	 * @throws CoreException if the operation was canceled or was failed; the status
+	 *     of the exception contains detail about the cause
+	 */
+	void assignData(String target, RObject data, IProgressMonitor monitor) throws CoreException;
+	
+//	void assignDataToAttribute(String expression, String attributeName, RObject data, IProgressMonitor monitor) throws CoreException;
+	
+	/**
+	 * Uploads a file or an other input stream to a file on the R host system.
+	 * <p>
+	 * The file name can be relative or absolute. A relative file name is handled relative
+	 * to the current R working directory. An absolute file name must be a valid absolute
+	 * path on the R host system.</p>
+	 * <p>
+	 * The input stream is not closed by the service.</p>
+	 * <p>
+	 * Typical pattern to upload a local file is:</p>
+	 * <pre>
+	 *     FileInputStream in= null;
+	 *     try {
+	 *         in= new FileInputStream(localfile);
+	 *         rservice.uploadFile(in, localfile.length(), "data.xml", 0, monitor);
+	 *     }
+	 *     finally {
+	 *         if (in != null) {
+	 *             in.close();
+	 *         }
+	 *     }
+	 * </pre>
+	 * 
+	 * @param in an input stream providing the content of the file
+	 * @param length the length of the content
+	 * @param fileName the name of the file on the R host system
+	 * @param options 0
+	 * @param monitor a progress monitor to catch cancellation and provide progress feedback
+	 * @throws CoreException if the operation was canceled or failed; the status
+	 *     of the exception contains detail about the cause
+	 */
+	void uploadFile(InputStream in, long length, String fileName, int options,
+			IProgressMonitor monitor) throws CoreException;
+	
+//	void uploadFile(byte[], long length, String fileName, int options, IProgressMonitor monitor) throws CoreException;
+	
+	/**
+	 * Downloads a file on the R host system to a local file or another output stream.
+	 * <p>
+	 * The file name can be relative or absolute. A relative file name is handled relative
+	 * to the current R working directory. An absolute file name must be a valid absolute
+	 * path on the R host system.</p>
+	 * <p>
+	 * The output stream is not closed by the service.</p>
+	 * <p>
+	 * Typical pattern to download to a local file is:</p>
+	 * <pre>
+	 *     FileOutputStream out= null;
+	 *     try {
+	 *         out= new FileOutputStream(localfile);
+	 *         rservice.downloadFile(out, "data.xml", 0, monitor);
+	 *     }
+	 *     finally {
+	 *         if (out != null) {
+	 *             out.close();
+	 *         }
+	 *     }
+	 * </pre>
+	 * 
+	 * @param out the output stream to write the content of the file to
+	 * @param fileName the name of the file on the R host system
+	 * @param options 0
+	 * @param monitor a progress monitor to catch cancellation and provide progress feedback
+	 * @throws CoreException if the operation was canceled or failed; the status
+	 *     of the exception contains detail about the cause
+	 */
+	void downloadFile(OutputStream out, String fileName, int options,
+			IProgressMonitor monitor) throws CoreException;
+	
+	/**
+	 * Downloads a file on the R host system into a byte array.
+	 * <p>
+	 * The file name can be relative or absolute. A relative file name is handled relative
+	 * to the current R working directory. An absolute file name must be a valid absolute
+	 * path on the R host system.</p>
+	 * <p>
+	 * The byte array represents the content of the complete file; the array has the length of
+	 * the file.</p>
+	 * 
+	 * @param fileName the name of the file on the R host system
+	 * @param options 0
+	 * @param monitor a progress monitor to catch cancellation and provide progress feedback
+	 * @return the file content
+	 * @throws CoreException if the operation was canceled or failed; the status
+	 *     of the exception contains detail about the cause
+	 */
+	byte[] downloadFile(String fileName, int options,
+			IProgressMonitor monitor) throws CoreException;
+	
+	/**
+	 * Creates a new function call builder for the specified function.
+	 * 
+	 * <p>The builder is valid as long as the RService owns the consumer. After the service is for
+	 * example closed, it must not longer be used.</p>
+	 * 
+	 * @param name the name of the function, optional with prefix namespace
+	 * 
+	 * @return a new function creator
+	 * @throws CoreException if the operation failed; the status
+	 *     of the exception contains detail about the cause
+	 */
+	FunctionCall createFunctionCall(String name) throws CoreException;
+	
+	/**
+	 * Creates a new creator for {@link RGraphic}s.
+	 * 
+	 * <p>The default options are:</p><ul>
+	 *   <li>MANAGED_OFF: the graphic is not managed by this RService.
+	 *       Important: the caller is responsible to dispose the graphic.</li>
+	 *   <li>R_CLOSE_OFF: the graphic is not closed if the device is closed in R.</li>
+	 * </ul>
+	 * 
+	 * @param options optional options, <code>0</code> for default
+	 * @return a new graphic creator
+	 * @throws CoreException if the operation failed; the status
+	 *     of the exception contains detail about the cause
+	 * 
+	 * @since de.walware.rj.services 0.5
+	 */
+	RGraphicCreator createRGraphicCreator(int options) throws CoreException;
+//	void beginCatchRGraphics(int options);
+//	Map<String, RGraphic> endCatchRGraphics();
+	
+}
diff --git a/core/org.eclipse.statet.rj.services.core/src/org/eclipse/statet/rj/services/RServiceControlExtension.java b/core/org.eclipse.statet.rj.services.core/src/org/eclipse/statet/rj/services/RServiceControlExtension.java
new file mode 100644
index 0000000..bff3264
--- /dev/null
+++ b/core/org.eclipse.statet.rj.services.core/src/org/eclipse/statet/rj/services/RServiceControlExtension.java
@@ -0,0 +1,71 @@
+/*=============================================================================#
+ # Copyright (c) 2011, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.services;
+
+import java.util.concurrent.Callable;
+import java.util.concurrent.locks.Lock;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+
+
+/**
+ * 
+ * @provisional
+ */
+public interface RServiceControlExtension {
+	
+	/**
+	 * Adds a cancel handler called when the tool is canceled to the stack of cancel handlers.
+	 * <p>
+	 * The cancel handler should return <code>true</code> if the cancel event was handled
+	 * completely and the other handlers will not be called.</p>
+	 * 
+	 * @param handler the handler
+	 */
+	void addCancelHandler(Callable<Boolean> handler);
+	
+	/**
+	 * Removes a cancel handler from the stack of cancel handlers.
+	 * 
+	 * @param handler the handler
+	 */
+	void removeCancelHandler(Callable<Boolean> handler);
+	
+	/**
+	 * The lock for wait operations.
+	 * 
+	 * @return the lock
+	 */
+	Lock getWaitLock();
+	
+	/**
+	 * Waits in the current tool thread.
+	 * <p>
+	 * If short background operations are waiting for execution, they are executed (depends on
+	 * implementation).</p>
+	 * <p>
+	 * The current thread must hold the lock {@link #getWaitLock()}. The method returns after a 
+	 * short waiting time, operations are executed <b>or</b> {@link #resume()} is called.</p>
+	 * 
+	 * @param monitor the current monitor
+	 */
+	void waitingForUser(IProgressMonitor monitor);
+	
+	/**
+	 * Resumes the tool thread which is waiting in {@link #waitingForUser(IProgressMonitor)}.
+	 */
+	void resume();
+	
+}
diff --git a/core/org.eclipse.statet.rj.services.core/src/org/eclipse/statet/rj/services/util/Graphic.java b/core/org.eclipse.statet.rj.services.core/src/org/eclipse/statet/rj/services/util/Graphic.java
new file mode 100644
index 0000000..c34776d
--- /dev/null
+++ b/core/org.eclipse.statet.rj.services.core/src/org/eclipse/statet/rj/services/util/Graphic.java
@@ -0,0 +1,106 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.services.util;
+
+import java.io.OutputStream;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+
+import org.eclipse.statet.rj.services.FunctionCall;
+import org.eclipse.statet.rj.services.RService;
+
+
+public abstract class Graphic {
+	
+	
+	public static final String UNIT_PX= "px";
+	public static final String UNIT_IN= "in";
+	public static final String UNIT_CM= "cm";
+	public static final String UNIT_MM= "mm";
+	
+	
+	String sizeUnit;
+	double sizeWidth;
+	double sizeHeight;
+	
+	int resolution= -1;
+	
+	
+	protected Graphic() {
+	}
+	
+	
+	/**
+	 * Sets the size of the graphic.
+	 * 
+	 * The unit can be one of the constants with prefix UNIT_ .
+	 * The default is pixel for raster graphic images (png) and inch for vector images (pdf).
+	 * 
+	 * @param width the width in the given unit
+	 * @param height the height in the given unit 
+	 * @param unit the unit of width and height arguments
+	 */
+	public void setSize(final double width, final double height, final String unit) {
+		this.sizeWidth= width;
+		this.sizeHeight= height;
+		this.sizeUnit= unit;
+	}
+	
+	/**
+	 * Sets the nominal resolution in dpi of the graphic.
+	 * 
+	 * @param resolution the resolution in dpi
+	 */
+	public void setResolution(final int resolution) {
+		this.resolution= resolution;
+	}
+	
+	
+	public byte[] create(final FunctionCall plot, final RService service, final IProgressMonitor monitor) throws CoreException {
+		final String filename= "plot-"+System.nanoTime()+".plot";
+		prepare(filename, service, monitor);
+		plot.evalVoid(monitor);
+		service.evalVoid("dev.off()", monitor);
+		return service.downloadFile(filename, 0, monitor);
+	}
+	
+	public void create(final FunctionCall plot, final OutputStream out, final RService service, final IProgressMonitor monitor) throws CoreException {
+		final String filename= "plot-"+System.nanoTime()+".plot";
+		prepare(filename, service, monitor);
+		plot.evalVoid(monitor);
+		service.evalVoid("dev.off()", monitor);
+		service.downloadFile(out, filename, 0, monitor);
+	}
+	
+	public byte[] create(final String plotCommand, final RService service, final IProgressMonitor monitor) throws CoreException {
+		final String filename= "plot-"+System.nanoTime()+".plot";
+		prepare(filename, service, monitor);
+		service.evalVoid(plotCommand, monitor);
+		service.evalVoid("dev.off()", monitor);
+		return service.downloadFile(filename, 0, monitor);
+	}
+	
+	public void create(final String plotCommand, final OutputStream out, final RService service, final IProgressMonitor monitor) throws CoreException {
+		final String filename= "plot-"+System.nanoTime()+".plot";
+		prepare(filename, service, monitor);
+		service.evalVoid(plotCommand, monitor);
+		service.evalVoid("dev.off()", monitor);
+		service.downloadFile(out, filename, 0, monitor);
+	}
+	
+	protected abstract void prepare(String filename, RService service, IProgressMonitor monitor) throws CoreException;
+	
+}
diff --git a/core/org.eclipse.statet.rj.services.core/src/org/eclipse/statet/rj/services/util/PdfGraphic.java b/core/org.eclipse.statet.rj.services.core/src/org/eclipse/statet/rj/services/util/PdfGraphic.java
new file mode 100644
index 0000000..3d736e8
--- /dev/null
+++ b/core/org.eclipse.statet.rj.services.core/src/org/eclipse/statet/rj/services/util/PdfGraphic.java
@@ -0,0 +1,63 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.services.util;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+
+import org.eclipse.statet.rj.services.FunctionCall;
+import org.eclipse.statet.rj.services.RService;
+
+
+public class PdfGraphic extends Graphic {
+	
+	
+	public PdfGraphic() {
+	}
+	
+	
+	@Override
+	public void setSize(final double width, final double height, final String unit) {
+		if (UNIT_PX.equals(unit)) {
+			throw new IllegalArgumentException("Pixel not supported by PDF graphic.");
+		}
+		super.setSize(width, height, unit);
+	}
+	
+	@Override
+	protected void prepare(final String filename, final RService service, final IProgressMonitor monitor) throws CoreException {
+		final FunctionCall png= service.createFunctionCall("pdf"); //$NON-NLS-1$
+		png.addChar("file", filename); //$NON-NLS-1$
+		if (this.resolution > 0) {
+			png.addInt("res", this.resolution); //$NON-NLS-1$
+		}
+		if (this.sizeUnit != null) {
+			if (this.sizeUnit.equals(UNIT_IN)) {
+				png.addNum("width", this.sizeWidth); //$NON-NLS-1$
+				png.addNum("height", this.sizeHeight); //$NON-NLS-1$
+			}
+			else if (this.sizeUnit.equals(UNIT_CM)) {
+				png.addNum("width", this.sizeWidth/2.54); //$NON-NLS-1$
+				png.addNum("height", this.sizeHeight/2.54); //$NON-NLS-1$
+			}
+			else if (this.sizeUnit.equals(UNIT_MM)) {
+				png.addNum("width", this.sizeWidth/25.4); //$NON-NLS-1$
+				png.addNum("height", this.sizeHeight/25.4); //$NON-NLS-1$
+			}
+		}
+		png.evalVoid(monitor);
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.services.core/src/org/eclipse/statet/rj/services/util/PngGraphic.java b/core/org.eclipse.statet.rj.services.core/src/org/eclipse/statet/rj/services/util/PngGraphic.java
new file mode 100644
index 0000000..7a8c660
--- /dev/null
+++ b/core/org.eclipse.statet.rj.services.core/src/org/eclipse/statet/rj/services/util/PngGraphic.java
@@ -0,0 +1,50 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.services.util;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+
+import org.eclipse.statet.rj.services.FunctionCall;
+import org.eclipse.statet.rj.services.RPlatform;
+import org.eclipse.statet.rj.services.RService;
+
+
+public class PngGraphic extends Graphic {
+	
+	
+	public PngGraphic() {
+	}
+	
+	
+	@Override
+	protected void prepare(final String filename, final RService service, final IProgressMonitor monitor) throws CoreException {
+		final FunctionCall png= service.createFunctionCall("png");
+		png.addChar("filename", filename);
+		if (this.resolution > 0) {
+			png.addInt("res", this.resolution);
+		}
+		if (this.sizeUnit != null) {
+			png.addNum("width", this.sizeWidth);
+			png.addNum("height", this.sizeHeight);
+			png.addChar("unit", this.sizeUnit);
+		}
+		if (service.getPlatform().getOsType().equals(RPlatform.OS_WINDOWS)) {
+			png.addLogi("restoreConsole", false);
+		}
+		png.evalVoid(monitor);
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.services.core/src/org/eclipse/statet/rj/services/util/RPkgInstallation.java b/core/org.eclipse.statet.rj.services.core/src/org/eclipse/statet/rj/services/util/RPkgInstallation.java
new file mode 100644
index 0000000..6d4a19d
--- /dev/null
+++ b/core/org.eclipse.statet.rj.services.core/src/org/eclipse/statet/rj/services/util/RPkgInstallation.java
@@ -0,0 +1,180 @@
+/*=============================================================================#
+ # Copyright (c) 2013, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.services.util;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.text.MessageFormat;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+
+import org.eclipse.statet.rj.data.RDataUtils;
+import org.eclipse.statet.rj.data.RIntegerStore;
+import org.eclipse.statet.rj.data.RVector;
+import org.eclipse.statet.rj.data.UnexpectedRDataException;
+import org.eclipse.statet.rj.renv.core.RNumVersion;
+import org.eclipse.statet.rj.renv.core.RPkg;
+import org.eclipse.statet.rj.renv.core.RPkgType;
+import org.eclipse.statet.rj.renv.core.RPkgUtils;
+import org.eclipse.statet.rj.services.FunctionCall;
+import org.eclipse.statet.rj.services.RJServices;
+import org.eclipse.statet.rj.services.RService;
+
+
+/**
+ * Utility to install an R package from a local file.
+ * <p>
+ * Run {@link #install(RService, IProgressMonitor)} to install the package.</p>
+ * <p>
+ * The class can be reused.</p>
+ * 
+ * @since de.walware.rj.services 2.0
+ */
+public class RPkgInstallation {
+	
+	
+	private final RPkg pkgInfo;
+	
+	private final File file;
+	
+	
+	public RPkgInstallation(final File file) throws CoreException {
+		if (file == null) {
+			throw new NullPointerException();
+		}
+		this.pkgInfo= RPkgUtils.checkPkgFileName(file.getName());
+		this.file= file;
+	}
+	
+	
+	public RPkg getPkg() {
+		return this.pkgInfo;
+	}
+	
+	protected String getPkgFileName() {
+		return this.file.getName();
+	}
+	
+	protected void uploadPkgFile(final String target, final RService r,
+			final IProgressMonitor monitor) throws CoreException, IOException {
+		FileInputStream in= null;
+		try {
+			in= new FileInputStream(this.file);
+			r.uploadFile(in, this.file.length(), target, 0, monitor);
+		}
+		finally {
+			if (in != null) {
+				try {
+					in.close();
+				}
+				catch (final IOException e) {}
+			}
+		}
+	}
+	
+	public void install(final RService r, final IProgressMonitor monitor) throws CoreException {
+		final String source= getPkgFileName();
+		final RPkgType pkgType= RPkgUtils.checkPkgType(source, r.getPlatform());
+		
+		Exception error= null;
+		String serverFile= null;
+		String libLoc= null;
+		try {
+			{	final RVector<RIntegerStore> data= RDataUtils.checkRIntVector(r.evalData(
+						"rj:::renv.isValidLibLoc(.libPaths()[1])", monitor )); //$NON-NLS-1$
+				final int state= RDataUtils.checkSingleIntValue(data);
+				libLoc= data.getNames().getChar(0);
+				if (state != 0) {
+					throw new CoreException(new Status(IStatus.ERROR, RJServices.BUNDLE_ID,
+							MessageFormat.format("The library location ''{0}'' is not writable.", libLoc) ));
+				}
+			}
+			
+			{	final FunctionCall call= r.createFunctionCall("dir.create"); //$NON-NLS-1$
+				call.addChar("rpkgs"); //$NON-NLS-1$
+				call.addLogi("showWarnings", false); //$NON-NLS-1$
+				call.evalVoid(monitor);
+				
+				serverFile= "rpkgs/" + source; //$NON-NLS-1$
+			}
+			
+			uploadPkgFile(serverFile, r, monitor);
+			
+			{	final FunctionCall call= r.createFunctionCall("install.packages"); //$NON-NLS-1$
+				call.addChar(serverFile);
+				call.addChar("lib", libLoc); //$NON-NLS-1$
+				call.addNull("repos"); //$NON-NLS-1$
+				call.addChar("type", RPkgUtils.getPkgTypeInstallKey(r.getPlatform(), pkgType)); //$NON-NLS-1$
+				call.evalVoid(monitor);
+			}
+			
+			{	final FunctionCall call= r.createFunctionCall("packageDescription"); //$NON-NLS-1$
+				call.addChar("pkg", this.pkgInfo.getName()); //$NON-NLS-1$
+				call.addChar("lib.loc", libLoc); //$NON-NLS-1$
+				call.addChar("fields", "Version"); //$NON-NLS-1$ //$NON-NLS-2$
+				final RVector<?> data= RDataUtils.checkRVector(call.evalData(monitor));
+				try {
+					final String s= RDataUtils.checkSingleCharValue(data);
+					final RNumVersion installedVersion= RNumVersion.create(s);
+					if (!installedVersion.equals(this.pkgInfo.getVersion())) {
+						throw new CoreException(new Status(IStatus.ERROR, RJServices.BUNDLE_ID,
+								MessageFormat.format("Validation of package installation failed: installed package has different version (found= {0}, expected= {1}).",
+										installedVersion.toString(), this.pkgInfo.getVersion().toString() )));
+					}
+				}
+				catch (final UnexpectedRDataException e) {
+					throw new CoreException(new Status(IStatus.ERROR, RJServices.BUNDLE_ID,
+							"Validation of package installation failed: no installed package found." ));
+				}
+			}
+			
+			clear(serverFile, r, monitor);
+			serverFile= null;
+		}
+		catch (final IOException e) {
+			error= e;
+		}
+		catch (final CoreException e) {
+			error= e;
+		}
+		catch (final UnexpectedRDataException e) {
+			error= e;
+		}
+		finally {
+			if (serverFile != null) {
+				try {
+					clear(serverFile, r, monitor);
+				}
+				catch (final Exception e) {}
+			}
+		}
+		if (error != null) {
+			throw new CoreException(new Status(IStatus.ERROR, RJServices.BUNDLE_ID,
+					MessageFormat.format("An error occurred when installing R package from {0}.",
+							source), error ));
+		}
+	}
+	
+	private void clear(final String target, final RService r, final IProgressMonitor monitor) throws CoreException {
+		final FunctionCall call= r.createFunctionCall("file.remove"); //$NON-NLS-1$
+		call.addChar(target);
+		call.evalVoid(monitor);
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.services.core/src/org/eclipse/statet/rj/services/util/dataaccess/AbstractRDataAdapter.java b/core/org.eclipse.statet.rj.services.core/src/org/eclipse/statet/rj/services/util/dataaccess/AbstractRDataAdapter.java
new file mode 100644
index 0000000..0ec2ef8
--- /dev/null
+++ b/core/org.eclipse.statet.rj.services.core/src/org/eclipse/statet/rj/services/util/dataaccess/AbstractRDataAdapter.java
@@ -0,0 +1,170 @@
+/*=============================================================================#
+ # Copyright (c) 2013, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.services.util.dataaccess;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+
+import org.eclipse.statet.rj.data.RDataUtils;
+import org.eclipse.statet.rj.data.RLanguage;
+import org.eclipse.statet.rj.data.RObject;
+import org.eclipse.statet.rj.data.RVector;
+import org.eclipse.statet.rj.data.UnexpectedRDataException;
+import org.eclipse.statet.rj.data.impl.DefaultRObjectFactory;
+import org.eclipse.statet.rj.services.FQRObjectRef;
+import org.eclipse.statet.rj.services.FunctionCall;
+import org.eclipse.statet.rj.services.RService;
+
+
+/**
+ * Adapter interface to load R data in one- or two-dimensional fragments.
+ * 
+ * @param <TRObject> type of R object
+ * @param <TFragmentObject> type of R object value fragments
+ * @since 2.0 (provisional)
+ */
+public abstract class AbstractRDataAdapter<TRObject extends RObject, TFragmentObject extends RObject> {
+	
+	
+	public static final int ROW_COUNT= 1 << 0;
+	public static final int STORE_TYPE= 1 << 2;
+	
+	protected static final String API_R_PREFIX= "rj:::sda002"; //$NON-NLS-1$
+	
+	
+	protected static void addXRef(final FunctionCall fcall, final FQRObjectRef ref) {
+		fcall.add("x.env", ref.getEnv()); //$NON-NLS-1$
+		fcall.add("x.expr", DefaultRObjectFactory.INSTANCE.createExpression( //$NON-NLS-1$
+				"x.env$" + ((RLanguage) ref.getName()).getSource() )); //$NON-NLS-1$
+	}
+	
+	
+	public abstract TRObject validate(RObject rObject)
+			throws UnexpectedRDataException;
+	public abstract TRObject validate(RObject rObject, TRObject referenceObject, int flags)
+			throws UnexpectedRDataException;
+	
+	public abstract long getRowCount(TRObject rObject);
+	public abstract long getColumnCount(TRObject rObject);
+	
+	
+	public void check(final FQRObjectRef ref, final TRObject referenceObject,
+			final RService r, final IProgressMonitor monitor) throws CoreException,
+			UnexpectedRDataException {
+		final RObject result;
+		{	final FunctionCall fcall= r.createFunctionCall(API_R_PREFIX + ".checkDataStruct"); //$NON-NLS-1$
+			addXRef(fcall, ref);
+			fcall.addChar("xClass1", referenceObject.getRClassName()); //$NON-NLS-1$
+			fcall.add("xDim", DefaultRObjectFactory.INSTANCE.createNumVector(new double[] { //$NON-NLS-1$
+					getRowCount(referenceObject),
+					getColumnCount(referenceObject),
+			}));
+			result= fcall.evalData(monitor);
+		}
+		if (RDataUtils.checkSingleLogiValue(result) == false) {
+			throw new UnexpectedRDataException("It seems something changed.");
+		}
+	}
+	
+	public TFragmentObject loadData(final FQRObjectRef ref, final TRObject referenceObject,
+			final LazyRStore.Fragment<TFragmentObject> fragment, final String rowMapping,
+			final RService r,
+			final IProgressMonitor monitor) throws CoreException, UnexpectedRDataException {
+		final RObject fragmentObject;
+		{	final FunctionCall fcall= r.createFunctionCall(getLoadDataFName());
+			addXRef(fcall, ref);
+			fcall.add("idxs", DefaultRObjectFactory.INSTANCE.createNumVector(new double[] { //$NON-NLS-1$
+					fragment.getRowBeginIdx() + 1,
+					fragment.getRowEndIdx(),
+					fragment.getColumnBeginIdx() + 1,
+					fragment.getColumnEndIdx(),
+			}));
+			if (rowMapping != null) {
+				fcall.addChar("rowMapping", rowMapping); //$NON-NLS-1$
+			}
+			
+			fragmentObject= fcall.evalData(monitor);
+		}
+		
+		return validateData(fragmentObject, referenceObject, fragment);
+	}
+	
+	protected abstract String getLoadDataFName();
+	
+	protected abstract TFragmentObject validateData(RObject rObject, TRObject referenceObject,
+			LazyRStore.Fragment<TFragmentObject> fragment)
+			throws UnexpectedRDataException;
+	
+	public void setData(final FQRObjectRef ref, final TRObject referenceObject,
+			final RDataAssignment assignment, final String rowMapping,
+			final RService r,
+			final IProgressMonitor monitor) throws CoreException, UnexpectedRDataException {
+		{	final FunctionCall fcall= r.createFunctionCall(getSetDataFName());
+			addXRef(fcall, ref);
+			fcall.add("idxs", DefaultRObjectFactory.INSTANCE.createNumVector(new double[] { //$NON-NLS-1$
+					assignment.getRowBeginIdx() + 1,
+					assignment.getRowEndIdx(),
+					assignment.getColumnBeginIdx() + 1,
+					assignment.getColumnEndIdx(),
+			}));
+			if (rowMapping != null) {
+				fcall.addChar("rowMapping", rowMapping); //$NON-NLS-1$
+			}
+			fcall.add("values", DefaultRObjectFactory.INSTANCE.createVector( //$NON-NLS-1$
+					assignment.getData() ));
+			
+			fcall.evalVoid(monitor);
+		}
+	}
+	
+	protected abstract String getSetDataFName();
+	
+	public RVector<?> loadRowNames(final FQRObjectRef ref, final TRObject referenceObject,
+			final LazyRStore.Fragment<RVector<?>> fragment, final String rowMapping,
+			final RService r, final IProgressMonitor monitor) throws CoreException,
+			UnexpectedRDataException {
+		final RObject fragmentObject;
+		{	final FunctionCall fcall= r.createFunctionCall(getLoadRowNamesFName());
+			addXRef(fcall, ref);
+			fcall.add("idxs", DefaultRObjectFactory.INSTANCE.createNumVector(new double[] { //$NON-NLS-1$
+					fragment.getRowBeginIdx() + 1,
+					fragment.getRowEndIdx(),
+			}));
+			if (rowMapping != null) {
+				fcall.addChar("rowMapping", rowMapping); //$NON-NLS-1$
+			}
+			
+			fragmentObject= fcall.evalData(monitor);
+		}
+		
+		return validateRowNames(fragmentObject, referenceObject, fragment);
+	}
+	
+	protected abstract String getLoadRowNamesFName();
+	
+	protected RVector<?> validateRowNames(final RObject rObject, final TRObject referenceObject,
+			final LazyRStore.Fragment<RVector<?>> fragment)
+			throws UnexpectedRDataException {
+		if (rObject.getRObjectType() == RObject.TYPE_NULL) {
+			return null;
+		}
+		
+		final RVector<?> vector= RDataUtils.checkRVector(rObject);
+		RDataUtils.checkLengthEqual(vector.getData(), fragment.getRowCount());
+		
+		return vector;
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.services.core/src/org/eclipse/statet/rj/services/util/dataaccess/LazyRStore.java b/core/org.eclipse.statet.rj.services.core/src/org/eclipse/statet/rj/services/util/dataaccess/LazyRStore.java
new file mode 100644
index 0000000..6203829
--- /dev/null
+++ b/core/org.eclipse.statet.rj.services.core/src/org/eclipse/statet/rj/services/util/dataaccess/LazyRStore.java
@@ -0,0 +1,448 @@
+/*=============================================================================#
+ # Copyright (c) 2013, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.services.util.dataaccess;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+
+/**
+ * 
+ * 
+ * @param <V> type of R object fragments
+ * @since 2.0 (provisional)
+ */
+public class LazyRStore<V> {
+	
+	
+	public final static int DEFAULT_FRAGMENT_SIZE= 2500;
+	
+	public final static class Fragment<W> extends RDataSubset {
+		
+		private static final byte SCHEDULED= (byte) 1 << 0;
+		private static final byte SET= (byte) 1 << 1;
+		
+		/** sequential number of fragments, first by fragment col, then by fragment row */
+		private final long number;
+		
+		private W rObject;
+		
+		private Fragment<W> newer;
+		private Fragment<W> older;
+		
+		private byte state;
+		
+		
+		Fragment(final long number,
+				final long rowBeginIdx, final long rowCount,
+				final long columnBeginIdx, final long columnCount) {
+			super(rowBeginIdx, rowCount, columnBeginIdx, columnCount);
+			this.number= number;
+		}
+		
+		
+		/**
+		 * Returns the R object for this fragment.
+		 * 
+		 * @return the R object for this fragment or <code>null</code>, if not available.
+		 */
+		public W getRObject() {
+			return this.rObject;
+		}
+		
+		
+		@Override
+		public String toString() {
+			final StringBuilder sb= new StringBuilder("LazyRStore$Fragment "); //$NON-NLS-1$
+			sb.append(this.number);
+			sb.append("\n\trows= ").append(getRowBeginIdx()).append("...").append(getRowEndIdx()); //$NON-NLS-1$ //$NON-NLS-2$
+			sb.append("\n\tcolumns= ").append(getColumnBeginIdx()).append("...").append(getColumnEndIdx()); //$NON-NLS-1$ //$NON-NLS-2$
+			return sb.toString();
+		}
+		
+	}
+	
+	
+	public static final int FORCE_SYNC= 1 << 0;
+	
+	public static interface Updater<T> {
+		
+		
+		void scheduleUpdate(LazyRStore<T> store,
+				RDataAssignment assignment, Fragment<T> fragment,
+				int flags, IProgressMonitor monitor);
+		
+	}
+	
+	
+	private final long columnCount;
+	private long rowCount;
+	
+	private final int maxFragmentCount;
+	private Fragment<V>[] fragments;
+	private int currentFragmentCount= 0;
+	private final Fragment<V> topFragment= new Fragment<>(-1, 0, 0, 0, 0);
+	private final Fragment<V> bottomFragment= new Fragment<>(-1, 0, 0, 0, 0);
+	
+	private final int fragmentRowCount;
+	private final int fragmentColCount;
+	private final long fragmentCountInRow;
+	
+	private final List<RDataAssignment> assignments= new ArrayList<>();
+	
+	private int scheduledCount;
+	private Fragment<V> scheduleNext;
+	private Updater<V> updater;
+	
+	
+	public LazyRStore(final long rowCount, final long columnCount,
+			final int maxFragmentCount,
+			final Updater<V> updater) {
+		this(rowCount, columnCount, maxFragmentCount, DEFAULT_FRAGMENT_SIZE, updater);
+	}
+	
+	public LazyRStore(final long rowCount, final long columnCount,
+			final int maxFragmentCount, final int fragmentSize,
+			final Updater<V> updater) {
+		this.columnCount= columnCount;
+		
+		this.maxFragmentCount= maxFragmentCount;
+		
+		this.fragmentColCount= (int) Math.min(columnCount, 25);
+		this.fragmentCountInRow= (columnCount - 1) / this.fragmentColCount + 1;
+		this.fragmentRowCount= fragmentSize / this.fragmentColCount;
+		
+		this.updater= updater;
+		
+		init(rowCount);
+	}
+	
+	public LazyRStore(final long rowCount, final long columnCount,
+			final int maxFragmentCount,
+			final int fragmentRowCount, final int fragmentColCount,
+			final Updater<V> updater) {
+		this.columnCount= columnCount;
+		
+		this.maxFragmentCount= maxFragmentCount;
+		
+		this.fragmentColCount= fragmentColCount;
+		this.fragmentCountInRow= (columnCount - 1) / fragmentColCount + 1;
+		this.fragmentRowCount= fragmentRowCount;
+		
+		this.updater= updater;
+		
+		init(rowCount);
+	}
+	
+	private void init(final long rowCount) {
+		this.fragments= new Fragment[Math.min(16, this.maxFragmentCount)];
+		
+		clear(rowCount);
+	}
+	
+	private long getNumber(final long rowIdx, final long columnIdx) {
+		return (rowIdx / this.fragmentRowCount) * this.fragmentCountInRow +
+				(columnIdx / this.fragmentColCount);
+	}
+	
+	
+	public LazyRStore.Fragment<V> getFragment(final long rowIdx, final long columnIdx,
+			final int flags, final IProgressMonitor monitor) {
+		if (rowIdx >= this.rowCount) {
+			return null;
+		}
+		final long number= getNumber(rowIdx, columnIdx);
+		final Fragment<V> fragment= getFragment(number, true);
+		
+		if ((fragment.state & Fragment.SET) != 0) {
+			return fragment;
+		}
+		
+		final boolean scheduleUpdate= (this.scheduledCount == 0);
+		
+		this.scheduleNext= this.topFragment;
+		
+		if ((fragment.state & Fragment.SCHEDULED) == 0) {
+			fragment.state= Fragment.SCHEDULED;
+			this.scheduledCount++;
+		}
+		
+		if (scheduleUpdate || (flags & FORCE_SYNC) != 0) {
+			this.updater.scheduleUpdate(this, null, fragment, flags, monitor);
+			
+			if ((fragment.state & Fragment.SET) != 0) {
+				return fragment;
+			}
+		}
+		
+		return null;
+	}
+	
+	public LazyRStore.Fragment<V> getLoadedFragment(final long rowIdx, final long columnIdx) {
+		if (rowIdx >= this.rowCount) {
+			return null;
+		}
+		final long number= getNumber(rowIdx, columnIdx);
+		final Fragment<V> fragment= getFragment(number, false);
+		
+		if ((fragment.state & Fragment.SET) != 0) {
+			return fragment;
+		}
+		return null;
+	}
+	
+	public LazyRStore.Fragment<V> getLoadedFragmentAny() {
+		Fragment<V> fragment= this.topFragment;
+		while (fragment != null) {
+			if ((fragment.state & Fragment.SET) != 0) {
+				return fragment;
+			}
+			fragment= fragment.older;
+		}
+		return null;
+	}
+	
+	public void set(final RDataAssignment assignment,
+			final int flags, final IProgressMonitor monitor) {
+		final Fragment<V> fragment= clear(assignment);
+		this.assignments.add(assignment);
+		
+		final boolean scheduleUpdate= (this.scheduledCount == 0);
+		
+		this.scheduledCount++; // assignment
+		
+		if (fragment != null) {
+			fragment.state= Fragment.SCHEDULED;
+			this.scheduledCount++;
+		}
+		
+		if (scheduleUpdate) {
+			this.updater.scheduleUpdate(this, assignment, fragment, flags, monitor);
+		}
+	}
+	
+	public Fragment<V> clear(final RDataSubset subset) {
+		Fragment<V> firstFragment= null;
+		long columnBeginIdx= (subset.getColumnBeginIdx() / this.fragmentColCount) * this.fragmentColCount; 
+		while (columnBeginIdx < subset.getColumnEndIdx()) {
+			long rowBeginIdx= (subset.getRowBeginIdx() / this.fragmentRowCount) * this.fragmentRowCount;
+			while (rowBeginIdx < subset.getRowEndIdx()) {
+				final long number= getNumber(rowBeginIdx, columnBeginIdx);
+				final int idx= indexOf(number);
+				if (idx >= 0) {
+					final Fragment<V> fragment= clearFragment(idx);
+					if (firstFragment == null) {
+						firstFragment= fragment;
+					}
+				}
+				rowBeginIdx= Math.min(rowBeginIdx + this.fragmentRowCount, this.rowCount);
+			}
+			columnBeginIdx= Math.min(columnBeginIdx + this.fragmentColCount, this.columnCount);
+		}
+		return firstFragment;
+	}
+	
+	
+	private int indexOf(final long number) {
+		final Fragment<V>[] array= this.fragments;
+		int low= 0;
+		int high= this.currentFragmentCount;
+		
+		while (low <= high) {
+			final int mid= (low + high) >> 1;
+			final Fragment<V> fragment= array[mid];
+			
+			if (fragment.number < number) {
+				low= mid + 1;
+			}
+			else if (fragment.number > number) {
+				high= mid - 1;
+			}
+			else {
+				return mid;
+			}
+		}
+		return - (low + 1);
+	}
+	
+	private Fragment<V> getFragment(final long number, final boolean create) {
+		if (this.topFragment.older.number == number) {
+			return this.topFragment.older;
+		}
+		
+		final Fragment<V>[] array= this.fragments;
+		int low= 0;
+		{	int high= this.currentFragmentCount - 1;
+			while (low <= high) {
+				final int mid= (low + high) >> 1;
+				final Fragment<V> fragment= array[mid];
+				
+				if (fragment.number < number) {
+					low= mid + 1;
+				}
+				else if (fragment.number > number) {
+					high= mid - 1;
+				}
+				else {
+					fragment.newer.older= fragment.older;
+					fragment.older.newer= fragment.newer;
+					fragment.newer= this.topFragment;
+					fragment.older= this.topFragment.older;
+					this.topFragment.older.newer= fragment;
+					this.topFragment.older= fragment;
+					return fragment;
+				}
+			}
+		}
+		if (!create) {
+			return null;
+		}
+		
+		final Fragment<V> fragment= createFragment(number);
+		{	if (array.length == this.currentFragmentCount) {
+				this.fragments= new Fragment[Math.min(this.currentFragmentCount * 2, this.maxFragmentCount)];
+				System.arraycopy(array, 0, this.fragments, 0, low);
+			}
+			System.arraycopy(array, low, this.fragments, low + 1, this.currentFragmentCount - low);
+			this.fragments[low]=  fragment;
+			this.currentFragmentCount++;
+		}
+		
+		fragment.newer= this.topFragment;
+		fragment.older= this.topFragment.older;
+		this.topFragment.older.newer= fragment;
+		this.topFragment.older= fragment;
+		
+		if (this.currentFragmentCount >= this.maxFragmentCount) {
+			removeOldestFragment();
+		}
+		
+		return fragment;
+	}
+	
+	private Fragment<V> createFragment(final long number) {
+		final long rowBeginIdx= (number / this.fragmentCountInRow) * this.fragmentRowCount;
+		final long rowEndIdx= Math.min(rowBeginIdx + this.fragmentRowCount, this.rowCount);
+		final long columnBeginIdx= (number % this.fragmentCountInRow) * this.fragmentColCount; 
+		final long columnEndIdx= Math.min(columnBeginIdx + this.fragmentColCount, this.columnCount);
+		return new Fragment<>(number,
+				rowBeginIdx, (rowEndIdx - rowBeginIdx),
+				columnBeginIdx, (columnEndIdx - columnBeginIdx) );
+	}
+	
+	private Fragment<V> clearFragment(final int idx) {
+		final Fragment<V> oldFragment= this.fragments[idx];
+		final Fragment<V> newFragment= new Fragment<>(oldFragment.number,
+				oldFragment.getRowBeginIdx(), oldFragment.getRowCount(),
+				oldFragment.getColumnBeginIdx(), oldFragment.getColumnCount() );
+		if (oldFragment.newer != null) {
+			newFragment.newer= oldFragment.newer;
+			newFragment.newer.older= newFragment;
+		}
+		if (oldFragment.older != null) {
+			newFragment.older= oldFragment.older;
+			newFragment.older.newer= newFragment;
+		}
+		return this.fragments[idx]= newFragment;
+	}
+	
+	private void removeOldestFragment() {
+		final Fragment<V> fragment= this.bottomFragment.newer;
+		if ((fragment.state & Fragment.SCHEDULED) != 0) {
+			fragment.state &= ~Fragment.SCHEDULED;
+			this.scheduledCount--;
+		}
+		if (this.scheduleNext == fragment) {
+			this.scheduleNext= fragment.older;
+		}
+		
+		final int idx= indexOf(fragment.number);
+		this.currentFragmentCount--;
+		System.arraycopy(this.fragments, idx + 1, this.fragments, idx, this.currentFragmentCount - idx);
+		this.fragments[this.currentFragmentCount]= null;
+		
+		fragment.newer.older= this.bottomFragment;
+		this.bottomFragment.newer= fragment.newer;
+		fragment.newer= null;
+		fragment.older= null;
+		return;
+	}
+	
+	
+	public void clear(final long rowCount) {
+		final Fragment<V>[] array= this.fragments;
+		for (int i= 0; i < this.currentFragmentCount; i++) {
+			array[i].state &= ~Fragment.SCHEDULED;
+			array[i]= null;
+		}
+		this.currentFragmentCount= 0;
+		this.topFragment.older= this.bottomFragment;
+		this.bottomFragment.newer= this.topFragment;
+		
+		this.scheduledCount= 0;
+		this.scheduleNext= this.topFragment;
+		
+		if (rowCount >= 0) {
+			this.rowCount= rowCount;
+		}
+	}
+	
+	public Fragment<V>[] getScheduledFragments() {
+		final Fragment<V>[] scheduledFragments= new Fragment[this.scheduledCount];
+		Fragment<V> fragment= this.topFragment.older;
+		int i= 0;
+		while (i < this.scheduledCount) {
+			if ((fragment.state & Fragment.SCHEDULED) != 0) {
+				scheduledFragments[i++]= fragment;
+			}
+			fragment= fragment.older;
+		}
+		return scheduledFragments;
+	}
+	
+	public Fragment<V> getNextScheduledFragment() {
+		if (this.scheduledCount == 0) {
+			return null;
+		}
+		Fragment<V> fragment= this.scheduleNext.older;
+		while (true) {
+			if ((fragment.state & Fragment.SCHEDULED) != 0) {
+				this.scheduleNext= fragment;
+				return fragment;
+			}
+			fragment= fragment.older;
+		}
+	}
+	
+	public void updateAssignment(final RDataAssignment assignment, final IStatus status) {
+		if (this.assignments.remove(assignment)) {
+			this.scheduledCount--;
+		}
+	}
+	
+	public void updateFragment(final Fragment<V> fragment, final V rObject) {
+		if ((fragment.state & Fragment.SET) != 0) {
+			throw new IllegalStateException();
+		}
+		fragment.rObject= rObject;
+		if ((fragment.state & Fragment.SCHEDULED) != 0) {
+			this.scheduledCount--;
+		}
+		fragment.state= Fragment.SET;
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.services.core/src/org/eclipse/statet/rj/services/util/dataaccess/RArrayAsVectorDataAdapter.java b/core/org.eclipse.statet.rj.services.core/src/org/eclipse/statet/rj/services/util/dataaccess/RArrayAsVectorDataAdapter.java
new file mode 100644
index 0000000..aa19602
--- /dev/null
+++ b/core/org.eclipse.statet.rj.services.core/src/org/eclipse/statet/rj/services/util/dataaccess/RArrayAsVectorDataAdapter.java
@@ -0,0 +1,133 @@
+/*=============================================================================#
+ # Copyright (c) 2013, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.services.util.dataaccess;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+
+import org.eclipse.statet.rj.data.RArray;
+import org.eclipse.statet.rj.data.RDataUtils;
+import org.eclipse.statet.rj.data.RObject;
+import org.eclipse.statet.rj.data.RVector;
+import org.eclipse.statet.rj.data.UnexpectedRDataException;
+import org.eclipse.statet.rj.data.impl.DefaultRObjectFactory;
+import org.eclipse.statet.rj.services.FQRObjectRef;
+import org.eclipse.statet.rj.services.FunctionCall;
+import org.eclipse.statet.rj.services.RService;
+import org.eclipse.statet.rj.services.util.dataaccess.LazyRStore.Fragment;
+
+
+/**
+ * Data adapter for {@link RArray} objects of any dimension, loaded as one-dimensional vectors.
+ * 
+ * @since 2.0 (provisional)
+ */
+public class RArrayAsVectorDataAdapter extends AbstractRDataAdapter<RArray<?>, RVector<?>> {
+	
+	
+	@Override
+	public RArray<?> validate(final RObject rObject) throws UnexpectedRDataException {
+		return RDataUtils.checkRArray(rObject);
+	}
+	
+	@Override
+	public RArray<?> validate(final RObject rObject, final RArray<?> referenceObject,
+			final int flags) throws UnexpectedRDataException {
+		final RArray<?> array= RDataUtils.checkRArray(rObject, referenceObject.getDim().getLength());
+		// check dim ?
+		if ((flags & ROW_COUNT) != 0) {
+			RDataUtils.checkLengthEqual(array, referenceObject.getLength());
+		}
+		if ((flags & STORE_TYPE) != 0) {
+			RDataUtils.checkData(array.getData(), referenceObject.getData().getStoreType());
+		}
+		return array;
+	}
+	
+	@Override
+	public long getRowCount(final RArray<?> rObject) {
+		return rObject.getLength();
+	}
+	
+	@Override
+	public long getColumnCount(final RArray<?> rObject) {
+		return 1;
+	}
+	
+	
+	@Override
+	protected String getLoadDataFName() {
+		return API_R_PREFIX + ".getDataVectorValues"; //$NON-NLS-1$
+	}
+	
+	@Override
+	protected String getSetDataFName() {
+		return API_R_PREFIX + ".setDataVectorValues"; //$NON-NLS-1$
+	}
+	
+	@Override
+	protected RVector<?> validateData(final RObject rObject, final RArray<?> referenceObject,
+			final Fragment<RVector<?>> fragment) throws UnexpectedRDataException {
+		final RVector<?> vector= RDataUtils.checkRVector(rObject);
+		RDataUtils.checkLengthEqual(vector, fragment.getRowCount());
+		
+		RDataUtils.checkData(rObject.getData(), referenceObject.getData().getStoreType());
+		
+		return vector;
+	}
+	
+	@Override
+	protected String getLoadRowNamesFName() {
+		throw new UnsupportedOperationException();
+	}
+	
+	public RVector<?> loadDimNames(final FQRObjectRef ref, final RArray<?> referenceObject,
+			final LazyRStore.Fragment<RVector<?>> fragment,
+			final RService r, final IProgressMonitor monitor) throws CoreException,
+			UnexpectedRDataException {
+		final RObject fragmentObject;
+		{	final FunctionCall fcall= r.createFunctionCall(API_R_PREFIX + ".getDataArrayDimNames"); //$NON-NLS-1$
+			addXRef(fcall, ref);
+			fcall.add("idxs", DefaultRObjectFactory.INSTANCE.createNumVector(new double[] { //$NON-NLS-1$
+					fragment.getRowBeginIdx() + 1,
+					fragment.getRowEndIdx(),
+			}));
+			
+			fragmentObject= fcall.evalData(monitor);
+		}
+		
+		return validateRowNames(fragmentObject, referenceObject, fragment);
+	}
+	
+	public RVector<?> loadDimItemNames(final FQRObjectRef ref, final RArray<?> referenceObject,
+			final int dim, final LazyRStore.Fragment<RVector<?>> fragment,
+			final RService r, final IProgressMonitor monitor) throws CoreException,
+			UnexpectedRDataException {
+		final RObject fragmentObject;
+		{	final FunctionCall fcall= r.createFunctionCall(API_R_PREFIX + ".getDataArrayDimItemNames"); //$NON-NLS-1$
+			addXRef(fcall, ref);
+			fcall.addInt("dimIdx", dim + 1); //$NON-NLS-1$
+			fcall.add("idxs", DefaultRObjectFactory.INSTANCE.createNumVector(new double[] { //$NON-NLS-1$
+					fragment.getRowBeginIdx() + 1,
+					fragment.getRowEndIdx(),
+		}));
+		
+		fragmentObject= fcall.evalData(monitor);
+		}
+		
+		return validateRowNames(fragmentObject, referenceObject, fragment);
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.services.core/src/org/eclipse/statet/rj/services/util/dataaccess/RDataAssignment.java b/core/org.eclipse.statet.rj.services.core/src/org/eclipse/statet/rj/services/util/dataaccess/RDataAssignment.java
new file mode 100644
index 0000000..c6d01fd
--- /dev/null
+++ b/core/org.eclipse.statet.rj.services.core/src/org/eclipse/statet/rj/services/util/dataaccess/RDataAssignment.java
@@ -0,0 +1,44 @@
+/*=============================================================================#
+ # Copyright (c) 2016, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.services.util.dataaccess;
+
+import org.eclipse.statet.rj.data.RStore;
+
+
+public class RDataAssignment extends RDataSubset {
+	
+	
+	private final RStore<?> data;
+	
+	
+	public RDataAssignment(final long rowIdx, final long columnIdx, final RStore<?> data) {
+		super(rowIdx, 1, columnIdx, 1);
+		
+		if (data == null) {
+			throw new NullPointerException("data"); //$NON-NLS-1$
+		}
+		if (data.getLength() > getLength()) {
+			throw new IllegalArgumentException("data.length"); //$NON-NLS-1$
+		}
+		this.data= data;
+	}
+	
+	
+	public RStore<?> getData() {
+		return this.data;
+	}
+	
+	
+}
diff --git a/core/org.eclipse.statet.rj.services.core/src/org/eclipse/statet/rj/services/util/dataaccess/RDataFrameDataAdapter.java b/core/org.eclipse.statet.rj.services.core/src/org/eclipse/statet/rj/services/util/dataaccess/RDataFrameDataAdapter.java
new file mode 100644
index 0000000..c71951d
--- /dev/null
+++ b/core/org.eclipse.statet.rj.services.core/src/org/eclipse/statet/rj/services/util/dataaccess/RDataFrameDataAdapter.java
@@ -0,0 +1,92 @@
+/*=============================================================================#
+ # Copyright (c) 2013, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.services.util.dataaccess;
+
+import org.eclipse.statet.rj.data.RDataFrame;
+import org.eclipse.statet.rj.data.RDataUtils;
+import org.eclipse.statet.rj.data.RObject;
+import org.eclipse.statet.rj.data.UnexpectedRDataException;
+import org.eclipse.statet.rj.services.util.dataaccess.LazyRStore.Fragment;
+
+
+/**
+ * Data adapter for {@link RDataFrame} objects.
+ * 
+ * @since 2.0 (provisional)
+ */
+public class RDataFrameDataAdapter extends AbstractRDataAdapter<RDataFrame, RDataFrame> {
+	
+	
+	@Override
+	public RDataFrame validate(final RObject rObject) throws UnexpectedRDataException {
+		return RDataUtils.checkRDataFrame(rObject);
+	}
+	
+	@Override
+	public RDataFrame validate(final RObject rObject, final RDataFrame referenceObject,
+			final int flags) throws UnexpectedRDataException {
+		final RDataFrame dataframe= RDataUtils.checkRDataFrame(rObject, referenceObject.getColumnCount());
+		if ((flags & ROW_COUNT) != 0) {
+			RDataUtils.checkRowCountEqual(dataframe, referenceObject.getRowCount());
+		}
+		if ((flags & STORE_TYPE) != 0) {
+			for (int i= 0; i < dataframe.getColumnCount(); i++) {
+				RDataUtils.checkData(dataframe.getColumn(i), referenceObject.getColumn(i).getStoreType());
+			}
+		}
+		return dataframe;
+	}
+	
+	@Override
+	public long getRowCount(final RDataFrame rObject) {
+		return rObject.getRowCount();
+	}
+	
+	@Override
+	public long getColumnCount(final RDataFrame rObject) {
+		return rObject.getColumnCount();
+	}
+	
+	
+	@Override
+	protected String getLoadDataFName() {
+		return API_R_PREFIX + ".getDataFrameValues"; //$NON-NLS-1$
+	}
+	
+	@Override
+	protected String getSetDataFName() {
+		return "rj:::.setDataFrameValues"; //$NON-NLS-1$
+	}
+	
+	@Override
+	protected RDataFrame validateData(final RObject rObject, final RDataFrame referenceObject,
+			final Fragment<RDataFrame> fragment) throws UnexpectedRDataException {
+		final RDataFrame dataframe= RDataUtils.checkRDataFrame(rObject, fragment.getColumnCount());
+		RDataUtils.checkRowCountEqual(dataframe, fragment.getRowCount());
+		
+		for (int i= 0; i < fragment.getColumnCount(); i++) {
+			RDataUtils.checkData(dataframe.getColumn(i),
+					referenceObject.getColumn(fragment.getColumnBeginIdx() + i).getStoreType() );
+		}
+		
+		return dataframe;
+	}
+	
+	@Override
+	protected String getLoadRowNamesFName() {
+		return API_R_PREFIX + ".getDataFrameRowNames"; //$NON-NLS-1$
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.services.core/src/org/eclipse/statet/rj/services/util/dataaccess/RDataSubset.java b/core/org.eclipse.statet.rj.services.core/src/org/eclipse/statet/rj/services/util/dataaccess/RDataSubset.java
new file mode 100644
index 0000000..168587d
--- /dev/null
+++ b/core/org.eclipse.statet.rj.services.core/src/org/eclipse/statet/rj/services/util/dataaccess/RDataSubset.java
@@ -0,0 +1,114 @@
+/*=============================================================================#
+ # Copyright (c) 2016, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.services.util.dataaccess;
+
+
+public class RDataSubset {
+	
+	
+	private final long rowBeginIdx;
+	private final long rowCount;
+	private final long columnBeginIdx;
+	private final long columnCount;
+	
+	
+	public RDataSubset(final long rowBeginIdx, final long rowCount,
+			final long columnBeginIdx, final long columnCount) {
+		this.rowBeginIdx= rowBeginIdx;
+		this.rowCount= rowCount;
+		this.columnBeginIdx= columnBeginIdx;
+		this.columnCount= columnCount;
+	}
+	
+	
+	/**
+	 * Returns the row begin index of the subset.
+	 * 
+	 * @return the begin index (zero-based)
+	 */
+	public final long getRowBeginIdx() {
+		return this.rowBeginIdx;
+	}
+	
+	/**
+	 * Returns the row end index (exclusive) of the subset.
+	 * 
+	 * @return the end index (zero-based)
+	 */
+	public final long getRowEndIdx() {
+		return this.rowBeginIdx + this.rowCount;
+	}
+	
+	/**
+	 * Returns the row count of the subset.
+	 * 
+	 * @return the count
+	 */
+	public final long getRowCount() {
+		return this.rowCount;
+	}
+	
+	public long toLocalRowIdx(final long rowIdx) {
+		final long idx;
+		if (rowIdx < this.rowBeginIdx
+				|| (idx= rowIdx - this.rowBeginIdx) >= this.rowCount) {
+			throw new IndexOutOfBoundsException(Long.toString(rowIdx));
+		}
+		return idx;
+	}
+	
+	/**
+	 * Returns the column begin index of the subset.
+	 * 
+	 * @return the index (zero-based)
+	 */
+	public final long getColumnBeginIdx() {
+		return this.columnBeginIdx;
+	}
+	
+	/**
+	 * Returns the column end index (exclusive) of the subset.
+	 * 
+	 * @return the index
+	 */
+	public final long getColumnEndIdx() {
+		return this.columnBeginIdx + this.columnCount;
+	}
+	
+	/**
+	 * Returns the column count of the subset.
+	 * 
+	 * @return the count
+	 */
+	public final long getColumnCount() {
+		return this.columnCount;
+	}
+	
+	public long toLocalColumnIdx(final long columnIdx) {
+		final long idx;
+		if (columnIdx < this.columnBeginIdx
+				|| (idx= columnIdx - this.columnBeginIdx) >= this.columnCount) {
+			throw new IndexOutOfBoundsException(Long.toString(columnIdx));
+		}
+		return idx;
+	}
+	
+	
+	public long getLength() {
+		return (this.rowCount * this.columnCount);
+	}
+	
+	
+}
diff --git a/core/org.eclipse.statet.rj.services.core/src/org/eclipse/statet/rj/services/util/dataaccess/RMatrixDataAdapter.java b/core/org.eclipse.statet.rj.services.core/src/org/eclipse/statet/rj/services/util/dataaccess/RMatrixDataAdapter.java
new file mode 100644
index 0000000..4a232de
--- /dev/null
+++ b/core/org.eclipse.statet.rj.services.core/src/org/eclipse/statet/rj/services/util/dataaccess/RMatrixDataAdapter.java
@@ -0,0 +1,90 @@
+/*=============================================================================#
+ # Copyright (c) 2013, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.services.util.dataaccess;
+
+import org.eclipse.statet.rj.data.RArray;
+import org.eclipse.statet.rj.data.RDataUtils;
+import org.eclipse.statet.rj.data.RObject;
+import org.eclipse.statet.rj.data.UnexpectedRDataException;
+import org.eclipse.statet.rj.services.util.dataaccess.LazyRStore.Fragment;
+
+
+/**
+ * Data adapter for two-dimensional {@link RArray} objects.
+ * 
+ * @since 2.0 (provisional)
+ */
+public class RMatrixDataAdapter extends AbstractRDataAdapter<RArray<?>, RArray<?>> {
+	
+	
+	@Override
+	public RArray<?> validate(final RObject rObject) throws UnexpectedRDataException {
+		return RDataUtils.checkRArray(rObject, 2);
+	}
+	
+	@Override
+	public RArray<?> validate(final RObject rObject, final RArray<?> referenceObject,
+			final int flags) throws UnexpectedRDataException {
+		final RArray<?> array= RDataUtils.checkRArray(rObject, 2);
+		RDataUtils.checkColumnCountEqual(array, RDataUtils.getColumnCount(referenceObject));
+		if ((flags & ROW_COUNT) != 0) {
+			RDataUtils.checkLengthEqual(array, referenceObject.getLength());
+		}
+		if ((flags & STORE_TYPE) != 0) {
+			RDataUtils.checkData(array.getData(), referenceObject.getData().getStoreType());
+		}
+		return array;
+	}
+	
+	@Override
+	public long getRowCount(final RArray<?> rObject) {
+		return rObject.getDim().getInt(0);
+	}
+	
+	@Override
+	public long getColumnCount(final RArray<?> rObject) {
+		return rObject.getDim().getInt(1);
+	}
+	
+	
+	@Override
+	protected String getLoadDataFName() {
+		return API_R_PREFIX + ".getDataMatrixValues"; //$NON-NLS-1$
+	}
+	
+	@Override
+	protected String getSetDataFName() {
+		return "rj:::.setDataMatrixValues";
+	}
+	
+	@Override
+	protected RArray<?> validateData(final RObject rObject, final RArray<?> referenceObject,
+			final Fragment<RArray<?>> fragment)
+			throws UnexpectedRDataException {
+		final RArray<?> array= RDataUtils.checkRArray(rObject, 2);
+		RDataUtils.checkColumnCountEqual(array, RDataUtils.checkIntLength(fragment.getColumnCount()));
+		RDataUtils.checkRowCountEqual(array, RDataUtils.checkIntLength(fragment.getRowCount()));
+		
+		RDataUtils.checkData(rObject.getData(), referenceObject.getData().getStoreType());
+		
+		return array;
+	}
+	
+	@Override
+	protected String getLoadRowNamesFName() {
+		return API_R_PREFIX + ".getDataMatrixRowNames"; //$NON-NLS-1$
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.services.core/src/org/eclipse/statet/rj/services/util/dataaccess/RVectorDataAdapter.java b/core/org.eclipse.statet.rj.services.core/src/org/eclipse/statet/rj/services/util/dataaccess/RVectorDataAdapter.java
new file mode 100644
index 0000000..9dd1a2b
--- /dev/null
+++ b/core/org.eclipse.statet.rj.services.core/src/org/eclipse/statet/rj/services/util/dataaccess/RVectorDataAdapter.java
@@ -0,0 +1,87 @@
+/*=============================================================================#
+ # Copyright (c) 2013, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.services.util.dataaccess;
+
+import org.eclipse.statet.rj.data.RDataUtils;
+import org.eclipse.statet.rj.data.RObject;
+import org.eclipse.statet.rj.data.RVector;
+import org.eclipse.statet.rj.data.UnexpectedRDataException;
+import org.eclipse.statet.rj.services.util.dataaccess.LazyRStore.Fragment;
+
+
+/**
+ * Data adapter for {@link RVector} objects.
+ * 
+ * @since 2.0 (provisional)
+ */
+public class RVectorDataAdapter extends AbstractRDataAdapter<RVector<?>, RVector<?>> {
+	
+	
+	@Override
+	public RVector<?> validate(final RObject rObject) throws UnexpectedRDataException {
+		return RDataUtils.checkRVector(rObject);
+	}
+	
+	@Override
+	public RVector<?> validate(final RObject rObject, final RVector<?> referenceObject,
+			final int flags) throws UnexpectedRDataException {
+		final RVector<?> vector= RDataUtils.checkRVector(rObject);
+		if ((flags & ROW_COUNT) != 0) {
+			RDataUtils.checkLengthEqual(vector, referenceObject.getLength());
+		}
+		if ((flags & STORE_TYPE) != 0) {
+			RDataUtils.checkData(vector.getData(), referenceObject.getData().getStoreType());
+		}
+		return vector;
+	}
+	
+	@Override
+	public long getRowCount(final RVector<?> rObject) {
+		return rObject.getLength();
+	}
+	
+	@Override
+	public long getColumnCount(final RVector<?> rObject) {
+		return 1;
+	}
+	
+	
+	@Override
+	protected String getLoadDataFName() {
+		return API_R_PREFIX + ".getDataVectorValues"; //$NON-NLS-1$
+	}
+	
+	@Override
+	protected String getSetDataFName() {
+		return API_R_PREFIX + ".setDataVectorValues"; //$NON-NLS-1$
+	}
+	
+	@Override
+	protected RVector<?> validateData(final RObject rObject, final RVector<?> referenceObject,
+			final Fragment<RVector<?>> fragment) throws UnexpectedRDataException {
+		final RVector<?> vector= RDataUtils.checkRVector(rObject);
+		RDataUtils.checkLengthEqual(vector, fragment.getRowCount());
+		
+		RDataUtils.checkData(rObject.getData(), referenceObject.getData().getStoreType());
+		
+		return vector;
+	}
+	
+	@Override
+	protected String getLoadRowNamesFName() {
+		return API_R_PREFIX + ".getDataVectorRowNames"; //$NON-NLS-1$
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/RCircle.java b/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/RCircle.java
new file mode 100644
index 0000000..8cac65f
--- /dev/null
+++ b/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/RCircle.java
@@ -0,0 +1,65 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.graphic.core;
+
+
+/**
+ * Circle with center <code>(x, y)</code> and radius <code>r</code>.
+ */
+public class RCircle extends RGraphicElement {
+	
+	
+	public final double x;
+	public final double y;
+	public final double r;
+	
+	
+	/**
+	 * Creates a new circle.
+	 * 
+	 * @param x x coordinate of the center
+	 * @param y y coordinate of the center
+	 * @param r radius
+	 */
+	public RCircle(final double x, final double y, final double r) {
+		this.x= x;
+		this.y= y;
+		this.r= r;
+	}
+	
+	
+	@Override
+	public final byte getInstructionType() {
+		return DRAW_CIRCLE;
+	}
+	
+	
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public String toString() {
+		final StringBuilder sb= new StringBuilder(40);
+		sb.append("Circle[(");
+		sb.append(this.x);
+		sb.append(",");
+		sb.append(this.y);
+		sb.append("), ");
+		sb.append(this.r);
+		sb.append("]");
+		return sb.toString();
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/RClipSetting.java b/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/RClipSetting.java
new file mode 100644
index 0000000..a154b84
--- /dev/null
+++ b/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/RClipSetting.java
@@ -0,0 +1,71 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.graphic.core;
+
+
+/**
+ * Rectangular clipping area with the vertexes <code>(x0, y0)</code>, <code>(x0, y1)</code>,
+ * <code>(x1, y1)</code>, <code>(x1, y1)</code>.
+ */
+public class RClipSetting extends RPaintSetting {
+	
+	
+	public final double x0;
+	public final double y0;
+	public final double x1;
+	public final double y1;
+	
+	
+	/**
+	 * Creates a new rectangular clipping area.
+	 * 
+	 * @param x0 lower x coordinate
+	 * @param y0 lower y coordinate
+	 * @param x1 higher x coordinate
+	 * @param y1 higher x coordinate
+	 */
+	public RClipSetting(final double x0, final double y0, final double x1, final double y1) {
+		this.x0= x0;
+		this.y0= y0;
+		this.x1= x1;
+		this.y1= y1;
+	}
+	
+	
+	@Override
+	public final byte getInstructionType() {
+		return SET_CLIP;
+	}
+	
+	
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public String toString() {
+		final StringBuilder sb= new StringBuilder(50);
+		sb.append("RClipSetting[(");
+		sb.append(this.x0);
+		sb.append(",");
+		sb.append(this.y0);
+		sb.append("), (");
+		sb.append(this.x1);
+		sb.append(",");
+		sb.append(this.y1);
+		sb.append(")]");
+		return sb.toString();
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/RColorSetting.java b/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/RColorSetting.java
new file mode 100644
index 0000000..f01c41c
--- /dev/null
+++ b/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/RColorSetting.java
@@ -0,0 +1,66 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.graphic.core;
+
+
+/**
+ * Configures paint color.
+ */
+public class RColorSetting extends RPaintSetting {
+	
+	
+	public final int color;
+	
+	
+	/**
+	 * Creates a new color setting.
+	 * 
+	 * @param color color
+	 */
+	public RColorSetting(final int color) {
+		this.color= color;
+	}
+	
+	
+	@Override
+	public final byte getInstructionType() {
+		return SET_COLOR;
+	}
+	
+	
+	public final int getAlpha() {
+		return ((this.color >> 24) & 255);
+	}
+	
+	
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public String toString() {
+		final StringBuilder sb= new StringBuilder();
+		sb.append("RPaintColor[(");
+		sb.append(this.color & 255);
+		sb.append(", ");
+		sb.append((this.color >> 8) & 255);
+		sb.append(", ");
+		sb.append((this.color >> 16) & 255);
+		sb.append("), ");
+		sb.append((this.color >> 24) & 255);
+		sb.append("]");
+		return sb.toString();
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/RFillSetting.java b/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/RFillSetting.java
new file mode 100644
index 0000000..4eedb13
--- /dev/null
+++ b/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/RFillSetting.java
@@ -0,0 +1,66 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.graphic.core;
+
+
+/**
+ * Configures filling paint color.
+ */
+public class RFillSetting extends RPaintSetting {
+	
+	
+	public final int color;
+	
+	
+	/**
+	 * Creates a new fill setting.
+	 * 
+	 * @param color color
+	 */
+	public RFillSetting(final int color) {
+		this.color= color;
+	}
+	
+	
+	@Override
+	public final byte getInstructionType() {
+		return SET_FILL;
+	}
+	
+	
+	public final int getAlpha() {
+		return ((this.color >> 24) & 255);
+	}
+	
+	
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public String toString() {
+		final StringBuilder sb= new StringBuilder();
+		sb.append("RPaintFill[(");
+		sb.append(this.color & 255);
+		sb.append(", ");
+		sb.append((this.color >> 8) & 255);
+		sb.append(", ");
+		sb.append((this.color >> 16) & 255);
+		sb.append("), ");
+		sb.append((this.color >> 24) & 255);
+		sb.append("]");
+		return sb.toString();
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/RFontSetting.java b/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/RFontSetting.java
new file mode 100644
index 0000000..4e17b9e
--- /dev/null
+++ b/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/RFontSetting.java
@@ -0,0 +1,92 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.graphic.core;
+
+
+/**
+ * Configures the text font.
+ */
+public class RFontSetting extends RPaintSetting {
+	
+	/**
+	 * Font family name, ~R: <code>par(familiy)</code>.
+	 **/
+	public final String family;
+	
+	/**
+	 * Font face constant, ~R: <code>par(font)</code>.
+	 * <p>
+	 * Values:
+	 *     1= default,
+	 *     2= bold,
+	 *     3= italic,
+	 *     4= bold and italic,
+	 *     5= symbol.</p>
+	 **/
+	public final int face;
+	
+	/**
+	 * Font size in points, ~R: ps * cex.
+	 */
+	public final float pointSize;
+	
+	/**
+	 * The line height factor, ~R: <code>par(lheight)</code>
+	 */
+	public final double lineHeight;
+	
+	
+	/**
+	 * Creates a new font setting.
+	 * 
+	 * @param family font family name
+	 * @param type face font face constant
+	 * @param pointSize font size in points
+	 * @param lineHeight line height factor
+	 */
+	public RFontSetting(final String family, final int face, final float pointSize,
+			final double lineHeight) {
+		this.family= family;
+		this.face= face;
+		this.pointSize= pointSize;
+		this.lineHeight= lineHeight;
+	}
+	
+	
+	@Override
+	public final byte getInstructionType() {
+		return SET_FONT;
+	}
+	
+	
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public String toString() {
+		final StringBuilder sb= new StringBuilder(40 + this.family.length());
+		sb.append("RFontParameter[");
+		sb.append(this.family);
+		sb.append(", ");
+		sb.append(this.face);
+		sb.append(", ");
+		sb.append(this.pointSize);
+		sb.append(", ");
+		sb.append(this.lineHeight);
+		sb.append("]");
+		return sb.toString();
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/RGraphic.java b/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/RGraphic.java
new file mode 100644
index 0000000..fcdc0d0
--- /dev/null
+++ b/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/RGraphic.java
@@ -0,0 +1,67 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.graphic.core;
+
+import java.util.List;
+
+
+/**
+ * An RGraphic represents the client side of a graphic (device)
+ * in R.
+ * <p>
+ * The attributes devId ({@link #getDevId()}) and active ({@link #isActive()},
+ * {@link Listener#activated()}, {@link Listener#deactivated()}) are equivalent
+ * to the device id and active device in R.</p>
+ * <p>
+ * A graphic has a sequence of graphic instructions describing how to paint the
+ * graphic ({@link #getInstructions()}). If not empty, the first instruction is
+ * of the type {@link RGraphicInstruction#INIT INIT}, followed by setting and
+ * drawing instructions. Settings are valid for all following drawing instructions
+ * until it is changed by a new setting instruction of the same type.</p>
+ */
+public interface RGraphic {
+	
+	
+	interface Listener {
+		
+		void activated();
+		void deactivated();
+		void drawingStarted();
+		void drawingStopped();
+		
+	}
+	
+	/**
+	 * Returns the device id of the graphic in R. Note that the device number presented in public
+	 * R functions is this device id + 1.
+	 * 
+	 * @return the device id
+	 */
+	int getDevId();
+	
+	/**
+	 * Returns if graphic device of this graphic is the active device in R.
+	 * 
+	 * @return <code>true</code> if it is active, otherwise <code>false</code>
+	 */
+	boolean isActive();
+	
+	List<? extends RGraphicInstruction> getInstructions();
+	
+	void addListener(Listener listener);
+	
+	void removeListener(Listener listener);
+	
+}
diff --git a/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/RGraphicElement.java b/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/RGraphicElement.java
new file mode 100644
index 0000000..c4adfe9
--- /dev/null
+++ b/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/RGraphicElement.java
@@ -0,0 +1,23 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.graphic.core;
+
+
+/**
+ * Parent of all instructions painting graphic elements (in contrast to {@link RPaintSetting}).
+ */
+public abstract class RGraphicElement implements RGraphicInstruction {
+	
+}
diff --git a/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/RGraphicInitialization.java b/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/RGraphicInitialization.java
new file mode 100644
index 0000000..ec1414d
--- /dev/null
+++ b/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/RGraphicInitialization.java
@@ -0,0 +1,52 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.graphic.core;
+
+
+/**
+ * First instruction of an R graphic.
+ */
+public class RGraphicInitialization implements RGraphicInstruction {
+	
+	
+	/**
+	 * The width the graphic is created for in R
+	 */
+	public final double width;
+	
+	/**
+	 * The height the graphic is created for in R
+	 */
+	public final double height;
+	
+	/**
+	 * The color of the device background
+	 */
+	public final int canvasColor;
+	
+	
+	public RGraphicInitialization(final double width, final double height, final int canvasColor) {
+		this.width= width;
+		this.height= height;
+		this.canvasColor= canvasColor;
+	}
+	
+	
+	@Override
+	public final byte getInstructionType() {
+		return INIT;
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/RGraphicInstruction.java b/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/RGraphicInstruction.java
new file mode 100644
index 0000000..a0f234d
--- /dev/null
+++ b/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/RGraphicInstruction.java
@@ -0,0 +1,54 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.graphic.core;
+
+
+/**
+ * Instruction to paint a R graphic.
+ * 
+ * An instruction has one of the instruction type defined in this interface.
+ * 
+ * @see RGraphic
+ */
+public interface RGraphicInstruction {
+	
+	
+	byte INIT= 0;
+	
+	byte SET_CLIP= 1;
+	byte SET_COLOR= 2;
+	byte SET_FILL= 3;
+	byte SET_LINE= 4;
+	byte SET_FONT= 5;
+	
+	byte DRAW_LINE= 6;
+	byte DRAW_RECTANGLE= 7;
+	byte DRAW_POLYLINE= 8;
+	byte DRAW_POLYGON= 9;
+	byte DRAW_CIRCLE= 10;
+	byte DRAW_TEXT= 11;
+	byte DRAW_RASTER= 12;
+	byte DRAW_PATH= 13;
+	
+	
+	/**
+	 * Gets the type of this instruction.
+	 * 
+	 * @return the instruction type
+	 * @see RGraphicInstruction
+	 */
+	byte getInstructionType();
+	
+}
diff --git a/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/RLine.java b/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/RLine.java
new file mode 100644
index 0000000..7b30a5e
--- /dev/null
+++ b/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/RLine.java
@@ -0,0 +1,70 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.graphic.core;
+
+
+/**
+ * Line with end points <code>(x0, y0)</code> and <code>(x1, y1)</code>.
+ */
+public class RLine extends RGraphicElement {
+	
+	
+	public final double x0;
+	public final double y0;
+	public final double x1;
+	public final double y1;
+	
+	
+	/**
+	 * Creates a new line
+	 * 
+	 * @param x0 x coordinate of point 1
+	 * @param y0 y coordinate of point 1
+	 * @param x1 x coordinate of point 2
+	 * @param y1 y coordinate of point 2
+	 */
+	public RLine(final double x0, final double y0, final double x1, final double y1) {
+		this.x0= x0;
+		this.y0= y0;
+		this.x1= x1;
+		this.y1= y1;
+	}
+	
+	
+	@Override
+	public final byte getInstructionType() {
+		return DRAW_LINE;
+	}
+	
+	
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public String toString() {
+		final StringBuilder sb= new StringBuilder(50);
+		sb.append("RLine[(");
+		sb.append(this.x0);
+		sb.append(",");
+		sb.append(this.y0);
+		sb.append("), (");
+		sb.append(this.x1);
+		sb.append(",");
+		sb.append(this.y1);
+		sb.append(")]");
+		return sb.toString();
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/RLineSetting.java b/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/RLineSetting.java
new file mode 100644
index 0000000..d2361dc
--- /dev/null
+++ b/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/RLineSetting.java
@@ -0,0 +1,96 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.graphic.core;
+
+
+/**
+ * Configures line width and type.
+ */
+public class RLineSetting extends RPaintSetting {
+	
+	
+	public static final int TYPE_BLANK= -1;
+	public static final int TYPE_SOLID= 0;
+	
+	public static final byte CAP_ROUND= 1;
+	public static final byte CAP_BUTT= 2;
+	public static final byte CAP_SQUARE= 3;
+	
+	public static final byte JOIN_ROUND= 1;
+	public static final byte JOIN_MITER= 2;
+	public static final byte JOIN_BEVEL= 3;
+	
+	
+	/**
+	 * Line type, ~R: <code>par(lty)</code>
+	 * <p>
+	 * Values (not the predefined R constants, see line style encoding):
+	 *     -1= blank,
+	 *     0= solid (default),
+	 *     encoded style
+	 */
+	public final int type;
+	
+	public final float width;
+	
+	public final byte cap;
+	
+	public final byte join;
+	public final float joinMiterLimit;
+	
+	
+	/**
+	 * Creates a new line setting.
+	 * 
+	 * @param type line type
+	 * @param width line width
+	 */
+	public RLineSetting(final int type, final float width,
+			final byte cap, final byte join, final float joinMiterLimit) {
+		this.type= type;
+		this.width= width;
+		this.cap= cap;
+		this.join= join;
+		this.joinMiterLimit= joinMiterLimit;
+	}
+	
+	
+	@Override
+	public final byte getInstructionType() {
+		return SET_LINE;
+	}
+	
+	
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public String toString() {
+		final StringBuilder sb= new StringBuilder(30);
+		sb.append("RLineSetting[");
+		sb.append(this.type);
+		sb.append(", ");
+		sb.append(this.width);
+		sb.append(", ");
+		sb.append(this.cap);
+		sb.append(", ");
+		sb.append(this.join);
+		sb.append(", ");
+		sb.append(this.joinMiterLimit);
+		sb.append("]");
+		return sb.toString();
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/RPaintSetting.java b/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/RPaintSetting.java
new file mode 100644
index 0000000..5156593
--- /dev/null
+++ b/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/RPaintSetting.java
@@ -0,0 +1,23 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.graphic.core;
+
+
+/**
+ * Parent of all instructions setting paint parameters (in contrast to {@link RGraphicElement}).
+ */
+public abstract class RPaintSetting implements RGraphicInstruction {
+	
+}
diff --git a/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/RPath.java b/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/RPath.java
new file mode 100644
index 0000000..786108b
--- /dev/null
+++ b/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/RPath.java
@@ -0,0 +1,83 @@
+/*=============================================================================#
+ # Copyright (c) 2011, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.graphic.core;
+
+
+/**
+ * Path with vertices <code>(x[1], y[1])</code>, ..., <code>(x[n-1], y[n-1])</code>.
+ */
+public class RPath extends RGraphicElement {
+	
+	
+	/**
+	 * Number of vertices per segment
+	 */
+	public final int[] n;
+	
+	/**
+	 * Coordinates of the vertices
+	 */
+	public final double[] x, y;
+	
+	public final int mode;
+	
+	
+	/**
+	 * Creates a new path
+	 * 
+	 * @param n {@link #n}
+	 * @param x {@link #x}
+	 * @param y {@link #y}
+	 * @winding {@link #mode}
+	 */
+	public RPath(final int[] n, final double[] x, final double[] y, final int mode) {
+		this.n= n;
+		this.x= x;
+		this.y= y;
+		this.mode= mode;
+	}
+	
+	
+	@Override
+	public final byte getInstructionType() {
+		return DRAW_PATH;
+	}
+	
+	
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public String toString() {
+		final int n= this.x.length;
+		if (n == 0) {
+			return "RPath[]";
+		}
+		final StringBuilder sb= new StringBuilder(14 + this.x.length*20);
+		sb.append("RPath[(");
+		sb.append(this.x[0]);
+		sb.append(",");
+		sb.append(this.y[0]);
+		for (int i= 1; i < n; i++) {
+			sb.append("), (");
+			sb.append(this.x[i]);
+			sb.append(",");
+			sb.append(this.y[i]);
+		}
+		sb.append(")]");
+		return sb.toString();
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/RPolygon.java b/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/RPolygon.java
new file mode 100644
index 0000000..34be464
--- /dev/null
+++ b/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/RPolygon.java
@@ -0,0 +1,72 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.graphic.core;
+
+
+/**
+ * Polygon with vertices <code>(x[1], y[1])</code>, ..., <code>(x[n-1], y[n-1])</code>.
+ */
+public class RPolygon extends RGraphicElement {
+	
+	
+	/**
+	 * Coordinates of the vertices.
+	 */
+	public final double[] x, y;
+	
+	
+	/**
+	 * Creates a new polygon
+	 * 
+	 * @param x {@link #x}
+	 * @param y {@link #y}
+	 */
+	public RPolygon(final double[] x, final double[] y) {
+		this.x= x;
+		this.y= y;
+	}
+	
+	
+	@Override
+	public final byte getInstructionType() {
+		return DRAW_POLYGON;
+	}
+	
+	
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public String toString() {
+		final int n= this.x.length;
+		if (n == 0) {
+			return "RPolygon[]";
+		}
+		final StringBuilder sb= new StringBuilder(14 + this.x.length*20);
+		sb.append("RPolygon[(");
+		sb.append(this.x[0]);
+		sb.append(",");
+		sb.append(this.y[0]);
+		for (int i= 1; i < n; i++) {
+			sb.append("), (");
+			sb.append(this.x[i]);
+			sb.append(",");
+			sb.append(this.y[i]);
+		}
+		sb.append(")]");
+		return sb.toString();
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/RPolyline.java b/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/RPolyline.java
new file mode 100644
index 0000000..a371222
--- /dev/null
+++ b/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/RPolyline.java
@@ -0,0 +1,72 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.graphic.core;
+
+
+/**
+ * Polyline through <code>(x[0], y[0])</code>, ..., <code>(x[n-1], y[n-1])</code>.
+ */
+public class RPolyline extends RGraphicElement {
+	
+	
+	/**
+	 * Coordinates of the vertices.
+	 */
+	public final double[] x, y;
+	
+	
+	/**
+	 * Creates a new polyline.
+	 * 
+	 * @param x {@link #x}
+	 * @param y {@link #y}
+	 */
+	public RPolyline(final double[] x, final double[] y) {
+		this.x= x;
+		this.y= y;
+	}
+	
+	
+	@Override
+	public final byte getInstructionType() {
+		return DRAW_POLYLINE;
+	}
+	
+	
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public String toString() {
+		final int n= this.x.length;
+		if (n == 0) {
+			return "RPolyline[]";
+		}
+		final StringBuilder sb= new StringBuilder(14 + this.x.length*20);
+		sb.append("RPolyline[(");
+		sb.append(this.x[0]);
+		sb.append(",");
+		sb.append(this.y[0]);
+		for (int i= 1; i < n; i++) {
+			sb.append("), (");
+			sb.append(this.x[i]);
+			sb.append(",");
+			sb.append(this.y[i]);
+		}
+		sb.append(")]");
+		return sb.toString();
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/RRaster.java b/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/RRaster.java
new file mode 100644
index 0000000..8bc17b1
--- /dev/null
+++ b/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/RRaster.java
@@ -0,0 +1,101 @@
+/*=============================================================================#
+ # Copyright (c) 2011, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.graphic.core;
+
+
+/**
+ * Raster image.
+ */
+public class RRaster extends RGraphicElement {
+	
+	/**
+	 * The image data to draw (RGBA).
+	 */
+	public final byte[] imgData;
+	/**
+	 * The dimension of the {@link #imgData image}.
+	 */
+	public final int imgWidth, imgHeight;
+	/**
+	 * The position for the bottom-left corner where to draw the image.
+	 */
+	public final double x, y;
+	/**
+	 * The dimension where to draw the image.
+	 */
+	public final double width, height;
+	/**
+	 * The degree to rotate anti-clockwise the image.
+	 */
+	public final double rotateDegree;
+	
+	public final boolean interpolate;
+	
+	
+	/**
+	 * Creates a new raster image element.
+	 * 
+	 * @param imgData {@link #imgData}
+	 * @param imgWidth {@link #imgWidth}
+	 * @param imgHeight {@link #imgHeight}
+	 * @param x {@link #x}
+	 * @param y {@link #y}
+	 * @param w {@link #width}
+	 * @param h {@link #height}
+	 * @param rDeg {@link #rotateDegree}
+	 * @param interpolate {@link #interpolate}
+	 */
+	public RRaster(final byte[] imgData, final int imgWidth, final int imgHeight,
+			final double x, final double y, final double w, final double h,
+			final double rDeg, final boolean interpolate) {
+		this.imgData= imgData;
+		this.imgWidth= imgWidth;
+		this.imgHeight= imgHeight;
+		this.x= x;
+		this.y= y;
+		this.width= w;
+		this.height= h;
+		this.rotateDegree= rDeg;
+		this.interpolate= interpolate;
+	}
+	
+	
+	@Override
+	public byte getInstructionType() {
+		return DRAW_RASTER;
+	}
+	
+	
+	@Override
+	public String toString() {
+		final StringBuilder sb= new StringBuilder(50);
+		sb.append("RRaster[(");
+		sb.append(this.x);
+		sb.append(",");
+		sb.append(this.y);
+		sb.append("), (");
+		sb.append(this.width);
+		sb.append(" x ");
+		sb.append(this.height);
+		sb.append(", ");
+		sb.append(this.rotateDegree);
+		sb.append(", \"");
+		sb.append(this.interpolate);
+		sb.append("\"]");
+		return sb.toString();
+	}
+	
+
+}
diff --git a/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/RRect.java b/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/RRect.java
new file mode 100644
index 0000000..c048e6a
--- /dev/null
+++ b/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/RRect.java
@@ -0,0 +1,71 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.graphic.core;
+
+
+/**
+ * Rectangle with the vertexes <code>(x0, y0)</code>, <code>(x0, y1)</code>,
+ * <code>(x1, y1)</code>, <code>(x1, y1)</code>.
+ */
+public class RRect extends RGraphicElement {
+	
+	
+	public final double x0;
+	public final double y0;
+	public final double x1;
+	public final double y1;
+	
+	
+	/**
+	 * Creates a new rectangle.
+	 * 
+	 * @param x0 lower x coordinate
+	 * @param y0 lower y coordinate
+	 * @param x1 higher x coordinate
+	 * @param y1 higher x coordinate
+	 */
+	public RRect(final double x0, final double y0, final double x1, final double y1) {
+		this.x0= x0;
+		this.y0= y0;
+		this.x1= x1;
+		this.y1= y1;
+	}
+	
+	
+	@Override
+	public final byte getInstructionType() {
+		return DRAW_RECTANGLE;
+	}
+	
+	
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public String toString() {
+		final StringBuilder sb= new StringBuilder(50);
+		sb.append("RRect[(");
+		sb.append(this.x0);
+		sb.append(",");
+		sb.append(this.y0);
+		sb.append("), (");
+		sb.append(this.x1);
+		sb.append(",");
+		sb.append(this.y1);
+		sb.append(")]");
+		return sb.toString();
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/RText.java b/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/RText.java
new file mode 100644
index 0000000..488103f
--- /dev/null
+++ b/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/RText.java
@@ -0,0 +1,84 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.graphic.core;
+
+
+/**
+ * Text at position <code>(x, y)</code>, horizontal adjusted by <code>hAdj</code>
+ * [0, 1] and rotated by <code>rDeg</code>.
+ */
+public class RText extends RGraphicElement {
+	
+	/**
+	 * The text to draw.
+	 */
+	public final String text;
+	/**
+	 * The position where to draw the text.
+	 */
+	public final double x, y;
+	/**
+	 * The factor for the horizontal adjustment of the text.
+	 */
+	public final double horizontalAdjust;
+	/**
+	 * The degrees for rotation of the text.
+	 */
+	public final double rotateDegree;
+	
+	
+	/**
+	 * Creates a new text element.
+	 * 
+	 * @param x {@link #x}
+	 * @param y {@link #y}
+	 * @param hAdj {@link #horizontalAdjust}
+	 * @param rDeg {@link #rotateDegree}
+	 * @param text {@link #text}
+	 */
+	public RText(final String text,
+			final double x, final double y, final double rDeg, final double hAdj) {
+		this.text= text;
+		this.x= x;
+		this.y= y;
+		this.horizontalAdjust= hAdj;
+		this.rotateDegree= rDeg;
+	}
+	
+	
+	@Override
+	public final byte getInstructionType() {
+		return DRAW_TEXT;
+	}
+	
+	
+	@Override
+	public String toString() {
+		final StringBuilder sb= new StringBuilder(50 + this.text.length());
+		sb.append("RText[(");
+		sb.append(this.x);
+		sb.append(",");
+		sb.append(this.y);
+		sb.append("), ");
+		sb.append(this.horizontalAdjust);
+		sb.append(", ");
+		sb.append(this.rotateDegree);
+		sb.append(", \"");
+		sb.append(this.text);
+		sb.append("\"]");
+		return sb.toString();
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/util/.gitignore b/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/util/.gitignore
new file mode 100644
index 0000000..86eb01d
--- /dev/null
+++ b/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/util/.gitignore
@@ -0,0 +1 @@
+/AdbSymbol.txt
diff --git a/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/util/CachedMapping.java b/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/util/CachedMapping.java
new file mode 100644
index 0000000..7d58fad
--- /dev/null
+++ b/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/util/CachedMapping.java
@@ -0,0 +1,45 @@
+/*=============================================================================#
+ # Copyright (c) 2011, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.graphic.core.util;
+
+
+public final class CachedMapping implements CharMapping {
+	
+	
+	private final CharMapping mapping;
+	
+	private String lastString;
+	private String lastEncoded;
+	
+	
+	public CachedMapping(final CharMapping mapping) {
+		this.mapping= mapping;
+	}
+	
+	
+	@Override
+	public int encode(final int codepoint) {
+		return this.mapping.encode(codepoint);
+	}
+	
+	@Override
+	public String encode(final String s) {
+		if (s.equals(this.lastString)) {
+			return this.lastEncoded;
+		}
+		return (this.lastEncoded= this.mapping.encode(s));
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/util/CharMapping.java b/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/util/CharMapping.java
new file mode 100644
index 0000000..d7395a5
--- /dev/null
+++ b/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/util/CharMapping.java
@@ -0,0 +1,25 @@
+/*=============================================================================#
+ # Copyright (c) 2011, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.graphic.core.util;
+
+
+public interface CharMapping {
+	
+	
+	int encode(int codepoint);
+	
+	String encode(String s);
+	
+}
diff --git a/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/util/CodeGenAdbSymbol.java b/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/util/CodeGenAdbSymbol.java
new file mode 100644
index 0000000..d9298dd
--- /dev/null
+++ b/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/util/CodeGenAdbSymbol.java
@@ -0,0 +1,60 @@
+/*=============================================================================#
+ # Copyright (c) 2011, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.graphic.core.util;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+
+
+/**
+ * Code generation for AdbSymbol
+ * 
+ * http://unicode.org/Public/MAPPINGS/VENDORS/ADOBE/symbol.txt
+ */
+class CodeGenAdbSymbol {
+	
+	
+	public static void main(final String[] args) throws Exception {
+		final File file= new File("bin/" + CodeGenAdbSymbol.class.getPackage().getName().replace('.', '/') + "/AdbSymbol.txt");
+		final BufferedReader reader= new BufferedReader(new FileReader(file));
+		String line;
+		while ((line= reader.readLine()) != null) {
+			if (line.length() == 0 || line.startsWith("#")) {
+				continue;
+			}
+			final String[] columns= line.split("\t");
+			if (columns.length != 4) {
+				throw new IOException(line);
+			}
+			
+			System.out.print("MAPPING[0x");
+			System.out.print(columns[0]);
+			System.out.print("]= 0x");
+			System.out.print(columns[1]);
+			System.out.print("; // ");
+			System.out.print(columns[2].substring(2));
+			
+			final int codepoint= Integer.parseInt(columns[0], 16);
+			if (new String(new int[] { codepoint }, 0, 1).length() != 1) {
+				throw new IOException("Warning: multichar codepoint");
+			}
+			
+			System.out.println();
+		}
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/util/Unicode2AdbSymbolMapping.java b/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/util/Unicode2AdbSymbolMapping.java
new file mode 100644
index 0000000..7f14f34
--- /dev/null
+++ b/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/util/Unicode2AdbSymbolMapping.java
@@ -0,0 +1,240 @@
+/*=============================================================================#
+ # Copyright (c) 2011, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.graphic.core.util;
+
+
+public final class Unicode2AdbSymbolMapping implements CharMapping {
+	
+	
+	private final static char[] ADBSYMBOL_U2C= new char[0xffff];
+	
+	static {
+		for (int i= 0; i < ADBSYMBOL_U2C.length; i++) {
+			ADBSYMBOL_U2C[i]= (char) i;
+		}
+		// Generated by CodeGenAdbSymbol
+		ADBSYMBOL_U2C[0x0020]= 0x20; // SPACE
+		ADBSYMBOL_U2C[0x00A0]= 0x20; // NO-BREAK SPACE
+		ADBSYMBOL_U2C[0x0021]= 0x21; // EXCLAMATION MARK
+		ADBSYMBOL_U2C[0x2200]= 0x22; // FOR ALL
+		ADBSYMBOL_U2C[0x0023]= 0x23; // NUMBER SIGN
+		ADBSYMBOL_U2C[0x2203]= 0x24; // THERE EXISTS
+		ADBSYMBOL_U2C[0x0025]= 0x25; // PERCENT SIGN
+		ADBSYMBOL_U2C[0x0026]= 0x26; // AMPERSAND
+		ADBSYMBOL_U2C[0x220B]= 0x27; // CONTAINS AS MEMBER
+		ADBSYMBOL_U2C[0x0028]= 0x28; // LEFT PARENTHESIS
+		ADBSYMBOL_U2C[0x0029]= 0x29; // RIGHT PARENTHESIS
+		ADBSYMBOL_U2C[0x2217]= 0x2A; // ASTERISK OPERATOR
+		ADBSYMBOL_U2C[0x002B]= 0x2B; // PLUS SIGN
+		ADBSYMBOL_U2C[0x002C]= 0x2C; // COMMA
+		ADBSYMBOL_U2C[0x2212]= 0x2D; // MINUS SIGN
+		ADBSYMBOL_U2C[0x002E]= 0x2E; // FULL STOP
+		ADBSYMBOL_U2C[0x002F]= 0x2F; // SOLIDUS
+		ADBSYMBOL_U2C[0x0030]= 0x30; // DIGIT ZERO
+		ADBSYMBOL_U2C[0x0031]= 0x31; // DIGIT ONE
+		ADBSYMBOL_U2C[0x0032]= 0x32; // DIGIT TWO
+		ADBSYMBOL_U2C[0x0033]= 0x33; // DIGIT THREE
+		ADBSYMBOL_U2C[0x0034]= 0x34; // DIGIT FOUR
+		ADBSYMBOL_U2C[0x0035]= 0x35; // DIGIT FIVE
+		ADBSYMBOL_U2C[0x0036]= 0x36; // DIGIT SIX
+		ADBSYMBOL_U2C[0x0037]= 0x37; // DIGIT SEVEN
+		ADBSYMBOL_U2C[0x0038]= 0x38; // DIGIT EIGHT
+		ADBSYMBOL_U2C[0x0039]= 0x39; // DIGIT NINE
+		ADBSYMBOL_U2C[0x003A]= 0x3A; // COLON
+		ADBSYMBOL_U2C[0x003B]= 0x3B; // SEMICOLON
+		ADBSYMBOL_U2C[0x003C]= 0x3C; // LESS-THAN SIGN
+		ADBSYMBOL_U2C[0x003D]= 0x3D; // EQUALS SIGN
+		ADBSYMBOL_U2C[0x003E]= 0x3E; // GREATER-THAN SIGN
+		ADBSYMBOL_U2C[0x003F]= 0x3F; // QUESTION MARK
+		ADBSYMBOL_U2C[0x2245]= 0x40; // APPROXIMATELY EQUAL TO
+		ADBSYMBOL_U2C[0x0391]= 0x41; // GREEK CAPITAL LETTER ALPHA
+		ADBSYMBOL_U2C[0x0392]= 0x42; // GREEK CAPITAL LETTER BETA
+		ADBSYMBOL_U2C[0x03A7]= 0x43; // GREEK CAPITAL LETTER CHI
+		ADBSYMBOL_U2C[0x0394]= 0x44; // GREEK CAPITAL LETTER DELTA
+		ADBSYMBOL_U2C[0x2206]= 0x44; // INCREMENT
+		ADBSYMBOL_U2C[0x0395]= 0x45; // GREEK CAPITAL LETTER EPSILON
+		ADBSYMBOL_U2C[0x03A6]= 0x46; // GREEK CAPITAL LETTER PHI
+		ADBSYMBOL_U2C[0x0393]= 0x47; // GREEK CAPITAL LETTER GAMMA
+		ADBSYMBOL_U2C[0x0397]= 0x48; // GREEK CAPITAL LETTER ETA
+		ADBSYMBOL_U2C[0x0399]= 0x49; // GREEK CAPITAL LETTER IOTA
+		ADBSYMBOL_U2C[0x03D1]= 0x4A; // GREEK THETA SYMBOL
+		ADBSYMBOL_U2C[0x039A]= 0x4B; // GREEK CAPITAL LETTER KAPPA
+		ADBSYMBOL_U2C[0x039B]= 0x4C; // GREEK CAPITAL LETTER LAMDA
+		ADBSYMBOL_U2C[0x039C]= 0x4D; // GREEK CAPITAL LETTER MU
+		ADBSYMBOL_U2C[0x039D]= 0x4E; // GREEK CAPITAL LETTER NU
+		ADBSYMBOL_U2C[0x039F]= 0x4F; // GREEK CAPITAL LETTER OMICRON
+		ADBSYMBOL_U2C[0x03A0]= 0x50; // GREEK CAPITAL LETTER PI
+		ADBSYMBOL_U2C[0x0398]= 0x51; // GREEK CAPITAL LETTER THETA
+		ADBSYMBOL_U2C[0x03A1]= 0x52; // GREEK CAPITAL LETTER RHO
+		ADBSYMBOL_U2C[0x03A3]= 0x53; // GREEK CAPITAL LETTER SIGMA
+		ADBSYMBOL_U2C[0x03A4]= 0x54; // GREEK CAPITAL LETTER TAU
+		ADBSYMBOL_U2C[0x03A5]= 0x55; // GREEK CAPITAL LETTER UPSILON
+		ADBSYMBOL_U2C[0x03C2]= 0x56; // GREEK SMALL LETTER FINAL SIGMA
+		ADBSYMBOL_U2C[0x03A9]= 0x57; // GREEK CAPITAL LETTER OMEGA
+		ADBSYMBOL_U2C[0x2126]= 0x57; // OHM SIGN
+		ADBSYMBOL_U2C[0x039E]= 0x58; // GREEK CAPITAL LETTER XI
+		ADBSYMBOL_U2C[0x03A8]= 0x59; // GREEK CAPITAL LETTER PSI
+		ADBSYMBOL_U2C[0x0396]= 0x5A; // GREEK CAPITAL LETTER ZETA
+		ADBSYMBOL_U2C[0x005B]= 0x5B; // LEFT SQUARE BRACKET
+		ADBSYMBOL_U2C[0x2234]= 0x5C; // THEREFORE
+		ADBSYMBOL_U2C[0x005D]= 0x5D; // RIGHT SQUARE BRACKET
+		ADBSYMBOL_U2C[0x22A5]= 0x5E; // UP TACK
+		ADBSYMBOL_U2C[0x005F]= 0x5F; // LOW LINE
+		ADBSYMBOL_U2C[0xF8E5]= 0x60; // RADICAL EXTENDER
+		ADBSYMBOL_U2C[0x03B1]= 0x61; // GREEK SMALL LETTER ALPHA
+		ADBSYMBOL_U2C[0x03B2]= 0x62; // GREEK SMALL LETTER BETA
+		ADBSYMBOL_U2C[0x03C7]= 0x63; // GREEK SMALL LETTER CHI
+		ADBSYMBOL_U2C[0x03B4]= 0x64; // GREEK SMALL LETTER DELTA
+		ADBSYMBOL_U2C[0x03B5]= 0x65; // GREEK SMALL LETTER EPSILON
+		ADBSYMBOL_U2C[0x03C6]= 0x66; // GREEK SMALL LETTER PHI
+		ADBSYMBOL_U2C[0x03B3]= 0x67; // GREEK SMALL LETTER GAMMA
+		ADBSYMBOL_U2C[0x03B7]= 0x68; // GREEK SMALL LETTER ETA
+		ADBSYMBOL_U2C[0x03B9]= 0x69; // GREEK SMALL LETTER IOTA
+		ADBSYMBOL_U2C[0x03D5]= 0x6A; // GREEK PHI SYMBOL
+		ADBSYMBOL_U2C[0x03BA]= 0x6B; // GREEK SMALL LETTER KAPPA
+		ADBSYMBOL_U2C[0x03BB]= 0x6C; // GREEK SMALL LETTER LAMDA
+		ADBSYMBOL_U2C[0x00B5]= 0x6D; // MICRO SIGN
+		ADBSYMBOL_U2C[0x03BC]= 0x6D; // GREEK SMALL LETTER MU
+		ADBSYMBOL_U2C[0x03BD]= 0x6E; // GREEK SMALL LETTER NU
+		ADBSYMBOL_U2C[0x03BF]= 0x6F; // GREEK SMALL LETTER OMICRON
+		ADBSYMBOL_U2C[0x03C0]= 0x70; // GREEK SMALL LETTER PI
+		ADBSYMBOL_U2C[0x03B8]= 0x71; // GREEK SMALL LETTER THETA
+		ADBSYMBOL_U2C[0x03C1]= 0x72; // GREEK SMALL LETTER RHO
+		ADBSYMBOL_U2C[0x03C3]= 0x73; // GREEK SMALL LETTER SIGMA
+		ADBSYMBOL_U2C[0x03C4]= 0x74; // GREEK SMALL LETTER TAU
+		ADBSYMBOL_U2C[0x03C5]= 0x75; // GREEK SMALL LETTER UPSILON
+		ADBSYMBOL_U2C[0x03D6]= 0x76; // GREEK PI SYMBOL
+		ADBSYMBOL_U2C[0x03C9]= 0x77; // GREEK SMALL LETTER OMEGA
+		ADBSYMBOL_U2C[0x03BE]= 0x78; // GREEK SMALL LETTER XI
+		ADBSYMBOL_U2C[0x03C8]= 0x79; // GREEK SMALL LETTER PSI
+		ADBSYMBOL_U2C[0x03B6]= 0x7A; // GREEK SMALL LETTER ZETA
+		ADBSYMBOL_U2C[0x007B]= 0x7B; // LEFT CURLY BRACKET
+		ADBSYMBOL_U2C[0x007C]= 0x7C; // VERTICAL LINE
+		ADBSYMBOL_U2C[0x007D]= 0x7D; // RIGHT CURLY BRACKET
+		ADBSYMBOL_U2C[0x223C]= 0x7E; // TILDE OPERATOR
+		ADBSYMBOL_U2C[0x20AC]= 0xA0; // EURO SIGN
+		ADBSYMBOL_U2C[0x03D2]= 0xA1; // GREEK UPSILON WITH HOOK SYMBOL
+		ADBSYMBOL_U2C[0x2032]= 0xA2; // PRIME
+		ADBSYMBOL_U2C[0x2264]= 0xA3; // LESS-THAN OR EQUAL TO
+		ADBSYMBOL_U2C[0x2044]= 0xA4; // FRACTION SLASH
+		ADBSYMBOL_U2C[0x2215]= 0xA4; // DIVISION SLASH
+		ADBSYMBOL_U2C[0x221E]= 0xA5; // INFINITY
+		ADBSYMBOL_U2C[0x0192]= 0xA6; // LATIN SMALL LETTER F WITH HOOK
+		ADBSYMBOL_U2C[0x2663]= 0xA7; // BLACK CLUB SUIT
+		ADBSYMBOL_U2C[0x2666]= 0xA8; // BLACK DIAMOND SUIT
+		ADBSYMBOL_U2C[0x2665]= 0xA9; // BLACK HEART SUIT
+		ADBSYMBOL_U2C[0x2660]= 0xAA; // BLACK SPADE SUIT
+		ADBSYMBOL_U2C[0x2194]= 0xAB; // LEFT RIGHT ARROW
+		ADBSYMBOL_U2C[0x2190]= 0xAC; // LEFTWARDS ARROW
+		ADBSYMBOL_U2C[0x2191]= 0xAD; // UPWARDS ARROW
+		ADBSYMBOL_U2C[0x2192]= 0xAE; // RIGHTWARDS ARROW
+		ADBSYMBOL_U2C[0x2193]= 0xAF; // DOWNWARDS ARROW
+		ADBSYMBOL_U2C[0x00B0]= 0xB0; // DEGREE SIGN
+		ADBSYMBOL_U2C[0x00B1]= 0xB1; // PLUS-MINUS SIGN
+		ADBSYMBOL_U2C[0x2033]= 0xB2; // DOUBLE PRIME
+		ADBSYMBOL_U2C[0x2265]= 0xB3; // GREATER-THAN OR EQUAL TO
+		ADBSYMBOL_U2C[0x00D7]= 0xB4; // MULTIPLICATION SIGN
+		ADBSYMBOL_U2C[0x221D]= 0xB5; // PROPORTIONAL TO
+		ADBSYMBOL_U2C[0x2202]= 0xB6; // PARTIAL DIFFERENTIAL
+		ADBSYMBOL_U2C[0x2022]= 0xB7; // BULLET
+		ADBSYMBOL_U2C[0x00F7]= 0xB8; // DIVISION SIGN
+		ADBSYMBOL_U2C[0x2260]= 0xB9; // NOT EQUAL TO
+		ADBSYMBOL_U2C[0x2261]= 0xBA; // IDENTICAL TO
+		ADBSYMBOL_U2C[0x2248]= 0xBB; // ALMOST EQUAL TO
+		ADBSYMBOL_U2C[0x2026]= 0xBC; // HORIZONTAL ELLIPSIS
+		ADBSYMBOL_U2C[0xF8E6]= 0xBD; // VERTICAL ARROW EXTENDER
+		ADBSYMBOL_U2C[0xF8E7]= 0xBE; // HORIZONTAL ARROW EXTENDER
+		ADBSYMBOL_U2C[0x21B5]= 0xBF; // DOWNWARDS ARROW WITH CORNER LEFTWARDS
+		ADBSYMBOL_U2C[0x2135]= 0xC0; // ALEF SYMBOL
+		ADBSYMBOL_U2C[0x2111]= 0xC1; // BLACK-LETTER CAPITAL I
+		ADBSYMBOL_U2C[0x211C]= 0xC2; // BLACK-LETTER CAPITAL R
+		ADBSYMBOL_U2C[0x2118]= 0xC3; // SCRIPT CAPITAL P
+		ADBSYMBOL_U2C[0x2297]= 0xC4; // CIRCLED TIMES
+		ADBSYMBOL_U2C[0x2295]= 0xC5; // CIRCLED PLUS
+		ADBSYMBOL_U2C[0x2205]= 0xC6; // EMPTY SET
+		ADBSYMBOL_U2C[0x2229]= 0xC7; // INTERSECTION
+		ADBSYMBOL_U2C[0x222A]= 0xC8; // UNION
+		ADBSYMBOL_U2C[0x2283]= 0xC9; // SUPERSET OF
+		ADBSYMBOL_U2C[0x2287]= 0xCA; // SUPERSET OF OR EQUAL TO
+		ADBSYMBOL_U2C[0x2284]= 0xCB; // NOT A SUBSET OF
+		ADBSYMBOL_U2C[0x2282]= 0xCC; // SUBSET OF
+		ADBSYMBOL_U2C[0x2286]= 0xCD; // SUBSET OF OR EQUAL TO
+		ADBSYMBOL_U2C[0x2208]= 0xCE; // ELEMENT OF
+		ADBSYMBOL_U2C[0x2209]= 0xCF; // NOT AN ELEMENT OF
+		ADBSYMBOL_U2C[0x2220]= 0xD0; // ANGLE
+		ADBSYMBOL_U2C[0x2207]= 0xD1; // NABLA
+		ADBSYMBOL_U2C[0xF6DA]= 0xD2; // REGISTERED SIGN SERIF
+		ADBSYMBOL_U2C[0xF6D9]= 0xD3; // COPYRIGHT SIGN SERIF
+		ADBSYMBOL_U2C[0xF6DB]= 0xD4; // TRADE MARK SIGN SERIF
+		ADBSYMBOL_U2C[0x220F]= 0xD5; // N-ARY PRODUCT
+		ADBSYMBOL_U2C[0x221A]= 0xD6; // SQUARE ROOT
+		ADBSYMBOL_U2C[0x22C5]= 0xD7; // DOT OPERATOR
+		ADBSYMBOL_U2C[0x00AC]= 0xD8; // NOT SIGN
+		ADBSYMBOL_U2C[0x2227]= 0xD9; // LOGICAL AND
+		ADBSYMBOL_U2C[0x2228]= 0xDA; // LOGICAL OR
+		ADBSYMBOL_U2C[0x21D4]= 0xDB; // LEFT RIGHT DOUBLE ARROW
+		ADBSYMBOL_U2C[0x21D0]= 0xDC; // LEFTWARDS DOUBLE ARROW
+		ADBSYMBOL_U2C[0x21D1]= 0xDD; // UPWARDS DOUBLE ARROW
+		ADBSYMBOL_U2C[0x21D2]= 0xDE; // RIGHTWARDS DOUBLE ARROW
+		ADBSYMBOL_U2C[0x21D3]= 0xDF; // DOWNWARDS DOUBLE ARROW
+		ADBSYMBOL_U2C[0x25CA]= 0xE0; // LOZENGE
+		ADBSYMBOL_U2C[0x2329]= 0xE1; // LEFT-POINTING ANGLE BRACKET
+		ADBSYMBOL_U2C[0xF8E8]= 0xE2; // REGISTERED SIGN SANS SERIF
+		ADBSYMBOL_U2C[0xF8E9]= 0xE3; // COPYRIGHT SIGN SANS SERIF
+		ADBSYMBOL_U2C[0xF8EA]= 0xE4; // TRADE MARK SIGN SANS SERIF
+		ADBSYMBOL_U2C[0x2211]= 0xE5; // N-ARY SUMMATION
+		ADBSYMBOL_U2C[0xF8EB]= 0xE6; // LEFT PAREN TOP
+		ADBSYMBOL_U2C[0xF8EC]= 0xE7; // LEFT PAREN EXTENDER
+		ADBSYMBOL_U2C[0xF8ED]= 0xE8; // LEFT PAREN BOTTOM
+		ADBSYMBOL_U2C[0xF8EE]= 0xE9; // LEFT SQUARE BRACKET TOP
+		ADBSYMBOL_U2C[0xF8EF]= 0xEA; // LEFT SQUARE BRACKET EXTENDER
+		ADBSYMBOL_U2C[0xF8F0]= 0xEB; // LEFT SQUARE BRACKET BOTTOM
+		ADBSYMBOL_U2C[0xF8F1]= 0xEC; // LEFT CURLY BRACKET TOP
+		ADBSYMBOL_U2C[0xF8F2]= 0xED; // LEFT CURLY BRACKET MID
+		ADBSYMBOL_U2C[0xF8F3]= 0xEE; // LEFT CURLY BRACKET BOTTOM
+		ADBSYMBOL_U2C[0xF8F4]= 0xEF; // CURLY BRACKET EXTENDER
+		ADBSYMBOL_U2C[0x232A]= 0xF1; // RIGHT-POINTING ANGLE BRACKET
+		ADBSYMBOL_U2C[0x222B]= 0xF2; // INTEGRAL
+		ADBSYMBOL_U2C[0x2320]= 0xF3; // TOP HALF INTEGRAL
+		ADBSYMBOL_U2C[0xF8F5]= 0xF4; // INTEGRAL EXTENDER
+		ADBSYMBOL_U2C[0x2321]= 0xF5; // BOTTOM HALF INTEGRAL
+		ADBSYMBOL_U2C[0xF8F6]= 0xF6; // RIGHT PAREN TOP
+		ADBSYMBOL_U2C[0xF8F7]= 0xF7; // RIGHT PAREN EXTENDER
+		ADBSYMBOL_U2C[0xF8F8]= 0xF8; // RIGHT PAREN BOTTOM
+		ADBSYMBOL_U2C[0xF8F9]= 0xF9; // RIGHT SQUARE BRACKET TOP
+		ADBSYMBOL_U2C[0xF8FA]= 0xFA; // RIGHT SQUARE BRACKET EXTENDER
+		ADBSYMBOL_U2C[0xF8FB]= 0xFB; // RIGHT SQUARE BRACKET BOTTOM
+		ADBSYMBOL_U2C[0xF8FC]= 0xFC; // RIGHT CURLY BRACKET TOP
+		ADBSYMBOL_U2C[0xF8FD]= 0xFD; // RIGHT CURLY BRACKET MID
+		ADBSYMBOL_U2C[0xF8FE]= 0xFE; // RIGHT CURLY BRACKET BOTTOM
+	}
+	
+	
+	@Override
+	public int encode(final int codepoint) {
+		return (codepoint >= 0 && codepoint < 0xffff) ? ADBSYMBOL_U2C[codepoint] : codepoint;
+	}
+	
+	@Override
+	public String encode(final String s) {
+		final char[] encodedChars= new char[s.length()];
+		for (int i= 0; i < s.length(); i++) {
+			final char c= s.charAt(i);
+			encodedChars[i]= (c >= 0 && c < 0xffff) ? ADBSYMBOL_U2C[c] : c;
+		}
+		return new String(encodedChars);
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.services.core/srcREnv/org/eclipse/statet/rj/renv/core/BasicRPkg.java b/core/org.eclipse.statet.rj.services.core/srcREnv/org/eclipse/statet/rj/renv/core/BasicRPkg.java
new file mode 100644
index 0000000..9eb392b
--- /dev/null
+++ b/core/org.eclipse.statet.rj.services.core/srcREnv/org/eclipse/statet/rj/renv/core/BasicRPkg.java
@@ -0,0 +1,84 @@
+/*=============================================================================#
+ # Copyright (c) 2012, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.renv.core;
+
+
+/**
+ * Basic immutable R package, implementation of {@link RPkg}.
+ * 
+ * @since de.walware.rj.renv.core 2.0
+ */
+public class BasicRPkg implements RPkg {
+	
+	
+	private final String name;
+	
+	private final RNumVersion version;
+	
+	
+	public BasicRPkg(final String name, final RNumVersion version) {
+		if (name == null) {
+			throw new NullPointerException("name"); //$NON-NLS-1$
+		}
+		if (version == null) {
+			throw new NullPointerException("version"); //$NON-NLS-1$
+		}
+		this.name= name;
+		this.version= version;
+	}
+	
+	
+	@Override
+	public String getName() {
+		return this.name;
+	}
+	
+	@Override
+	public RNumVersion getVersion() {
+		return this.version;
+	}
+	
+	
+	@Override
+	public int hashCode() {
+		return this.name.hashCode() + this.version.hashCode() * 7;
+	}
+	
+	@Override
+	public boolean equals(final Object obj) {
+		if (this == obj) {
+			return true;
+		}
+		if (!(obj instanceof RPkg)) {
+			return false;
+		}
+		final RPkg other= (RPkg) obj;
+		return (this.name.equals(other.getName()) && this.version.equals(other.getVersion()));
+	}
+	
+	
+	@Override
+	public String toString() {
+		if (this.version == RNumVersion.NONE) {
+			return this.name;
+		}
+		final StringBuilder sb= new StringBuilder(this.name.length() + this.version.toString().length() + 12);
+		sb.append(this.name);
+		sb.append(" (" + "version= ").append(this.version.toString());
+		sb.append(')');
+		return sb.toString();
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.services.core/srcREnv/org/eclipse/statet/rj/renv/core/BasicRPkgDescription.java b/core/org.eclipse.statet.rj.services.core/srcREnv/org/eclipse/statet/rj/renv/core/BasicRPkgDescription.java
new file mode 100644
index 0000000..f11352e
--- /dev/null
+++ b/core/org.eclipse.statet.rj.services.core/srcREnv/org/eclipse/statet/rj/renv/core/BasicRPkgDescription.java
@@ -0,0 +1,86 @@
+/*=============================================================================#
+ # Copyright (c) 2010, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.renv.core;
+
+
+/**
+ * Basic immutable R package description, implementation {@link RPkgDescription}.
+ * 
+ * @since de.walware.rj.renv.core 2.0
+ */
+public class BasicRPkgDescription extends BasicRPkg implements RPkgDescription {
+	
+	
+	private final String title;
+	private final String description;
+	
+	private final String author;
+	private final String maintainer;
+	private final String url;
+	
+	private final String built;
+	
+	
+	public BasicRPkgDescription(final String name, final RNumVersion version,
+			final String title, final String desription,
+			final String author, final String maintainer, final String url,
+			final String built) {
+		super(name, version);
+		this.title= title;
+		this.description= desription;
+		this.author= author;
+		this.maintainer= maintainer;
+		this.url= url;
+		this.built= built;
+	}
+	
+	
+	@Override
+	public String getTitle() {
+		return this.title;
+	}
+	
+	@Override
+	public String getDescription() {
+		return this.description;
+	}
+	
+	@Override
+	public String getAuthor() {
+		return this.author;
+	}
+	
+	@Override
+	public String getMaintainer() {
+		return this.maintainer;
+	}
+	
+	@Override
+	public String getUrl() {
+		return this.url;
+	}
+	
+	@Override
+	public String getBuilt() {
+		return this.built;
+	}
+	
+	
+	@Override
+	public boolean equals(final Object obj) {
+		return (obj instanceof RPkgDescription && super.equals(obj));
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.services.core/srcREnv/org/eclipse/statet/rj/renv/core/RNumVersion.java b/core/org.eclipse.statet.rj.services.core/srcREnv/org/eclipse/statet/rj/renv/core/RNumVersion.java
new file mode 100644
index 0000000..701a267
--- /dev/null
+++ b/core/org.eclipse.statet.rj.services.core/srcREnv/org/eclipse/statet/rj/renv/core/RNumVersion.java
@@ -0,0 +1,204 @@
+/*=============================================================================#
+ # Copyright (c) 2012, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.renv.core;
+
+import java.util.Arrays;
+import java.util.Iterator;
+
+
+/**
+ * @since de.walware.rj.renv.core 2.0
+ */
+public final class RNumVersion {
+	
+	// First int in numeric version is the operator
+	
+	
+	public static final RNumVersion NONE= new RNumVersion(""); //$NON-NLS-1$
+	
+	
+	public static RNumVersion create(final String s) {
+		if (s == null || s.isEmpty()) {
+			return NONE;
+		}
+		return new RNumVersion(s);
+	}
+	
+	
+	private static final int OP_UNSUPPORTED= -2;
+	private static final int OP_NONE= -1;
+	
+	private static final int OP_GE= 2;
+	
+	static {
+		NONE.numeric= new int[] { OP_NONE };
+	}
+	
+	
+	private static final int[] parseVersion(final String s) {
+		final int[] v= new int[(3 + s.length())/2];
+		int idx= 1;
+		int i= 0;
+		if (s.startsWith(">=")) { //$NON-NLS-1$
+			v[0]= OP_GE;
+			i= 2;
+		}
+		int start= -3;
+		for (; i < s.length(); i++) {
+			final char c= s.charAt(i);
+			if (start == -3 && c == ' ') {
+				continue;
+			}
+			if (c >= '0' && c <= '9') {
+				if (start < 0) {
+					start= i;
+				}
+				continue;
+			}
+			if (start >= 0) {
+				v[idx++]= Integer.parseInt(s.substring(start, i));
+				start= -1;
+				if (c == '.' || c == '-') {
+					continue;
+				}
+			}
+			break;
+		}
+		if (start >= 0) {
+			v[idx++]= Integer.parseInt(s.substring(start, s.length()));
+		}
+		if (idx <= 2) {
+			v[0]= OP_UNSUPPORTED;
+			idx= 1;
+		}
+		return (v.length == idx) ? v : Arrays.copyOf(v, idx);
+	}
+	
+	
+	private final String string;
+	
+	/** use {@link #getNumericVersion()} */
+	private volatile int[] numeric;
+	
+	
+	private RNumVersion(final String s) {
+		this.string= s;
+	}
+	
+	
+	public boolean isGreaterEqualThan(final RNumVersion pkgVersion2) {
+		return isGreaterEqualThan(getNumericVersion(), pkgVersion2.getNumericVersion());
+	}
+	
+	private boolean isGreaterEqualThan(final int[] v1, final int[] v2) {
+		final int l= Math.max(v1.length, v2.length);
+		for (int i= 1; i < l; i++) {
+			final int diff= ((i < v1.length) ? v1[i] : 0) - ((i < v2.length) ? v2[i] : 0);
+			if (diff > 0) {
+				return true;
+			}
+			else if (diff < 0) {
+				return false;
+			}
+		}
+		return true;
+	}
+	
+	public boolean isGreaterThan(final RNumVersion pkgVersion2) {
+		return isGreaterThan(getNumericVersion(), pkgVersion2.getNumericVersion());
+	}
+	
+	private boolean isGreaterThan(final int[] v1, final int[] v2) {
+		final int l= Math.max(v1.length, v2.length);
+		for (int i= 1; i < l; i++) {
+			final int diff= ((i < v1.length) ? v1[i] : 0) - ((i < v2.length) ? v2[i] : 0);
+			if (diff > 0) {
+				return true;
+			}
+			else if (diff < 0) {
+				return false;
+			}
+		}
+		return false;
+	}
+	
+	public boolean isSmallerThan(final RNumVersion pkgVersion2) {
+		return isSmallerThan(getNumericVersion(), pkgVersion2.getNumericVersion());
+	}
+	
+	private boolean isSmallerThan(final int[] v1, final int[] v2) {
+		final int l= Math.max(v1.length, v2.length);
+		for (int i= 1; i < l; i++) {
+			final int diff= ((i < v1.length) ? v1[i] : 0) - ((i < v2.length) ? v2[i] : 0);
+			if (diff < 0) {
+				return true;
+			}
+			else if (diff > 0) {
+				return false;
+			}
+		}
+		return false;
+	}
+	
+	public boolean isSatisfiedBy(final RNumVersion pkgVersion2) {
+		final int[] v1= getNumericVersion();
+		switch (v1[0]) {
+		case OP_GE:
+			return isGreaterEqualThan(pkgVersion2.getNumericVersion(), v1);
+		default:
+			return true;
+		}
+	}
+	
+	public boolean isSatisfiedByAny(final Iterator<RNumVersion> pkgVersion2) {
+		final int[] v1= getNumericVersion();
+		switch (v1[0]) {
+		case OP_GE:
+			while (pkgVersion2.hasNext()) {
+				if (isGreaterEqualThan(pkgVersion2.next().getNumericVersion(), v1)) {
+					return true;
+				}
+			}
+			return false;
+		default:
+			return pkgVersion2.hasNext();
+		}
+	}
+	
+	private int[] getNumericVersion() {
+		if (this.numeric == null) {
+			this.numeric= parseVersion(this.string);
+		}
+		return this.numeric;
+	}
+	
+	
+	@Override
+	public int hashCode() {
+		return this.string.hashCode();
+	}
+	
+	@Override
+	public boolean equals(final Object obj) {
+		return (this == obj || (obj instanceof RNumVersion
+				&& this.string.equals(((RNumVersion) obj).string) ));
+	}
+	
+	@Override
+	public String toString() {
+		return this.string;
+	}
+	
+}
diff --git a/core/org.eclipse.statet.rj.services.core/srcREnv/org/eclipse/statet/rj/renv/core/RPkg.java b/core/org.eclipse.statet.rj.services.core/srcREnv/org/eclipse/statet/rj/renv/core/RPkg.java
new file mode 100644
index 0000000..59f9aaa
--- /dev/null
+++ b/core/org.eclipse.statet.rj.services.core/srcREnv/org/eclipse/statet/rj/renv/core/RPkg.java
@@ -0,0 +1,42 @@
+/*=============================================================================#
+ # Copyright (c) 2012, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.renv.core;
+
+
+/**
+ * R package.
+ * 
+ * Basic interface for representation of an R package.
+ * 
+ * @since de.walware.rj.renv.core 2.0
+ */
+public interface RPkg {
+	
+	
+	/**
+	 * The name of the package.
+	 * 
+	 * @return the name
+	 */
+	String getName();
+	
+	/**
+	 * The version of the package.
+	 * 
+	 * @return the version
+	 */
+	RNumVersion getVersion();
+	
+}
diff --git a/core/org.eclipse.statet.rj.services.core/srcREnv/org/eclipse/statet/rj/renv/core/RPkgDescription.java b/core/org.eclipse.statet.rj.services.core/srcREnv/org/eclipse/statet/rj/renv/core/RPkgDescription.java
new file mode 100644
index 0000000..dfafa6d
--- /dev/null
+++ b/core/org.eclipse.statet.rj.services.core/srcREnv/org/eclipse/statet/rj/renv/core/RPkgDescription.java
@@ -0,0 +1,38 @@
+/*=============================================================================#
+ # Copyright (c) 2010, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.renv.core;
+
+
+/**
+ * R package description.
+ * 
+ * @since de.walware.rj.renv.core 2.0
+ */
+public interface RPkgDescription extends RPkg {
+	
+	
+	String getTitle();
+	
+	String getDescription();
+	
+	String getAuthor();
+	
+	String getMaintainer();
+	
+	String getUrl();
+	
+	String getBuilt();
+	
+}
diff --git a/core/org.eclipse.statet.rj.services.core/srcREnv/org/eclipse/statet/rj/renv/core/RPkgType.java b/core/org.eclipse.statet.rj.services.core/srcREnv/org/eclipse/statet/rj/renv/core/RPkgType.java
new file mode 100644
index 0000000..a7eba1d
--- /dev/null
+++ b/core/org.eclipse.statet.rj.services.core/srcREnv/org/eclipse/statet/rj/renv/core/RPkgType.java
@@ -0,0 +1,46 @@
+/*=============================================================================#
+ # Copyright (c) 2012, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.renv.core;
+
+
+/**
+ * Type ({@link #SOURCE source} or {@link #BINARY binary}) of R packages.
+ * 
+ * @since de.walware.rj.renv.core 2.0
+ */
+public enum RPkgType {
+	
+	
+	SOURCE("Source"),
+	BINARY("Binary");
+	
+	
+	private final String label;
+	
+	
+	private RPkgType(final String label) {
+		if (label == null) {
+			throw new NullPointerException("label"); //$NON-NLS-1$
+		}
+		this.label= label;
+	}
+	
+	
+	public String getLabel() {
+		return this.label;
+	}
+	
+	
+}
diff --git a/core/org.eclipse.statet.rj.services.core/srcREnv/org/eclipse/statet/rj/renv/core/RPkgUtils.java b/core/org.eclipse.statet.rj.services.core/srcREnv/org/eclipse/statet/rj/renv/core/RPkgUtils.java
new file mode 100644
index 0000000..83dcffa
--- /dev/null
+++ b/core/org.eclipse.statet.rj.services.core/srcREnv/org/eclipse/statet/rj/renv/core/RPkgUtils.java
@@ -0,0 +1,115 @@
+/*=============================================================================#
+ # Copyright (c) 2012, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.renv.core;
+
+import java.text.MessageFormat;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+
+import org.eclipse.statet.rj.services.RJServices;
+import org.eclipse.statet.rj.services.RPlatform;
+
+
+/**
+ * @since de.walware.rj.renv.core 2.0
+ */
+public class RPkgUtils {
+	
+	
+	private static boolean isWin(final RPlatform rPlatform) {
+		return rPlatform.getOsType().equals(RPlatform.OS_WINDOWS);
+	}
+	
+	private static boolean isMac(final RPlatform rPlatform) {
+		return rPlatform.getOSName().regionMatches(true, 0, "Mac OS", 0, 6); //$NON-NLS-1$
+	}
+	
+	public static RPkgType getPkgType(final String fileName, final RPlatform rPlatform) {
+		if (fileName.endsWith(".tar.gz")) { //$NON-NLS-1$
+			return RPkgType.SOURCE;
+		}
+		if (isWin(rPlatform)) {
+			if (fileName.toLowerCase().endsWith(".zip")) { //$NON-NLS-1$
+				return RPkgType.BINARY;
+			}
+		}
+		else if (isMac(rPlatform)) {
+			if (fileName.endsWith(".tgz")) { //$NON-NLS-1$
+				return RPkgType.BINARY;
+			}
+		}
+		return null;
+	}
+	
+	public static RPkgType checkPkgType(final String fileName, final RPlatform rPlatform) throws CoreException {
+		final RPkgType pkgType= getPkgType(fileName, rPlatform);
+		if (pkgType == null) {
+			throw new CoreException(new Status(IStatus.ERROR, RJServices.BUNDLE_ID,
+					MessageFormat.format("Invalid file name ''{0}'' (unsupported extension) for R package on {1}.",
+							fileName, rPlatform.getOSName() )));
+		}
+		return pkgType;
+	}
+	
+	/**
+	 * Checks if the given file name has the standard format <code>name_version.extension</code>.
+	 * 
+	 * @param fileName the file name to check
+	 * @return a R package object with the detected name and version.
+	 * @throws CoreException if the file name has not the standard format.
+	 */
+	public static RPkg checkPkgFileName(final String fileName) throws CoreException {
+		final int extIdx;
+		if (fileName.endsWith(".tar.gz")) { //$NON-NLS-1$
+			extIdx= fileName.length() - 7;
+		}
+		else if (fileName.endsWith(".zip") || fileName.endsWith(".tgz")) { //$NON-NLS-1$ //$NON-NLS-2$
+			extIdx= fileName.length() - 4;
+		}
+		else {
+			throw new CoreException(new Status(IStatus.ERROR, RJServices.BUNDLE_ID,
+					MessageFormat.format("Invalid file name ''{0}'' (unsupported extension) for R package.",
+							fileName )));
+		}
+		
+		final int versionIdx= fileName.indexOf('_');
+		if (versionIdx < 0) {
+			throw new CoreException(new Status(IStatus.ERROR, RJServices.BUNDLE_ID,
+					MessageFormat.format("Invalid file name ''{0}'' (missing version) for R package.",
+							fileName )));
+		}
+		return new BasicRPkg(fileName.substring(0, versionIdx),
+				RNumVersion.create(fileName.substring(versionIdx + 1, extIdx)) );
+	}
+	
+	public static String getPkgTypeInstallKey(final RPlatform rPlatform, final RPkgType pkgType) {
+		if (pkgType == RPkgType.SOURCE) {
+			return "source"; //$NON-NLS-1$
+		}
+		if (pkgType == RPkgType.BINARY) {
+			if (isWin(rPlatform)) {
+				return "win.binary"; //$NON-NLS-1$
+			}
+			else if (isMac(rPlatform)) {
+				return "mac.binary.leopard"; //$NON-NLS-1$
+			}
+		}
+		return null;
+	}
+	
+	
+}
diff --git a/eclient/_build/org.eclipse.statet.rj.eclient-feature/.project b/eclient/_build/org.eclipse.statet.rj.eclient-feature/.project
new file mode 100644
index 0000000..3c68cf6
--- /dev/null
+++ b/eclient/_build/org.eclipse.statet.rj.eclient-feature/.project
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>org.eclipse.statet.rj.eclient.core-feature</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.pde.FeatureBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.pde.FeatureNature</nature>
+	</natures>
+</projectDescription>
diff --git a/eclient/_build/org.eclipse.statet.rj.eclient-feature/build.properties b/eclient/_build/org.eclipse.statet.rj.eclient-feature/build.properties
new file mode 100644
index 0000000..4fc35c8
--- /dev/null
+++ b/eclient/_build/org.eclipse.statet.rj.eclient-feature/build.properties
@@ -0,0 +1,2 @@
+bin.includes= feature.xml,\
+              feature.properties
diff --git a/eclient/_build/org.eclipse.statet.rj.eclient-feature/feature.properties b/eclient/_build/org.eclipse.statet.rj.eclient-feature/feature.properties
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/eclient/_build/org.eclipse.statet.rj.eclient-feature/feature.properties
diff --git a/eclient/_build/org.eclipse.statet.rj.eclient-feature/feature.xml b/eclient/_build/org.eclipse.statet.rj.eclient-feature/feature.xml
new file mode 100644
index 0000000..3ab7cbf
--- /dev/null
+++ b/eclient/_build/org.eclipse.statet.rj.eclient-feature/feature.xml
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<feature
+      id="org.eclipse.statet.rj.eclient"
+      version="2.1.0.qualifier"
+      label="StatET RJ - Eclipse Client"
+      provider-name="Eclipse.org"
+      license-feature="org.eclipse.license"
+      license-feature-version="1.0.1">
+
+   <description url="https://www.eclipse.org/statet">
+      Client of high-level Java-R library RJ for projects based on the Eclipse Workbench
+   </description>
+
+   <copyright>
+      Copyright (c) 2003, 2017 Stephan Wahlbrink and others. All rights reserved.
+   </copyright>
+
+   <license url="%license_url">
+      %license_text
+   </license>
+
+   <requires>
+      <import feature="org.eclipse.statet.rj.core" version="2.1.0" match="equivalent"/>
+      <import feature="org.eclipse.statet.ecommons.e" version="1.2.0" match="compatible"/>
+   </requires>
+
+   <plugin
+         id="org.eclipse.statet.rj.services.core"
+         download-size="0"
+         install-size="0"
+         version="0.0.0"
+         unpack="false"/>
+
+   <plugin
+         id="org.eclipse.statet.rj.client"
+         download-size="0"
+         install-size="0"
+         version="0.0.0"
+         unpack="false"/>
+
+   <plugin
+         id="org.eclipse.statet.rj.eclient"
+         download-size="0"
+         install-size="0"
+         version="0.0.0"
+         unpack="false"/>
+
+   <plugin
+         id="org.eclipse.statet.rj.eclient.graphics"
+         download-size="0"
+         install-size="0"
+         version="0.0.0"
+         unpack="false"/>
+
+</feature>
diff --git a/eclient/org.eclipse.statet.rj.eclient.core/.classpath b/eclient/org.eclipse.statet.rj.eclient.core/.classpath
new file mode 100644
index 0000000..eca7bdb
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.core/.classpath
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
+	<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+	<classpathentry kind="src" path="src"/>
+	<classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/eclient/org.eclipse.statet.rj.eclient.core/.gitignore b/eclient/org.eclipse.statet.rj.eclient.core/.gitignore
new file mode 100644
index 0000000..5e56e04
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.core/.gitignore
@@ -0,0 +1 @@
+/bin
diff --git a/eclient/org.eclipse.statet.rj.eclient.core/.project b/eclient/org.eclipse.statet.rj.eclient.core/.project
new file mode 100644
index 0000000..889e8b2
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.core/.project
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>org.eclipse.statet.rj.eclient.core</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.jdt.core.javabuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.pde.ManifestBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.pde.SchemaBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.pde.PluginNature</nature>
+		<nature>org.eclipse.jdt.core.javanature</nature>
+	</natures>
+</projectDescription>
diff --git a/eclient/org.eclipse.statet.rj.eclient.core/.settings/org.eclipse.core.resources.prefs b/eclient/org.eclipse.statet.rj.eclient.core/.settings/org.eclipse.core.resources.prefs
new file mode 100644
index 0000000..95ae74d
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.core/.settings/org.eclipse.core.resources.prefs
@@ -0,0 +1,3 @@
+eclipse.preferences.version=1
+encoding/<project>=UTF-8
+encoding/about.ini=ISO-8859-1
diff --git a/eclient/org.eclipse.statet.rj.eclient.core/.settings/org.eclipse.core.runtime.prefs b/eclient/org.eclipse.statet.rj.eclient.core/.settings/org.eclipse.core.runtime.prefs
new file mode 100644
index 0000000..5a0ad22
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.core/.settings/org.eclipse.core.runtime.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+line.separator=\n
diff --git a/eclient/org.eclipse.statet.rj.eclient.core/.settings/org.eclipse.jdt.core.prefs b/eclient/org.eclipse.statet.rj.eclient.core/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000..ccb1eaa
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.core/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,325 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.codeComplete.argumentPrefixes=
+org.eclipse.jdt.core.codeComplete.argumentSuffixes=
+org.eclipse.jdt.core.codeComplete.fieldPrefixes=
+org.eclipse.jdt.core.codeComplete.fieldSuffixes=
+org.eclipse.jdt.core.codeComplete.localPrefixes=
+org.eclipse.jdt.core.codeComplete.localSuffixes=
+org.eclipse.jdt.core.codeComplete.staticFieldPrefixes=
+org.eclipse.jdt.core.codeComplete.staticFieldSuffixes=
+org.eclipse.jdt.core.codeComplete.staticFinalFieldPrefixes=
+org.eclipse.jdt.core.codeComplete.staticFinalFieldSuffixes=
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=1.8
+org.eclipse.jdt.core.compiler.debug.lineNumber=generate
+org.eclipse.jdt.core.compiler.debug.localVariable=generate
+org.eclipse.jdt.core.compiler.debug.sourceFile=generate
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.source=1.8
+org.eclipse.jdt.core.formatter.align_fields_grouping_blank_lines=2147483647
+org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_assignment=0
+org.eclipse.jdt.core.formatter.alignment_for_binary_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_compact_if=16
+org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=80
+org.eclipse.jdt.core.formatter.alignment_for_enum_constants=0
+org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16
+org.eclipse.jdt.core.formatter.alignment_for_expressions_in_for_loop_header=0
+org.eclipse.jdt.core.formatter.alignment_for_method_declaration=0
+org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16
+org.eclipse.jdt.core.formatter.alignment_for_parameterized_type_references=0
+org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_resources_in_try=85
+org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=16
+org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_type_arguments=0
+org.eclipse.jdt.core.formatter.alignment_for_type_parameters=0
+org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch=16
+org.eclipse.jdt.core.formatter.blank_lines_after_imports=2
+org.eclipse.jdt.core.formatter.blank_lines_after_package=1
+org.eclipse.jdt.core.formatter.blank_lines_before_field=0
+org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=1
+org.eclipse.jdt.core.formatter.blank_lines_before_imports=1
+org.eclipse.jdt.core.formatter.blank_lines_before_member_type=1
+org.eclipse.jdt.core.formatter.blank_lines_before_method=1
+org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=2
+org.eclipse.jdt.core.formatter.blank_lines_before_package=1
+org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=1
+org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=1
+org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_block=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_lambda_body=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=false
+org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=false
+org.eclipse.jdt.core.formatter.comment.format_block_comments=true
+org.eclipse.jdt.core.formatter.comment.format_header=false
+org.eclipse.jdt.core.formatter.comment.format_html=true
+org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=true
+org.eclipse.jdt.core.formatter.comment.format_line_comments=true
+org.eclipse.jdt.core.formatter.comment.format_source_code=true
+org.eclipse.jdt.core.formatter.comment.indent_parameter_description=false
+org.eclipse.jdt.core.formatter.comment.indent_root_tags=true
+org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert
+org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=do not insert
+org.eclipse.jdt.core.formatter.comment.line_length=100
+org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries=false
+org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries=true
+org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments=false
+org.eclipse.jdt.core.formatter.compact_else_if=true
+org.eclipse.jdt.core.formatter.continuation_indentation=2
+org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=2
+org.eclipse.jdt.core.formatter.disabling_tag=@formatter\:off
+org.eclipse.jdt.core.formatter.enabling_tag=@formatter\:on
+org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false
+org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true
+org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true
+org.eclipse.jdt.core.formatter.indent_empty_lines=true
+org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true
+org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true
+org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true
+org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=false
+org.eclipse.jdt.core.formatter.indentation.size=4
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_enum_constant=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_label=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_type_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert
+org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert
+org.eclipse.jdt.core.formatter.insert_space_after_lambda_arrow=insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources=insert
+org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert
+org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=insert
+org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert
+org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw=insert
+org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.join_lines_in_comments=true
+org.eclipse.jdt.core.formatter.join_wrapped_lines=true
+org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=false
+org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false
+org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=false
+org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false
+org.eclipse.jdt.core.formatter.lineSplit=100
+org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false
+org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=false
+org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0
+org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=1
+org.eclipse.jdt.core.formatter.parentheses_positions_in_annotation=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_catch_clause=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_enum_constant_declaration=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_for_statment=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_if_while_statement=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_lambda_declaration=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_method_delcaration=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_method_invocation=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_switch_statement=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_try_clause=common_lines
+org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=true
+org.eclipse.jdt.core.formatter.tabulation.char=tab
+org.eclipse.jdt.core.formatter.tabulation.size=4
+org.eclipse.jdt.core.formatter.use_on_off_tags=false
+org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false
+org.eclipse.jdt.core.formatter.wrap_before_assignment_operator=false
+org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true
+org.eclipse.jdt.core.formatter.wrap_before_conditional_operator=false
+org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch=true
+org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true
+org.eclipse.jdt.core.javaFormatter=org.eclipse.jdt.core.defaultJavaFormatter
diff --git a/eclient/org.eclipse.statet.rj.eclient.core/.settings/org.eclipse.jdt.ui.prefs b/eclient/org.eclipse.statet.rj.eclient.core/.settings/org.eclipse.jdt.ui.prefs
new file mode 100644
index 0000000..e62a4f5
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.core/.settings/org.eclipse.jdt.ui.prefs
@@ -0,0 +1,131 @@
+cleanup.add_default_serial_version_id=true
+cleanup.add_generated_serial_version_id=false
+cleanup.add_missing_annotations=true
+cleanup.add_missing_deprecated_annotations=true
+cleanup.add_missing_methods=false
+cleanup.add_missing_nls_tags=false
+cleanup.add_missing_override_annotations=true
+cleanup.add_missing_override_annotations_interface_methods=true
+cleanup.add_serial_version_id=false
+cleanup.always_use_blocks=true
+cleanup.always_use_parentheses_in_expressions=true
+cleanup.always_use_this_for_non_static_field_access=true
+cleanup.always_use_this_for_non_static_method_access=false
+cleanup.convert_functional_interfaces=false
+cleanup.convert_to_enhanced_for_loop=false
+cleanup.correct_indentation=false
+cleanup.format_source_code=false
+cleanup.format_source_code_changes_only=false
+cleanup.insert_inferred_type_arguments=false
+cleanup.make_local_variable_final=true
+cleanup.make_parameters_final=true
+cleanup.make_private_fields_final=true
+cleanup.make_type_abstract_if_missing_method=false
+cleanup.make_variable_declarations_final=true
+cleanup.never_use_blocks=false
+cleanup.never_use_parentheses_in_expressions=false
+cleanup.organize_imports=true
+cleanup.qualify_static_field_accesses_with_declaring_class=false
+cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true
+cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=false
+cleanup.qualify_static_member_accesses_with_declaring_class=true
+cleanup.qualify_static_method_accesses_with_declaring_class=false
+cleanup.remove_private_constructors=true
+cleanup.remove_redundant_type_arguments=true
+cleanup.remove_trailing_whitespaces=false
+cleanup.remove_trailing_whitespaces_all=true
+cleanup.remove_trailing_whitespaces_ignore_empty=false
+cleanup.remove_unnecessary_casts=true
+cleanup.remove_unnecessary_nls_tags=true
+cleanup.remove_unused_imports=true
+cleanup.remove_unused_local_variables=false
+cleanup.remove_unused_private_fields=true
+cleanup.remove_unused_private_members=false
+cleanup.remove_unused_private_methods=true
+cleanup.remove_unused_private_types=true
+cleanup.sort_members=false
+cleanup.sort_members_all=false
+cleanup.use_anonymous_class_creation=false
+cleanup.use_blocks=true
+cleanup.use_blocks_only_for_return_and_throw=false
+cleanup.use_lambda=true
+cleanup.use_parentheses_in_expressions=false
+cleanup.use_this_for_non_static_field_access=true
+cleanup.use_this_for_non_static_field_access_only_if_necessary=false
+cleanup.use_this_for_non_static_method_access=true
+cleanup.use_this_for_non_static_method_access_only_if_necessary=true
+cleanup.use_type_arguments=false
+cleanup_profile=_StatET
+cleanup_settings_version=2
+eclipse.preferences.version=1
+editor_save_participant_org.eclipse.jdt.ui.postsavelistener.cleanup=true
+formatter_profile=_StatET
+formatter_settings_version=12
+org.eclipse.jdt.ui.exception.name=e
+org.eclipse.jdt.ui.gettersetter.use.is=true
+org.eclipse.jdt.ui.ignorelowercasenames=true
+org.eclipse.jdt.ui.importorder=\#;java;javax;com.ibm.icu;org.osgi;org.eclipse;;org.eclipse.statet.jcommons;org.eclipse.statet.ecommons;org.eclipse.statet;
+org.eclipse.jdt.ui.javadoc=true
+org.eclipse.jdt.ui.keywordthis=true
+org.eclipse.jdt.ui.ondemandthreshold=99
+org.eclipse.jdt.ui.overrideannotation=true
+org.eclipse.jdt.ui.staticondemandthreshold=99
+org.eclipse.jdt.ui.text.custom_code_templates=<?xml version\="1.0" encoding\="UTF-8" standalone\="no"?><templates><template autoinsert\="true" context\="gettercomment_context" deleted\="false" description\="Comment for getter method" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.gettercomment" name\="gettercomment">/**\n * @return the ${bare_field_name}\n */</template><template autoinsert\="true" context\="settercomment_context" deleted\="false" description\="Comment for setter method" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.settercomment" name\="settercomment">/**\n * @param ${param} the ${bare_field_name} to set\n */</template><template autoinsert\="true" context\="constructorcomment_context" deleted\="false" description\="Comment for created constructors" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.constructorcomment" name\="constructorcomment">/**\n * ${tags}\n */</template><template autoinsert\="false" context\="filecomment_context" deleted\="false" description\="Comment for created Java files" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.filecomment" name\="filecomment">/*\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\#\n \# Copyright (c) ${year} ${user} and others.\n # \n # This program and the accompanying materials are made available under the\n # terms of the Eclipse Public License 2.0 which is available at\n # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n # which is available at https://www.apache.org/licenses/LICENSE-2.0.\n # \n # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n # \n \# Contributors\:\n \#     ${user} - initial API and implementation\n \#\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=*/</template><template autoinsert\="false" context\="typecomment_context" deleted\="false" description\="Comment for created types" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.typecomment" name\="typecomment">/**\n * \n * ${tags}\n */</template><template autoinsert\="true" context\="fieldcomment_context" deleted\="false" description\="Comment for fields" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.fieldcomment" name\="fieldcomment">/**\n * \n */</template><template autoinsert\="true" context\="methodcomment_context" deleted\="false" description\="Comment for non-overriding methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.methodcomment" name\="methodcomment">/**\n * ${tags}\n */</template><template autoinsert\="false" context\="overridecomment_context" deleted\="false" description\="Comment for overriding methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.overridecomment" name\="overridecomment"/><template autoinsert\="true" context\="delegatecomment_context" deleted\="false" description\="Comment for delegate methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.delegatecomment" name\="delegatecomment">/**\n * ${tags}\n * ${see_to_target}\n */</template><template autoinsert\="false" context\="newtype_context" deleted\="false" description\="Newly created files" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.newtype" name\="newtype">${filecomment}\n\n${package_declaration}\n\n${typecomment}\n${type_declaration}</template><template autoinsert\="true" context\="classbody_context" deleted\="false" description\="Code in new class type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.classbody" name\="classbody">\n</template><template autoinsert\="true" context\="interfacebody_context" deleted\="false" description\="Code in new interface type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.interfacebody" name\="interfacebody">\n</template><template autoinsert\="true" context\="enumbody_context" deleted\="false" description\="Code in new enum type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.enumbody" name\="enumbody">\n</template><template autoinsert\="true" context\="annotationbody_context" deleted\="false" description\="Code in new annotation type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.annotationbody" name\="annotationbody">\n</template><template autoinsert\="true" context\="catchblock_context" deleted\="false" description\="Code in new catch blocks" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.catchblock" name\="catchblock">// ${todo} Auto-generated catch block\n${exception_var}.printStackTrace();</template><template autoinsert\="true" context\="methodbody_context" deleted\="false" description\="Code in created method stubs" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.methodbody" name\="methodbody">// ${todo} Auto-generated method stub\n${body_statement}</template><template autoinsert\="true" context\="constructorbody_context" deleted\="false" description\="Code in created constructor stubs" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.constructorbody" name\="constructorbody">${body_statement}\n// ${todo} Auto-generated constructor stub</template><template autoinsert\="true" context\="getterbody_context" deleted\="false" description\="Code in created getters" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.getterbody" name\="getterbody">return ${field};</template><template autoinsert\="true" context\="setterbody_context" deleted\="false" description\="Code in created setters" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.setterbody" name\="setterbody">${field} \= ${param};</template></templates>
+sp_cleanup.add_default_serial_version_id=true
+sp_cleanup.add_generated_serial_version_id=false
+sp_cleanup.add_missing_annotations=true
+sp_cleanup.add_missing_deprecated_annotations=true
+sp_cleanup.add_missing_methods=false
+sp_cleanup.add_missing_nls_tags=false
+sp_cleanup.add_missing_override_annotations=true
+sp_cleanup.add_missing_override_annotations_interface_methods=true
+sp_cleanup.add_serial_version_id=false
+sp_cleanup.always_use_blocks=true
+sp_cleanup.always_use_parentheses_in_expressions=true
+sp_cleanup.always_use_this_for_non_static_field_access=true
+sp_cleanup.always_use_this_for_non_static_method_access=false
+sp_cleanup.convert_functional_interfaces=false
+sp_cleanup.convert_to_enhanced_for_loop=false
+sp_cleanup.correct_indentation=false
+sp_cleanup.format_source_code=false
+sp_cleanup.format_source_code_changes_only=false
+sp_cleanup.insert_inferred_type_arguments=false
+sp_cleanup.make_local_variable_final=true
+sp_cleanup.make_parameters_final=true
+sp_cleanup.make_private_fields_final=true
+sp_cleanup.make_type_abstract_if_missing_method=false
+sp_cleanup.make_variable_declarations_final=false
+sp_cleanup.never_use_blocks=false
+sp_cleanup.never_use_parentheses_in_expressions=false
+sp_cleanup.on_save_use_additional_actions=true
+sp_cleanup.organize_imports=true
+sp_cleanup.qualify_static_field_accesses_with_declaring_class=false
+sp_cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true
+sp_cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=false
+sp_cleanup.qualify_static_member_accesses_with_declaring_class=true
+sp_cleanup.qualify_static_method_accesses_with_declaring_class=false
+sp_cleanup.remove_private_constructors=true
+sp_cleanup.remove_redundant_type_arguments=true
+sp_cleanup.remove_trailing_whitespaces=false
+sp_cleanup.remove_trailing_whitespaces_all=false
+sp_cleanup.remove_trailing_whitespaces_ignore_empty=true
+sp_cleanup.remove_unnecessary_casts=true
+sp_cleanup.remove_unnecessary_nls_tags=false
+sp_cleanup.remove_unused_imports=false
+sp_cleanup.remove_unused_local_variables=false
+sp_cleanup.remove_unused_private_fields=false
+sp_cleanup.remove_unused_private_members=false
+sp_cleanup.remove_unused_private_methods=false
+sp_cleanup.remove_unused_private_types=true
+sp_cleanup.sort_members=false
+sp_cleanup.sort_members_all=false
+sp_cleanup.use_anonymous_class_creation=false
+sp_cleanup.use_blocks=true
+sp_cleanup.use_blocks_only_for_return_and_throw=false
+sp_cleanup.use_lambda=false
+sp_cleanup.use_parentheses_in_expressions=false
+sp_cleanup.use_this_for_non_static_field_access=true
+sp_cleanup.use_this_for_non_static_field_access_only_if_necessary=false
+sp_cleanup.use_this_for_non_static_method_access=true
+sp_cleanup.use_this_for_non_static_method_access_only_if_necessary=true
+sp_cleanup.use_type_arguments=false
diff --git a/eclient/org.eclipse.statet.rj.eclient.core/META-INF/MANIFEST.MF b/eclient/org.eclipse.statet.rj.eclient.core/META-INF/MANIFEST.MF
new file mode 100644
index 0000000..0a9d294
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.core/META-INF/MANIFEST.MF
@@ -0,0 +1,12 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-SymbolicName: org.eclipse.statet.rj.eclient.core;singleton:=true
+Bundle-Version: 2.1.0.qualifier
+Bundle-Vendor: Eclipse.org
+Bundle-Name: StatET RJ - Eclipse Client - Core
+Bundle-ActivationPolicy: lazy
+Bundle-RequiredExecutionEnvironment: JavaSE-1.8
+Require-Bundle: org.eclipse.statet.ecommons.runtime.core;bundle-version="1.1.0";visibility:=reexport,
+ org.eclipse.statet.rj.data;bundle-version="[2.1.0,2.2.0)";visibility:=reexport,
+ org.eclipse.statet.rj.services.core;bundle-version="[2.1.0,2.2.0)";visibility:=reexport
+Export-Package: org.eclipse.statet.rj.eclient.core;version="1.2.0"
diff --git a/eclient/org.eclipse.statet.rj.eclient.core/about.html b/eclient/org.eclipse.statet.rj.eclient.core/about.html
new file mode 100644
index 0000000..7206cec
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.core/about.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+		"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+<title>About</title>
+</head>
+<body lang="EN-US">
+<h2>About This Content</h2>
+
+<p>December 1, 2017</p>
+<h3>License</h3>
+
+<p>
+	The Eclipse Foundation makes available all content in this plug-in
+	(&quot;Content&quot;). Unless otherwise indicated below, the Content
+	is provided to you under the terms and conditions of the Eclipse
+	Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is
+	available at <a href="https://www.eclipse.org/legal/epl-2.0">https://www.eclipse.org/legal/epl-2.0</a>.
+	For purposes of the EPL, &quot;Program&quot; will mean the Content.
+</p>
+
+<p>
+	If you did not receive this Content directly from the Eclipse
+	Foundation, the Content is being redistributed by another party
+	(&quot;Redistributor&quot;) and different terms and conditions may
+	apply to your use of any object code in the Content. Check the
+	Redistributor's license that was provided with the Content. If no such
+	license exists, contact the Redistributor. Unless otherwise indicated
+	below, the terms and conditions of the EPL still apply to any source
+	code in the Content and such source code may be obtained at <a
+	href="https://www.eclipse.org/">https://www.eclipse.org</a>.
+</p>
+
+</body>
+</html>
diff --git a/eclient/org.eclipse.statet.rj.eclient.core/about.ini b/eclient/org.eclipse.statet.rj.eclient.core/about.ini
new file mode 100644
index 0000000..bfba74e
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.core/about.ini
@@ -0,0 +1,7 @@
+featureImage= rj32.png
+aboutText= \
+StatET RJ - Eclipse Client\n\
+\n\
+Copyright (c) 2003, 2017 Stephan Wahlbrink and others. All rights reserved.\n\
+Visit https://www.eclipse.org/statet\n\
+\n\
diff --git a/eclient/org.eclipse.statet.rj.eclient.core/build.properties b/eclient/org.eclipse.statet.rj.eclient.core/build.properties
new file mode 100644
index 0000000..3240dd3
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.core/build.properties
@@ -0,0 +1,11 @@
+source..= src/
+output..= bin/
+javacDefaultEncoding..= UTF-8
+
+bin.includes= META-INF/,\
+              plugin.xml,\
+              .,\
+              about.html,\
+              about.ini,\
+              rj32.png
+src.includes= .settings/org.eclipse.core.resources.prefs
diff --git a/eclient/org.eclipse.statet.rj.eclient.core/plugin.xml b/eclient/org.eclipse.statet.rj.eclient.core/plugin.xml
new file mode 100644
index 0000000..8d0cd29
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.core/plugin.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<?eclipse version="3.4"?>
+<!--
+ #=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================#
+-->
+
+<plugin>
+   
+</plugin>
diff --git a/eclient/org.eclipse.statet.rj.eclient.core/rj32.png b/eclient/org.eclipse.statet.rj.eclient.core/rj32.png
new file mode 100644
index 0000000..d9450d1
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.core/rj32.png
Binary files differ
diff --git a/eclient/org.eclipse.statet.rj.eclient.core/src/org/eclipse/statet/rj/eclient/core/AbstractRToolCommandHandler.java b/eclient/org.eclipse.statet.rj.eclient.core/src/org/eclipse/statet/rj/eclient/core/AbstractRToolCommandHandler.java
new file mode 100644
index 0000000..ae24e3d
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.core/src/org/eclipse/statet/rj/eclient/core/AbstractRToolCommandHandler.java
@@ -0,0 +1,42 @@
+/*=============================================================================#
+ # Copyright (c) 2012, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.eclient.core;
+
+import java.util.Map;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+
+import org.eclipse.statet.ecommons.ts.core.ToolCommandHandler;
+import org.eclipse.statet.ecommons.ts.core.ToolService;
+
+
+/**
+ * @since 1.2
+ */
+public abstract class AbstractRToolCommandHandler implements ToolCommandHandler {
+	
+	
+	@Override
+	public IStatus execute(final String id, final ToolService service, final Map<String, Object> data,
+			final IProgressMonitor monitor) throws CoreException {
+		return execute(id, (RToolService) service, data, monitor);
+	}
+	
+	protected abstract IStatus execute(String id, RToolService r, Map<String, Object> data,
+			IProgressMonitor monitor) throws CoreException;
+	
+}
diff --git a/eclient/org.eclipse.statet.rj.eclient.core/src/org/eclipse/statet/rj/eclient/core/AbstractRToolRunnable.java b/eclient/org.eclipse.statet.rj.eclient.core/src/org/eclipse/statet/rj/eclient/core/AbstractRToolRunnable.java
new file mode 100644
index 0000000..b208740
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.core/src/org/eclipse/statet/rj/eclient/core/AbstractRToolRunnable.java
@@ -0,0 +1,75 @@
+/*=============================================================================#
+ # Copyright (c) 2010, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.eclient.core;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+
+import org.eclipse.statet.ecommons.ts.core.Tool;
+import org.eclipse.statet.ecommons.ts.core.ToolRunnable;
+import org.eclipse.statet.ecommons.ts.core.ToolService;
+
+
+/**
+ * Abstract runnable for R tool.
+ * 
+ * Sub class should implement at least the method {@link #run(RToolService, IProgressMonitor)},
+ * which is called by the R tool and gives access to the {@link RToolService} API.
+ * 
+ * @since 1.2
+ */
+public abstract class AbstractRToolRunnable implements ToolRunnable {
+	
+	
+	private final String fTypeId;
+	private final String fLabel;
+	
+	
+	public AbstractRToolRunnable(final String typeId, final String label) {
+		this.fTypeId= typeId;
+		this.fLabel= label;
+	}
+	
+	
+	@Override
+	public String getTypeId() {
+		return this.fTypeId;
+	}
+	
+	@Override
+	public String getLabel() {
+		return this.fLabel;
+	}
+	
+	@Override
+	public boolean canRunIn(final Tool tool) {
+		return tool.isProvidingFeatureSet("org.eclipse.statet.rj.services.RService"); //$NON-NLS-1$
+	}
+	
+	@Override
+	public boolean changed(final int event, final Tool tool) {
+		return true;
+	}
+	
+	@Override
+	public void run(final ToolService service,
+			final IProgressMonitor monitor) throws CoreException {
+		run((RToolService) service, monitor);
+	}
+	
+	protected abstract void run(RToolService r,
+			IProgressMonitor monitor) throws CoreException;
+	
+}
diff --git a/eclient/org.eclipse.statet.rj.eclient.core/src/org/eclipse/statet/rj/eclient/core/RToolService.java b/eclient/org.eclipse.statet.rj.eclient.core/src/org/eclipse/statet/rj/eclient/core/RToolService.java
new file mode 100644
index 0000000..90a7455
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.core/src/org/eclipse/statet/rj/eclient/core/RToolService.java
@@ -0,0 +1,27 @@
+/*=============================================================================#
+ # Copyright (c) 2012, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.eclient.core;
+
+import org.eclipse.statet.ecommons.ts.core.ToolService;
+
+import org.eclipse.statet.rj.services.RService;
+
+
+/**
+ * @since 1.2
+ */
+public interface RToolService extends ToolService, RService {
+	
+}
diff --git a/eclient/org.eclipse.statet.rj.eclient.core/src/org/eclipse/statet/rj/eclient/core/ToolFQRObjectRef.java b/eclient/org.eclipse.statet.rj.eclient.core/src/org/eclipse/statet/rj/eclient/core/ToolFQRObjectRef.java
new file mode 100644
index 0000000..5ee87e4
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.core/src/org/eclipse/statet/rj/eclient/core/ToolFQRObjectRef.java
@@ -0,0 +1,106 @@
+/*=============================================================================#
+ # Copyright (c) 2016, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.eclient.core;
+
+import org.eclipse.statet.ecommons.ts.core.Tool;
+
+import org.eclipse.statet.rj.data.RLanguage;
+import org.eclipse.statet.rj.data.RObject;
+import org.eclipse.statet.rj.data.RReference;
+import org.eclipse.statet.rj.services.FQRObjectRef;
+
+
+public class ToolFQRObjectRef implements FQRObjectRef {
+	
+	
+	private static boolean isValidEnvObject(final RObject env) {
+		switch (env.getRObjectType()) {
+		case RObject.TYPE_REFERENCE:
+			return (((RReference) env).getReferencedRObjectType() == RObject.TYPE_ENVIRONMENT);
+		case RObject.TYPE_LANGUAGE:
+			return (((RLanguage) env).getLanguageType() == RLanguage.CALL);
+		default:
+			return false;
+		}
+	}
+	
+	private static boolean isValidNameObject(final RObject env) {
+		switch (env.getRObjectType()) {
+		case RObject.TYPE_LANGUAGE:
+			switch (((RLanguage) env).getLanguageType()) {
+			case RLanguage.NAME:
+			case RLanguage.CALL:
+				return true;
+			default:
+				return false;
+			}
+		default:
+			return false;
+		}
+	}
+	
+	
+	private final Tool tool;
+	
+	private final RObject env;
+	
+	private final RObject name;
+	
+	
+	public ToolFQRObjectRef(final Tool tool, final RObject env, final RObject name) {
+		if (tool == null) {
+			throw new NullPointerException("tool"); //$NON-NLS-1$
+		}
+		if (env == null) {
+			throw new NullPointerException("env"); //$NON-NLS-1$
+		}
+		if (!isValidEnvObject(env)) {
+			throw new IllegalArgumentException("env"); //$NON-NLS-1$
+		}
+		if (name == null) {
+			throw new NullPointerException("name"); //$NON-NLS-1$
+		}
+		if (!isValidNameObject(name)) {
+			throw new IllegalArgumentException("name"); //$NON-NLS-1$
+		}
+		
+		this.tool= tool;
+		this.env= env;
+		this.name= name;
+	}
+	
+	
+	@Override
+	public Tool getRHandle() {
+		return this.tool;
+	}
+	
+	@Override
+	public RObject getEnv() {
+		return this.env;
+	}
+	
+	@Override
+	public RObject getName() {
+		return this.name;
+	}
+	
+	
+	@Override
+	public String toString() {
+		return this.env + "\n" + this.name.toString();
+	}
+	
+}
diff --git a/eclient/org.eclipse.statet.rj.eclient.graphics/.classpath b/eclient/org.eclipse.statet.rj.eclient.graphics/.classpath
new file mode 100644
index 0000000..eca7bdb
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.graphics/.classpath
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
+	<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+	<classpathentry kind="src" path="src"/>
+	<classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/eclient/org.eclipse.statet.rj.eclient.graphics/.gitignore b/eclient/org.eclipse.statet.rj.eclient.graphics/.gitignore
new file mode 100644
index 0000000..5e56e04
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.graphics/.gitignore
@@ -0,0 +1 @@
+/bin
diff --git a/eclient/org.eclipse.statet.rj.eclient.graphics/.project b/eclient/org.eclipse.statet.rj.eclient.graphics/.project
new file mode 100644
index 0000000..9fe0f82
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.graphics/.project
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>org.eclipse.statet.rj.eclient.graphics</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.jdt.core.javabuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.pde.ManifestBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.pde.SchemaBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.pde.PluginNature</nature>
+		<nature>org.eclipse.jdt.core.javanature</nature>
+	</natures>
+</projectDescription>
diff --git a/eclient/org.eclipse.statet.rj.eclient.graphics/.settings/org.eclipse.core.resources.prefs b/eclient/org.eclipse.statet.rj.eclient.graphics/.settings/org.eclipse.core.resources.prefs
new file mode 100644
index 0000000..99f26c0
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.graphics/.settings/org.eclipse.core.resources.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+encoding/<project>=UTF-8
diff --git a/eclient/org.eclipse.statet.rj.eclient.graphics/.settings/org.eclipse.core.runtime.prefs b/eclient/org.eclipse.statet.rj.eclient.graphics/.settings/org.eclipse.core.runtime.prefs
new file mode 100644
index 0000000..5a0ad22
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.graphics/.settings/org.eclipse.core.runtime.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+line.separator=\n
diff --git a/eclient/org.eclipse.statet.rj.eclient.graphics/.settings/org.eclipse.jdt.core.prefs b/eclient/org.eclipse.statet.rj.eclient.graphics/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000..ccb1eaa
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.graphics/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,325 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.codeComplete.argumentPrefixes=
+org.eclipse.jdt.core.codeComplete.argumentSuffixes=
+org.eclipse.jdt.core.codeComplete.fieldPrefixes=
+org.eclipse.jdt.core.codeComplete.fieldSuffixes=
+org.eclipse.jdt.core.codeComplete.localPrefixes=
+org.eclipse.jdt.core.codeComplete.localSuffixes=
+org.eclipse.jdt.core.codeComplete.staticFieldPrefixes=
+org.eclipse.jdt.core.codeComplete.staticFieldSuffixes=
+org.eclipse.jdt.core.codeComplete.staticFinalFieldPrefixes=
+org.eclipse.jdt.core.codeComplete.staticFinalFieldSuffixes=
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=1.8
+org.eclipse.jdt.core.compiler.debug.lineNumber=generate
+org.eclipse.jdt.core.compiler.debug.localVariable=generate
+org.eclipse.jdt.core.compiler.debug.sourceFile=generate
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.source=1.8
+org.eclipse.jdt.core.formatter.align_fields_grouping_blank_lines=2147483647
+org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_assignment=0
+org.eclipse.jdt.core.formatter.alignment_for_binary_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_compact_if=16
+org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=80
+org.eclipse.jdt.core.formatter.alignment_for_enum_constants=0
+org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16
+org.eclipse.jdt.core.formatter.alignment_for_expressions_in_for_loop_header=0
+org.eclipse.jdt.core.formatter.alignment_for_method_declaration=0
+org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16
+org.eclipse.jdt.core.formatter.alignment_for_parameterized_type_references=0
+org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_resources_in_try=85
+org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=16
+org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_type_arguments=0
+org.eclipse.jdt.core.formatter.alignment_for_type_parameters=0
+org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch=16
+org.eclipse.jdt.core.formatter.blank_lines_after_imports=2
+org.eclipse.jdt.core.formatter.blank_lines_after_package=1
+org.eclipse.jdt.core.formatter.blank_lines_before_field=0
+org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=1
+org.eclipse.jdt.core.formatter.blank_lines_before_imports=1
+org.eclipse.jdt.core.formatter.blank_lines_before_member_type=1
+org.eclipse.jdt.core.formatter.blank_lines_before_method=1
+org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=2
+org.eclipse.jdt.core.formatter.blank_lines_before_package=1
+org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=1
+org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=1
+org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_block=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_lambda_body=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=false
+org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=false
+org.eclipse.jdt.core.formatter.comment.format_block_comments=true
+org.eclipse.jdt.core.formatter.comment.format_header=false
+org.eclipse.jdt.core.formatter.comment.format_html=true
+org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=true
+org.eclipse.jdt.core.formatter.comment.format_line_comments=true
+org.eclipse.jdt.core.formatter.comment.format_source_code=true
+org.eclipse.jdt.core.formatter.comment.indent_parameter_description=false
+org.eclipse.jdt.core.formatter.comment.indent_root_tags=true
+org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert
+org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=do not insert
+org.eclipse.jdt.core.formatter.comment.line_length=100
+org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries=false
+org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries=true
+org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments=false
+org.eclipse.jdt.core.formatter.compact_else_if=true
+org.eclipse.jdt.core.formatter.continuation_indentation=2
+org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=2
+org.eclipse.jdt.core.formatter.disabling_tag=@formatter\:off
+org.eclipse.jdt.core.formatter.enabling_tag=@formatter\:on
+org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false
+org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true
+org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true
+org.eclipse.jdt.core.formatter.indent_empty_lines=true
+org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true
+org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true
+org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true
+org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=false
+org.eclipse.jdt.core.formatter.indentation.size=4
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_enum_constant=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_label=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_type_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert
+org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert
+org.eclipse.jdt.core.formatter.insert_space_after_lambda_arrow=insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources=insert
+org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert
+org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=insert
+org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert
+org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw=insert
+org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.join_lines_in_comments=true
+org.eclipse.jdt.core.formatter.join_wrapped_lines=true
+org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=false
+org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false
+org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=false
+org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false
+org.eclipse.jdt.core.formatter.lineSplit=100
+org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false
+org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=false
+org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0
+org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=1
+org.eclipse.jdt.core.formatter.parentheses_positions_in_annotation=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_catch_clause=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_enum_constant_declaration=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_for_statment=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_if_while_statement=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_lambda_declaration=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_method_delcaration=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_method_invocation=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_switch_statement=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_try_clause=common_lines
+org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=true
+org.eclipse.jdt.core.formatter.tabulation.char=tab
+org.eclipse.jdt.core.formatter.tabulation.size=4
+org.eclipse.jdt.core.formatter.use_on_off_tags=false
+org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false
+org.eclipse.jdt.core.formatter.wrap_before_assignment_operator=false
+org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true
+org.eclipse.jdt.core.formatter.wrap_before_conditional_operator=false
+org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch=true
+org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true
+org.eclipse.jdt.core.javaFormatter=org.eclipse.jdt.core.defaultJavaFormatter
diff --git a/eclient/org.eclipse.statet.rj.eclient.graphics/.settings/org.eclipse.jdt.ui.prefs b/eclient/org.eclipse.statet.rj.eclient.graphics/.settings/org.eclipse.jdt.ui.prefs
new file mode 100644
index 0000000..e62a4f5
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.graphics/.settings/org.eclipse.jdt.ui.prefs
@@ -0,0 +1,131 @@
+cleanup.add_default_serial_version_id=true
+cleanup.add_generated_serial_version_id=false
+cleanup.add_missing_annotations=true
+cleanup.add_missing_deprecated_annotations=true
+cleanup.add_missing_methods=false
+cleanup.add_missing_nls_tags=false
+cleanup.add_missing_override_annotations=true
+cleanup.add_missing_override_annotations_interface_methods=true
+cleanup.add_serial_version_id=false
+cleanup.always_use_blocks=true
+cleanup.always_use_parentheses_in_expressions=true
+cleanup.always_use_this_for_non_static_field_access=true
+cleanup.always_use_this_for_non_static_method_access=false
+cleanup.convert_functional_interfaces=false
+cleanup.convert_to_enhanced_for_loop=false
+cleanup.correct_indentation=false
+cleanup.format_source_code=false
+cleanup.format_source_code_changes_only=false
+cleanup.insert_inferred_type_arguments=false
+cleanup.make_local_variable_final=true
+cleanup.make_parameters_final=true
+cleanup.make_private_fields_final=true
+cleanup.make_type_abstract_if_missing_method=false
+cleanup.make_variable_declarations_final=true
+cleanup.never_use_blocks=false
+cleanup.never_use_parentheses_in_expressions=false
+cleanup.organize_imports=true
+cleanup.qualify_static_field_accesses_with_declaring_class=false
+cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true
+cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=false
+cleanup.qualify_static_member_accesses_with_declaring_class=true
+cleanup.qualify_static_method_accesses_with_declaring_class=false
+cleanup.remove_private_constructors=true
+cleanup.remove_redundant_type_arguments=true
+cleanup.remove_trailing_whitespaces=false
+cleanup.remove_trailing_whitespaces_all=true
+cleanup.remove_trailing_whitespaces_ignore_empty=false
+cleanup.remove_unnecessary_casts=true
+cleanup.remove_unnecessary_nls_tags=true
+cleanup.remove_unused_imports=true
+cleanup.remove_unused_local_variables=false
+cleanup.remove_unused_private_fields=true
+cleanup.remove_unused_private_members=false
+cleanup.remove_unused_private_methods=true
+cleanup.remove_unused_private_types=true
+cleanup.sort_members=false
+cleanup.sort_members_all=false
+cleanup.use_anonymous_class_creation=false
+cleanup.use_blocks=true
+cleanup.use_blocks_only_for_return_and_throw=false
+cleanup.use_lambda=true
+cleanup.use_parentheses_in_expressions=false
+cleanup.use_this_for_non_static_field_access=true
+cleanup.use_this_for_non_static_field_access_only_if_necessary=false
+cleanup.use_this_for_non_static_method_access=true
+cleanup.use_this_for_non_static_method_access_only_if_necessary=true
+cleanup.use_type_arguments=false
+cleanup_profile=_StatET
+cleanup_settings_version=2
+eclipse.preferences.version=1
+editor_save_participant_org.eclipse.jdt.ui.postsavelistener.cleanup=true
+formatter_profile=_StatET
+formatter_settings_version=12
+org.eclipse.jdt.ui.exception.name=e
+org.eclipse.jdt.ui.gettersetter.use.is=true
+org.eclipse.jdt.ui.ignorelowercasenames=true
+org.eclipse.jdt.ui.importorder=\#;java;javax;com.ibm.icu;org.osgi;org.eclipse;;org.eclipse.statet.jcommons;org.eclipse.statet.ecommons;org.eclipse.statet;
+org.eclipse.jdt.ui.javadoc=true
+org.eclipse.jdt.ui.keywordthis=true
+org.eclipse.jdt.ui.ondemandthreshold=99
+org.eclipse.jdt.ui.overrideannotation=true
+org.eclipse.jdt.ui.staticondemandthreshold=99
+org.eclipse.jdt.ui.text.custom_code_templates=<?xml version\="1.0" encoding\="UTF-8" standalone\="no"?><templates><template autoinsert\="true" context\="gettercomment_context" deleted\="false" description\="Comment for getter method" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.gettercomment" name\="gettercomment">/**\n * @return the ${bare_field_name}\n */</template><template autoinsert\="true" context\="settercomment_context" deleted\="false" description\="Comment for setter method" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.settercomment" name\="settercomment">/**\n * @param ${param} the ${bare_field_name} to set\n */</template><template autoinsert\="true" context\="constructorcomment_context" deleted\="false" description\="Comment for created constructors" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.constructorcomment" name\="constructorcomment">/**\n * ${tags}\n */</template><template autoinsert\="false" context\="filecomment_context" deleted\="false" description\="Comment for created Java files" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.filecomment" name\="filecomment">/*\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\#\n \# Copyright (c) ${year} ${user} and others.\n # \n # This program and the accompanying materials are made available under the\n # terms of the Eclipse Public License 2.0 which is available at\n # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n # which is available at https://www.apache.org/licenses/LICENSE-2.0.\n # \n # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n # \n \# Contributors\:\n \#     ${user} - initial API and implementation\n \#\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=*/</template><template autoinsert\="false" context\="typecomment_context" deleted\="false" description\="Comment for created types" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.typecomment" name\="typecomment">/**\n * \n * ${tags}\n */</template><template autoinsert\="true" context\="fieldcomment_context" deleted\="false" description\="Comment for fields" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.fieldcomment" name\="fieldcomment">/**\n * \n */</template><template autoinsert\="true" context\="methodcomment_context" deleted\="false" description\="Comment for non-overriding methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.methodcomment" name\="methodcomment">/**\n * ${tags}\n */</template><template autoinsert\="false" context\="overridecomment_context" deleted\="false" description\="Comment for overriding methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.overridecomment" name\="overridecomment"/><template autoinsert\="true" context\="delegatecomment_context" deleted\="false" description\="Comment for delegate methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.delegatecomment" name\="delegatecomment">/**\n * ${tags}\n * ${see_to_target}\n */</template><template autoinsert\="false" context\="newtype_context" deleted\="false" description\="Newly created files" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.newtype" name\="newtype">${filecomment}\n\n${package_declaration}\n\n${typecomment}\n${type_declaration}</template><template autoinsert\="true" context\="classbody_context" deleted\="false" description\="Code in new class type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.classbody" name\="classbody">\n</template><template autoinsert\="true" context\="interfacebody_context" deleted\="false" description\="Code in new interface type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.interfacebody" name\="interfacebody">\n</template><template autoinsert\="true" context\="enumbody_context" deleted\="false" description\="Code in new enum type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.enumbody" name\="enumbody">\n</template><template autoinsert\="true" context\="annotationbody_context" deleted\="false" description\="Code in new annotation type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.annotationbody" name\="annotationbody">\n</template><template autoinsert\="true" context\="catchblock_context" deleted\="false" description\="Code in new catch blocks" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.catchblock" name\="catchblock">// ${todo} Auto-generated catch block\n${exception_var}.printStackTrace();</template><template autoinsert\="true" context\="methodbody_context" deleted\="false" description\="Code in created method stubs" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.methodbody" name\="methodbody">// ${todo} Auto-generated method stub\n${body_statement}</template><template autoinsert\="true" context\="constructorbody_context" deleted\="false" description\="Code in created constructor stubs" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.constructorbody" name\="constructorbody">${body_statement}\n// ${todo} Auto-generated constructor stub</template><template autoinsert\="true" context\="getterbody_context" deleted\="false" description\="Code in created getters" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.getterbody" name\="getterbody">return ${field};</template><template autoinsert\="true" context\="setterbody_context" deleted\="false" description\="Code in created setters" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.setterbody" name\="setterbody">${field} \= ${param};</template></templates>
+sp_cleanup.add_default_serial_version_id=true
+sp_cleanup.add_generated_serial_version_id=false
+sp_cleanup.add_missing_annotations=true
+sp_cleanup.add_missing_deprecated_annotations=true
+sp_cleanup.add_missing_methods=false
+sp_cleanup.add_missing_nls_tags=false
+sp_cleanup.add_missing_override_annotations=true
+sp_cleanup.add_missing_override_annotations_interface_methods=true
+sp_cleanup.add_serial_version_id=false
+sp_cleanup.always_use_blocks=true
+sp_cleanup.always_use_parentheses_in_expressions=true
+sp_cleanup.always_use_this_for_non_static_field_access=true
+sp_cleanup.always_use_this_for_non_static_method_access=false
+sp_cleanup.convert_functional_interfaces=false
+sp_cleanup.convert_to_enhanced_for_loop=false
+sp_cleanup.correct_indentation=false
+sp_cleanup.format_source_code=false
+sp_cleanup.format_source_code_changes_only=false
+sp_cleanup.insert_inferred_type_arguments=false
+sp_cleanup.make_local_variable_final=true
+sp_cleanup.make_parameters_final=true
+sp_cleanup.make_private_fields_final=true
+sp_cleanup.make_type_abstract_if_missing_method=false
+sp_cleanup.make_variable_declarations_final=false
+sp_cleanup.never_use_blocks=false
+sp_cleanup.never_use_parentheses_in_expressions=false
+sp_cleanup.on_save_use_additional_actions=true
+sp_cleanup.organize_imports=true
+sp_cleanup.qualify_static_field_accesses_with_declaring_class=false
+sp_cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true
+sp_cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=false
+sp_cleanup.qualify_static_member_accesses_with_declaring_class=true
+sp_cleanup.qualify_static_method_accesses_with_declaring_class=false
+sp_cleanup.remove_private_constructors=true
+sp_cleanup.remove_redundant_type_arguments=true
+sp_cleanup.remove_trailing_whitespaces=false
+sp_cleanup.remove_trailing_whitespaces_all=false
+sp_cleanup.remove_trailing_whitespaces_ignore_empty=true
+sp_cleanup.remove_unnecessary_casts=true
+sp_cleanup.remove_unnecessary_nls_tags=false
+sp_cleanup.remove_unused_imports=false
+sp_cleanup.remove_unused_local_variables=false
+sp_cleanup.remove_unused_private_fields=false
+sp_cleanup.remove_unused_private_members=false
+sp_cleanup.remove_unused_private_methods=false
+sp_cleanup.remove_unused_private_types=true
+sp_cleanup.sort_members=false
+sp_cleanup.sort_members_all=false
+sp_cleanup.use_anonymous_class_creation=false
+sp_cleanup.use_blocks=true
+sp_cleanup.use_blocks_only_for_return_and_throw=false
+sp_cleanup.use_lambda=false
+sp_cleanup.use_parentheses_in_expressions=false
+sp_cleanup.use_this_for_non_static_field_access=true
+sp_cleanup.use_this_for_non_static_field_access_only_if_necessary=false
+sp_cleanup.use_this_for_non_static_method_access=true
+sp_cleanup.use_this_for_non_static_method_access_only_if_necessary=true
+sp_cleanup.use_type_arguments=false
diff --git a/eclient/org.eclipse.statet.rj.eclient.graphics/META-INF/MANIFEST.MF b/eclient/org.eclipse.statet.rj.eclient.graphics/META-INF/MANIFEST.MF
new file mode 100644
index 0000000..b8a3c0e
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.graphics/META-INF/MANIFEST.MF
@@ -0,0 +1,22 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-SymbolicName: org.eclipse.statet.rj.eclient.graphics;singleton:=true
+Bundle-Version: 2.1.0.qualifier
+Bundle-Vendor: Eclipse.org
+Bundle-Name: StatET RJ - Eclipse Client - R Graphics
+Bundle-ActivationPolicy: lazy
+Bundle-Activator: org.eclipse.statet.internal.rj.eclient.graphics.RGraphicsPlugin
+Bundle-RequiredExecutionEnvironment: JavaSE-1.8
+Require-Bundle: org.eclipse.core.runtime;bundle-version="3.10.0",
+ org.eclipse.statet.rj.services.core;bundle-version="[2.1.0,2.2.0)",
+ org.eclipse.statet.rj.client;bundle-version="[2.1.0,2.2.0)",
+ org.eclipse.statet.rj.eclient.core;bundle-version="[2.1.0,2.2.0)",
+ org.eclipse.ui;bundle-version="3.6.0",
+ org.eclipse.statet.ecommons.uimisc;bundle-version="[1.6.0,1.7.0)"
+Import-Package: org.eclipse.statet.ecommons.collections;version="1.6.0",
+ org.eclipse.statet.ecommons.databinding,
+ org.eclipse.statet.jcommons.collections;version="1.0.0",
+ org.eclipse.statet.jcommons.lang;version="1.0.0"
+Export-Package: org.eclipse.statet.rj.eclient.graphics,
+ org.eclipse.statet.rj.eclient.graphics.comclient,
+ org.eclipse.statet.rj.eclient.graphics.util
diff --git a/eclient/org.eclipse.statet.rj.eclient.graphics/about.html b/eclient/org.eclipse.statet.rj.eclient.graphics/about.html
new file mode 100644
index 0000000..7206cec
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.graphics/about.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+		"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+<title>About</title>
+</head>
+<body lang="EN-US">
+<h2>About This Content</h2>
+
+<p>December 1, 2017</p>
+<h3>License</h3>
+
+<p>
+	The Eclipse Foundation makes available all content in this plug-in
+	(&quot;Content&quot;). Unless otherwise indicated below, the Content
+	is provided to you under the terms and conditions of the Eclipse
+	Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is
+	available at <a href="https://www.eclipse.org/legal/epl-2.0">https://www.eclipse.org/legal/epl-2.0</a>.
+	For purposes of the EPL, &quot;Program&quot; will mean the Content.
+</p>
+
+<p>
+	If you did not receive this Content directly from the Eclipse
+	Foundation, the Content is being redistributed by another party
+	(&quot;Redistributor&quot;) and different terms and conditions may
+	apply to your use of any object code in the Content. Check the
+	Redistributor's license that was provided with the Content. If no such
+	license exists, contact the Redistributor. Unless otherwise indicated
+	below, the terms and conditions of the EPL still apply to any source
+	code in the Content and such source code may be obtained at <a
+	href="https://www.eclipse.org/">https://www.eclipse.org</a>.
+</p>
+
+</body>
+</html>
diff --git a/eclient/org.eclipse.statet.rj.eclient.graphics/build.properties b/eclient/org.eclipse.statet.rj.eclient.graphics/build.properties
new file mode 100644
index 0000000..d7ffd88
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.graphics/build.properties
@@ -0,0 +1,10 @@
+source..= src/
+output..= bin/
+javacDefaultEncoding..= UTF-8
+
+bin.includes= META-INF/,\
+              plugin.xml,\
+              .,\
+              icons/,\
+              about.html
+src.includes= .settings/org.eclipse.core.resources.prefs
diff --git a/eclient/org.eclipse.statet.rj.eclient.graphics/icons/loctool_16/locator-cancel.png b/eclient/org.eclipse.statet.rj.eclient.graphics/icons/loctool_16/locator-cancel.png
new file mode 100644
index 0000000..fd4d1c0
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.graphics/icons/loctool_16/locator-cancel.png
Binary files differ
diff --git a/eclient/org.eclipse.statet.rj.eclient.graphics/icons/loctool_16/locator-done.png b/eclient/org.eclipse.statet.rj.eclient.graphics/icons/loctool_16/locator-done.png
new file mode 100644
index 0000000..185b13c
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.graphics/icons/loctool_16/locator-done.png
Binary files differ
diff --git a/eclient/org.eclipse.statet.rj.eclient.graphics/icons/loctool_16/resize-fit-r.png b/eclient/org.eclipse.statet.rj.eclient.graphics/icons/loctool_16/resize-fit-r.png
new file mode 100644
index 0000000..ed4095f
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.graphics/icons/loctool_16/resize-fit-r.png
Binary files differ
diff --git a/eclient/org.eclipse.statet.rj.eclient.graphics/plugin.xml b/eclient/org.eclipse.statet.rj.eclient.graphics/plugin.xml
new file mode 100644
index 0000000..43a93dc
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.graphics/plugin.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<?eclipse version="3.4"?>
+<!--
+ #=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================#
+-->
+
+<plugin>
+   
+   <extension
+         point="org.eclipse.equinox.preferences.preferences">
+      <initializer
+            class="org.eclipse.statet.internal.rj.eclient.graphics.PreferenceInitializer">
+      </initializer>
+   </extension>
+   
+</plugin>
diff --git a/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/internal/rj/eclient/graphics/CircleElement.java b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/internal/rj/eclient/graphics/CircleElement.java
new file mode 100644
index 0000000..c4d4ef8
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/internal/rj/eclient/graphics/CircleElement.java
@@ -0,0 +1,29 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.internal.rj.eclient.graphics;
+
+import org.eclipse.statet.rj.eclient.graphics.ERGraphicInstruction;
+import org.eclipse.statet.rj.graphic.core.RCircle;
+
+
+public class CircleElement extends RCircle implements ERGraphicInstruction {
+	
+	
+	public CircleElement(final double x, final double y, final double r) {
+		super(x, y, r);
+	}
+	
+	
+}
diff --git a/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/internal/rj/eclient/graphics/ClipSetting.java b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/internal/rj/eclient/graphics/ClipSetting.java
new file mode 100644
index 0000000..09c3dbb
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/internal/rj/eclient/graphics/ClipSetting.java
@@ -0,0 +1,29 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.internal.rj.eclient.graphics;
+
+import org.eclipse.statet.rj.eclient.graphics.ERGraphicInstruction;
+import org.eclipse.statet.rj.graphic.core.RClipSetting;
+
+
+public class ClipSetting extends RClipSetting implements ERGraphicInstruction {
+	
+	
+	public ClipSetting(final double x0, final double y0, final double x1, final double y1) {
+		super(x0, y0, x1, y1);
+	}
+	
+	
+}
diff --git a/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/internal/rj/eclient/graphics/ColorManager.java b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/internal/rj/eclient/graphics/ColorManager.java
new file mode 100644
index 0000000..2da8f4d
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/internal/rj/eclient/graphics/ColorManager.java
@@ -0,0 +1,55 @@
+/*=============================================================================#
+ # Copyright (c) 2011, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.internal.rj.eclient.graphics;
+
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.widgets.Display;
+
+import org.eclipse.statet.ecommons.collections.IntHashMap;
+import org.eclipse.statet.ecommons.collections.IntMap.IntEntry;
+
+
+public class ColorManager {
+	
+	
+	private final Display display;
+	
+	private final IntHashMap<Color> colors= new IntHashMap<>(0x7f);
+	
+	
+	public ColorManager(final Display display) {
+		this.display= display;
+	}
+	
+	
+	public synchronized Color getColor(final int rgb) {
+		Color color= this.colors.get(rgb);
+		if (color == null) {
+			color= new Color(this.display,
+					(rgb & 0xff), ((rgb >>> 8) & 0xff), ((rgb >>> 16) & 0xff) );
+			this.colors.put(rgb, color);
+		}
+		return color;
+	}
+	
+	
+	public void dispose() {
+		for (final IntEntry<Color> entry : this.colors.entryIntSet()) {
+			entry.getValue().dispose();
+		}
+		this.colors.clear();
+	}
+	
+}
diff --git a/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/internal/rj/eclient/graphics/ColorSetting.java b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/internal/rj/eclient/graphics/ColorSetting.java
new file mode 100644
index 0000000..3ff0e97
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/internal/rj/eclient/graphics/ColorSetting.java
@@ -0,0 +1,35 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.internal.rj.eclient.graphics;
+
+import org.eclipse.swt.graphics.Color;
+
+import org.eclipse.statet.rj.eclient.graphics.ERGraphicInstruction;
+import org.eclipse.statet.rj.graphic.core.RColorSetting;
+
+
+public class ColorSetting extends RColorSetting implements ERGraphicInstruction {
+	
+	
+	public final Color swtColor;
+	
+	
+	public ColorSetting(final int color, final Color swtColor) {
+		super(color);
+		this.swtColor= swtColor;
+	}
+	
+	
+}
diff --git a/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/internal/rj/eclient/graphics/EclipseRGraphic.java b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/internal/rj/eclient/graphics/EclipseRGraphic.java
new file mode 100644
index 0000000..6b47463
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/internal/rj/eclient/graphics/EclipseRGraphic.java
@@ -0,0 +1,1312 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.internal.rj.eclient.graphics;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.Callable;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.preferences.IPreferencesService;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.SWTException;
+import org.eclipse.swt.graphics.GC;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.ImageData;
+import org.eclipse.swt.graphics.PaletteData;
+import org.eclipse.swt.graphics.Path;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.ui.statushandlers.StatusManager;
+
+import org.eclipse.statet.jcommons.collections.CopyOnWriteIdentityListSet;
+import org.eclipse.statet.jcommons.collections.ImCollections;
+
+import org.eclipse.statet.ecommons.runtime.core.StatusChangeListener;
+import org.eclipse.statet.ecommons.ts.core.Tool;
+import org.eclipse.statet.ecommons.ui.util.UIAccess;
+
+import org.eclipse.statet.internal.rj.eclient.graphics.FontManager.FontFamily;
+import org.eclipse.statet.rj.eclient.graphics.DefaultGCRenderer;
+import org.eclipse.statet.rj.eclient.graphics.ERGraphic;
+import org.eclipse.statet.rj.eclient.graphics.ERGraphicInstruction;
+import org.eclipse.statet.rj.eclient.graphics.LocatorCallback;
+import org.eclipse.statet.rj.eclient.graphics.RGraphics;
+import org.eclipse.statet.rj.eclient.graphics.comclient.ToolRClientGraphicActions;
+import org.eclipse.statet.rj.eclient.graphics.util.CopyToDevRunnable;
+import org.eclipse.statet.rj.graphic.core.RGraphicInitialization;
+import org.eclipse.statet.rj.graphic.core.RGraphicInstruction;
+import org.eclipse.statet.rj.graphic.core.util.CachedMapping;
+import org.eclipse.statet.rj.graphic.core.util.CharMapping;
+import org.eclipse.statet.rj.graphic.core.util.Unicode2AdbSymbolMapping;
+import org.eclipse.statet.rj.server.client.RClientGraphic;
+import org.eclipse.statet.rj.server.client.RClientGraphicFactory;
+import org.eclipse.statet.rj.services.RService;
+import org.eclipse.statet.rj.services.RServiceControlExtension;
+
+
+/**
+ * R graphic implementation of this plug-in. Implements R side API ({@link RClientGraphic})
+ * as well as client side API ({@link ERGraphic}, {@link org.eclipse.statet.rj.graphic.core.RGraphic}).
+ */
+public class EclipseRGraphic implements RClientGraphic, ERGraphic {
+	
+	
+	private static final CharMapping ADBSYMBOL_MAPPING= new CachedMapping(
+			new Unicode2AdbSymbolMapping() );
+	
+	private static final long MILLI_NANOS= 1000000L;
+	
+	private static final int DIRECT_RED_MASK=   0x0000FF00;
+	private static final int DIRECT_GREEN_MASK= 0x00FF0000;
+	private static final int DIRECT_BLUE_MASK=  0xFF000000;
+	private static final PaletteData DIRECT_PALETTE= new PaletteData(
+			DIRECT_RED_MASK, DIRECT_GREEN_MASK, DIRECT_BLUE_MASK );
+	
+	private static final LocatorCallback R_LOCATOR_CALLBACK= new LocatorCallback() {
+		
+		@Override
+		public String getMessage() {
+			return "→ Locate a point by mouse click (request from R)";
+		}
+		
+		@Override
+		public int located(final double x, final double y) {
+			return NEXT;
+		}
+		
+		@Override
+		public void stopped(final String type) {
+		}
+		
+	};
+	
+	
+	private static void disposeElements(final ERGraphicInstruction[] instructions,
+			final int beginIdx, final int endIdx) {
+		try {
+			for (int i= beginIdx; i < endIdx; i++) {
+				switch (instructions[i].getInstructionType()) {
+				case RGraphicInstruction.DRAW_RASTER: {
+					final Image image= ((RasterElement) instructions[i]).swtImage;
+					if (image != null && !image.isDisposed()) {
+						image.dispose();
+					}
+					continue; }
+				case RGraphicInstruction.DRAW_PATH: {
+					final Path path= ((PathElement) instructions[i]).swtPath;
+					if (path != null && !path.isDisposed()) {
+						path.dispose();
+					}
+					continue; }
+				default:
+					continue;
+				}
+			}
+		}
+		catch (final SWTException e) {
+			if (e.code != SWT.ERROR_DEVICE_DISPOSED) {
+				StatusManager.getManager().handle(new Status(IStatus.ERROR, RGraphics.BUNDLE_ID,
+						"An error occurred when disposing SWT resources.", e ));
+			}
+		}
+	}
+	
+	private static class DisposeRunnable implements Runnable {
+		
+		private final ERGraphicInstruction[] instructions;
+		private final int size;
+		
+		private boolean delay;
+		
+		public DisposeRunnable(final ERGraphicInstruction[] instructions, final int size) {
+			this.instructions= instructions;
+			this.size= size;
+		}
+		
+		@Override
+		public void run() {
+			if (this.delay) {
+				this.delay= false;
+				Display.getCurrent().timerExec(5000, this);
+			}
+			
+			disposeElements(this.instructions, 0, this.size);
+		}
+		
+	}
+	
+	
+	private final int devId;
+	
+	private int canvasColor;
+	
+	private int drawingStopDelay= 33; // ms after stop
+	private int drawingForceDelay= 333; // ms after last update
+	
+	private final EclipseRGraphicFactory manager;
+	private boolean isRClosed;
+	private boolean isLocalClosed;
+	
+	private final Object stateLock= new Object();
+	private boolean isActive;
+	private boolean isActiveNotified;
+	private int mode= 1;
+	private int modeNotified;
+	private long drawingStoppedStamp;
+	private long instructionsNotifiedStamp;
+	private boolean stateNotificationDirectScheduled;
+	private boolean stateNotificationDelayedScheduled;
+	private final Runnable stateNotificationRunnable= new Runnable() {
+		@Override
+		public void run() {
+			int type= 0;
+			Runnable runnable= null;
+			try {
+				while (true) {
+					boolean reset= false;
+					List<ERGraphicInstruction> update= null;
+					synchronized (EclipseRGraphic.this.stateLock) {
+						if (type == 0
+								&& !EclipseRGraphic.this.stateNotificationDirectScheduled
+								&& EclipseRGraphic.this.stateNotificationDelayedScheduled) {
+							EclipseRGraphic.this.stateNotificationDirectScheduled= true;
+							EclipseRGraphic.this.stateNotificationDelayedScheduled= false;
+						}
+						if (EclipseRGraphic.this.isActive != EclipseRGraphic.this.isActiveNotified) {
+							EclipseRGraphic.this.isActiveNotified= EclipseRGraphic.this.isActive;
+							type= (EclipseRGraphic.this.isActive) ? 1 : 2;
+						}
+						else if ((EclipseRGraphic.this.mode == 1 || EclipseRGraphic.this.instructionsUpdateSize > 0)
+								&& EclipseRGraphic.this.modeNotified != 1 ) {
+							// start
+							EclipseRGraphic.this.modeNotified= 1;
+							type= 3;
+						}
+						else if (EclipseRGraphic.this.instructionsUpdateSize > 0) {
+							// update
+							final long stamp= System.nanoTime();
+							int t= EclipseRGraphic.this.drawingForceDelay - (int) ((stamp - EclipseRGraphic.this.instructionsNotifiedStamp) / MILLI_NANOS);
+							if (t > 10 && EclipseRGraphic.this.mode != 1) {
+								t= Math.min(t, EclipseRGraphic.this.drawingStopDelay - (int) ((stamp - EclipseRGraphic.this.drawingStoppedStamp) / MILLI_NANOS));
+							}
+							if (t <= 10) {
+								reset= (EclipseRGraphic.this.instructionsUpdateStart == 0);
+								
+								synchronized (EclipseRGraphic.this.instructionsLock) {
+									if (reset && EclipseRGraphic.this.instructionsSize > 0) {
+										runnable= new DisposeRunnable(EclipseRGraphic.this.instructions, EclipseRGraphic.this.instructionsSize);
+									}
+									EclipseRGraphic.this.instructions= EclipseRGraphic.this.instructionsUpdate;
+									EclipseRGraphic.this.instructionsSize= EclipseRGraphic.this.instructionsUpdateStart + EclipseRGraphic.this.instructionsUpdateSize;
+								}
+								update= ImCollections.newList(EclipseRGraphic.this.instructionsUpdate)
+										.subList(EclipseRGraphic.this.instructionsUpdateStart, EclipseRGraphic.this.instructionsUpdateStart + EclipseRGraphic.this.instructionsUpdateSize);
+//								System.out.println("InstrUpdate: \treset= " + reset + " \tcount= " + update.size() + " \ttdiff= " + ((stamp - this.instructionsNotifiedStamp) / MILLI_NANOS));
+								EclipseRGraphic.this.instructionsUpdateStart= EclipseRGraphic.this.instructionsSize;
+								EclipseRGraphic.this.instructionsUpdateSize= 0;
+								EclipseRGraphic.this.instructionsNotifiedStamp= stamp;
+								type= 5;
+							}
+							else {
+								if (!EclipseRGraphic.this.stateNotificationDelayedScheduled) {
+									EclipseRGraphic.this.stateNotificationDelayedScheduled= true;
+									EclipseRGraphic.this.display.timerExec(10 + Math.min(t, EclipseRGraphic.this.drawingStopDelay), this);
+								}
+								EclipseRGraphic.this.stateNotificationDirectScheduled= false;
+								type= 0;
+								return;
+							}
+						}
+						else if (EclipseRGraphic.this.mode != 1 && EclipseRGraphic.this.modeNotified == 1 ) {
+							// stop
+							final long stamp= System.nanoTime();
+							final int t= EclipseRGraphic.this.drawingStopDelay - (int) ((stamp - EclipseRGraphic.this.drawingStoppedStamp) / MILLI_NANOS);
+							if (t <= 10) {
+								EclipseRGraphic.this.modeNotified= 0;
+								type= 4;
+							}
+							else {
+								if (!EclipseRGraphic.this.stateNotificationDelayedScheduled) {
+									EclipseRGraphic.this.stateNotificationDelayedScheduled= true;
+									EclipseRGraphic.this.display.timerExec(10 + t, this);
+								}
+								EclipseRGraphic.this.stateNotificationDirectScheduled= false;
+								type= 0;
+								return;
+							}
+						}
+						else {
+							// done
+							EclipseRGraphic.this.stateNotificationDirectScheduled= false;
+							type= 0;
+							return;
+						}
+					}
+					
+					
+					switch (type) {
+					case 1:
+						for (final Listener listener : EclipseRGraphic.this.graphicListeners.toList()) {
+							listener.activated();
+						}
+						break;
+					case 2:
+						for (final Listener listener : EclipseRGraphic.this.graphicListeners.toList()) {
+							listener.deactivated();
+						}
+						break;
+					case 3:
+						for (final Listener listener : EclipseRGraphic.this.graphicListeners.toList()) {
+							listener.drawingStarted();
+						}
+						break;
+					case 4:
+						for (final Listener listener : EclipseRGraphic.this.graphicListeners.toList()) {
+							listener.drawingStopped();
+						}
+						break;
+					case 5:
+						for (final Listener listener : EclipseRGraphic.this.graphicListeners.toList()) {
+							if (listener instanceof ListenerInstructionsExtension) {
+								((ListenerInstructionsExtension) listener).instructionsChanged(reset, update);
+							}
+						}
+//						System.out.println("InstrNotif: ns= " + (System.nanoTime() - this.instructionsNotifiedStamp));
+						break;
+					}
+				}
+			}
+			finally {
+				if (type != 0) {
+					synchronized (EclipseRGraphic.this.stateLock) {
+						EclipseRGraphic.this.stateNotificationDirectScheduled= false;
+					}
+				}
+				if (runnable != null) {
+					execInDisplay(runnable);
+				}
+			}
+		}
+	};
+	
+	
+	private final int options;
+	private final ToolRClientGraphicActions actions;
+	private volatile double[] nextSize;
+	private double[] size;
+	
+	private FontFamily currentFontFamily;
+	private int currentFontSize;
+	private int currentFontStyle;
+	private int currentFontRFace;
+	private CharMapping currentFontMapping;
+	
+	private String lastStringEnc;
+	private double[] lastStringWidth;
+	
+	private final Display display;
+	private boolean isDisposed;
+	private final FontManager swtFontManager;
+	private final ColorManager swtColorManager;
+	
+	private String serifFontName;
+	private String sansFontName;
+	private String monoFontName;
+	private String symbolFontName;
+	private CharMapping symbolFontMapping;
+	
+	/** List of newly added instructions */
+	private ERGraphicInstruction[] instructionsNew= new ERGraphicInstruction[1]; // initial init
+	/** Count of newly added instructions in {@link #instructionsNew} */
+	private int instructionsNewSize;
+	/** Current list of instructions, notified + not yet notified */
+	private ERGraphicInstruction[] instructionsUpdate;
+	/** Index of first not yet notified instruction in {@link #instructionsUpdate} */
+	private int instructionsUpdateStart;
+	/** Count of not yet notified instructions in {@link #instructionsUpdate} */
+	private int instructionsUpdateSize;
+	/** Lock for {@link #instructions} and {@link #instructionsSize} */
+	private final Object instructionsLock= new Object();
+	/** List of notified instructions */
+	private ERGraphicInstruction[] instructions;
+	/** Count of notified instructions in {@link #instructions} */
+	private int instructionsSize;
+	
+	private final Object userExchangeLock= new Object();
+	private String userExchangeRType;
+	private RServiceControlExtension userExchangeRCallback;
+	
+	private volatile LocatorCallback locatorCallback; // != null => started
+	private LocatorCallback locatorNotified;
+	private IStatus locatorMessage;
+	private Collection<String> locatorStopTypes= Collections.emptySet();
+	private double[] locatorLocationValue; // only used for R
+	private final Object locatorAnswerLock= new Object(); // pipe for answers
+	
+	private final CopyOnWriteIdentityListSet<ERGraphic.Listener> graphicListeners= new CopyOnWriteIdentityListSet<>();
+	
+	private IStatus message= Status.OK_STATUS;
+	private final CopyOnWriteIdentityListSet<StatusChangeListener> messageListeners= new CopyOnWriteIdentityListSet<>();
+	
+	private boolean locatorNotificationDirectScheduled;
+	private boolean locatorNotificationDeferredScheduled;
+	private long locatorDeferredStamp;
+	private final Runnable locatorNotificationRunnable= new Runnable() {
+		@Override
+		public void run() {
+			int type= 0;
+			try {
+				while (true) {
+					synchronized (EclipseRGraphic.this.userExchangeLock) {
+						if (type == 0
+								&& !EclipseRGraphic.this.locatorNotificationDirectScheduled
+								&& EclipseRGraphic.this.locatorNotificationDeferredScheduled) {
+							EclipseRGraphic.this.locatorNotificationDirectScheduled= true;
+							EclipseRGraphic.this.locatorNotificationDeferredScheduled= false;
+						}
+						if (EclipseRGraphic.this.locatorCallback != null && EclipseRGraphic.this.locatorNotified == null
+								&& EclipseRGraphic.this.locatorDeferredStamp == Long.MIN_VALUE) {
+							EclipseRGraphic.this.locatorNotified= EclipseRGraphic.this.locatorCallback;
+							type= 1;
+						}
+						else if (EclipseRGraphic.this.locatorNotified != null
+								&& (EclipseRGraphic.this.locatorCallback != EclipseRGraphic.this.locatorNotified || EclipseRGraphic.this.locatorCallback == null) ){
+							EclipseRGraphic.this.locatorNotified= null;
+							type= 2;
+						}
+						else if (EclipseRGraphic.this.locatorDeferredStamp != Long.MIN_VALUE
+								&& EclipseRGraphic.this.locatorCallback != null) {
+							final int t= (int) ((EclipseRGraphic.this.locatorDeferredStamp - System.nanoTime()) / 1000000);
+							if (t <= 10) {
+								internalStopLocator(false);
+								type= 3;
+								continue;
+							}
+							else {
+								if (!EclipseRGraphic.this.locatorNotificationDeferredScheduled) {
+									EclipseRGraphic.this.locatorNotificationDeferredScheduled= true;
+									EclipseRGraphic.this.display.timerExec(t + 10, this);
+								}
+								EclipseRGraphic.this.locatorNotificationDirectScheduled= false;
+								type= 0;
+								return;
+							}
+						}
+						else {
+							EclipseRGraphic.this.locatorNotificationDirectScheduled= false;
+							type= 0;
+							return;
+						}
+					}
+					
+					switch (type) {
+					case 1:
+						for (final Listener listener : EclipseRGraphic.this.graphicListeners.toList()) {
+							if (listener instanceof ListenerLocatorExtension) {
+								((ListenerLocatorExtension) listener).locatorStarted();
+							}
+						}
+						break;
+					case 2:
+						for (final Listener listener : EclipseRGraphic.this.graphicListeners.toList()) {
+							if (listener instanceof ListenerLocatorExtension) {	
+								((ListenerLocatorExtension) listener).locatorStopped();
+							}
+						}
+						break;
+					}
+					updateMessage();
+				}
+			}
+			finally {
+				if (type != 0) {
+					synchronized (EclipseRGraphic.this.userExchangeLock) {
+						EclipseRGraphic.this.locatorNotificationDirectScheduled= false;
+					}
+				}
+			}
+		}
+	};
+	
+	
+	public EclipseRGraphic(final int devId, final double w, final double h, final InitConfig config,
+			final boolean active, final ToolRClientGraphicActions actions, final int options,
+			final EclipseRGraphicFactory manager) {
+		this.devId= devId;
+		this.isActive= active;
+		this.actions= actions;
+		this.manager= manager;
+		this.options= options;
+		
+		this.display= UIAccess.getDisplay();
+		this.swtFontManager= manager.getFontManager(this.display);
+//		this.swtFontManager= new FontManager(this.display); // -> dispose!
+		this.swtColorManager= manager.getColorManager(this.display);
+		
+		this.size= this.nextSize= new double[] { w, h };
+		initPanel(w, h, config);
+	}
+	
+	
+	@Override
+	public String getLabel() {
+		final StringBuilder sb= new StringBuilder();
+		sb.append("Device ");
+		sb.append(this.devId + 1);
+		if (this.actions != null) {
+			final String rLabel= this.actions.getRLabel();
+			if (rLabel != null && rLabel.length() > 0) {
+				sb.append(" │ ");
+				sb.append(rLabel);
+			}
+		}
+		final boolean locator= isLocatorStarted();
+		if (this.isActive || locator) {
+			sb.append(" \t<"); //$NON-NLS-1$
+			if (this.isActive) {
+				sb.append("active+"); //$NON-NLS-1$
+			}
+			if (locator) {
+				sb.append("locator+"); //$NON-NLS-1$
+			}
+			sb.replace(sb.length()-1, sb.length(), ">"); //$NON-NLS-1$
+		}
+		return sb.toString();
+	}
+	
+	private void add(final ERGraphicInstruction instr) {
+		// adding is always in R thread
+		if (this.instructionsNew == null) {
+			this.instructionsNew= new ERGraphicInstruction[512];
+		}
+		else if (this.instructionsNewSize >= this.instructionsNew.length) {
+			final ERGraphicInstruction[] newArray= new ERGraphicInstruction[this.instructionsNewSize + 512];
+//			System.out.println("NewArray " + this.instructionsNewSize + " -> " + newArray.length);
+			System.arraycopy(this.instructionsNew, 0, newArray, 0, this.instructionsNewSize);
+			this.instructionsNew= newArray;
+		}
+		this.instructionsNew[this.instructionsNewSize]= instr;
+		this.instructionsNewSize++;
+	}
+	
+	protected void initPanel(final double w, final double h, final InitConfig config) {
+		this.drawingStopDelay= 33;
+		this.drawingForceDelay= 333;
+		
+		this.currentFontFamily= null;
+		this.currentFontMapping= null;
+		
+		final IPreferencesService preferences= Platform.getPreferencesService();
+		this.serifFontName= preferences.getString(RGraphics.FONTS_PREF_QUALIFIER, RGraphics.PREF_FONTS_SERIF_FONTNAME_KEY, "", null);
+		this.sansFontName= preferences.getString(RGraphics.FONTS_PREF_QUALIFIER, RGraphics.PREF_FONTS_SANS_FONTNAME_KEY, "", null);
+		this.monoFontName= preferences.getString(RGraphics.FONTS_PREF_QUALIFIER, RGraphics.PREF_FONTS_MONO_FONTNAME_KEY, "", null);
+		if (preferences.getBoolean(RGraphics.FONTS_PREF_QUALIFIER, RGraphics.PREF_FONTS_SYMBOL_USE_KEY, true, null)) {
+			this.symbolFontName= preferences.getString(RGraphics.FONTS_PREF_QUALIFIER, RGraphics.PREF_FONTS_SYMBOL_FONTNAME_KEY, "Symbol", null); //$NON-NLS-1$
+			final String encoding= preferences.getString(RGraphics.FONTS_PREF_QUALIFIER, RGraphics.PREF_FONTS_SYMBOL_ENCODING_KEY, "AdobeSymbol", null); //$NON-NLS-1$
+			if ("AdobeSymbol".equals(encoding)) { //$NON-NLS-1$
+				this.symbolFontMapping= ADBSYMBOL_MAPPING;
+			}
+			else {
+				this.symbolFontMapping= null;
+			}
+		}
+		else {
+			this.symbolFontName= null;
+			this.symbolFontMapping= null;
+		}
+		this.canvasColor= (config.canvasColor & 0xffffff);
+		
+		add(new GraphicInitialization(w, h, this.canvasColor, this.swtColorManager.getColor(this.canvasColor)));
+	}
+	
+	@Override
+	public void reset(final double w, final double h, final InitConfig config) {
+		synchronized (this.stateLock) {
+			internalReset();
+		}
+		
+		initPanel(w, h, config);
+	}
+	
+	private void internalReset() {
+		if (this.instructionsNew != null) {
+			if (this.instructionsNewSize > 0) {
+				disposeElements(this.instructionsNew, 0, this.instructionsNewSize);
+			}
+			this.instructionsNew= null;
+			this.instructionsNewSize= 0;
+		}
+		if (this.instructionsUpdate != null) {
+			if (this.instructionsUpdateSize > 0) {
+				disposeElements(this.instructionsUpdate, this.instructionsUpdateStart, this.instructionsUpdateStart+this.instructionsUpdateSize);
+			}
+			this.instructionsUpdate= null;
+			this.instructionsUpdateStart= 0;
+			this.instructionsUpdateSize= 0;
+		}
+		this.drawingStoppedStamp= System.nanoTime();
+		this.instructionsNotifiedStamp= this.drawingStoppedStamp - 1000 * MILLI_NANOS;
+	}
+	
+	private void execInDisplay(final Runnable runnable) {
+		try {
+			this.display.asyncExec(runnable);
+		}
+		catch (final SWTException e) {
+			if (e.code != SWT.ERROR_DEVICE_DISPOSED) {
+				throw e;
+			}
+		}
+	}
+	
+	@Override
+	public int getDevId() {
+		return this.devId;
+	}
+	
+	@Override
+	public void setActive(final boolean active) {
+		if (this.isActive == active) {
+			return;
+		}
+		synchronized (this.stateLock) {
+			this.isActive= active;
+			if (this.isDisposed) {
+				return;
+			}
+			if (!this.stateNotificationDirectScheduled) {
+				this.stateNotificationDirectScheduled= true;
+				execInDisplay(this.stateNotificationRunnable);
+			}
+		}
+	}
+	
+	@Override
+	public boolean isActive() {
+		return this.isActive;
+	}
+	
+	@Override
+	public void setMode(final int mode) {
+		synchronized (this.stateLock) {
+			if (this.mode == mode) {
+				return;
+			}
+			if (mode != 1) {
+				this.drawingStoppedStamp= System.nanoTime();
+				flushNewInstructions();
+			}
+			this.mode= mode;
+			if (this.isDisposed) {
+				return;
+			}
+			if (mode == 1 && this.modeNotified != 1 // need start
+					&& !this.stateNotificationDirectScheduled ) {
+				this.stateNotificationDirectScheduled= true;
+				execInDisplay(this.stateNotificationRunnable);
+			}
+			else if (mode != 1 // stop
+					&& !(this.stateNotificationDirectScheduled || this.stateNotificationDelayedScheduled) ) {
+				this.stateNotificationDirectScheduled= true;
+				execInDisplay(this.stateNotificationRunnable);
+			}
+		}
+	}
+	
+	private void flushNewInstructions() {
+		if (this.instructionsNewSize > 0) {
+			if (this.instructionsUpdate == null) {
+				this.instructionsUpdate= this.instructionsNew;
+				this.instructionsUpdateStart= 0;
+				this.instructionsUpdateSize= this.instructionsNewSize;
+				this.instructionsNew= null;
+				this.instructionsNewSize= 0;
+			}
+			else {
+				final int newSize= this.instructionsUpdateStart + this.instructionsUpdateSize + this.instructionsNewSize;
+				if (newSize > this.instructionsUpdate.length) {
+					final ERGraphicInstruction[] newArray= new ERGraphicInstruction[newSize + 512];
+					System.arraycopy(this.instructionsUpdate, 0, newArray, 0, this.instructionsUpdateStart + this.instructionsUpdateSize);
+					this.instructionsUpdate= newArray;
+				}
+				System.arraycopy(this.instructionsNew, 0, this.instructionsUpdate, this.instructionsUpdateStart + this.instructionsUpdateSize, this.instructionsNewSize);
+				this.instructionsUpdateSize+= this.instructionsNewSize;
+				this.instructionsNewSize= 0;
+			}
+		}
+	}
+	
+	private List<ERGraphicInstruction> getCurrentInstructions() {
+		synchronized (this.stateLock) {
+			flushNewInstructions();
+			return ImCollections.newList(this.instructionsUpdate).subList(0,
+					this.instructionsSize + this.instructionsUpdateSize );
+		}
+	}
+	
+	@Override
+	public double[] computeSize() {
+		return this.size;
+	}
+	
+	
+	protected void printFont() {
+		System.out.println(this.currentFontFamily.name + " " + this.currentFontStyle + " " + this.currentFontSize);
+	}
+	
+	@Override
+	public double[] computeFontMetric(final int ch) {
+//		System.out.println("==\nTextMetrics: \"" + ((char) ch) + "\" (" + ch + ")"); printFont();
+		return this.currentFontFamily.getCharMetrics(this.currentFontStyle, this.currentFontSize,
+				(this.currentFontMapping != null) ? this.currentFontMapping.encode(ch) : ch );
+	}
+	
+	@Override
+	public double[] computeStringWidth(final String txt) {
+//		System.out.println("==\nTextWidth: \"" + txt + "\""); printFont();
+		return computeStringWidthEnc((this.currentFontMapping != null) ? this.currentFontMapping.encode(txt) : txt);
+	}
+	
+	protected final double[] computeStringWidthEnc(final String text) {
+		if (text.equals(this.lastStringEnc)) {
+			return this.lastStringWidth;
+		}
+		
+		final double[] answer= this.currentFontFamily.getStringWidth(this.currentFontStyle, this.currentFontSize, text);
+		
+		this.lastStringEnc= text;
+		return (this.lastStringWidth= answer);
+	}
+	
+	
+	@Override
+	public void addSetClip(final double x0, final double y0, final double x1, final double y1) {
+		final ClipSetting instr= new ClipSetting(x0, y0, x1, y1);
+		add(instr);
+	}
+	
+	@Override
+	public void addSetColor(final int color) {
+		final ColorSetting instr= new ColorSetting(color,
+				this.swtColorManager.getColor((color & 0xffffff)) );
+		add(instr);
+	}
+	
+	@Override
+	public void addSetFill(final int color) {
+		final FillSetting instr= new FillSetting(color,
+				this.swtColorManager.getColor((color & 0xffffff)) );
+		add(instr);
+	}
+	
+	@Override
+	public void addSetFont(String family, final int face, final float pointSize,
+			final float lineHeight) {
+//		System.out.println("==\nSetFont: \"" + family + "\" " + face + " " + pointSize);
+		switch (face) {
+		case 2:
+		case 3:
+		case 4:
+			family= getFontName(family);
+			this.currentFontStyle= face - 1;
+			this.currentFontMapping= null;
+			break;
+		case 5:
+			if (this.symbolFontName != null) {
+				family= this.symbolFontName;
+				this.currentFontStyle= 0;
+				this.currentFontMapping= this.symbolFontMapping;
+				break;
+			}
+			//$FALL-THROUGH$
+		default:
+			family= getFontName(family);
+			this.currentFontStyle= 0;
+			this.currentFontMapping= null;
+			break;
+		}
+		this.currentFontFamily= this.swtFontManager.getFamily(family);
+		this.currentFontRFace= face;
+		this.currentFontSize= (int) (pointSize + 0.5);
+		
+		this.lastStringEnc= null;
+		
+		final FontSetting instr= new FontSetting(family, face, pointSize, lineHeight,
+				this.currentFontFamily.getSWTFont(this.currentFontStyle, this.currentFontSize),
+				this.currentFontFamily.getSWTFontProperties(this.currentFontStyle, this.currentFontSize) );
+		add(instr);
+	}
+	
+	private String getFontName(final String family) {
+		if (family.length() == 0 || family.equals("sansserif")) {
+			return this.sansFontName;
+		}
+		else if (family.equals("serif")) {
+			return this.serifFontName;
+		}
+		else if (family.equals("mono")) {
+			return this.monoFontName;
+		}
+		else {
+			return family;
+		}
+	}
+	
+	@Override
+	public void addSetLine(final int type, final float width,
+			final byte cap, final byte join, final float joinMiterLimit) {
+		final LineSetting instr= new LineSetting(type, width, cap, join, joinMiterLimit);
+		add(instr);
+	}
+	
+	@Override
+	public void addDrawLine(final double x0, final double y0, final double x1, final double y1) {
+		final LineElement instr= new LineElement(x0, y0, x1, y1);
+		add(instr);
+	}
+	
+	@Override
+	public void addDrawRect(final double x0, final double y0, final double x1, final double y1) {
+		final RectElement instr= new RectElement(x0, y0, x1, y1);
+		add(instr);
+	}
+	
+	@Override
+	public void addDrawPolyline(final double[] x, final double[] y) {
+		final PolylineElement instr= new PolylineElement(x, y);
+		add(instr);
+	}
+	
+	@Override
+	public void addDrawPolygon(final double[] x, final double[] y) {
+		final PolygonElement instr= new PolygonElement(x, y);
+		add(instr);
+	}
+	
+	@Override
+	public void addDrawPath(final int[] n, final double[] x, final double[] y, final int winding) {
+		final Path path= new Path(this.display);
+		int k= 0, end= 0;
+		for (int i= 0; i < n.length; i++) {
+			end+= n[i];
+			path.moveTo((float) Math.floor(x[k] + 0.5), (float) Math.floor(y[k++] + 0.5));
+			while (k < end) {
+				path.lineTo((float) Math.floor(x[k] + 0.5), (float) Math.floor(y[k++] + 0.5));
+			}
+			path.close();
+		}
+		final PathElement instr= new PathElement(n, x, y, winding, path);
+		add(instr);
+	}
+	
+	@Override
+	public void addDrawCircle(final double x, final double y, final double r) {
+		final CircleElement instr= new CircleElement(x, y, r);
+		add(instr);
+	}
+	
+	@Override
+	public void addDrawText(final String txt,
+			final double x, final double y, final double rDeg, final double hAdj) {
+//		System.out.println("==\nDrawText: " + x + ", " + y + " " + hAdj + " \"" + txt + "\""); printFont();
+		final String text= (this.currentFontMapping != null) ? this.currentFontMapping.encode(txt) : txt;
+		final TextElement instr= new TextElement(text, x, y, rDeg, hAdj,
+				(hAdj != 0) ? computeStringWidthEnc(text)[0] : 0);
+		add(instr);
+	}
+	
+	@Override
+	public void addDrawRaster(final byte[] imgData, final boolean hasAlpha,
+			final int imgWidth, final int imgHeight,
+			final double x, final double y, final double w, final double h,
+			final double rDeg, final boolean interpolate) {
+		final ImageData imageData= new ImageData(imgWidth, imgHeight, 32, DIRECT_PALETTE, 4, imgData);
+		if (hasAlpha) {
+			final byte[] alpha= new byte[imgWidth*imgHeight];
+			for (int i= 0; i < alpha.length; i++) {
+				alpha[i]= imgData[i*4 + 3];
+			}
+			imageData.alphaData= alpha;
+		}
+		final Image swtImage= new Image(this.display, imageData);
+		final RasterElement instr= new RasterElement(imgData, imgWidth, imgHeight, x, y, w, h,
+				rDeg, interpolate, swtImage );
+		add(instr);
+	}
+	
+	@Override
+	public byte[] capture(final int width, final int height) {
+		ImageData imageData;
+		{	Image image= null;
+			GC gc= null;
+			try {
+				image= new Image(this.display, width, height);
+				gc= new GC(image);
+				final DefaultGCRenderer renderer= new DefaultGCRenderer();
+				final List<ERGraphicInstruction> instructions= getCurrentInstructions();
+				if (instructions.isEmpty()) {
+					return null;
+				}
+				{	final RGraphicInitialization init= (RGraphicInitialization) instructions.get(0);
+					double scale;
+					if (width == (int) (init.width + 0.5)) {
+						scale= 1.0;
+					}
+					else {
+						scale= width / init.width;
+					}
+					renderer.clear(scale);
+				}
+				renderer.paint(gc, instructions);
+				gc.dispose();
+				gc= null;
+				imageData= image.getImageData();
+				image.dispose();
+				image= null;
+			}
+			finally {
+				if (gc != null && !gc.isDisposed()) {
+					gc.dispose();
+				}
+				if (image != null && !image.isDisposed()) {
+					image.dispose();
+				}
+			}
+		}
+		if (imageData == null || !imageData.palette.isDirect) {
+			return null;
+		}
+		if (imageData.palette.redMask != DIRECT_RED_MASK
+				|| imageData.palette.greenMask != DIRECT_GREEN_MASK
+				|| imageData.palette.blueMask != DIRECT_BLUE_MASK
+				|| imageData.scanlinePad != 4
+				|| imageData.bytesPerLine != width * 4
+				|| imageData.data.length != width * height * 4 ) {
+			final byte[] data= (imageData.data.length == width * height * 4) ?
+					imageData.data : new byte[width * height * 4];
+			final int blueMask= imageData.palette.blueMask;
+			final int blueShift= imageData.palette.blueShift;
+			final int greenMask= imageData.palette.greenMask;
+			final int greenShift= imageData.palette.greenShift;
+			final int redMask= imageData.palette.redMask;
+			final int redShift= imageData.palette.redShift;
+			int i= 0;
+			for (int y= 0; y < height; y++) {
+				for (int x= 0; x < width; x++) {
+					final int p= imageData.getPixel(x, y);
+					data[i++]= (blueShift < 0) ?
+							(byte) ((p & blueMask) >>> -blueShift) :
+							(byte) ((p & blueMask) << blueShift);
+					data[i++]= (greenShift < 0) ?
+							(byte) ((p & greenMask) >>> -greenShift) :
+							(byte) ((p & greenMask) << greenShift);
+					data[i++]= (redShift < 0) ?
+							(byte) ((p & redMask) >>> -redShift) :
+							(byte) ((p & redMask) << redShift);
+					data[i++]= (byte) 255;
+				}
+			}
+			return data;
+		}
+		return imageData.data;
+	}
+	
+	
+	protected void waitRUserExchange(final String type, final RService r, final IProgressMonitor monitor,
+			final Callable<Boolean> cancelListener) {
+		final RServiceControlExtension rControl= (r instanceof RServiceControlExtension) ?
+				(RServiceControlExtension) r : null;
+		if (rControl != null && cancelListener != null) {
+			rControl.addCancelHandler(cancelListener);
+			rControl.getWaitLock().lock();
+		}
+		try {
+			while (true) {
+				synchronized (this.userExchangeLock) {
+					if (this.userExchangeRType != type) {
+						this.userExchangeRCallback= null;
+						return;
+					}
+					if (this.isLocalClosed || this.isRClosed || monitor.isCanceled() ) {
+						this.userExchangeRType= null;
+						this.userExchangeRCallback= null;
+						return;
+					}
+					this.userExchangeRCallback= rControl;
+				}
+				
+				if (rControl != null) {
+					rControl.waitingForUser(monitor);
+				}
+				else {
+					try {
+						Thread.sleep(50);
+					}
+					catch (final InterruptedException e) {
+					}
+				}
+			}
+		}
+		finally {
+			if (rControl != null && cancelListener != null) {
+				rControl.getWaitLock().unlock();
+				rControl.removeCancelHandler(cancelListener);
+			}
+		}
+	}
+	
+	
+	private void internalStartLocator(final LocatorCallback callback) {
+		this.locatorCallback= callback;
+		this.locatorMessage= new Status(IStatus.INFO, RGraphics.BUNDLE_ID, callback.getMessage());
+		this.locatorStopTypes= callback.getStopTypes();
+		this.locatorDeferredStamp= Long.MIN_VALUE;
+		
+		if (this.display.isDisposed()) {
+			return;
+		}
+		if (!this.locatorNotificationDirectScheduled) {
+			execInDisplay(this.locatorNotificationRunnable);
+		}
+	}
+	
+	private void internalStopLocator(final boolean deferred) {
+		if (deferred) {
+			this.locatorDeferredStamp= System.nanoTime() + 500 * MILLI_NANOS;
+			if (this.display.isDisposed()) {
+				return;
+			}
+			if (!(this.locatorNotificationDirectScheduled || this.locatorNotificationDeferredScheduled)) {
+				this.locatorNotificationDirectScheduled= true;
+				execInDisplay(this.locatorNotificationRunnable);
+			}
+			return;
+		}
+		
+		this.locatorCallback= null;
+		this.locatorMessage= null;
+		this.locatorStopTypes= Collections.emptySet();
+		this.locatorDeferredStamp= Long.MIN_VALUE;
+		
+		if (this.display.isDisposed()) {
+			return;
+		}
+		if (!this.locatorNotificationDirectScheduled) {
+			this.locatorNotificationDirectScheduled= true;
+			execInDisplay(this.locatorNotificationRunnable);
+		}
+	}
+	
+	@Override
+	public double[] runRLocator(final RService r, final IProgressMonitor monitor) {
+		synchronized (this.userExchangeLock) {
+			if (this.locatorCallback != null && this.locatorCallback != R_LOCATOR_CALLBACK) {
+				return null;
+			}
+			this.userExchangeRType= "locator";
+			internalStartLocator(R_LOCATOR_CALLBACK);
+			
+			this.locatorLocationValue= null;
+		}
+		waitRUserExchange("locator", r, monitor, new Callable<Boolean>() {
+			@Override
+			public Boolean call() {
+				return Boolean.valueOf(answerLocator(null, null, true));
+			}
+		});
+		final double[] value;
+		synchronized (this.userExchangeLock) {
+			value= this.locatorLocationValue;
+			if (this.userExchangeRType == "locator") {
+				this.userExchangeRType= null;
+			}
+			// avoid flickering as well as stale locators
+			internalStopLocator(value != null);
+		}
+		return value;
+	}
+	
+	@Override
+	public IStatus startLocalLocator(final LocatorCallback callback) {
+		if (callback == null) {
+			throw new NullPointerException("callback"); //$NON-NLS-1$
+		}
+		synchronized (this.userExchangeLock) {
+			if (this.locatorCallback != null && this.locatorCallback != callback) {
+				return new Status(IStatus.ERROR, RGraphics.BUNDLE_ID, "Another locator is already started.");
+			}
+			internalStartLocator(callback);
+		}
+		return Status.OK_STATUS;
+	}
+	
+	@Override
+	public boolean isLocatorStarted() {
+		return (this.locatorCallback != null);
+	}
+	
+	@Override
+	public Collection<String> getLocatorStopTypes() {
+		return this.locatorStopTypes;
+	}
+	
+	@Override
+	public void returnLocator(final double x, final double y) {
+		answerLocator(null, new double[] { x, y }, false);
+	}
+	
+	@Override
+	public void stopLocator(final String type) {
+		answerLocator(type, null, false);
+	}
+	
+	private boolean answerLocator(final String type, final double[] xy,
+			final boolean onlyR) {
+		synchronized (this.locatorAnswerLock) {
+			RServiceControlExtension rControl= null;
+			LocatorCallback callback;
+			synchronized (this.userExchangeLock) {
+				if (this.locatorCallback == null || this.locatorDeferredStamp != Long.MIN_VALUE) {
+					return false;
+				}
+				if (this.locatorCallback == R_LOCATOR_CALLBACK) {
+					if (this.userExchangeRType == "locator") { //$NON-NLS-1$
+						this.userExchangeRType= null;
+						rControl= this.userExchangeRCallback;
+					}
+					else {
+						return false;
+					}
+				}
+				else if (onlyR) {
+					return false;
+				}
+				if (xy == null && type != null && !this.locatorStopTypes.contains(type)) {
+					return false;
+				}
+				this.locatorLocationValue= xy;
+				callback= this.locatorCallback;
+			}
+			
+			final int code;
+			if (callback == R_LOCATOR_CALLBACK) {
+				if (xy != null) {
+					code= -1;
+				}
+				else {
+					code= LocatorCallback.STOP;
+				}
+				if (rControl != null) {
+					rControl.getWaitLock().lock();
+					try {
+						rControl.resume();
+					}
+					finally {
+						rControl.getWaitLock().unlock();
+					}
+				}
+			}
+			else {
+				if (xy != null) {
+					code= callback.located(xy[0], xy[1]);
+				}
+				else {
+					code= LocatorCallback.STOP;
+					callback.stopped(type);
+				}
+			}
+			synchronized (this.userExchangeLock) {
+				if (code == LocatorCallback.NEXT) {
+					internalStartLocator(callback);
+				}
+				else {
+					internalStopLocator((code == -1));
+				}
+			}
+			return true;
+		}
+	}
+	
+	
+	public void closeFromR() {
+		this.isRClosed= true;
+		if (this.isLocalClosed
+				|| (this.options & RClientGraphicFactory.R_CLOSE_OFF) == 0) {
+			dispose();
+		}
+		answerLocator(null, null, true);
+		setActive(false);
+	}
+	
+	protected void dispose() {
+		this.graphicListeners.clear();
+		Runnable runnable= null;
+		synchronized (this.stateLock) {
+			if (!this.isDisposed) {
+				this.isDisposed= true;
+				internalReset();
+				synchronized (this.instructionsLock) {
+					if (this.instructionsSize > 0) {
+						runnable= new DisposeRunnable(this.instructions, this.instructionsSize);
+					}
+					this.instructionsSize= 0;
+					this.instructions= null;
+				}
+			}
+		}
+		if (runnable != null) {
+			execInDisplay(runnable);
+		}
+	}
+	
+	
+	@Override
+	public List<ERGraphicInstruction> getInstructions() {
+		synchronized (this.instructionsLock) {
+			return (this.instructionsSize > 0) ?
+					ImCollections.newList(this.instructions).subList(0, this.instructionsSize) :
+					ImCollections.<ERGraphicInstruction>emptyList();
+		}
+	}
+	
+	@Override
+	public Tool getRHandle() {
+		if (this.actions != null) {
+			return this.actions.getRHandle();
+		}
+		return null;
+	}
+	
+	@Override
+	public IStatus resize(final double w, final double h) {
+		if (this.actions != null) {
+			this.nextSize= new double[] { w, h };
+			return this.actions.resizeGraphic(this.devId, new Runnable() {
+				@Override
+				public void run() {
+					EclipseRGraphic.this.size= EclipseRGraphic.this.nextSize;
+				}
+			});
+		}
+		return null;
+	}
+	
+	@Override
+	public IStatus close() {
+		if (this.isRClosed) {
+			this.isLocalClosed= true;
+			dispose();
+		}
+		if (this.actions != null) {
+			answerLocator(null, null, false);
+			return this.actions.closeGraphic(this.devId);
+		}
+		else {
+			this.isLocalClosed= true;
+			answerLocator(null, null, false);
+			this.manager.close(this);
+			dispose();
+		}
+		return null;
+	}
+	
+	@Override
+	public void addListener(final Listener listener) {
+		this.graphicListeners.add(listener);
+	}
+	
+	@Override
+	public void removeListener(final Listener listener) {
+		this.graphicListeners.remove(listener);
+	}
+	
+	protected void updateMessage() {
+		IStatus message;
+		if (this.locatorMessage != null) {
+			message= this.locatorMessage;
+		}
+		else {
+			message= Status.OK_STATUS;
+		}
+		if (!this.message.equals(message)) {
+			this.message= message;
+			for (final StatusChangeListener listener : this.messageListeners.toList()) {
+				listener.statusChanged(message);
+			}
+		}
+	}
+	
+	@Override
+	public IStatus getMessage() {
+		return this.message;
+	}
+	
+	@Override
+	public void addMessageListener(final StatusChangeListener listener) {
+		this.messageListeners.add(listener);
+	}
+	
+	@Override
+	public void removeMessageListener(final StatusChangeListener listener) {
+		this.messageListeners.remove(listener);
+	}
+	
+	
+	protected void preAction() throws CoreException {
+		if (this.actions == null || this.actions.getRHandle() == null) {
+			throw new UnsupportedOperationException();
+		}
+		if (this.isRClosed) {
+			throw new CoreException(new Status(IStatus.ERROR, RGraphics.BUNDLE_ID,
+					"The R graphic device is already closed." ));
+		}
+	}
+	
+	@Override
+	@Deprecated
+	public IStatus copy(final String toDev, final String toDevFile, final String toDevArgs)
+			throws CoreException {
+		preAction();
+		return this.actions.getRHandle().getQueue().add(new CopyToDevRunnable(this,
+				toDev, toDevFile, toDevArgs ));
+	}
+	
+	@Override
+	public void copy(final String toDev, final String toDevFile, final String toDevArgs,
+			final IProgressMonitor monitor) throws CoreException {
+		preAction();
+		this.actions.copy(this.devId, toDev, toDevFile, toDevArgs, monitor);
+	}
+	
+	@Override
+	public double[] convertGraphic2User(final double[] xy,
+			final IProgressMonitor monitor) throws CoreException {
+		preAction();
+		return this.actions.convertGraphic2User(this.devId, xy, monitor);
+	}
+	
+	@Override
+	public double[] convertUser2Graphic(final double[] xy,
+			final IProgressMonitor monitor) throws CoreException {
+		preAction();
+		return this.actions.convertUser2Graphic(this.devId, xy, monitor);
+	}
+	
+}
diff --git a/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/internal/rj/eclient/graphics/EclipseRGraphicFactory.java b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/internal/rj/eclient/graphics/EclipseRGraphicFactory.java
new file mode 100644
index 0000000..d17aae4
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/internal/rj/eclient/graphics/EclipseRGraphicFactory.java
@@ -0,0 +1,271 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.internal.rj.eclient.graphics;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicReference;
+
+import org.eclipse.core.runtime.ISafeRunnable;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.SafeRunner;
+import org.eclipse.core.runtime.preferences.IPreferencesService;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.widgets.Display;
+
+import org.eclipse.statet.jcommons.collections.CopyOnWriteIdentityListSet;
+import org.eclipse.statet.jcommons.collections.ImIdentityList;
+import org.eclipse.statet.jcommons.collections.ImList;
+
+import org.eclipse.statet.ecommons.ui.util.UIAccess;
+
+import org.eclipse.statet.rj.eclient.graphics.ERGraphic;
+import org.eclipse.statet.rj.eclient.graphics.ERGraphicsManager;
+import org.eclipse.statet.rj.eclient.graphics.RGraphics;
+import org.eclipse.statet.rj.eclient.graphics.RGraphicsPreferencePage;
+import org.eclipse.statet.rj.eclient.graphics.comclient.ToolRClientGraphicActions;
+import org.eclipse.statet.rj.server.client.RClientGraphic;
+import org.eclipse.statet.rj.server.client.RClientGraphicActions;
+import org.eclipse.statet.rj.server.client.RClientGraphicFactory;
+
+
+/**
+ * Factory and manager implementation for R graphics under Eclipse.
+ * <p>
+ * Public class is {@link org.eclipse.statet.rj.eclient.graphics.comclient.ERGraphicFactory}.</p>
+ */
+public class EclipseRGraphicFactory implements RClientGraphicFactory, ERGraphicsManager {
+	
+	
+	private static class AddedSafeRunnable implements ISafeRunnable {
+		
+		ERGraphic graphic;
+		ERGraphicsManager.Listener listener;
+		
+		@Override
+		public void run() {
+			this.listener.graphicAdded(this.graphic);
+		}
+		
+		@Override
+		public void handleException(final Throwable exception) {
+//			RGraphicsPlugin.getDefault().getLog().log(new Status(IStatus.ERROR, RGraphicsPlugin.BUNDLE_ID, 0,
+//					"An error occurred when notifying.", exception));  //$NON-NLS-1$
+		}
+		
+	}
+	
+	private static class RemovedSafeRunnable implements ISafeRunnable {
+		
+		ERGraphic graphic;
+		ERGraphicsManager.Listener listener;
+		
+		@Override
+		public void run() {
+			this.listener.graphicRemoved(this.graphic);
+		}
+		
+		@Override
+		public void handleException(final Throwable exception) {
+		}
+		
+	}
+	
+	private static class ShowSafeRunnable implements ISafeRunnable {
+		
+		ERGraphic graphic;
+		ERGraphicsManager.ListenerShowExtension listener;
+		
+		int bestPriority;
+		ERGraphicsManager.ListenerShowExtension bestListener;
+		
+		@Override
+		public void run() {
+			if (this.listener != null) {
+				final int priority= this.listener.canShowGraphic(this.graphic);
+				if (priority > this.bestPriority) {
+					this.bestPriority= priority;
+					this.bestListener= this.listener;
+				}
+			}
+			else {
+				this.bestListener.showGraphic(this.graphic);
+			}
+		}
+		
+		@Override
+		public void handleException(final Throwable exception) {
+//			RGraphicsPlugin.getDefault().getLog().log(new Status(IStatus.ERROR, RGraphicsPlugin.BUNDLE_ID, 0,
+//					"An error occurred when notifying.", exception));  //$NON-NLS-1$
+		}
+		
+	}
+	
+	
+	private final CopyOnWriteIdentityListSet<EclipseRGraphic> graphics= new CopyOnWriteIdentityListSet<>();
+	
+	private final CopyOnWriteIdentityListSet<ERGraphicsManager.Listener> listeners= new CopyOnWriteIdentityListSet<>();
+	private final AddedSafeRunnable addedRunnable= new AddedSafeRunnable();
+	private final RemovedSafeRunnable removedRunnable= new RemovedSafeRunnable();
+	private final ShowSafeRunnable showRunnable= new ShowSafeRunnable();
+	
+	private final Display defaultDisplay;
+	private final FontManager fontManager;
+	private final ColorManager colorManager;
+	
+	
+	public EclipseRGraphicFactory() {
+		this.defaultDisplay= UIAccess.getDisplay();
+		this.fontManager= new FontManager(this.defaultDisplay);
+		this.colorManager= new ColorManager(this.defaultDisplay);
+		this.defaultDisplay.asyncExec(new Runnable() {
+			@Override
+			public void run() {
+				EclipseRGraphicFactory.this.defaultDisplay.disposeExec(new Runnable() {
+					@Override
+					public void run() {
+						EclipseRGraphicFactory.this.fontManager.dispose();
+						EclipseRGraphicFactory.this.colorManager.dispose();
+					}
+				});
+			}
+		});
+	}
+	
+	
+	@Override
+	public Map<String, ? extends Object> getInitServerProperties() {
+		final Map<String, Object> map= new HashMap<>();
+		final IPreferencesService preferences= Platform.getPreferencesService();
+		final AtomicReference<double[]> dpi= new AtomicReference<>();
+		dpi.set(RGraphicsPreferencePage.parseDPI(preferences.getString(
+				RGraphics.PREF_DISPLAY_QUALIFIER, RGraphics.PREF_DISPLAY_CUSTOM_DPI_KEY, null, null )));
+		if (dpi.get() == null) {
+			Display.getDefault().syncExec(new Runnable() {
+				@Override
+				public void run() {
+					final Point point= Display.getCurrent().getDPI();
+					dpi.set(new double[] { point.x, point.y });
+				}
+			});
+			if (dpi.get() == null) {
+				dpi.set(new double[] { 96.0, 96.0 });
+			}
+		}
+		map.put("display.ppi", dpi.get()); //$NON-NLS-1$
+		return map;
+	}
+	
+	@Override
+	public RClientGraphic newGraphic(final int devId, final double w, final double h,
+			final RClientGraphic.InitConfig config,
+			final boolean active, final RClientGraphicActions actions, final int options) {
+		final EclipseRGraphic egraphic= new EclipseRGraphic(devId, w, h, config, active,
+				(actions instanceof ToolRClientGraphicActions) ? (ToolRClientGraphicActions) actions : null,
+				options, this );
+		if ((options & MANAGED_OFF) == 0) {
+			this.defaultDisplay.syncExec(new Runnable() {
+				@Override
+				public void run() {
+					EclipseRGraphicFactory.this.graphics.add(egraphic);
+					final ImIdentityList<Listener> listeners= EclipseRGraphicFactory.this.listeners.toList();
+					
+					EclipseRGraphicFactory.this.showRunnable.graphic= egraphic;
+					EclipseRGraphicFactory.this.showRunnable.bestPriority= Integer.MIN_VALUE;
+					for (final Listener listener : listeners) {
+						if (listener instanceof ListenerShowExtension) {
+							EclipseRGraphicFactory.this.showRunnable.listener= (ListenerShowExtension) listener;
+							SafeRunner.run(EclipseRGraphicFactory.this.showRunnable);
+						}
+					}
+					EclipseRGraphicFactory.this.showRunnable.listener= null;
+					if (EclipseRGraphicFactory.this.showRunnable.bestPriority >= 0) {
+						SafeRunner.run(EclipseRGraphicFactory.this.showRunnable);
+					}
+					EclipseRGraphicFactory.this.showRunnable.bestListener= null;
+					EclipseRGraphicFactory.this.showRunnable.graphic= null;
+					
+					EclipseRGraphicFactory.this.addedRunnable.graphic= egraphic;
+					for (final Listener listener : listeners) {
+						EclipseRGraphicFactory.this.addedRunnable.listener= listener;
+						SafeRunner.run(EclipseRGraphicFactory.this.addedRunnable);
+					}
+					EclipseRGraphicFactory.this.addedRunnable.listener= null;
+					EclipseRGraphicFactory.this.addedRunnable.graphic= null;
+				}
+			});
+		}
+		return egraphic;
+	}
+	
+	@Override
+	public void closeGraphic(final RClientGraphic graphic) {
+		final EclipseRGraphic egraphic= (EclipseRGraphic) graphic;
+		close(egraphic);
+		egraphic.closeFromR();
+	}
+	
+	void close(final EclipseRGraphic graphic) {
+		if (!this.defaultDisplay.isDisposed()) {
+			this.defaultDisplay.syncExec(new Runnable() {
+				@Override
+				public void run() {
+					EclipseRGraphicFactory.this.graphics.remove(graphic);
+					final ImIdentityList<Listener> listeners= EclipseRGraphicFactory.this.listeners.toList();
+					
+					EclipseRGraphicFactory.this.removedRunnable.graphic= graphic;
+					for (final Listener listener : listeners) {
+						EclipseRGraphicFactory.this.removedRunnable.listener= listener;
+						SafeRunner.run(EclipseRGraphicFactory.this.removedRunnable);
+					}
+					EclipseRGraphicFactory.this.removedRunnable.listener= null;
+					EclipseRGraphicFactory.this.removedRunnable.graphic= null;
+				}
+			});
+		}
+	}
+	
+	
+	public FontManager getFontManager(final Display display) {
+		if (display == this.defaultDisplay) {
+			return this.fontManager;
+		}
+		return null;
+	}
+	
+	public ColorManager getColorManager(final Display display) {
+		if (display == this.defaultDisplay) {
+			return this.colorManager;
+		}
+		return null;
+	}
+	
+	
+	@Override
+	public ImList<? extends ERGraphic> getAllGraphics() {
+		return this.graphics.toList();
+	}
+	
+	@Override
+	public void addListener(final Listener listener) {
+		this.listeners.add(listener);
+	}
+	
+	@Override
+	public void removeListener(final Listener listener) {
+		this.listeners.remove(listener);
+	}
+	
+}
diff --git a/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/internal/rj/eclient/graphics/FillSetting.java b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/internal/rj/eclient/graphics/FillSetting.java
new file mode 100644
index 0000000..7661eee
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/internal/rj/eclient/graphics/FillSetting.java
@@ -0,0 +1,35 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.internal.rj.eclient.graphics;
+
+import org.eclipse.swt.graphics.Color;
+
+import org.eclipse.statet.rj.eclient.graphics.ERGraphicInstruction;
+import org.eclipse.statet.rj.graphic.core.RFillSetting;
+
+
+public class FillSetting extends RFillSetting implements ERGraphicInstruction {
+	
+	
+	public final Color swtColor;
+	
+	
+	public FillSetting(final int color, final Color swtColor) {
+		super(color);
+		this.swtColor= swtColor;
+	}
+	
+	
+}
diff --git a/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/internal/rj/eclient/graphics/FontManager.java b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/internal/rj/eclient/graphics/FontManager.java
new file mode 100644
index 0000000..33afa74
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/internal/rj/eclient/graphics/FontManager.java
@@ -0,0 +1,570 @@
+/*=============================================================================#
+ # Copyright (c) 2011, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.internal.rj.eclient.graphics;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Device;
+import org.eclipse.swt.graphics.Font;
+import org.eclipse.swt.graphics.FontData;
+import org.eclipse.swt.graphics.FontMetrics;
+import org.eclipse.swt.graphics.GC;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.ImageData;
+import org.eclipse.swt.widgets.Display;
+
+
+public class FontManager {
+	
+	private static final int[] R2SWT_STYLE= new int[] {
+			SWT.NONE,
+			SWT.BOLD,
+			SWT.ITALIC,
+			SWT.BOLD | SWT.ITALIC,
+	};
+	private static final int R_STYLE_COUNT= 4;
+	
+	
+	private static final int HR_FONTSIZE= 60;
+	private static final double HR_FACTOR= HR_FONTSIZE;
+	private static final int HR_MIN_FONTSIZE= HR_FONTSIZE / 2;
+	
+	
+	private static final class FontInstance {
+		
+		private static final double[] UNINITIALIZED= new double[0];
+		
+		public final int size;
+		public final Font swtFont;
+		
+		private double[] swtFontProperties; // [ baselineOffset ] -> FontSetting
+		
+		private int baseLine;
+		private double metricTolerance= 0;
+		private double ascentUp= Integer.MIN_VALUE;
+		private double ascentLow= Integer.MIN_VALUE;
+		
+		private int[] charAbove255;
+		private double[] charMetrics= UNINITIALIZED;
+		private double[] strWidth= UNINITIALIZED;
+		
+		
+		public FontInstance(final int size, final Font font) {
+			this.size= size;
+			this.swtFont= font;
+		}
+		
+		
+		public void init(final GC gc) {
+			final FontMetrics fontMetrics= gc.getFontMetrics();
+			this.baseLine= fontMetrics.getLeading() + fontMetrics.getAscent();
+			this.metricTolerance= fontMetrics.getAscent() * 0.05;
+			
+			this.swtFontProperties= new double[] {
+					this.baseLine,
+			};
+		}
+		
+		public int checkChar(final int ch) {
+			if (ch <= 0) {
+				return 0;
+			}
+			else if (ch <= 255) {
+				return ch;
+			}
+			else if (this.charAbove255 == null){
+				this.charAbove255= new int[256];
+				this.charAbove255[0]= ch;
+				return 256 + 0;
+			}
+			else {
+				for (int i= 0; i < this.charAbove255.length; i++) {
+					final int c= this.charAbove255[i];
+					if (c == 0) {
+						this.charAbove255[i]= c;
+						return 256 + i;
+					}
+					else if (c == ch) {
+						return 256 + i;
+					}
+				}
+				final int[] newChar= new int[this.charAbove255.length + 256];
+				System.arraycopy(this.charAbove255, 0, newChar, 0, this.charAbove255.length);
+				newChar[this.charAbove255.length]= ch;
+				this.charAbove255= newChar;
+				return this.charAbove255.length - 256;
+			}
+		}
+		
+	}
+	
+	
+	private static final class TestGC {
+		
+		
+		private final GC testGC;
+		
+		private FontInstance font;
+		
+		private final Image image;
+		private final int imageWidth;
+		private final int imageHeigth;
+		private final int imagePixelBytes;
+		private final int imageLineBytes;
+		private final byte imageBlankData;
+		
+		private ImageData imageData;
+		
+		
+		public TestGC(final Device device) {
+			final GC tempGC= new GC(device);
+			final Font tempFont= new Font(device, new FontData(device.getSystemFont().getFontData()[0].getName(), HR_FONTSIZE, 0));
+			tempGC.setFont(tempFont);
+			this.imageHeigth= (int) (tempGC.getFontMetrics().getHeight() * 1.5);
+			this.imageWidth= this.imageHeigth * 2;
+			tempGC.dispose();
+			tempFont.dispose();
+			
+			this.image= new Image(device, this.imageWidth, this.imageHeigth);
+			
+			this.testGC= new GC(this.image);
+			this.testGC.setAdvanced(true);
+			this.testGC.setAntialias(SWT.ON);
+			this.testGC.setTextAntialias(SWT.ON);
+			this.testGC.setInterpolation(SWT.HIGH);
+			this.testGC.setAlpha(255);
+			this.testGC.setBackground(device.getSystemColor(SWT.COLOR_WHITE));
+			this.testGC.setForeground(device.getSystemColor(SWT.COLOR_BLACK));
+			this.testGC.setFont(null);
+			this.font= null;
+			
+			clearImage();
+			this.imageData= this.image.getImageData();
+			this.imageLineBytes= this.imageData.bytesPerLine;
+			this.imagePixelBytes= Math.max(this.imageData.bytesPerLine / this.imageData.width, 1);
+			this.imageBlankData= this.imageData.data[0];
+		}
+		
+		
+		public void setFont(final FontInstance font) {
+//			if (gcFont != font) { // E-Bug #319125
+				this.font= font;
+				this.testGC.setFont(font.swtFont);
+//			}
+			if (this.font.baseLine == 0) {
+				this.font.init(this.testGC);
+				this.testGC.setFont(font.swtFont); // E-Bug #319125
+			}
+		}
+		
+		public FontInstance getFont() {
+			return this.font;
+		}
+		
+		public int getStringWidth(final String txt) {
+			return this.testGC.stringExtent(txt).x;
+		}
+		
+		public void clearImage() {
+			this.testGC.fillRectangle(0, 0, this.imageWidth, this.imageHeigth);
+			this.imageData= null;
+		}
+		
+		private void drawText(final String txt) {
+			this.testGC.drawString(txt, 0, 0, true);
+		}
+		
+		public int findFirstLine() {
+			if (this.imageData == null) {
+				this.imageData= this.image.getImageData();
+			}
+			final byte[] data= this.imageData.data;
+			for (int i= 0; i < data.length; i+= this.imagePixelBytes) {
+				if (data[i] != this.imageBlankData) {
+					return (i / this.imageLineBytes);
+				}
+			}
+			return -1;
+		}
+		
+		public int findLastLine() {
+			if (this.imageData == null) {
+				this.imageData= this.image.getImageData();
+			}
+			final byte[] data= this.imageData.data;
+			for (int i= data.length - this.imagePixelBytes; i >= 0; i-= this.imagePixelBytes) {
+				if (data[i] != this.imageBlankData) {
+					return (i / this.imageLineBytes);
+				}
+			}
+			return -1;
+		}
+		
+		
+		public void dispose() {
+			if (!this.testGC.isDisposed()) {
+				this.testGC.dispose();
+			}
+			if (!this.image.isDisposed()) {
+				this.image.dispose();
+			}
+		}
+		
+	}
+	
+	
+	public final class FontFamily {
+		
+		private static final double POLISH_SMALL_MAX_FACTOR= 0.4;
+		private static final double POLISH_SMALL_ADD_CORR= 0.04;
+		private static final double POLISH_ADD_CONST= 0.05;
+		private static final double POLISH_ADD_REL= 0.1;
+		
+		private static final int METRIC_IDX_ADVWIDTH= 0;
+		private static final int METRIC_IDX_ASCENT= 1;
+		private static final int METRIC_IDX_DESCENT= 2;
+		private static final int METRIC_COUNT= 3;
+		
+		
+		final String name;
+		
+		final FontInstance[][] fonts= new FontInstance[R_STYLE_COUNT][];
+		
+		
+		private FontFamily(final String name) {
+			this.name= name;
+		}
+		
+		
+		private FontInstance get(final int style, final int size) {
+			FontInstance[] styleFonts= this.fonts[style];
+			if (styleFonts == null) {
+				this.fonts[style]= styleFonts= new FontInstance[4];
+			}
+			int idx;
+			if (size == HR_FONTSIZE) {
+				idx= 0;
+			}
+			else {
+				idx= styleFonts.length;
+				for (int i= 1; i < styleFonts.length; i++) {
+					if (styleFonts[i] != null) {
+						if (styleFonts[i].size == size) {
+							idx= i;
+							break;
+						}
+					}
+					else {
+						idx= i;
+						break;
+					}
+				}
+				if (idx >= styleFonts.length) {
+					this.fonts[style]= new FontInstance[styleFonts.length+4];
+					System.arraycopy(styleFonts, 0, this.fonts[style], 0, styleFonts.length);
+					styleFonts= this.fonts[style];
+				}
+			}
+			if (styleFonts[idx] == null) {
+				final FontData fontData= new FontData(this.name, size, R2SWT_STYLE[style]);
+				styleFonts[idx]= new FontInstance(size,
+						new Font(FontManager.this.display, fontData));
+			}
+			return styleFonts[idx];
+		}
+		
+		public synchronized Font getSWTFont(final int style, final int size) {
+			return get(style, size).swtFont;
+		}
+		
+		public synchronized double[] getCharMetrics(final int style, final int size, final int ch) {
+			final FontInstance font= get(style, HR_FONTSIZE);
+			final double factor= size / HR_FACTOR;
+			final int chIdx= font.checkChar(ch) * METRIC_COUNT;
+			
+			final double[] answer= new double[3];
+			
+			if (chIdx >= font.charMetrics.length
+					|| font.charMetrics[chIdx] == 0) {
+				synchronized (getTestLock()) {
+					final TestGC gc= getTestGC();
+					gc.setFont(font);
+					
+					if (font.charMetrics.length == 0) {
+						font.charMetrics= new double[Math.max(512 * METRIC_COUNT,
+								chIdx + 128 * METRIC_COUNT)];
+						
+						font.charMetrics[' ' * METRIC_COUNT + METRIC_IDX_ADVWIDTH] =
+								(gc.testGC.getAdvanceWidth('m') * 0.2 + gc.testGC.getAdvanceWidth(' ') * 1.0) / 2.0;
+						font.charMetrics[' ' * METRIC_COUNT + METRIC_IDX_ASCENT]= 0;
+						font.charMetrics[' ' * METRIC_COUNT + METRIC_IDX_DESCENT]= 0;
+						
+						font.ascentUp= checkCharAscentMean(gc, new char[] { 'A', 'M', 'O', 'E' });
+						font.ascentLow= checkCharAscentMean(gc, new char[] { 'a', 'm', 'p', 'w' });
+						
+						font.charMetrics[0 * METRIC_COUNT + METRIC_IDX_ADVWIDTH] =
+								font.charMetrics['M' * METRIC_COUNT + METRIC_IDX_ADVWIDTH];
+						font.charMetrics[0 * METRIC_COUNT + METRIC_IDX_ASCENT] =
+								(font.ascentUp > 0) ? font.ascentUp : 0;
+						font.charMetrics[0 * METRIC_COUNT + METRIC_IDX_DESCENT]= 0;
+					}
+					else if (chIdx >= font.charMetrics.length) {
+						final double[] newArray= new double[(chIdx + 128 * METRIC_COUNT)];
+						System.arraycopy(font.charMetrics, 0, newArray, 0, font.charMetrics.length);
+						font.charMetrics= newArray;
+					}
+					
+					if (font.charMetrics[chIdx] == 0) {
+						computeCharHeights(gc, ch, chIdx);
+					}
+					
+//					Point sext= gc.stringExtent(new String(new int[] { this.currentChar }, 0, 1));
+//					Point text= gc.textExtent(new String(new int[] { this.currentChar }, 0, 1), SWT.TRANSPARENT);
+//					System.out.println("height= " + gc.getHeight());
+//					System.out.println("leading= " + gc.getLeading());
+//					System.out.println("ascent= " + gc.getAscent());
+//					System.out.println("descent= " + gc.getDescent());
+//					System.out.println("stringExtend.y= " + sext.y);
+//					System.out.println("textExtend.y= " + text.y);
+//					System.out.println("stringExtend.x= " + sext.x);
+//					System.out.println("textExtend.x= " + text.x);
+//					System.out.println("advanceWidth= " + gc.getAdvanceWidth((char) this.currentChar));
+//					System.out.println("charWidth= " + gc.getCharWidth((char) this.currentChar));
+//					System.out.println("averageCharWidth= " + gc.getFontMetrics.getAverageCharWidth());
+//					System.out.println(this.currentAnswer[2]);
+				}
+			}
+			
+			answer[0]= polish(font.charMetrics[chIdx + METRIC_IDX_ASCENT] + 1.01 / factor, factor);
+			answer[1]= polish(font.charMetrics[chIdx + METRIC_IDX_DESCENT], factor);
+			answer[2]= polish(font.charMetrics[chIdx + METRIC_IDX_ADVWIDTH], factor);
+			
+//			System.out.println("-> " + Arrays.toString(answer));
+			return answer;
+		}
+		
+		private void computeCharHeights(final TestGC gc, final int ch, final int idx) {
+			final FontInstance font= gc.getFont();
+			font.charMetrics[idx + METRIC_IDX_ADVWIDTH] =
+					gc.testGC.getAdvanceWidth((char) ch);
+			
+			final String s= String.valueOf((char) ch);
+			
+			gc.clearImage();
+			gc.drawText(s);
+			final int firstLine= gc.findFirstLine();
+			if (firstLine >= 0) {
+				double ascent= font.baseLine - firstLine;
+				if (Math.abs(ascent - font.ascentUp) <= font.metricTolerance) {
+					ascent= font.ascentUp;
+				}
+				else if (Math.abs(ascent - font.ascentLow) <= font.metricTolerance) {
+					ascent= font.ascentLow;
+				}
+				int descent= gc.findLastLine() - font.baseLine + 1;
+				if (Math.abs(descent) <= font.metricTolerance) {
+					descent= 0;
+				}
+				font.charMetrics[idx + METRIC_IDX_ASCENT]= ascent;
+				font.charMetrics[idx + METRIC_IDX_DESCENT]= descent;
+			}
+			else {
+				font.charMetrics[idx + METRIC_IDX_ASCENT]= 0;
+				font.charMetrics[idx + METRIC_IDX_DESCENT]= 0;
+			}
+			
+			if (idx / METRIC_COUNT < font.strWidth.length
+					&& font.strWidth[idx / METRIC_COUNT] == 0) {
+				font.strWidth[idx / METRIC_COUNT]= gc.getStringWidth(s);
+			}
+		}
+		
+		private double checkCharAscentMean(final TestGC gc, final char[] chars) {
+			final FontInstance font= gc.getFont();
+			double mean= 0;
+			for (int i= 0; i < chars.length; i++) {
+				computeCharHeights(gc, chars[i], chars[i] * METRIC_COUNT);
+				mean+= font.charMetrics[chars[i] * METRIC_COUNT + METRIC_IDX_ASCENT];
+				gc.testGC.setFont(font.swtFont); // E-Bug #319125
+			}
+			mean /= chars.length;
+			mean= polish(mean * 2.0, 1.0) / 2.0;
+			for (int i= 0; i < chars.length; i++) {
+				if (Math.abs(mean - font.charMetrics[chars[i] * METRIC_COUNT + METRIC_IDX_ASCENT]) > font.metricTolerance) {
+					return Integer.MIN_VALUE;
+				}
+			}
+			for (int i= 0; i < chars.length; i++) {
+				font.charMetrics[chars[i] * METRIC_COUNT + METRIC_IDX_ASCENT]= mean;
+			}
+			return mean;
+		}
+		
+		public synchronized double[] getStringWidth(final int style, final int size, final String text) {
+			final FontInstance font;
+			final double factor;
+			final int chIdx;
+			if (size < HR_MIN_FONTSIZE && text.length() == 1) {
+				font= get(style, HR_FONTSIZE);
+				factor= size / HR_FACTOR;
+				chIdx= font.checkChar(text.charAt(0));
+			}
+			else {
+				font= get(style, size);
+				factor= 1.0;
+				chIdx= -1;
+			}
+			
+			final double[] answer= new double[] { (8 * text.length()) };
+			
+			if (chIdx < 0
+					|| chIdx >= font.strWidth.length
+					|| font.strWidth[chIdx] == 0) {
+				synchronized (getTestLock()) {
+					final TestGC gc= getTestGC();
+					gc.setFont(font);
+					
+					final double width= gc.getStringWidth(text);
+					answer[0]= width;
+					if (chIdx >= 0) {
+						if (font.strWidth.length == 0) {
+							font.strWidth= new double[Math.max(512, chIdx + 256)];
+						}
+						else if (chIdx >= font.strWidth.length) {
+							final double[] newWidth= new double[chIdx + 128];
+							System.arraycopy(font.strWidth, 0, newWidth, 0, font.strWidth.length);
+							font.strWidth= newWidth;
+						}
+						font.strWidth[chIdx]= width;
+					}
+				}
+			}
+			else {
+				answer[0]= font.strWidth[chIdx];
+			}
+			if (factor != 1.0) {
+//				this.currentAnswer[0]= Math.round((this.currentAnswer[0] * (factor * HR_ROUND_FACTOR)) + HR_ROUND_ADD) / HR_ROUND_FACTOR;
+				answer[0]= polish(answer[0], factor);
+			}
+			
+//			System.out.println("-> " + Arrays.toString(answer));
+			return answer;
+		}
+		
+		public synchronized double[] getSWTFontProperties(final int style, final int size) {
+			final FontInstance font= get(style, size); // no HR!
+			if (font.swtFontProperties == null) {
+				synchronized (getTestLock()) {
+					final TestGC gc= getTestGC();
+					gc.setFont(font);
+				}
+			}
+			return font.swtFontProperties;
+		}
+		
+		private double polish(final double p, final double factor) {
+			if (p == 0) {
+				return 0;
+			}
+			final double add= (factor < POLISH_SMALL_MAX_FACTOR) ?
+					(POLISH_SMALL_ADD_CORR / factor + POLISH_ADD_CONST) :
+					(POLISH_SMALL_ADD_CORR/POLISH_SMALL_MAX_FACTOR + POLISH_ADD_CONST);
+			if (p > 0) {
+				return Math.round((p + POLISH_ADD_REL) * factor + add);
+			}
+			else {
+				return Math.round((p - POLISH_ADD_REL) * factor - add);
+			}
+		}
+		
+		
+		public void dispose() {
+			for (int style= 0; style < R_STYLE_COUNT; style++) {
+				final FontInstance[] styleFonts= this.fonts[style];
+				if (styleFonts != null) {
+					for (int i= 0; i < styleFonts.length; i++) {
+						if (styleFonts[i] != null && styleFonts[i].swtFont != null) {
+							if (!styleFonts[i].swtFont.isDisposed()) {
+								styleFonts[i].swtFont.dispose();
+							}
+							styleFonts[i]= null;
+						}
+					}
+				}
+			}
+		}
+		
+	}
+	
+	
+	private final Display display;
+	
+	private final Object testGCLock= new Object();
+	private TestGC testGC;
+	private boolean disposed;
+	
+	private final Map<String, FontFamily> fontFamilies= new HashMap<>();
+	
+	
+	public FontManager(final Display display) {
+		this.display= display;
+	}
+	
+	
+	public synchronized FontFamily getFamily(final String family) {
+		FontFamily fontFamily= this.fontFamilies.get(family);
+		if (fontFamily == null) {
+			fontFamily= new FontFamily(family);
+			this.fontFamilies.put(family, fontFamily);
+		}
+		return fontFamily;
+	}
+	
+	
+	protected final Object getTestLock() {
+		return this.testGCLock;
+	}
+	
+	protected final TestGC getTestGC() {
+		if (this.testGC == null) {
+			this.display.syncExec(new Runnable() {
+				@Override
+				public void run() {
+					if (!FontManager.this.disposed) {
+						FontManager.this.testGC= new TestGC(FontManager.this.display);
+					}
+				}
+			});
+		}
+		return this.testGC;
+	}
+	
+	
+	public void dispose() {
+		this.disposed= true;
+		for (final FontFamily fontFamily : this.fontFamilies.values()) {
+			fontFamily.dispose();
+		}
+		this.fontFamilies.clear();
+		
+		if (this.testGC != null) {
+			this.testGC.dispose();
+			this.testGC= null;
+		}
+	}
+	
+}
diff --git a/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/internal/rj/eclient/graphics/FontSetting.java b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/internal/rj/eclient/graphics/FontSetting.java
new file mode 100644
index 0000000..5c2c5d0
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/internal/rj/eclient/graphics/FontSetting.java
@@ -0,0 +1,38 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.internal.rj.eclient.graphics;
+
+import org.eclipse.swt.graphics.Font;
+
+import org.eclipse.statet.rj.eclient.graphics.ERGraphicInstruction;
+import org.eclipse.statet.rj.graphic.core.RFontSetting;
+
+
+public final class FontSetting extends RFontSetting implements ERGraphicInstruction {
+	
+	
+	public final Font swtFont;
+	public final double[] swtProperties;
+	
+	
+	public FontSetting(final String family, final int face, final float pointSize, final double lineHeight,
+			final Font swtFont, final double[] swtProperties) {
+		super(family, face, pointSize, lineHeight);
+		this.swtFont= swtFont;
+		this.swtProperties= swtProperties;
+	}
+	
+	
+}
diff --git a/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/internal/rj/eclient/graphics/GraphicInitialization.java b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/internal/rj/eclient/graphics/GraphicInitialization.java
new file mode 100644
index 0000000..05f2d9a
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/internal/rj/eclient/graphics/GraphicInitialization.java
@@ -0,0 +1,37 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.internal.rj.eclient.graphics;
+
+import org.eclipse.swt.graphics.Color;
+
+import org.eclipse.statet.rj.eclient.graphics.ERGraphicInstruction;
+import org.eclipse.statet.rj.graphic.core.RGraphicInitialization;
+
+
+public class GraphicInitialization extends RGraphicInitialization implements ERGraphicInstruction {
+	
+	
+	public final Color swtCanvasColor;
+	
+	
+	public GraphicInitialization(final double width, final double height, final int canvasColor,
+			final Color swtCanvasColor) {
+		super(width, height, canvasColor);
+		
+		this.swtCanvasColor= swtCanvasColor;
+	}
+	
+	
+}
diff --git a/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/internal/rj/eclient/graphics/LineElement.java b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/internal/rj/eclient/graphics/LineElement.java
new file mode 100644
index 0000000..dccf2e9
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/internal/rj/eclient/graphics/LineElement.java
@@ -0,0 +1,29 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.internal.rj.eclient.graphics;
+
+import org.eclipse.statet.rj.eclient.graphics.ERGraphicInstruction;
+import org.eclipse.statet.rj.graphic.core.RLine;
+
+
+public class LineElement extends RLine implements ERGraphicInstruction {
+	
+	
+	public LineElement(final double x0, final double y0, final double x1, final double y1) {
+		super(x0, y0, x1, y1);
+	}
+	
+	
+}
diff --git a/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/internal/rj/eclient/graphics/LineSetting.java b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/internal/rj/eclient/graphics/LineSetting.java
new file mode 100644
index 0000000..077f969
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/internal/rj/eclient/graphics/LineSetting.java
@@ -0,0 +1,76 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.internal.rj.eclient.graphics;
+
+import org.eclipse.swt.SWT;
+
+import org.eclipse.statet.rj.eclient.graphics.ERGraphicInstruction;
+import org.eclipse.statet.rj.graphic.core.RLineSetting;
+
+
+public final class LineSetting extends RLineSetting implements ERGraphicInstruction {
+	
+	
+	public LineSetting(final int type, final float width, final byte cap, final byte join,
+			final float joinMiterLimit) {
+		super(type, width, cap, join, joinMiterLimit);
+	}
+	
+	
+	public int swtCap() {
+		switch(this.cap) {
+		case CAP_ROUND:
+			return SWT.CAP_ROUND;
+		case CAP_BUTT:
+			return SWT.CAP_FLAT;
+		case CAP_SQUARE:
+			return SWT.CAP_SQUARE;
+		default:
+			assert (false);
+			return SWT.CAP_ROUND;
+		}
+	}
+	
+	public int swtJoin() {
+		switch (this.join) {
+		case JOIN_ROUND:
+			return SWT.JOIN_ROUND;
+		case JOIN_MITER:
+			return SWT.JOIN_MITER;
+		case JOIN_BEVEL:
+			return SWT.JOIN_BEVEL;
+		default:
+			assert (false);
+			return SWT.JOIN_ROUND;
+		}
+	}
+	
+	public int[] swtDashes() {
+		int rPattern= this.type;
+		int length= 0;
+		while (rPattern != 0) {
+			length++;
+			rPattern>>>= 4;
+		}
+		final int[] dashes= new int[length];
+		rPattern= this.type;
+		for (int i= 0; i < length; i++) {
+			dashes[i]= (rPattern & 0xf);
+			rPattern>>>= 4;
+		}
+		return dashes;
+	}
+	
+}
diff --git a/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/internal/rj/eclient/graphics/PathElement.java b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/internal/rj/eclient/graphics/PathElement.java
new file mode 100644
index 0000000..278d274
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/internal/rj/eclient/graphics/PathElement.java
@@ -0,0 +1,37 @@
+/*=============================================================================#
+ # Copyright (c) 2011, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.internal.rj.eclient.graphics;
+
+import org.eclipse.swt.graphics.Path;
+
+import org.eclipse.statet.rj.eclient.graphics.ERGraphicInstruction;
+import org.eclipse.statet.rj.graphic.core.RPath;
+
+
+public class PathElement extends RPath implements ERGraphicInstruction {
+	
+	
+	public final Path swtPath;
+	
+	
+	public PathElement(final int[] n, final double[] x, final double[] y, final int mode,
+			final Path swtPath) {
+		super(n, x, y, mode);
+		
+		this.swtPath= swtPath;
+	}
+	
+	
+}
diff --git a/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/internal/rj/eclient/graphics/PolygonElement.java b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/internal/rj/eclient/graphics/PolygonElement.java
new file mode 100644
index 0000000..7602346
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/internal/rj/eclient/graphics/PolygonElement.java
@@ -0,0 +1,29 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.internal.rj.eclient.graphics;
+
+import org.eclipse.statet.rj.eclient.graphics.ERGraphicInstruction;
+import org.eclipse.statet.rj.graphic.core.RPolygon;
+
+
+public class PolygonElement extends RPolygon implements ERGraphicInstruction {
+	
+	
+	public PolygonElement(final double[] x, final double[] y) {
+		super(x, y);
+	}
+	
+	
+}
diff --git a/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/internal/rj/eclient/graphics/PolylineElement.java b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/internal/rj/eclient/graphics/PolylineElement.java
new file mode 100644
index 0000000..e51435f
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/internal/rj/eclient/graphics/PolylineElement.java
@@ -0,0 +1,29 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.internal.rj.eclient.graphics;
+
+import org.eclipse.statet.rj.eclient.graphics.ERGraphicInstruction;
+import org.eclipse.statet.rj.graphic.core.RPolyline;
+
+
+public class PolylineElement extends RPolyline implements ERGraphicInstruction {
+	
+	
+	public PolylineElement(final double[] x, final double[] y) {
+		super(x, y);
+	}
+	
+	
+}
diff --git a/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/internal/rj/eclient/graphics/PreferenceInitializer.java b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/internal/rj/eclient/graphics/PreferenceInitializer.java
new file mode 100644
index 0000000..530ff4b
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/internal/rj/eclient/graphics/PreferenceInitializer.java
@@ -0,0 +1,51 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.internal.rj.eclient.graphics;
+
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.preferences.AbstractPreferenceInitializer;
+import org.eclipse.core.runtime.preferences.DefaultScope;
+import org.eclipse.core.runtime.preferences.IEclipsePreferences;
+
+import org.eclipse.statet.rj.eclient.graphics.RGraphics;
+
+
+public class PreferenceInitializer extends AbstractPreferenceInitializer {
+	
+	
+	public PreferenceInitializer() {
+	}
+	
+	
+	@Override
+	public void initializeDefaultPreferences() {
+		final DefaultScope defaultScope= new DefaultScope();
+		final IEclipsePreferences node= defaultScope.getNode(RGraphics.FONTS_PREF_QUALIFIER);
+		if (Platform.getOS().startsWith("win")) {
+			node.put(RGraphics.PREF_FONTS_SERIF_FONTNAME_KEY, "Times New Roman"); //$NON-NLS-1$
+			node.put(RGraphics.PREF_FONTS_SANS_FONTNAME_KEY, "Arial"); //$NON-NLS-1$
+			node.put(RGraphics.PREF_FONTS_MONO_FONTNAME_KEY, "Courier New"); //$NON-NLS-1$
+		}
+		else {
+			node.put(RGraphics.PREF_FONTS_SERIF_FONTNAME_KEY, "Serif"); //$NON-NLS-1$
+			node.put(RGraphics.PREF_FONTS_SANS_FONTNAME_KEY, "Sans"); //$NON-NLS-1$
+			node.put(RGraphics.PREF_FONTS_MONO_FONTNAME_KEY, "Mono"); //$NON-NLS-1$
+		}
+		node.putBoolean(RGraphics.PREF_FONTS_SYMBOL_USE_KEY, true);
+		node.put(RGraphics.PREF_FONTS_SYMBOL_FONTNAME_KEY, "Symbol"); //$NON-NLS-1$
+		node.put(RGraphics.PREF_FONTS_SYMBOL_ENCODING_KEY, "AdobeSymbol"); //$NON-NLS-1$
+	}
+	
+}
diff --git a/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/internal/rj/eclient/graphics/RGraphicsPlugin.java b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/internal/rj/eclient/graphics/RGraphicsPlugin.java
new file mode 100644
index 0000000..c4d8406
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/internal/rj/eclient/graphics/RGraphicsPlugin.java
@@ -0,0 +1,126 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.internal.rj.eclient.graphics;
+
+import static org.eclipse.statet.ecommons.ui.util.ImageRegistryUtil.T_LOCTOOL;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.osgi.framework.BundleContext;
+
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.jface.resource.ImageRegistry;
+import org.eclipse.ui.plugin.AbstractUIPlugin;
+
+import org.eclipse.statet.jcommons.lang.Disposable;
+
+import org.eclipse.statet.ecommons.ui.util.ImageRegistryUtil;
+
+import org.eclipse.statet.rj.eclient.graphics.RGraphics;
+
+
+/**
+ * Plug-in <code>org.eclipse.statet.rj.eclient.graphics</code>.
+ */
+public class RGraphicsPlugin extends AbstractUIPlugin {
+	
+	
+	public static final String IMG_LOCTOOL_RESIZE_FIT_R= RGraphics.BUNDLE_ID + "/image/loctool/resize-fit-r"; //$NON-NLS-1$
+	
+	public static final String IMG_LOCTOOL_LOCATOR_DONE= RGraphics.BUNDLE_ID + "/image/loctool/locator-done"; //$NON-NLS-1$
+	public static final String IMG_LOCTOOL_LOCATOR_CANCEL= RGraphics.BUNDLE_ID + "/image/loctool/locator-cancel"; //$NON-NLS-1$
+	
+	
+	private static RGraphicsPlugin instance;
+	
+	/**
+	 * Returns the shared plug-in instance
+	 *
+	 * @return the shared instance
+	 */
+	public static RGraphicsPlugin getDefault() {
+		return instance;
+	}
+	
+	
+	private boolean started;
+	
+	private final List<Disposable> disposables= new ArrayList<>();
+	
+	
+	public RGraphicsPlugin() {
+	}
+	
+	
+	@Override
+	public void start(final BundleContext context) throws Exception {
+		super.start(context);
+		instance= this;
+		this.started= true;
+	}
+	
+	@Override
+	public void stop(final BundleContext context) throws Exception {
+		try {
+			synchronized (this) {
+				this.started= false;
+			}
+			
+			for (final Disposable listener : this.disposables) {
+				try {
+					listener.dispose();
+				}
+				catch (final Throwable e) {
+					getLog().log(new Status(IStatus.ERROR, RGraphics.BUNDLE_ID, 0,
+							"Error occured when dispose module", e )); 
+				}
+			}
+			this.disposables.clear();
+		}
+		finally {
+			instance= null;
+			super.stop(context);
+		}
+	}
+	
+	
+	@Override
+	protected void initializeImageRegistry(final ImageRegistry reg) {
+		if (!this.started) {
+			throw new IllegalStateException("Plug-in is not started.");
+		}
+		final ImageRegistryUtil util= new ImageRegistryUtil(this);
+		
+		util.register(IMG_LOCTOOL_RESIZE_FIT_R, T_LOCTOOL, "resize-fit-r.png");
+		
+		util.register(IMG_LOCTOOL_LOCATOR_DONE, T_LOCTOOL, "locator-done.png");
+		util.register(IMG_LOCTOOL_LOCATOR_CANCEL, T_LOCTOOL, "locator-cancel.png");
+	}
+	
+	public void registerPluginDisposable(final Disposable listener) {
+		if (listener == null) {
+			throw new NullPointerException();
+		}
+		synchronized (this) {
+			if (!this.started) {
+				throw new IllegalStateException("Plug-in is not started.");
+			}
+			this.disposables.add(listener);
+		}
+	}
+	
+}
diff --git a/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/internal/rj/eclient/graphics/RasterElement.java b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/internal/rj/eclient/graphics/RasterElement.java
new file mode 100644
index 0000000..2ccb7e8
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/internal/rj/eclient/graphics/RasterElement.java
@@ -0,0 +1,39 @@
+/*=============================================================================#
+ # Copyright (c) 2011, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.internal.rj.eclient.graphics;
+
+import org.eclipse.swt.graphics.Image;
+
+import org.eclipse.statet.rj.eclient.graphics.ERGraphicInstruction;
+import org.eclipse.statet.rj.graphic.core.RRaster;
+
+
+public class RasterElement extends RRaster implements ERGraphicInstruction {
+	
+	
+	public final Image swtImage;
+	
+	
+	public RasterElement(final byte[] imgData, final int imgWidth, final int imgHeight,
+			final double x, final double y, final double w, final double h,
+			final double rDeg, final boolean interpolate,
+			final Image swtImage) {
+		super(imgData, imgWidth, imgHeight, x, y, w, h, rDeg, interpolate);
+		
+		this.swtImage= swtImage;
+	}
+	
+	
+}
diff --git a/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/internal/rj/eclient/graphics/RectElement.java b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/internal/rj/eclient/graphics/RectElement.java
new file mode 100644
index 0000000..b5a69b7
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/internal/rj/eclient/graphics/RectElement.java
@@ -0,0 +1,29 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.internal.rj.eclient.graphics;
+
+import org.eclipse.statet.rj.eclient.graphics.ERGraphicInstruction;
+import org.eclipse.statet.rj.graphic.core.RRect;
+
+
+public class RectElement extends RRect implements ERGraphicInstruction {
+	
+	
+	public RectElement(final double x0, final double y0, final double x1, final double y1) {
+		super(x0, y0, x1, y1);
+	}
+	
+	
+}
diff --git a/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/internal/rj/eclient/graphics/TextElement.java b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/internal/rj/eclient/graphics/TextElement.java
new file mode 100644
index 0000000..daef7be
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/internal/rj/eclient/graphics/TextElement.java
@@ -0,0 +1,35 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.internal.rj.eclient.graphics;
+
+import org.eclipse.statet.rj.eclient.graphics.ERGraphicInstruction;
+import org.eclipse.statet.rj.graphic.core.RText;
+
+
+public class TextElement extends RText implements ERGraphicInstruction {
+	
+	
+	public final double swtStrWidth;
+	
+	
+	public TextElement(final String text,
+			final double x, final double y, final double rDeg, final double hAdj,
+			final double swtStrWidth) {
+		super(text, x, y, rDeg, hAdj);
+		this.swtStrWidth= swtStrWidth;
+	}
+	
+	
+}
diff --git a/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/rj/eclient/graphics/DefaultGCRenderer.java b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/rj/eclient/graphics/DefaultGCRenderer.java
new file mode 100644
index 0000000..e1d451c
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/rj/eclient/graphics/DefaultGCRenderer.java
@@ -0,0 +1,508 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.eclient.graphics;
+
+import java.util.List;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.GC;
+import org.eclipse.swt.graphics.LineAttributes;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.graphics.Transform;
+
+import org.eclipse.statet.internal.rj.eclient.graphics.CircleElement;
+import org.eclipse.statet.internal.rj.eclient.graphics.ClipSetting;
+import org.eclipse.statet.internal.rj.eclient.graphics.ColorSetting;
+import org.eclipse.statet.internal.rj.eclient.graphics.FillSetting;
+import org.eclipse.statet.internal.rj.eclient.graphics.FontSetting;
+import org.eclipse.statet.internal.rj.eclient.graphics.GraphicInitialization;
+import org.eclipse.statet.internal.rj.eclient.graphics.LineElement;
+import org.eclipse.statet.internal.rj.eclient.graphics.LineSetting;
+import org.eclipse.statet.internal.rj.eclient.graphics.PathElement;
+import org.eclipse.statet.internal.rj.eclient.graphics.PolygonElement;
+import org.eclipse.statet.internal.rj.eclient.graphics.PolylineElement;
+import org.eclipse.statet.internal.rj.eclient.graphics.RasterElement;
+import org.eclipse.statet.internal.rj.eclient.graphics.RectElement;
+import org.eclipse.statet.internal.rj.eclient.graphics.TextElement;
+import org.eclipse.statet.rj.graphic.core.RGraphicInstruction;
+import org.eclipse.statet.rj.graphic.core.RLineSetting;
+import org.eclipse.statet.rj.server.client.RClientGraphic;
+
+
+public class DefaultGCRenderer {
+	
+	
+	private static int swtLineJoin2Cap(final int join) {
+		return (join == SWT.JOIN_ROUND) ? SWT.CAP_ROUND : SWT.CAP_FLAT;
+	}
+	
+	
+	private double scale= 1.0f;
+	
+	private final LineAttributes lineAttributes= new LineAttributes(1.0f);
+	private Color lineColor;
+	private int lineAlpha;
+	private Color fillColor;
+	private int fillAlpha;
+	private final double[] fontProperties= new double[1];
+	private int xMax;
+	private int yMax;
+	
+	
+	public void clear(final double scale) {
+		this.scale= scale;
+		this.lineColor= null;
+		this.lineAlpha= 0xff;
+		this.fillColor= null;
+		this.fillAlpha= 0xff;
+		this.lineAttributes.style= SWT.LINE_SOLID;
+		this.lineAttributes.width= (float) scale;
+		this.lineAttributes.cap= SWT.CAP_ROUND;
+		this.lineAttributes.join= SWT.JOIN_ROUND;
+		this.lineAttributes.miterLimit= (float) (10.0 * scale);
+		this.xMax= 0;
+		this.yMax= 0;
+	}
+	
+	public void paint(final GC gc, final List<? extends ERGraphicInstruction> instructions) {
+		final Transform defaultTransform= null;
+		final Transform tempTransform= new Transform(gc.getDevice());
+		final double scale= this.scale;
+		int currentAlpha= -1;
+		int currentInterpolation= -1;
+		int currentFillRule= -1;
+		Color lineColor= this.lineColor;
+		int lineAlpha= this.lineAlpha;
+		Color fillColor= this.fillColor;
+		int fillAlpha= this.fillAlpha;
+		
+		try {
+			gc.setAdvanced(true);
+			gc.setAntialias(SWT.ON);
+			gc.setTextAntialias(SWT.ON);
+			gc.setLineAttributes(this.lineAttributes);
+			gc.setTransform(defaultTransform);
+			gc.setAlpha(currentAlpha);
+			if (this.lineColor != null) {
+				gc.setForeground(this.lineColor);
+			}
+			if (this.fillColor != null) {
+				gc.setBackground(this.fillColor);
+			}
+			int ixmax= this.xMax;
+			int iymax= this.yMax;
+			
+			for (final ERGraphicInstruction instr : instructions) {
+				switch (instr.getInstructionType()) {
+				case RGraphicInstruction.INIT: {
+						final GraphicInitialization init= (GraphicInitialization) instr;
+						ixmax= (int) (init.width * scale + 0.5);
+						iymax= (int) (init.height * scale + 0.5);
+						gc.setBackground(init.swtCanvasColor);
+						gc.setAlpha(currentAlpha= 0xff);
+						gc.setClipping((Rectangle) null);
+						gc.fillRectangle(0, 0, ixmax, iymax);
+	//					gc.setBackground(fillColor= gc.getDevice().getSystemColor(SWT.COLOR_WHITE));
+	//					gc.setForeground(lineColor= gc.getDevice().getSystemColor(SWT.COLOR_BLACK));
+						gc.setClipping(0, 0, ixmax, iymax);
+						continue;
+					}
+				
+				case RGraphicInstruction.SET_CLIP: {
+						final ClipSetting setting= (ClipSetting) instr;
+						
+						final int ix0= (int) (setting.x0 * scale + 1.5);
+						final int iy0= (int) (setting.y0 * scale + 1.5);
+						gc.setClipping(ix0, iy0,
+								(int) Math.min((setting.x1 * scale + 0.5), ixmax) - ix0,
+								(int) Math.min((setting.y1 * scale + 0.5), iymax) - iy0 );
+						continue;
+					}
+				
+				case RGraphicInstruction.SET_COLOR: {
+						final ColorSetting setting= (ColorSetting) instr;
+						
+						lineAlpha= setting.getAlpha();
+						gc.setForeground(lineColor= setting.swtColor);
+						continue;
+					}
+				
+				case RGraphicInstruction.SET_FILL: {
+						final FillSetting setting= (FillSetting) instr;
+						
+						fillAlpha= setting.getAlpha();
+						gc.setBackground(fillColor= setting.swtColor);
+						continue;
+					}
+				
+				case RGraphicInstruction.SET_LINE: {
+						final LineSetting setting= (LineSetting) instr;
+						
+						this.lineAttributes.cap= setting.swtCap();
+						this.lineAttributes.join= setting.swtJoin();
+						this.lineAttributes.miterLimit= (float) (setting.joinMiterLimit * scale);
+						switch (setting.type) {
+						case RLineSetting.TYPE_SOLID:
+							this.lineAttributes.style= SWT.LINE_SOLID;
+							this.lineAttributes.width= (float) (setting.width * scale);
+							gc.setLineAttributes(this.lineAttributes);
+							continue;
+						case RLineSetting.TYPE_BLANK:
+							this.lineAttributes.style= SWT.LINE_SOLID;
+							this.lineAttributes.width= 0.0f;
+							gc.setLineAttributes(this.lineAttributes);
+							continue;
+//						case 0x44:
+//							this.tempLineAttributes.style= SWT.LINE_DASH;
+//							this.tempLineAttributes.width= (float) (setting.width * scale);
+//							gc.setLineAttributes(this.tempLineAttributes);
+//							continue;
+//						case 0x13:
+//							this.tempLineAttributes.style= SWT.LINE_DOT;
+//							this.tempLineAttributes.width= (float) (setting.width * scale);
+//							gc.setLineAttributes(this.tempLineAttributes);
+//							continue;
+//						case 0x1343:
+//							this.tempLineAttributes.style= SWT.LINE_DASHDOT;
+//							this.tempLineAttributes.width= (float) (setting.width * scale);
+//							gc.setLineAttributes(this.tempLineAttributes);
+//							continue;
+						default:
+							this.lineAttributes.style= SWT.LINE_SOLID;
+							this.lineAttributes.width= (float) (setting.width * scale);
+							gc.setLineAttributes(this.lineAttributes);
+							gc.setLineDash(setting.swtDashes());
+							continue;
+						}
+					}
+				
+				case RGraphicInstruction.SET_FONT: {
+						final FontSetting setting= (FontSetting) instr;
+						
+						gc.setFont(setting.swtFont);
+						this.fontProperties[0]= setting.swtProperties[0];
+						continue;
+					}
+				
+				case RGraphicInstruction.DRAW_LINE: {
+						final LineElement element= (LineElement) instr;
+						
+						if (lineAlpha != currentAlpha) {
+							gc.setAlpha(currentAlpha= lineAlpha);
+						}
+						gc.drawLine(
+								(int) (element.x0 * scale + 0.5),
+								(int) (element.y0 * scale + 0.5),
+								(int) (element.x1 * scale + 0.5),
+								(int) (element.y1 * scale + 0.5) );
+						continue;
+					}
+				
+				case RGraphicInstruction.DRAW_RECTANGLE: {
+						final RectElement element= (RectElement) instr;
+						
+						// small dots: priority on size / center
+						// default: priority on edges
+						final int ix0, iy0;
+						final int iw, ih;
+						if ((element.x1 - element.x0) < 5.1111 && (element.y1 - element.y0) < 5.1111) {
+							iw= (int) ((element.x1 - element.x0) * scale + 0.5);
+							if (lineAlpha == 0) {
+								ix0= (int) (((element.x0 + element.x1) * scale - iw) / 2.0 + 0.5);
+//								System.out.println("(a==0) ix0= " + ix0 + " (" + (float) (((element.x0 + element.x1) * scale - iw) / 2.0) + ")"
+//										+ ", x0= " + (float) (element.x0 * scale) + ", iw= " + iw + " (" + (float) ((element.x1 - element.x0) * scale) + ")"
+//										+ ", c= " + (float) ((element.x0 + element.x1) * scale / 2.0));
+							}
+							else {
+								ix0= (int) (((element.x0 + element.x1) * scale - (iw + 1)) / 2.0 + 0.5);
+//								System.out.println("(a!=0) ix0= " + ix0 + " (" + (float) (((element.x0 + element.x1) * scale - (iw + 1)) / 2.0) + ")"
+//										+ ", x0= " + (float) (element.x0 * scale) + ", iw= " + iw + "+1 (" + (float) ((element.x1 - element.x0) * scale) + ")"
+//										+ ", c= " + (float) ((element.x0 + element.x1) * scale / 2.0));
+							}
+							ih= (int) ((element.y1 - element.y0) * scale + 0.5);
+							if (lineAlpha == 0) {
+								iy0= (int) (((element.y0 + element.y1) * scale - ih) / 2.0 + 0.5);
+							}
+							else {
+								iy0= (int) (((element.y0 + element.y1) * scale - (ih + 1)) / 2.0 + 0.5);
+							}
+						}
+						else {
+							ix0= (int) (element.x0 * scale + 0.5);
+							if (lineAlpha == 0) {
+								iw= (int) (element.x1 * scale + 0.5) - ix0 + 1;
+							}
+							else {
+								iw= (int) (element.x1 * scale + 0.5) - ix0;
+							}
+							iy0= (int) (element.y0 * scale + 0.5);
+							if (lineAlpha == 0) {
+								ih= (int) (element.y1 * scale + 0.5) - iy0 + 1;
+							}
+							else {
+								ih= (int) (element.y1 * scale + 0.5) - iy0;
+							}
+						}
+						
+						if (iw == 0 || ih == 0) {
+							if (lineAlpha == 0) {
+								continue;
+							}
+							if (lineAlpha != currentAlpha) {
+								gc.setAlpha(currentAlpha= lineAlpha);
+							}
+							gc.setLineCap(swtLineJoin2Cap(this.lineAttributes.join));
+							gc.drawLine(ix0, iy0, ix0 + iw, iy0 + ih);
+							gc.setLineCap(this.lineAttributes.cap);
+							continue;
+						}
+						if (fillAlpha != 0) {
+							if (lineAlpha == 0) {
+								if (fillAlpha != currentAlpha) {
+									gc.setAlpha(currentAlpha= fillAlpha);
+								}
+								gc.fillRectangle(ix0, iy0, iw, ih);
+								continue;
+							}
+							if (iw > 1 && ih > 1) {
+								if (fillAlpha != currentAlpha) {
+									gc.setAlpha(currentAlpha= fillAlpha);
+								}
+								gc.fillRectangle(ix0 + 1, iy0 + 1, iw - 1, ih - 1);
+							}
+						}
+						if (lineAlpha != 0) {
+							if (lineAlpha != currentAlpha) {
+								gc.setAlpha(currentAlpha= lineAlpha);
+							}
+							gc.drawRectangle(ix0, iy0, iw, ih);
+						}
+						continue;
+					}
+				
+				case RGraphicInstruction.DRAW_POLYLINE: {
+						final PolylineElement element= (PolylineElement) instr;
+						
+						final int[] icoord;
+						{	final int n= element.x.length;
+							icoord= new int[n * 2];
+							for (int i= 0, j= 0; j < n; j++) {
+								icoord[i++]= (int) (element.x[j] * scale + 0.5);
+								icoord[i++]= (int) (element.y[j] * scale + 0.5);
+							}
+						}
+						
+						if (lineAlpha != currentAlpha) {
+							gc.setAlpha(currentAlpha= lineAlpha);
+						}
+						gc.drawPolyline(icoord);
+						continue;
+					}
+				
+				case RGraphicInstruction.DRAW_POLYGON: {
+						final PolygonElement element= (PolygonElement) instr;
+						
+						final int[] icoord;
+						{	final int n= element.x.length;
+							icoord= new int[n * 2];
+							for (int i= 0, j= 0; j < n; j++) {
+								icoord[i++]= (int) (element.x[j] * scale + 0.5);
+								icoord[i++]= (int) (element.y[j] * scale + 0.5);
+							}
+						}
+						
+						if (fillAlpha != 0) {
+							if (fillAlpha != currentAlpha) {
+								gc.setAlpha(currentAlpha= fillAlpha);
+							}
+							if (SWT.FILL_EVEN_ODD != currentFillRule) {
+								gc.setFillRule(currentFillRule= SWT.FILL_EVEN_ODD);
+							}
+							gc.fillPolygon(icoord);
+						}
+						if (lineAlpha != 0) {
+							if (lineAlpha != currentAlpha) {
+								gc.setAlpha(currentAlpha= lineAlpha);
+							}
+							gc.drawPolygon(icoord);
+						}
+						continue;
+					}
+				
+				case RGraphicInstruction.DRAW_PATH: {
+						final PathElement element= (PathElement) instr;
+						
+						{	final int fillRule= ((element.mode & RClientGraphic.MASK_FILL_RULE) == RClientGraphic.FILL_WIND_NON_ZERO) ?
+									SWT.FILL_WINDING : SWT.FILL_EVEN_ODD;
+							if (fillRule != currentFillRule) {
+								gc.setFillRule(currentFillRule= fillRule);
+							}
+						}
+						if (fillAlpha != 0) {
+							if (fillAlpha != currentAlpha) {
+								gc.setAlpha(currentAlpha= fillAlpha);
+							}
+							gc.fillPath(element.swtPath);
+						}
+						if (lineAlpha != 0) {
+							if (lineAlpha != currentAlpha) {
+								gc.setAlpha(currentAlpha= lineAlpha);
+							}
+							gc.drawPath(element.swtPath);
+						}
+						continue;
+					}
+				
+				case RGraphicInstruction.DRAW_CIRCLE: {
+						final CircleElement element= (CircleElement) instr;
+						
+						final int id= (int) (element.r * 2.0 + 0.5);
+						tempTransform.setElements(1, 0, 0, 1,
+								(float) (element.x - id / 2.0),
+								(float) (element.y - id / 2.0) );
+						gc.setTransform(tempTransform);
+						
+						if (fillAlpha != 0) {
+							if (fillAlpha != currentAlpha) {
+								gc.setAlpha(currentAlpha= fillAlpha);
+							}
+							gc.fillOval(1, 1, id-1, id-1);
+						}
+						if (lineAlpha != 0) {
+							if (lineAlpha != currentAlpha) {
+								gc.setAlpha(currentAlpha= lineAlpha);
+							}
+							gc.drawOval(0, 0, id, id);
+						}
+						
+						gc.setTransform(defaultTransform);
+						continue;
+					}
+				
+				case RGraphicInstruction.DRAW_TEXT: {
+						final TextElement element= (TextElement) instr;
+						
+						final double hShift;
+						if (element.horizontalAdjust != 0.0) {
+							hShift= element.horizontalAdjust * element.swtStrWidth;
+						}
+						else {
+							hShift= 0.0;
+						}
+						
+						if (element.rotateDegree != 0.0) {
+							tempTransform.setElements(1, 0, 0, 1,
+									(float) (element.x * scale),
+									(float) (element.y * scale) );
+							tempTransform.rotate((float) -element.rotateDegree);
+							tempTransform.translate(
+									(float) Math.floor(1.1111 - hShift),
+									(float) Math.floor(0.0511 - this.fontProperties[0]) );
+							gc.setTransform(tempTransform);
+							
+							if (lineAlpha != currentAlpha) {
+								gc.setAlpha(currentAlpha= lineAlpha);
+							}
+							gc.drawString(element.text, 0, 0, true);
+							
+							gc.setTransform(defaultTransform);
+							continue;
+						}
+						else {
+							if (lineAlpha != currentAlpha) {
+								gc.setAlpha(currentAlpha= lineAlpha);
+							}
+							gc.drawString(element.text,
+									(int) Math.floor(1.1111 + element.x - hShift),
+									(int) Math.floor(0.6111 + element.y - this.fontProperties[0]),
+									true );
+							
+							continue;
+						}
+					}
+				
+				case RGraphicInstruction.DRAW_RASTER: {
+						final RasterElement element= (RasterElement) instr;
+						
+						if (0xff != currentAlpha) {
+							gc.setAlpha(currentAlpha= 0xff);
+						}
+						{	final int interpolation= (element.interpolate) ? SWT.LOW : SWT.NONE;
+							if (interpolation != currentInterpolation) {
+								gc.setInterpolation(currentInterpolation= interpolation);
+							}
+						}
+						
+						final int ix, iy;
+						final int ih, iw;
+						if (element.width >= 0) {
+							ix= (int) Math.floor(element.x * scale + 0.5);
+							iw= (int) (element.width * scale + 0.5);
+						}
+						else {
+							ix= (int) Math.floor((element.x + element.height) * scale + 0.5);
+							iw= (int) (-element.width * scale + 0.5);
+						}
+						if (element.height >= 0) {
+							iy= (int) Math.floor(element.y * scale + 0.5);
+							ih= (int) (element.height * scale + 0.5);
+						}
+						else {
+							iy= (int) Math.floor((element.y + element.height) * scale + 0.5);
+							ih= (int) (-element.height * scale + 0.5);
+						}
+						
+						if (element.rotateDegree != 0.0) {
+							tempTransform.setElements(1, 0, 0, 1,
+									(float) (element.x * scale),
+									(float) (element.y * scale) );
+							tempTransform.rotate(-(float) element.rotateDegree);
+							if (element.width < 0 || element.height < 0) {
+								tempTransform.translate(
+										(element.width < 0) ? -iw : 0,
+										(element.height < 0) ? -ih : 0 );
+							}
+							gc.setTransform(tempTransform);
+							
+							gc.drawImage(element.swtImage, 0, 0, element.imgWidth, element.imgHeight,
+									0, 0, iw, ih );
+							
+							gc.setTransform(defaultTransform);
+							continue;
+						}
+						else {
+							gc.drawImage(element.swtImage, 0, 0, element.imgWidth, element.imgHeight,
+									ix, iy, iw, ih );
+							
+							continue;
+						}
+					}
+				}
+			}
+			
+			this.lineColor= lineColor;
+			this.lineAlpha= lineAlpha;
+			this.fillColor= fillColor;
+			this.fillAlpha= fillAlpha;
+			this.xMax= ixmax;
+			this.yMax= iymax;
+		}
+		finally {
+			tempTransform.dispose();
+		}
+	}
+	
+}
diff --git a/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/rj/eclient/graphics/ERGraphic.java b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/rj/eclient/graphics/ERGraphic.java
new file mode 100644
index 0000000..7fa71da
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/rj/eclient/graphics/ERGraphic.java
@@ -0,0 +1,275 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.eclient.graphics;
+
+import java.util.Collection;
+import java.util.List;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+
+import org.eclipse.statet.ecommons.runtime.core.StatusChangeListener;
+import org.eclipse.statet.ecommons.ts.core.Tool;
+
+import org.eclipse.statet.rj.graphic.core.RGraphic;
+
+
+/**
+ * R graphic for Eclipse based clients.
+ * 
+ * <h4>Coordinate systems:</h4>
+ * <p>
+ * The <b>graphic coordinate</b> system is used to draw the graphic, the point of origin is the upper
+ * left corner, values increasing to the right and downward respectively.</p>
+ * <p>
+ * The <b>user coordinate</b> system is defined by the main x-axis and y-axis of the plot using
+ * the original units of the plotted values, if possible.<p>
+ * 
+ */
+public interface ERGraphic extends RGraphic {
+	
+	/**
+	 * @see ERGraphic#addListener(Listener)
+	 * @see ERGraphic#removeListener(Listener)
+	 * @since 1.0
+	 */
+	interface ListenerLocatorExtension extends Listener {
+		
+		/**
+		 * Is called when a locator is started or restarted (next point).
+		 * <p>
+		 * The method is called in the display thread.</p>
+		 */
+		void locatorStarted();
+		
+		/**
+		 * Is called when a locator is stopped.
+		 * <p>
+		 * The method is called in the display thread.</p>
+		 */
+		void locatorStopped();
+		
+	}
+	
+	
+	/**
+	 * The default locator stop type indicating that the user does not want to select more points
+	 * (OK, in R also called stop, default action for right mouse click).
+	 * 
+	 * @since 1.0
+	 */
+	String LOCATOR_DONE= "done"; //$NON-NLS-1$
+	
+	/**
+	 * Locator stop type indicating that the user wants to cancel the locator.
+	 * 
+	 * @since 1.0
+	 */
+	String LOCATOR_CANCEL= "cancel"; //$NON-NLS-1$
+	
+	/**
+	 * @since 1.0
+	 */
+	interface ListenerInstructionsExtension extends Listener {
+		
+		void instructionsChanged(boolean reset, List<ERGraphicInstruction> added);
+		
+	}
+	
+	
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	int getDevId();
+	
+	/**
+	 * Returns the current label for this graphic
+	 * <p>
+	 * The label can change if the graphic (device) is activated or a locator is started or stopped.
+	 * </p>
+	 * 
+	 * @return the current label
+	 */
+	String getLabel();
+	
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	boolean isActive();
+	
+	Tool getRHandle();
+	
+	@Override
+	List<? extends ERGraphicInstruction> getInstructions();
+	
+	IStatus resize(double w, double h);
+	
+	IStatus close();
+	
+	/**
+	 * Returns the current message for the graphic.
+	 * <p>
+	 * The standard OK message means there is no message.  If the message changes messages listeners
+	 * registered for this graphic ({@link #addMessageListener(StatusChangeListener)}, 
+	 * {@link #removeMessageListener(StatusChangeListener)}) are notified.</p>
+	 * <p>
+	 * The message I can be shown for example in the status line of the application.</p>
+	 * 
+	 * @return the current message to show
+	 * @since 1.0
+	 */
+	IStatus getMessage();
+	
+	/**
+	 * Registers a new message listener for this graphic.
+	 * 
+	 * @param listener the listener to add
+	 * @since 1.0
+	 */
+	void addMessageListener(StatusChangeListener listener);
+	
+	/**
+	 * Removes a message listener registered for this graphic.
+	 * 
+	 * @param listener the listener to remove
+	 * @since 1.0
+	 */
+	void removeMessageListener(StatusChangeListener listener);
+	
+	
+	/**
+	 * Starts a local locator requesting the user to select a point in the graphic.
+	 * <p>
+	 * The method starts the locator and returns directly; it does not wait for an answer.
+	 * If a locator is already installed for this graphic (local or from R), the method does 
+	 * nothing and returns an error status.</p>
+	 * <p>
+	 * The locator callback configures the request and receives the answer(s).  The answer can be
+	 * a coordinate located by the user ({@link LocatorCallback#located(double, double)}) or 
+	 * a stop command ({@link LocatorCallback#stopped(String)}.</p>
+	 * <p>
+	 * Graphic listeners implementing {@link ListenerLocatorExtension} and registered for this
+	 * graphic ({@link #addListener(Listener)}, {@link #removeListener(Listener)}) are notified 
+	 * if the locator is started and if it is finally stopped.</p>
+	 * 
+	 * @param callback the callback called to handover the answer(s)
+	 * @return An OK status if the locator is started for the given callback, otherwise 
+	 *     an error status
+	 * @see LocatorCallback
+	 * @since 1.0
+	 */
+	IStatus startLocalLocator(LocatorCallback callback);
+	
+	/**
+	 * Returns true if any locator (local or from R) is started for this graphic.
+	 * 
+	 * @return <code>true</code> if a locator is started, otherwise <code>false</code>
+	 * @since 1.0
+	 */
+	boolean isLocatorStarted();
+	
+	/**
+	 * Returns a collection of currently supported stop types.
+	 * <p>
+	 * If no locator is started, the method returns an empty collection.</p>
+	 * 
+	 * @return a list of supported stop types
+	 * @see LocatorCallback#getStopTypes()
+	 * @since 1.0
+	 */
+	Collection<String> getLocatorStopTypes();
+	
+	/**
+	 * Answers a locator request with the specified coordinates.
+	 * <p>
+	 * If no locator is started, the method does nothing.</p>
+	 * 
+	 * @param x the x value of the graphic coordinate
+	 * @param y the y value of the graphic coordinate
+	 * @since 1.0
+	 */
+	void returnLocator(double x, double y);
+	
+	/**
+	 * Answers a locator request with the specified stop command.
+	 * <p>
+	 * If no locator is started or does not support the specified type, the method does nothing.</p>
+	 * 
+	 * @param type the stop type or <code>null</code>
+	 * @see LocatorCallback#getStopTypes()
+	 * @since 1.0
+	 */
+	void stopLocator(String type);
+	
+	
+	/**
+	 * @deprecated {@link #copy(String, String, String, IProgressMonitor)} or
+	 *     {@link org.eclipse.statet.rj.eclient.graphics.util.CopyToDevRunnable}
+	 */
+	@Deprecated
+	IStatus copy(String toDev, String toDevFile, String toDevArgs) throws CoreException;
+	
+	/**
+	 * Copies the graphic to another R graphic device.
+	 * <p>
+	 * This is an R based function.  The caller must have exclusive access to the R service.  The 
+	 * graphic must be available in R.</p>
+	 * 
+	 * @param toDev the name of the target device
+	 * @param toDevFile the name of the file for file based devices
+	 * @param toDevArgs other R arguments for the target arguments
+	 * @param monitor
+	 * @throws CoreException
+	 * @since 1.0
+	 */
+	void copy(String toDev, String toDevFile, String toDevArgs,
+			IProgressMonitor monitor) throws CoreException;
+	
+	/**
+	 * Converts a coordinate (x, y) from graphic to user coordinate system.
+	 * <p>
+	 * This is an R based function.  The caller must have exclusive access to the R service.  The 
+	 * graphic must be available in R.</p>
+	 * 
+	 * @param xy the graphic coordinate to convert
+	 * @param monitor
+	 * @return the converted user coordinate
+	 * @throws CoreException
+	 * @see ERGraphic coordinate systems
+	 * @since 1.0
+	 */
+	double[] convertGraphic2User(double[] xy,
+			IProgressMonitor monitor) throws CoreException;
+	
+	/**
+	 * Converts a coordinate (x, y) from user to graphic coordinate system.
+	 * <p>
+	 * This is an R based function.  The caller must have exclusive access to the R service.  The 
+	 * graphic must be available in R.</p>
+	 * 
+	 * @param xy the graphic coordinate to convert
+	 * @param monitor
+	 * @return the converted user coordinate
+	 * @throws CoreException
+	 * @see ERGraphic coordinate systems
+	 * @since 1.0
+	 */
+	double[] convertUser2Graphic(double[] xy,
+			IProgressMonitor monitor) throws CoreException;
+	
+}
diff --git a/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/rj/eclient/graphics/ERGraphicInstruction.java b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/rj/eclient/graphics/ERGraphicInstruction.java
new file mode 100644
index 0000000..90ecd4f
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/rj/eclient/graphics/ERGraphicInstruction.java
@@ -0,0 +1,25 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.eclient.graphics;
+
+import org.eclipse.statet.rj.graphic.core.RGraphicInstruction;
+
+
+/**
+ * Instruction of an {@link ERGraphic}.
+ */
+public interface ERGraphicInstruction extends RGraphicInstruction {
+	
+}
diff --git a/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/rj/eclient/graphics/ERGraphicsManager.java b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/rj/eclient/graphics/ERGraphicsManager.java
new file mode 100644
index 0000000..15d6435
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/rj/eclient/graphics/ERGraphicsManager.java
@@ -0,0 +1,62 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.eclient.graphics;
+
+import java.util.List;
+
+
+/**
+ * Manager for a collection of R graphics.
+ */
+public interface ERGraphicsManager {
+	
+	
+	interface Listener {
+		
+		void graphicAdded(ERGraphic graphic);
+		
+		void graphicRemoved(ERGraphic graphic);
+		
+	}
+	
+	interface ListenerShowExtension extends Listener {
+		
+		/**
+		 * If the listener can show the graphic
+		 * 
+		 * <code>-1</code> not supported
+		 * <code>&gt;= 0</code> priority (higher more appropriate)
+		 * @param graphic the graphic to show
+		 * @return
+		 */
+		int canShowGraphic(ERGraphic graphic);
+		
+		/**
+		 * If the listener was selected (highest priority) to show the graphic
+		 * 
+		 * @param graphic the graphic to show
+		 */
+		void showGraphic(ERGraphic graphic);
+		
+	}
+	
+	
+	void addListener(Listener listener);
+	
+	void removeListener(Listener listener);
+	
+	List<? extends ERGraphic> getAllGraphics();
+	
+}
diff --git a/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/rj/eclient/graphics/LocatorCallback.java b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/rj/eclient/graphics/LocatorCallback.java
new file mode 100644
index 0000000..df149e2
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/rj/eclient/graphics/LocatorCallback.java
@@ -0,0 +1,119 @@
+/*=============================================================================#
+ # Copyright (c) 2011, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.eclient.graphics;
+
+import java.util.Collection;
+
+import org.eclipse.statet.jcommons.collections.ImCollections;
+import org.eclipse.statet.jcommons.collections.ImList;
+
+
+/**
+ * Callback for a local locator.
+ * <p>
+ * When using the locator function of {@link ERGraphic}, the locator callback configures the 
+ * request and receives the answer.  When starting a local locator using {@link ERGraphic#startLocalLocator(LocatorCallback)}
+ * the callback must be specified as argument.  The callback configures the locator request
+ * and receives the answer(s).</p>
+ * <p>
+ * The methods {@link #getMessage()} and {@link #getStopTypes()} allows to configure the behavior
+ * of the locator.  The properties can be used for example in the GUI.  The values can change
+ * for each point to locate; the properties are checked at beginning and again after 
+ * {@link #located(double, double)} was called and request one more point.</p>
+ * <p>
+ * The callback is notified by points located by the user are by calling ({@link LocatorCallback#located(double, double)}).
+ * Note that the callback receives graphic coordinates.  The method can return {@link #NEXT}
+ * to request a next point or {@link #STOP} to stop the locator.  The locator is also stopped
+ * if the method {@link LocatorCallback#stopped(String)} was called.</p>
+ * <p>
+ * Stop types allow to specify a special user action when stopping the locator.  Stop types known 
+ * by the default implementation are {@link ERGraphic#LOCATOR_DONE} and {@link ERGraphic#LOCATOR_CANCEL}
+ * representing the usual OK and Cancel action.  The {@link RGraphicCompositeActionSet} provides
+ * buttons for both actions.</p>
+ * 
+ * @since 1.0
+ */
+public abstract class LocatorCallback {
+	
+	
+	protected static final ImList<String> DEFAULT_STOP_TYPES= ImCollections.newList(ERGraphic.LOCATOR_DONE);
+	
+	/**
+	 * Return code for {@link #located(double, double)} indicating to stop directly the locator
+	 * ({@link #stopped(String)} is not called).
+	 */
+	public static final int STOP= 0;
+	
+	/**
+	 * Return code for {@link #located(double, double)} indicating to restart/continue the locator
+	 * requesting the next point.
+	 */
+	public static final int NEXT= 1;
+	
+	
+	public LocatorCallback() {
+	}
+	
+	
+	/**
+	 * Returns the current message for the locator.
+	 * 
+	 * @return the current message
+	 */
+	public String getMessage() {
+		return "→ Locate a point by mouse click";
+	}
+	
+	/**
+	 * Returns the currently supported stop types for the locator.
+	 * 
+	 * @return a collection of stop types, an empty collection if no regular stop is supported
+	 * @see #stopped(String)
+	 */
+	public Collection<String> getStopTypes() {
+		return DEFAULT_STOP_TYPES;
+	}
+	
+	/**
+	 * Is called if the user selected a value.
+	 * <p>
+	 * The method is called by the graphic. Other class must use {@link ERGraphic#returnLocator(double, double)}
+	 * to specify a located point.
+	 * It is not guaranteed that the method is called in a special thread.</p>
+	 * 
+	 * @param x value of the graphic coordinate
+	 * @param y value of the graphic coordinate
+	 * @return a known return code
+	 * @see #STOP
+	 * @see #NEXT
+	 */
+	public abstract int located(double x, double y);
+	
+	/**
+	 * Is called if the locator was stopped by the user or graphic manager.
+	 * <p>
+	 * The stop type is one of the {@link #getStopTypes() supported stop types} of the locator or 
+	 * also <code>null</code>.  <code>null</code> as stop type is always allowed and is used for 
+	 * example if the graphic was closed.</p>
+	 * <p>
+	 * The method is called by the graphic. Other class must use {@link ERGraphic#stopLocator(String)}
+	 * to stop the locator.
+	 * It is not guaranteed that the method is called in a special thread.</p>
+	 * 
+	 * @param type the stop type
+	 */
+	public abstract void stopped(String type);
+	
+}
diff --git a/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/rj/eclient/graphics/OldGCRenderer.java b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/rj/eclient/graphics/OldGCRenderer.java
new file mode 100644
index 0000000..a4e9e27
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/rj/eclient/graphics/OldGCRenderer.java
@@ -0,0 +1,299 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.eclient.graphics;
+
+import java.util.List;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.GC;
+import org.eclipse.swt.graphics.LineAttributes;
+import org.eclipse.swt.graphics.Transform;
+
+import org.eclipse.statet.internal.rj.eclient.graphics.CircleElement;
+import org.eclipse.statet.internal.rj.eclient.graphics.ClipSetting;
+import org.eclipse.statet.internal.rj.eclient.graphics.ColorSetting;
+import org.eclipse.statet.internal.rj.eclient.graphics.FillSetting;
+import org.eclipse.statet.internal.rj.eclient.graphics.FontSetting;
+import org.eclipse.statet.internal.rj.eclient.graphics.GraphicInitialization;
+import org.eclipse.statet.internal.rj.eclient.graphics.LineElement;
+import org.eclipse.statet.internal.rj.eclient.graphics.LineSetting;
+import org.eclipse.statet.internal.rj.eclient.graphics.PolygonElement;
+import org.eclipse.statet.internal.rj.eclient.graphics.PolylineElement;
+import org.eclipse.statet.internal.rj.eclient.graphics.RectElement;
+import org.eclipse.statet.internal.rj.eclient.graphics.TextElement;
+import org.eclipse.statet.rj.graphic.core.RGraphicInstruction;
+
+
+public class OldGCRenderer {
+	
+	
+	private float scale= 1.0f;
+	
+	private final LineAttributes lineAttributes= new LineAttributes(1.0f);
+	private Color lineColor;
+	private int lineAlpha;
+	private Color fillColor;
+	private int fillAlpha;
+	private int xMax;
+	private int yMax;
+	
+	
+	public void clear(final float scale) {
+		this.scale= scale;
+		this.lineColor= null;
+		this.lineAlpha= 0xff;
+		this.fillColor= null;
+		this.fillAlpha= 0xff;
+		this.lineAttributes.style= SWT.LINE_SOLID;
+		this.lineAttributes.width= scale;
+		this.xMax= 0;
+		this.yMax= 0;
+	}
+	
+	public void paint(final GC gc, final List<? extends ERGraphicInstruction> instructions) {
+		final Transform defaultTransform= null;
+		Transform tempTransform= null;
+		final float scale= this.scale;
+		int currentAlpha= -1;
+		int lineAlpha= this.lineAlpha;
+		int fillAlpha= this.fillAlpha;
+		try {
+			gc.setAdvanced(true);
+			gc.setAntialias(SWT.ON);
+			gc.setTextAntialias(SWT.ON);
+			gc.setLineAttributes(this.lineAttributes);
+			gc.setTransform(defaultTransform);
+			gc.setAlpha(currentAlpha);
+			if (this.lineColor != null) {
+				gc.setForeground(this.lineColor);
+			}
+			if (this.fillColor != null) {
+				gc.setBackground(this.fillColor);
+			}
+			int ixmax= this.xMax;
+			int iymax= this.yMax;
+			
+			for (final ERGraphicInstruction instr : instructions) {
+				switch (instr.getInstructionType()) {
+				case RGraphicInstruction.INIT:
+					final GraphicInitialization init= (GraphicInitialization) instr;
+					ixmax= (int) (((init.width) * scale) + 0.5);
+					iymax= (int) (((init.height) * scale) + 0.5);
+					gc.setBackground(gc.getDevice().getSystemColor(SWT.COLOR_WHITE));
+					gc.setForeground(gc.getDevice().getSystemColor(SWT.COLOR_BLACK));
+					gc.setAlpha(0xff);
+					gc.fillRectangle(0, 0, ixmax, iymax);
+					gc.setClipping(0, 0, ixmax, iymax);
+					continue;
+				case RGraphicInstruction.SET_CLIP: {
+					final ClipSetting setting= (ClipSetting) instr;
+					final int ix0= (int) ((setting.x0 * scale) + 0.5);
+					final int iy0= (int) ((setting.y0 * scale) + 0.5);
+					gc.setClipping(ix0, iy0,
+							(int) Math.min(((setting.x1 * scale) + 0.5), ixmax) - ix0,
+							(int) Math.min(((setting.y1 * scale) + 0.5), iymax) - iy0 );
+					continue; }
+				case RGraphicInstruction.SET_COLOR: {
+					final ColorSetting setting= (ColorSetting) instr;
+					lineAlpha= setting.getAlpha();
+					gc.setForeground(setting.swtColor);
+					continue; }
+				case RGraphicInstruction.SET_FILL: {
+					final FillSetting setting= (FillSetting) instr;
+					fillAlpha= setting.getAlpha();
+					gc.setBackground(setting.swtColor);
+					continue; }
+				case RGraphicInstruction.SET_LINE: {
+					final LineSetting setting= (LineSetting) instr;
+					switch (setting.type) {
+					case 0:
+						this.lineAttributes.style= SWT.LINE_SOLID;
+						this.lineAttributes.width= setting.width * scale;
+						gc.setLineAttributes(this.lineAttributes);
+						continue;
+					case -1:
+						this.lineAttributes.style= SWT.LINE_SOLID;
+						this.lineAttributes.width= 0.0f;
+						gc.setLineAttributes(this.lineAttributes);
+						continue;
+	//				case 0x44:
+	//					this.tempLineAttributes.style= SWT.LINE_DASH;
+	//					this.tempLineAttributes.width= (float) (setting.width * scale);
+	//					gc.setLineAttributes(this.tempLineAttributes);
+	//					continue;
+	//				case 0x13:
+	//					this.tempLineAttributes.style= SWT.LINE_DOT;
+	//					this.tempLineAttributes.width= (float) (setting.width * scale);
+	//					gc.setLineAttributes(this.tempLineAttributes);
+	//					continue;
+	//				case 0x1343:
+	//					this.tempLineAttributes.style= SWT.LINE_DASHDOT;
+	//					this.tempLineAttributes.width= (float) (setting.width * scale);
+	//					gc.setLineAttributes(this.tempLineAttributes);
+	//					continue;
+					}
+					
+					int rPattern= setting.type;
+					int length= 0;
+					while (rPattern != 0) {
+						length++;
+						rPattern >>>= 4;
+					}
+					final int[] dashes= new int[length];
+					rPattern= setting.type;
+					for (int i= 0; i < length; i++) {
+						dashes[i]= (rPattern & 0xf);
+						rPattern >>>= 4;
+					}
+					gc.setLineDash(dashes);
+					gc.setLineWidth((int) (setting.width * scale + 0.5));
+					continue; }
+				case RGraphicInstruction.SET_FONT: {
+					final FontSetting setting= (FontSetting) instr;
+					gc.setFont(setting.swtFont);
+					continue; }
+				case RGraphicInstruction.DRAW_LINE: {
+					final LineElement element= (LineElement) instr;
+					if (lineAlpha != currentAlpha) {
+						gc.setAlpha(currentAlpha= lineAlpha);
+					}
+					gc.drawLine(
+							(int) (element.x0 * scale + 0.5),
+							(int) (element.y0 * scale + 0.5),
+							(int) (element.x1 * scale + 0.5),
+							(int) (element.y1 * scale + 0.5) );
+					continue; }
+				case RGraphicInstruction.DRAW_RECTANGLE: {
+					final RectElement element= (RectElement) instr;
+					final int ix0= (int) (element.x0 * scale + 0.5);
+					final int iy0= (int) (element.y0 * scale + 0.5);
+					final int iw= (int) (element.x1 * scale + 0.5) - ix0;
+					final int ih= (int) (element.y1 * scale + 0.5) - iy0;
+					if (fillAlpha != 0) {
+						if (fillAlpha != currentAlpha) {
+							gc.setAlpha(currentAlpha= fillAlpha);
+						}
+						gc.fillRectangle(ix0, iy0, iw, ih);
+					}
+					if (lineAlpha != 0) {
+						if (lineAlpha != currentAlpha) {
+							gc.setAlpha(currentAlpha= lineAlpha);
+						}
+						gc.drawRectangle(ix0, iy0, iw, ih);
+					}
+					continue; }
+				case RGraphicInstruction.DRAW_POLYLINE: {
+					final PolylineElement element= (PolylineElement) instr;
+					final int n= element.x.length;
+					final int[] icoord= new int[n * 2];
+					for (int i= 0, j= 0; j < n; j++) {
+						icoord[i++]= (int) (element.x[j] * scale + 0.5);
+						icoord[i++]= (int) (element.y[j] * scale + 0.5);
+					}
+					gc.drawPolyline(icoord);
+					continue; }
+				case RGraphicInstruction.DRAW_POLYGON: {
+					final PolygonElement element= (PolygonElement) instr;
+					final int n= element.x.length;
+					final int[] icoord= new int[n * 2];
+					for (int i= 0, j= 0; j < n; j++) {
+						icoord[i++]= (int) (element.x[j] * scale + 0.5);
+						icoord[i++]= (int) (element.y[j] * scale + 0.5);
+					}
+					if (fillAlpha != 0) {
+						if (fillAlpha != currentAlpha) {
+							gc.setAlpha(currentAlpha= fillAlpha);
+						}
+						gc.fillPolygon(icoord);
+					}
+					if (lineAlpha != 0) {
+						if (lineAlpha != currentAlpha) {
+							gc.setAlpha(currentAlpha= lineAlpha);
+						}
+						gc.drawPolygon(icoord);
+					}
+					continue; }
+				case RGraphicInstruction.DRAW_CIRCLE: {
+					final CircleElement element= (CircleElement) instr;
+					final int id= (int) (element.r * scale * 2.0 + 0.5);
+					final int ix0= (int) ((element.x - element.r) * scale + 0.5);
+					final int iy0= (int) ((element.y - element.r) * scale + 0.5);
+					if (fillAlpha != 0) {
+						if (fillAlpha != currentAlpha) {
+							gc.setAlpha(currentAlpha= fillAlpha);
+						}
+						gc.fillOval(ix0, iy0, id, id);
+					}
+					if (lineAlpha != 0) {
+						if (lineAlpha != currentAlpha) {
+							gc.setAlpha(currentAlpha= lineAlpha);
+						}
+						gc.drawOval(ix0, iy0, id, id);
+					}
+					continue; }
+				case RGraphicInstruction.DRAW_TEXT: {
+					final TextElement element= (TextElement) instr;
+					final double hShift;
+					if (element.horizontalAdjust != 0.0) {
+						hShift= element.horizontalAdjust * gc.textExtent(element.text, (SWT.DRAW_DELIMITER | SWT.DRAW_TAB | SWT.DRAW_TRANSPARENT)).x;
+					}
+					else {
+						hShift= 0.0;
+					}
+					if (element.rotateDegree != 0.0) {
+						if (tempTransform == null) {
+							tempTransform= new Transform(gc.getDevice());
+						}
+						tempTransform.identity();
+						tempTransform.translate((float) (element.x * scale), (float) (element.y * scale));
+						tempTransform.rotate((float) -element.rotateDegree);
+						tempTransform.translate((float) - hShift, - gc.getFontMetrics().getAscent());
+						gc.setTransform(tempTransform);
+						if (lineAlpha != currentAlpha) {
+							gc.setAlpha(currentAlpha= lineAlpha);
+						}
+						gc.drawText(element.text, 0, 0,
+								(SWT.DRAW_DELIMITER | SWT.DRAW_TAB | SWT.DRAW_TRANSPARENT) );
+						gc.setTransform(defaultTransform);
+					}
+					else {
+						if (lineAlpha != currentAlpha) {
+							gc.setAlpha(currentAlpha= lineAlpha);
+						}
+						gc.drawText(element.text,
+								(int) (((element.x - hShift) * scale) + 0.5),
+								(int) ((element.y * scale) + 0.5) - gc.getFontMetrics().getAscent(),
+								(SWT.DRAW_DELIMITER | SWT.DRAW_TAB | SWT.DRAW_TRANSPARENT) );
+					}
+					continue; }
+				}
+			}
+			
+			this.lineColor= gc.getForeground();
+			this.lineAlpha= lineAlpha;
+			this.fillColor= gc.getBackground();
+			this.fillAlpha= fillAlpha;
+			this.xMax= ixmax;
+			this.yMax= iymax;
+		}
+		finally {
+			if (tempTransform != null) {
+				tempTransform.dispose();
+			}
+		}
+	}
+	
+}
diff --git a/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/rj/eclient/graphics/PageBookRGraphicView.java b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/rj/eclient/graphics/PageBookRGraphicView.java
new file mode 100644
index 0000000..55ccb42
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/rj/eclient/graphics/PageBookRGraphicView.java
@@ -0,0 +1,538 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.eclient.graphics;
+
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.List;
+
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.commands.IHandler2;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.jface.action.IMenuManager;
+import org.eclipse.jface.action.IStatusLineManager;
+import org.eclipse.jface.action.IToolBarManager;
+import org.eclipse.jface.action.Separator;
+import org.eclipse.jface.action.StatusLineContributionItem;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.IActionBars;
+import org.eclipse.ui.IMemento;
+import org.eclipse.ui.IViewReference;
+import org.eclipse.ui.IViewSite;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.PartInitException;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.menus.CommandContributionItemParameter;
+import org.eclipse.ui.part.IPageBookViewPage;
+import org.eclipse.ui.services.IServiceLocator;
+import org.eclipse.ui.statushandlers.StatusManager;
+import org.eclipse.ui.views.IViewDescriptor;
+
+import org.eclipse.statet.ecommons.ts.core.Tool;
+import org.eclipse.statet.ecommons.ui.SharedUIResources;
+import org.eclipse.statet.ecommons.ui.actions.HandlerCollection;
+import org.eclipse.statet.ecommons.ui.actions.HandlerContributionItem;
+import org.eclipse.statet.ecommons.ui.actions.SimpleContributionItem;
+import org.eclipse.statet.ecommons.ui.mpbv.ISession;
+import org.eclipse.statet.ecommons.ui.mpbv.ManagedPageBookView;
+import org.eclipse.statet.ecommons.ui.util.UIAccess;
+
+import org.eclipse.statet.rj.eclient.core.AbstractRToolRunnable;
+import org.eclipse.statet.rj.eclient.core.RToolService;
+
+
+/**
+ * Multi page view for R graphics.
+ * <p>
+ * No view is registered by this plug-in.</p>
+ */
+public abstract class PageBookRGraphicView extends ManagedPageBookView<PageBookRGraphicView.RGraphicSession> {
+	
+	
+	public class RGraphicSession implements ISession {
+		
+		
+		private final ERGraphic graphic;
+		
+		
+		public RGraphicSession(final ERGraphic graphic) {
+			this.graphic= graphic;
+		}
+		
+		
+		@Override
+		public ImageDescriptor getImageDescriptor() {
+			return ImageDescriptor.createFromImage(getTitleImage());
+		}
+		
+		@Override
+		public String getLabel() {
+			return this.graphic.getLabel();
+		}
+		
+		public ERGraphic getGraphic() {
+			return this.graphic;
+		}
+		
+	}
+	
+	public static class ShowRequiredViewListener implements ERGraphicsManager.ListenerShowExtension {
+		
+		
+		private final String viewId;
+		
+		
+		public ShowRequiredViewListener(final String viewId) {
+			this.viewId= viewId;
+		}
+		
+		
+		@Override
+		public int canShowGraphic(final ERGraphic graphic) {
+			return 0;
+		}
+		
+		private static String getId(final IViewReference ref) {
+			// E-Bug #405563
+			final String id= ref.getId();
+			final int idx= id.indexOf(':');
+			return (idx >= 0) ? id.substring(0, idx) : id;
+		}
+		
+		@Override
+		public void showGraphic(final ERGraphic graphic) {
+			try {
+				final IWorkbenchPage page= getBestPage(graphic);
+				String secondaryId= ""; //$NON-NLS-1$
+				final IViewReference[] refs= page.getViewReferences();
+				for (int i= 0; i < refs.length; i++) { // search views not yet instanced
+					if (this.viewId.equals(getId(refs[i])) && refs[i].getView(false) == null) {
+						if (refs[i].getSecondaryId() == null) {
+							secondaryId= null;
+							break;
+						}
+						if (secondaryId == "") { //$NON-NLS-1$
+							secondaryId= refs[i].getSecondaryId();
+						}
+					}
+				}
+				if (secondaryId == "") { //$NON-NLS-1$
+					secondaryId= "t"+System.currentTimeMillis(); //$NON-NLS-1$
+				}
+				newViewGraphic= graphic;
+				page.showView(this.viewId, secondaryId, IWorkbenchPage.VIEW_VISIBLE );
+			}
+			catch (final PartInitException e) {
+				StatusManager.getManager().handle(new Status(IStatus.ERROR, RGraphics.BUNDLE_ID,
+						"An error occurred when opening a new R Graphics view.", e ));
+			}
+			finally {
+				newViewGraphic= null;
+			}
+		}
+		
+		protected IWorkbenchPage getBestPage(final ERGraphic graphic) {
+			return UIAccess.getActiveWorkbenchPage(true);
+		}
+		
+		@Override
+		public void graphicAdded(final ERGraphic graphic) {
+		}
+		
+		@Override
+		public void graphicRemoved(final ERGraphic graphic) {
+		}
+		
+	}
+	
+	
+	protected static abstract class NewDevHandler extends AbstractHandler {
+		
+		
+		public NewDevHandler() {
+		}
+		
+		
+		protected abstract Tool getTool() throws CoreException;
+		
+		@Override
+		public Object execute(final ExecutionEvent event) throws ExecutionException {
+			try {
+				final Tool tool= getTool();
+				if (tool != null) {
+					tool.getQueue().add(new AbstractRToolRunnable(
+						"r/rj/gd/new", "New R Graphic") { //$NON-NLS-1$
+						
+						@Override
+						public void run(final RToolService r,
+								final IProgressMonitor monitor) throws CoreException {
+							r.evalVoid("rj.gd::rj.GD()", monitor); //$NON-NLS-1$
+						}
+						
+					});
+				}
+			}
+			catch (final CoreException e) {
+				if (e.getStatus().getSeverity() != IStatus.CANCEL) {
+					StatusManager.getManager().handle(new Status(IStatus.ERROR, RGraphics.BUNDLE_ID, -1,
+							"An error occurrend when creating a new graphic device.", e),
+							StatusManager.LOG | StatusManager.SHOW);
+				}
+			}
+			return null;
+		}
+		
+	}
+	
+	
+	private static class RGraphicComparator implements Comparator<RGraphicSession> {
+		
+		public RGraphicComparator() {
+		}
+		
+		@Override
+		public int compare(final RGraphicSession o1, final RGraphicSession o2) {
+			final Tool handle1= o1.graphic.getRHandle();
+			final Tool handle2= o2.graphic.getRHandle();
+			if (handle1 == null) {
+				if (handle2 == null) {
+					return 0;
+				}
+				return Integer.MIN_VALUE;
+			}
+			else if (handle2 == null) {
+				return Integer.MAX_VALUE;
+			}
+			if (handle1 != handle2) {
+				final int diff= handle1.getLabel(Tool.LONG_LABEL).compareTo(handle2.getLabel(Tool.LONG_LABEL));
+				if (diff != 0) {
+					return diff;
+				}
+			}
+			return o1.graphic.getDevId() - o2.graphic.getDevId();
+		}
+		
+	}
+	
+	
+	private static class OpenAdditionalViewHandler extends AbstractHandler {
+		
+		private final IViewSite viewSite;
+		
+		public OpenAdditionalViewHandler(final IViewSite viewSite) {
+			this.viewSite= viewSite;
+		}
+		
+		@Override
+		public Object execute(final ExecutionEvent event) throws ExecutionException {
+			try {
+				final String secondaryId= "t" + System.currentTimeMillis(); //$NON-NLS-1$
+				this.viewSite.getWorkbenchWindow().getActivePage().showView(this.viewSite.getId(),
+						secondaryId, IWorkbenchPage.VIEW_ACTIVATE );
+			}
+			catch (final PartInitException e) {
+				StatusManager.getManager().handle(new Status(IStatus.ERROR, RGraphics.BUNDLE_ID, -1,
+						"An error occurred when opening an additional R graphics view.", e));
+			}
+			return null;
+		}
+		
+	}
+	
+	private class PinPageAction extends SimpleContributionItem {
+		
+		public PinPageAction() {
+			super(SharedUIResources.getImages().getDescriptor(SharedUIResources.LOCTOOL_PIN_PAGE_IMAGE_ID),
+					SharedUIResources.getImages().getDescriptor(SharedUIResources.LOCTOOLD_PIN_PAGE_IMAGE_ID),
+					"Pin Graphic Page", "P", SimpleContributionItem.STYLE_CHECK);
+			setChecked(PageBookRGraphicView.this.pinPage);
+		}
+		
+		@Override
+		protected void execute() throws ExecutionException {
+			PageBookRGraphicView.this.pinPage= !PageBookRGraphicView.this.pinPage;
+			setChecked(PageBookRGraphicView.this.pinPage);
+		}
+		
+	}
+	
+	
+	private static ERGraphic newViewGraphic;
+	
+	private ERGraphicsManager manager;
+	private final ERGraphicsManager.ListenerShowExtension managerListener= new ERGraphicsManager.ListenerShowExtension() {
+		private ERGraphic toShow;
+		@Override
+		public int canShowGraphic(final ERGraphic graphic) {
+			return PageBookRGraphicView.this.canShowGraphic(graphic);
+		}
+		@Override
+		public void showGraphic(final ERGraphic graphic) {
+			this.toShow= graphic;
+			final IViewSite site= getViewSite();
+			try {
+				site.getPage().showView(site.getId(), site.getSecondaryId(), IWorkbenchPage.VIEW_VISIBLE);
+			}
+			catch (final PartInitException e) {}
+		}
+		@Override
+		public void graphicAdded(final ERGraphic graphic) {
+			add(graphic, graphic == this.toShow
+					|| (graphic.isActive() && (!PageBookRGraphicView.this.pinPage || getCurrentSession() == null)) );
+			this.toShow= null;
+		}
+		@Override
+		public void graphicRemoved(final ERGraphic graphic) {
+			final RGraphicSession session= getSession(graphic);
+			if (session != null) {
+				PageBookRGraphicView.super.closePage(session);
+			}
+		}
+	};
+	
+	private boolean pinPage;
+	
+	private final ERGraphic.Listener graphicListener= new ERGraphic.ListenerLocatorExtension() {
+		@Override
+		public void activated() {
+			updateTitle();
+		}
+		@Override
+		public void deactivated() {
+			updateTitle();
+		}
+		@Override
+		public void drawingStarted() {
+		}
+		@Override
+		public void drawingStopped() {
+		}
+		@Override
+		public void locatorStarted() {
+			updateTitle();
+		}
+		@Override
+		public void locatorStopped() {
+			updateTitle();
+		}
+	};
+	
+	private StatusLineContributionItem positionStatusLineItem;
+	
+	
+	public PageBookRGraphicView() {
+	}
+	
+	
+	@Override
+	public void init(final IViewSite site, final IMemento memento) throws PartInitException {
+		setSessionComparator(new RGraphicComparator());
+		super.init(site, memento);
+		this.manager= loadManager();
+	}
+	
+	protected abstract ERGraphicsManager loadManager();
+	
+	@Override
+	public void createPartControl(final Composite parent) {
+		super.createPartControl(parent);
+		if (this.manager != null) {
+			this.manager.addListener(this.managerListener);
+			ERGraphic active= newViewGraphic;
+			if (active != null) {
+				final List<? extends ERGraphic> graphics= this.manager.getAllGraphics();
+				for (final ERGraphic graphic : graphics) {
+					add(graphic, false);
+				}
+			}
+			else {
+				final List<? extends ERGraphic> graphics= this.manager.getAllGraphics();
+				for (final ERGraphic graphic : graphics) {
+					add(graphic, false);
+					if (graphic.isActive()) {
+						active= graphic;
+					}
+				}
+				if (active == null && !graphics.isEmpty()) {
+					active= graphics.get(graphics.size()-1);
+				}
+			}
+			if (active != null) {
+				final RGraphicSession session= getSession(active);
+				if (session != null) {
+					showPage(session);
+				}
+			}
+		}
+	}
+	
+	public RGraphicSession getSession(final ERGraphic graphic) {
+		final List<RGraphicSession> sessions= getSessions();
+		for (final RGraphicSession session : sessions) {
+			if (session.getGraphic() == graphic) {
+				return session;
+			}
+		}
+		return null;
+	}
+	
+	protected int canShowGraphic(final ERGraphic graphic) {
+		final RGraphicSession session= getCurrentSession();
+		int canShow;
+		if (session != null && session.getGraphic() == graphic) {
+			canShow= (this.pinPage) ? 20 : 10;
+		}
+		else if (this.pinPage && session != null) {
+			return -1;
+		}
+		else {
+			canShow= 1;
+		}
+		if (getViewSite().getPage().isPartVisible(this)) {
+			canShow+=2;
+		}
+		return canShow;
+	}
+	
+	protected void add(final ERGraphic graphic, final boolean show) {
+		super.newPage(new RGraphicSession(graphic), show);
+	}
+	
+	@Override
+	protected String getNoPageTitle() {
+		return "No graphics at this time.";
+	}
+	
+	@Override
+	protected IHandler2 createNewPageHandler() {
+		return null;
+	}
+	
+	
+	@Override
+	protected void initActions(final IServiceLocator serviceLocator, final HandlerCollection handlers) {
+		super.initActions(serviceLocator, handlers);
+		
+		final OpenAdditionalViewHandler openViewHandler= new OpenAdditionalViewHandler(getViewSite());
+		handlers.add(".OpenView", openViewHandler);
+	}
+	
+	@Override
+	protected void contributeToActionBars(final IServiceLocator serviceLocator, final IActionBars actionBars, final HandlerCollection handlers) {
+		super.contributeToActionBars(serviceLocator, actionBars, handlers);
+		
+		final IMenuManager menuManager= actionBars.getMenuManager();
+		menuManager.add(new Separator("view"));
+		final IViewDescriptor viewDescriptor= PlatformUI.getWorkbench().getViewRegistry().find(getViewSite().getId());
+		menuManager.add(new HandlerContributionItem(new CommandContributionItemParameter(serviceLocator,
+				null, HandlerContributionItem.NO_COMMAND_ID, null,
+				viewDescriptor.getImageDescriptor(), null, null,
+				NLS.bind("Open Additional {0} View", viewDescriptor.getLabel()), "O", null,
+				HandlerContributionItem.STYLE_PUSH, null, false), handlers.get(".OpenView")));
+		menuManager.add(new Separator("save"));
+		menuManager.add(new Separator(SharedUIResources.ADDITIONS_MENU_ID));
+		
+		menuManager.add(new Separator("settings")); //$NON-NLS-1$
+		menuManager.add(new SimpleContributionItem("Preferences...", "P") {
+			@Override
+			protected void execute() throws ExecutionException {
+				final Shell shell= getViewSite().getShell();
+				final String[] preferencePages= collectContextMenuPreferencePages();
+				if (preferencePages.length > 0 && (shell == null || !shell.isDisposed())) {
+					org.eclipse.ui.dialogs.PreferencesUtil.createPreferenceDialogOn(shell, preferencePages[0], preferencePages, null).open();
+				}
+			}
+		});
+		
+		final IToolBarManager toolBarManager= actionBars.getToolBarManager();
+		toolBarManager.insertAfter("page_control.change_page", new PinPageAction()); //$NON-NLS-1$
+		
+		final IStatusLineManager lineManager= actionBars.getStatusLineManager();
+		this.positionStatusLineItem= new StatusLineContributionItem(RGraphicCompositeActionSet.POSITION_STATUSLINE_ITEM_ID, 20);
+		lineManager.add(this.positionStatusLineItem);
+	}
+	
+	private String[] collectContextMenuPreferencePages() {
+		final List<String> pageIds= new ArrayList<>();
+		collectContextMenuPreferencePages(pageIds);
+		return pageIds.toArray(new String[pageIds.size()]);
+	}
+	
+	protected void collectContextMenuPreferencePages(final List<String> pageIds) {
+	}
+	
+	
+	@Override
+	protected RGraphicPage doCreatePage(final RGraphicSession session) {
+		return new RGraphicPage(session.getGraphic());
+	}
+	
+	@Override
+	protected void initPage(final IPageBookViewPage page) {
+		super.initPage(page);
+		if (page instanceof RGraphicPage) {
+			((RGraphicPage) page).init(this.positionStatusLineItem);
+		}
+	}
+	
+	@Override
+	public void closePage(final RGraphicSession session) {
+		final IStatus status= session.getGraphic().close();
+		if (status != null && status.getSeverity() < IStatus.ERROR) {
+			return;
+		}
+		super.closePage(session);
+	}
+	
+	@Override
+	protected void onPageShowing(final IPageBookViewPage page, final RGraphicSession session) {
+		if (session != null) {
+			session.getGraphic().addListener(this.graphicListener);
+		}
+		super.onPageShowing(page, session);
+	}
+	
+	@Override
+	protected void onPageHiding(final IPageBookViewPage page, final RGraphicSession session) {
+		if (session != null) {
+			session.getGraphic().removeListener(this.graphicListener);
+		}
+		if (this.positionStatusLineItem != null) {
+			this.positionStatusLineItem.setText(""); //$NON-NLS-1$
+		}
+		super.onPageHiding(page, session);
+	}
+	
+	@Override
+	public void dispose() {
+		if (this.manager != null) {
+			this.manager.removeListener(this.managerListener);
+		}
+		final RGraphicSession session= getCurrentSession();
+		if (session != null) {
+			session.getGraphic().removeListener(this.graphicListener);
+		}
+		super.dispose();
+	}
+	
+}
diff --git a/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/rj/eclient/graphics/RGraphicCanvas.java b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/rj/eclient/graphics/RGraphicCanvas.java
new file mode 100644
index 0000000..aef25a8
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/rj/eclient/graphics/RGraphicCanvas.java
@@ -0,0 +1,106 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.eclient.graphics;
+
+import java.util.Collections;
+import java.util.List;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.PaintEvent;
+import org.eclipse.swt.events.PaintListener;
+import org.eclipse.swt.graphics.GC;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.widgets.Canvas;
+import org.eclipse.swt.widgets.Composite;
+
+import org.eclipse.statet.internal.rj.eclient.graphics.GraphicInitialization;
+
+
+/**
+ * SWT control to paint an R graphic.
+ * <p>
+ * See {@link RGraphicComposite} for a higher API widget.</p>
+ */
+public class RGraphicCanvas extends Canvas implements PaintListener {
+	
+	
+	public static final List<ERGraphicInstruction> NO_GRAPHIC= Collections.emptyList();
+	
+	
+	private List<? extends ERGraphicInstruction> graphicInstructions;
+	private final DefaultGCRenderer renderer;
+	
+	private GraphicInitialization init;
+	
+	
+	public RGraphicCanvas(final Composite parent) {
+		super(parent, checkStyle(0));
+		
+		this.graphicInstructions= Collections.emptyList();
+		this.renderer= new DefaultGCRenderer();
+		addPaintListener(this);
+	}
+	
+	private static int checkStyle(int style) {
+		style |= SWT.NO_REDRAW_RESIZE | SWT.NO_BACKGROUND;
+		style |= SWT.DOUBLE_BUFFERED;
+		return style;
+	}
+	
+	public void setInstructions(final List<? extends ERGraphicInstruction> graphicData) {
+		this.graphicInstructions= graphicData;
+		if (!this.graphicInstructions.isEmpty()) {
+			this.init= (GraphicInitialization) this.graphicInstructions.get(0);
+		}
+		else {
+			this.init= null;
+		}
+	}
+	
+	@Override
+	public Point computeSize(final int wHint, final int hHint, final boolean changed) {
+		final GraphicInitialization init= this.init;
+		if (init != null) {
+			return new Point((int) (init.width + 0.5), (int) (init.height + 0.5));
+		}
+		else {
+			return super.computeSize(wHint, hHint, changed);
+		}
+	}
+	
+	public double widget2graphicsX(final double x) {
+		return x; // scale
+	}
+	
+	public double widget2graphicY(final double y) {
+		return y; // scale
+	}
+	
+	@Override
+	public void paintControl(final PaintEvent e) {
+		final GC gc= e.gc;
+		
+		final Rectangle clientArea= getClientArea();
+		setBackground(gc.getDevice().getSystemColor(SWT.COLOR_WIDGET_BACKGROUND));
+		drawBackground(gc, 0, 0, clientArea.width, clientArea.height);
+		if (this.graphicInstructions.isEmpty()) {
+			return;
+		}
+		this.renderer.clear(1.0f); // scale
+		this.renderer.paint(gc, this.graphicInstructions);
+	}
+	
+}
diff --git a/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/rj/eclient/graphics/RGraphicComposite.java b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/rj/eclient/graphics/RGraphicComposite.java
new file mode 100644
index 0000000..9654a69
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/rj/eclient/graphics/RGraphicComposite.java
@@ -0,0 +1,550 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.eclient.graphics;
+
+import java.util.List;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.DisposeEvent;
+import org.eclipse.swt.events.DisposeListener;
+import org.eclipse.swt.events.MouseEvent;
+import org.eclipse.swt.events.MouseListener;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Layout;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.ScrollBar;
+
+
+/**
+ * Composite to display an R graphic.
+ */
+public class RGraphicComposite extends Composite
+		implements ERGraphic.ListenerInstructionsExtension, ERGraphic.ListenerLocatorExtension {
+	
+	
+	/**
+	 * This class provides the layout for RGraphicComposite
+	 */
+	private static class ScrolledCompositeLayout extends Layout {
+		
+		static final int DEFAULT_WIDTH	= 64;
+		static final int DEFAULT_HEIGHT	= 64;
+		
+		
+		private boolean inLayout= false;
+		
+		
+		public ScrolledCompositeLayout() {
+		}
+		
+		
+		@Override
+		protected boolean flushCache(final Control control) {
+			return true;
+		}
+		
+		@Override
+		protected Point computeSize(final Composite composite, final int wHint, final int hHint, final boolean flushCache) {
+			final RGraphicComposite sc= (RGraphicComposite) composite;
+			final Point size= new Point(wHint, hHint);
+			if (wHint == SWT.DEFAULT) {
+				size.x= Math.max(DEFAULT_WIDTH, sc.width);
+			}
+			if (hHint == SWT.DEFAULT) {
+				size.y= Math.max(DEFAULT_HEIGHT, sc.height);
+			}
+			return size;
+		}
+		
+		@Override
+		protected void layout(final Composite composite, final boolean flushCache) {
+			if (this.inLayout || composite == null) {
+				return;
+			}
+			final RGraphicComposite sc= (RGraphicComposite) composite;
+			final ScrollBar hBar= sc.getHorizontalBar();
+			final ScrollBar vBar= sc.getVerticalBar();
+			
+			if (hBar.getSize().y >= sc.getSize().y) {
+				return;
+			}
+			if (vBar.getSize().x >= sc.getSize().x) {
+				return;
+			}
+			
+			this.inLayout= true;
+			
+			final Rectangle previousBounds= sc.canvas.getBounds();
+			boolean hVisible= sc.needHBar(previousBounds, false);
+			final boolean vVisible= sc.needVBar(previousBounds, hVisible);
+			if (!hVisible && vVisible) {
+				hVisible= sc.needHBar(previousBounds, vVisible);
+			}
+			hBar.setVisible(hVisible);
+			vBar.setVisible(vVisible);
+			
+			final Rectangle clientArea= sc.getClientArea();
+			final int x;
+			final int y;
+			final int width= sc.width;
+			final int height= sc.height;
+			hBar.setThumb(clientArea.width);
+			hBar.setPageIncrement(clientArea.width);
+			if (hVisible) {
+				x= (sc.changedLayout || previousBounds.x >= 0) ? 0 :
+						Math.max(previousBounds.x, clientArea.width - width);
+				hBar.setSelection(-x);
+			}
+			else {
+				x= (clientArea.width - width) / 2;
+				hBar.setSelection(0);
+			}
+			vBar.setThumb(clientArea.height);
+			vBar.setPageIncrement(clientArea.height);
+			if (vVisible) {
+				y= (sc.changedLayout || previousBounds.y >= 0) ? 0 :
+						Math.max(previousBounds.y, clientArea.height - height);
+				vBar.setSelection(-y);
+			}
+			else {
+				y= (clientArea.height - height) / 2;
+				vBar.setSelection(0);
+			}
+			
+			sc.changedLayout= false;
+			sc.canvas.setBounds(x, y, width, height);
+			this.inLayout= false;
+		}
+		
+	}
+	
+	private class PanListener implements Listener {
+		
+		private boolean started;
+		private Point startMouse;
+		
+		@Override
+		public void handleEvent(final Event event) {
+			switch (event.type) {
+			case SWT.MouseDown:
+				if (event.button == 2) {
+					this.started= true;
+					updateCursor();
+					
+					this.startMouse= checkedPoint(event);
+					return;
+				}
+				else {
+					this.started= false;
+					return;
+				}
+			case SWT.MouseExit:
+			case SWT.MouseMove:
+				if (this.started) {
+					pan(checkedPoint(event));
+					return;
+				}
+				else {
+					return;
+				}
+			case SWT.MouseUp:
+				if (this.started && event.button == 2) {
+					this.started= false;
+					updateCursor();
+					return;
+				}
+				else {
+					return;
+				}
+			case SWT.KeyDown:
+				switch (event.keyCode) {
+				case SWT.ARROW_DOWN:
+					if (update(getVerticalBar(), RGraphicComposite.this.panIncrement)) {
+						scrollV();
+					}
+					return;
+				case SWT.ARROW_UP:
+					if (update(getVerticalBar(), -RGraphicComposite.this.panIncrement)) {
+						scrollV();
+					}
+					return;
+				case SWT.ARROW_RIGHT:
+					if (update(getHorizontalBar(), RGraphicComposite.this.panIncrement)) {
+						scrollH();
+					}
+					return;
+				case SWT.ARROW_LEFT:
+					if (update(getHorizontalBar(), -RGraphicComposite.this.panIncrement)) {
+						scrollH();
+					}
+					return;
+				default:
+					return;
+				}
+			}
+		}
+		
+		private Point checkedPoint(final Event event) {
+			if (event.item == RGraphicComposite.this) {
+				return new Point(event.x, event.y);
+			}
+			else {
+				final Point point= ((Control) event.widget).toDisplay(event.x, event.y);
+				return RGraphicComposite.this.toControl(point);
+			}
+		}
+		
+		private void pan(final Point point) {
+			if (update(getHorizontalBar(), this.startMouse.x - point.x)) {
+				scrollH();
+			}
+			if (update(getVerticalBar(), this.startMouse.y - point.y)) {
+				scrollV();
+			}
+			this.startMouse= point;
+		}
+		
+		private boolean update(final ScrollBar bar, final int step) {
+			if (bar != null && bar.isVisible()) {
+				int selection= bar.getSelection() + step;
+				if (selection < 0) {
+					selection= 0;
+				}
+				else if (selection > bar.getMaximum()) {
+					selection= bar.getMaximum() - bar.getThumb();
+				}
+				bar.setSelection(selection);
+				return true;
+			}
+			return false;
+		}
+		
+	}
+	
+	
+	private static int checkStyle (final int style) {
+		final int mask= SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER | SWT.LEFT_TO_RIGHT | SWT.RIGHT_TO_LEFT;
+		return style & mask;
+	}
+	
+	
+	private ERGraphic graphic;
+	
+	private RGraphicCanvas canvas;
+	
+	private int width= 0;
+	private int height= 0;
+	
+	private boolean changedLayout;
+	private boolean changedContent;
+	
+	private int panIncrement;
+	private final PanListener panListener;
+	
+	private MouseListener locatorListener;
+	
+	
+	public RGraphicComposite(final Composite parent, final ERGraphic graphic) {
+		super(parent, checkStyle(SWT.H_SCROLL | SWT.V_SCROLL));
+		super.setLayout(new ScrolledCompositeLayout());
+		
+		this.panIncrement= 10;
+		
+		final ScrollBar hBar= getHorizontalBar();
+		hBar.setVisible(false);
+		hBar.addListener(SWT.Selection, new Listener() {
+			@Override
+			public void handleEvent(final Event event) {
+				scrollH();
+			}
+		});
+		hBar.setIncrement(this.panIncrement);
+		final ScrollBar vBar= getVerticalBar();
+		vBar.setVisible(false);
+		vBar.addListener(SWT.Selection, new Listener() {
+			@Override
+			public void handleEvent(final Event event) {
+				scrollV();
+			}
+		});
+		vBar.setIncrement(this.panIncrement);
+		addListener(SWT.Resize, new Listener() {
+			@Override
+			public void handleEvent(final Event event) {
+//				checkContentSize();
+			}
+		});
+		createCanvas();
+		final Listener updateListener= new Listener() {
+			@Override
+			public void handleEvent(final Event event) {
+				if (RGraphicComposite.this.changedContent) {
+					updateGraphic();
+				}
+			}
+		};
+		addListener(SWT.Show, updateListener);
+		addListener(SWT.Activate, updateListener);
+		
+		this.panListener= new PanListener();
+		addListener(SWT.MouseDown, this.panListener);
+		addListener(SWT.MouseMove, this.panListener);
+		addListener(SWT.MouseExit, this.panListener);
+		addListener(SWT.MouseUp, this.panListener);
+		addListener(SWT.KeyDown, this.panListener);
+		this.canvas.addListener(SWT.MouseDown, this.panListener);
+		this.canvas.addListener(SWT.MouseMove, this.panListener);
+		this.canvas.addListener(SWT.MouseExit, this.panListener);
+		this.canvas.addListener(SWT.MouseUp, this.panListener);
+		this.canvas.addListener(SWT.KeyDown, this.panListener);
+		
+		setGraphic(graphic);
+		
+		addDisposeListener(new DisposeListener() {
+			@Override
+			public void widgetDisposed(final DisposeEvent e) {
+				disconnect();
+			}
+		});
+	}
+	
+	private void createCanvas() {
+		this.canvas= new RGraphicCanvas(this);
+	}
+	
+	boolean needHBar(final Rectangle contentRect, final boolean vVisible) {
+		final Rectangle hostRect= getBounds();
+		hostRect.width-= 2 * getBorderWidth();
+		if (vVisible) {
+			hostRect.width-= getVerticalBar().getSize().x;
+		}
+		return (this.width > hostRect.width);
+	}
+	
+	boolean needVBar(final Rectangle contentRect, final boolean hVisible) {
+		final Rectangle hostRect= getBounds();
+		hostRect.height-= 2 * getBorderWidth();
+		if (hVisible) {
+			hostRect.height-= getHorizontalBar().getSize().y;
+		}
+		return (this.height > hostRect.height);
+	}
+	
+	private void scrollH() {
+		final Point location= this.canvas.getLocation();
+		final ScrollBar hBar= getHorizontalBar();
+		if (hBar != null && hBar.isVisible()) {
+			final int hSelection= hBar.getSelection();
+			this.canvas.setLocation(-hSelection, location.y);
+		}
+	}
+	
+	private void scrollV() {
+		final Point location= this.canvas.getLocation();
+		final ScrollBar vBar= getVerticalBar();
+		if (vBar != null && vBar.isVisible()) {
+			final int vSelection= vBar.getSelection();
+			this.canvas.setLocation(location.x, -vSelection);
+		}
+	}
+	
+	
+	protected void disconnect() {
+		if (this.graphic != null) {
+			this.graphic.removeListener(this);
+		}
+		locatorStopped();
+	}
+	
+	public void setGraphic(final ERGraphic graphic) {
+		disconnect();
+		
+		this.graphic= graphic;
+		if (this.graphic != null) {
+			this.graphic.addListener(this);
+		}
+		
+		instructionsChanged(true, null);
+		
+		if (this.graphic != null && this.graphic.isLocatorStarted()) {
+			locatorStarted();
+		}
+	}
+	
+	/**
+	 * {@inheritDoc}
+	 * <p>
+	 * Note: No Layout can be set on this Control because it already
+	 * manages the size and position of its children.</p>
+	 */
+	@Override
+	public void setLayout (final Layout layout) {
+		checkWidget();
+		return;
+	}
+	
+	@Override
+	public void activated() {
+	}
+	
+	@Override
+	public void deactivated() {
+	}
+	
+	@Override
+	public void drawingStarted() {
+	}
+	
+	@Override
+	public void instructionsChanged(final boolean reset, final List<ERGraphicInstruction> added) {
+		this.changedContent= true;
+		if (isVisible()) {
+			updateGraphic();
+		}
+	}
+	
+	@Override
+	public void drawingStopped() {
+	}
+	
+	@Override
+	public void locatorStarted() {
+		if (this.locatorListener == null) {
+			this.locatorListener= new MouseListener() {
+				@Override
+				public void mouseDown(final MouseEvent e) {
+					switch (e.button) { 
+					case 1:
+						RGraphicComposite.this.graphic.returnLocator(
+								RGraphicComposite.this.canvas.widget2graphicsX(e.x), RGraphicComposite.this.canvas.widget2graphicY(e.y));
+						break;
+					case 3:
+						RGraphicComposite.this.graphic.stopLocator(ERGraphic.LOCATOR_DONE);
+						break;
+					default:
+						break;
+					}
+				}
+				@Override
+				public void mouseUp(final MouseEvent e) {
+				}
+				@Override
+				public void mouseDoubleClick(final MouseEvent e) {
+				}
+			};
+			this.canvas.addMouseListener(this.locatorListener);
+			updateCursor();
+		}
+	}
+	
+	@Override
+	public void locatorStopped() {
+		if (this.locatorListener != null) {
+			this.canvas.removeMouseListener(this.locatorListener);
+			this.locatorListener= null;
+			updateCursor();
+		}
+	}
+	
+	private void updateCursor() {
+		if (this.panListener.started) {
+			this.canvas.setCursor(Display.getCurrent().getSystemCursor(SWT.CURSOR_HAND));
+		}
+		else if (this.locatorListener != null) {
+			this.canvas.setCursor(Display.getCurrent().getSystemCursor(SWT.CURSOR_CROSS));
+		}
+		else {
+			this.canvas.setCursor(null);
+		}
+	}
+	
+	private void checkContentSize() {
+		final Point size= this.canvas.computeSize(SWT.DEFAULT, SWT.DEFAULT);
+		if (this.width == size.x && this.height == size.y) {
+			return;
+		}
+		this.changedLayout= true;
+		this.width= size.x;
+		this.height= size.y;
+		this.canvas.setSize(this.width, this.height);
+		
+		final ScrollBar hBar= getHorizontalBar();
+		hBar.setMaximum(this.width);
+		
+		final ScrollBar vBar= getVerticalBar();
+		vBar.setMaximum(this.height);
+		layout(false);
+	}
+	
+	
+	public void redrawGraphic() {
+		this.canvas.redraw();
+	}
+	
+	private void updateGraphic() {
+		this.changedContent= false;
+		final List<? extends ERGraphicInstruction> instructions= (this.graphic != null) ?
+				this.graphic.getInstructions() : RGraphicCanvas.NO_GRAPHIC;
+		this.canvas.setInstructions(instructions);
+		checkContentSize();
+		this.canvas.redraw();
+	}
+	
+	public double[] getGraphicFitSize() {
+		final Rectangle bounds= getBounds();
+		return new double[] { bounds.width, bounds.height };
+	}
+	
+	public Control getControl() {
+		return this;
+	}
+	
+	/**
+	 * Returns the control on which the graphic is painted
+	 * 
+	 * @since 1.0
+	 */
+	public Control getGraphicWidget() {
+		return this.canvas;
+	}
+	
+	/**
+	 * Converts a horizontal display coordinate of the {@link #getGraphicWidget() graphic widget}
+	 * to its graphic coordinate value.
+	 * 
+	 * @since 1.0
+	 * @see ERGraphic Coordinate systems of R graphics
+	 */
+	public double convertWidget2GraphicX(final int x) {
+		return this.canvas.widget2graphicsX(x);
+	}
+	
+	/**
+	 * Converts a vertical display coordinate of the {@link #getGraphicWidget() graphic widget}
+	 * to its graphic coordinate value.
+	 * 
+	 * @since 1.0
+	 * @see ERGraphic Coordinate systems of R graphics
+	 */
+	public double convertWidget2GraphicY(final int y) {
+		return this.canvas.widget2graphicY(y);
+	}
+	
+}
diff --git a/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/rj/eclient/graphics/RGraphicCompositeActionSet.java b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/rj/eclient/graphics/RGraphicCompositeActionSet.java
new file mode 100644
index 0000000..fc7fff4
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/rj/eclient/graphics/RGraphicCompositeActionSet.java
@@ -0,0 +1,485 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.eclient.graphics;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.commands.IHandler2;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.jface.action.IToolBarManager;
+import org.eclipse.jface.action.Separator;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.resource.ImageRegistry;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.ui.IActionBars;
+import org.eclipse.ui.menus.CommandContributionItemParameter;
+import org.eclipse.ui.services.IServiceLocator;
+
+import org.eclipse.statet.jcommons.collections.CopyOnWriteIdentityListSet;
+import org.eclipse.statet.jcommons.collections.ImIdentityList;
+
+import org.eclipse.statet.ecommons.ts.core.SystemRunnable;
+import org.eclipse.statet.ecommons.ts.core.Tool;
+import org.eclipse.statet.ecommons.ui.SharedUIResources;
+import org.eclipse.statet.ecommons.ui.actions.HandlerCollection;
+import org.eclipse.statet.ecommons.ui.actions.HandlerContributionItem;
+
+import org.eclipse.statet.internal.rj.eclient.graphics.RGraphicsPlugin;
+import org.eclipse.statet.rj.eclient.core.AbstractRToolRunnable;
+import org.eclipse.statet.rj.eclient.core.RToolService;
+import org.eclipse.statet.rj.eclient.graphics.util.AbstractLocalLocator;
+
+
+/**
+ * Actions for R graphics in an {@link RGraphicComposite}.
+ */
+public class RGraphicCompositeActionSet implements ERGraphic.ListenerLocatorExtension {
+	
+	
+	public static final String POSITION_STATUSLINE_ITEM_ID= "position"; //$NON-NLS-1$
+	
+	public static final String CONTEXT_MENU_GROUP_ID= "context"; //$NON-NLS-1$
+	public static final String SIZE_MENU_GROUP_ID= "size"; //$NON-NLS-1$
+	
+	private static final String LOCATOR_DONE_COMMAND_ID= ".locator.done"; //$NON-NLS-1$
+	private static final String LOCATOR_CANCEL_COMMAND_ID= ".locator.cancel"; //$NON-NLS-1$
+	private static final String RESIZE_FIT_COMMAND_ID= ".resize.fit"; //$NON-NLS-1$
+	
+	
+	public static interface LocationListener {
+		
+		void loading();
+		
+		void located(double x, double y);
+		
+	}
+	
+	
+	private class ResizeFitRHandler extends AbstractHandler {
+		
+		public ResizeFitRHandler() {
+		}
+		
+		@Override
+		public void setEnabled(final Object evaluationContext) {
+			setBaseEnabled(RGraphicCompositeActionSet.this.graphic != null);
+		}
+		
+		@Override
+		public Object execute(final ExecutionEvent event) throws ExecutionException {
+			if (RGraphicCompositeActionSet.this.graphic == null) {
+				return null;
+			}
+			final double[] size= RGraphicCompositeActionSet.this.graphicComposite.getGraphicFitSize();
+			final IStatus status= RGraphicCompositeActionSet.this.graphic.resize(size[0], size[1]);
+			if (status == null || !status.isOK()) {
+				// TODO: Status message
+				Display.getCurrent().beep();
+			}
+			return null;
+		}
+		
+	}
+	
+	protected class StopLocatorHandler extends AbstractHandler {
+		
+		private final String type;
+		
+		public StopLocatorHandler(final String type) {
+			this.type= type;
+		}
+		
+		@Override
+		public void setEnabled(final Object evaluationContext) {
+			setBaseEnabled(RGraphicCompositeActionSet.this.graphic != null && RGraphicCompositeActionSet.this.graphic.isLocatorStarted()
+					&& RGraphicCompositeActionSet.this.graphic.getLocatorStopTypes().contains(this.type) );
+		}
+		
+		@Override
+		public Object execute(final ExecutionEvent event) throws ExecutionException {
+			if (RGraphicCompositeActionSet.this.graphic == null) {
+				return null;
+			}
+			RGraphicCompositeActionSet.this.graphic.stopLocator(this.type);
+			return null;
+		}
+		
+	}
+	
+	private static abstract class ConversionRunnable extends AbstractRToolRunnable implements SystemRunnable {
+		
+		private final ERGraphic graphic;
+		
+		private boolean scheduled;
+		
+		private double[] todoSource;
+		
+		private double[] convertedSource;
+		private double[] convertedTarget;
+		
+		
+		public ConversionRunnable(final ERGraphic graphic) {
+			super("r/rjgd/position", "Converting graphic coordinates"); //$NON-NLS-1$
+			this.graphic= graphic;
+		}
+		
+		
+		public boolean schedule(final double[] source) {
+			synchronized (this) {
+				this.todoSource= source;
+				if (this.scheduled) {
+					return true;
+				}
+				final IStatus status= this.graphic.getRHandle().getQueue().addHot(this);
+				if (status.isOK()) {
+					this.scheduled= true;
+					return true;
+				}
+				return false;
+			}
+		}
+		
+		public void cancel() {
+			synchronized (this) {
+				if (this.scheduled) {
+					this.scheduled= false;
+					this.todoSource= null;
+					this.graphic.getRHandle().getQueue().removeHot(this);
+				}
+			}
+		}
+		
+		
+		@Override
+		public boolean canRunIn(final Tool tool) {
+			return (tool == this.graphic.getRHandle() && super.canRunIn(tool));
+		}
+		
+		@Override
+		public boolean changed(final int event, final Tool tool) {
+			switch (event) {
+			case MOVING_FROM:
+				return false;
+			case REMOVING_FROM:
+			case BEING_ABANDONED:
+			case FINISHING_ERROR:
+			case FINISHING_CANCEL:
+				synchronized (this) {
+					this.scheduled= false;
+					break;
+				}
+			case FINISHING_OK:
+				converted(this.graphic, this.convertedSource, this.convertedTarget);
+				break;
+			}
+			return true;
+		}
+		
+		@Override
+		protected void run(final RToolService service,
+				final IProgressMonitor monitor) throws CoreException {
+			double[] source= null;
+			double[] target= null;
+			while (true) {
+				synchronized (this) {
+					this.convertedSource= source;
+					this.convertedTarget= target;
+					
+					source= this.todoSource;
+					if (source == null) {
+						this.scheduled= false;
+						return;
+					}
+					this.todoSource= null;
+				}
+				target= this.graphic.convertGraphic2User(source, monitor);
+			}
+		}
+		
+		protected abstract void converted(ERGraphic graphic, double[] source, double[] target);
+		
+	}
+	
+	private class MouseLocationListener implements Listener {
+		
+		private double[] currentGraphic;
+		private double[] currentTarget;
+		
+		
+		@Override
+		public void handleEvent(final Event event) {
+			switch (event.type) {
+			case SWT.MouseDown:
+				if (event.button == 1) {
+					final double[] request= this.currentGraphic= new double[] {
+							RGraphicCompositeActionSet.this.graphicComposite.convertWidget2GraphicX(event.x),
+							RGraphicCompositeActionSet.this.graphicComposite.convertWidget2GraphicY(event.y) };
+					this.currentTarget= null;
+					event.display.timerExec(1000, new Runnable() {
+						@Override
+						public void run() {
+							if (MouseLocationListener.this.currentTarget == null && MouseLocationListener.this.currentGraphic == request
+									&& !RGraphicCompositeActionSet.this.graphicComposite.isDisposed()) {
+								notifyMouseLocationListeners(null);
+							}
+						}
+					});
+					if (RGraphicCompositeActionSet.this.mouseLocationRunnable == null) {
+						RGraphicCompositeActionSet.this.mouseLocationRunnable= new ConversionRunnable(RGraphicCompositeActionSet.this.graphic) {
+							@Override
+							protected void converted(final ERGraphic graphic,
+									final double[] source, final double[] target) {
+								if (RGraphicCompositeActionSet.this.graphic == graphic) {
+									RGraphicCompositeActionSet.this.display.asyncExec(new Runnable() {
+										@Override
+										public void run() {
+											if (RGraphicCompositeActionSet.this.graphic == graphic
+													&& source != null && target != null && MouseLocationListener.this.currentGraphic != null
+													&& source[0] == MouseLocationListener.this.currentGraphic[0] && source[1] == MouseLocationListener.this.currentGraphic[1]) {
+												MouseLocationListener.this.currentTarget= target;
+												notifyMouseLocationListeners(target);
+											}
+										}
+									});
+								}
+							}
+						};
+					}
+					RGraphicCompositeActionSet.this.mouseLocationRunnable.schedule(this.currentGraphic);
+				}
+				break;
+			}
+		}
+		
+	}
+	
+	
+	private final List<IActionBars> actionBars= new ArrayList<>(4);
+	
+	private ERGraphic graphic;
+	private final RGraphicComposite graphicComposite;
+	private final Display display;
+	
+	private HandlerCollection handlerCollection;
+	
+	private final CopyOnWriteIdentityListSet<LocationListener> mouseLocationListeners= new CopyOnWriteIdentityListSet<>();
+	private MouseLocationListener mouseListenerListener;
+	private ConversionRunnable mouseLocationRunnable;
+	
+	
+	public RGraphicCompositeActionSet(final RGraphicComposite composite) {
+		this.graphicComposite= composite;
+		this.display= this.graphicComposite.getDisplay();
+	}
+	
+	
+	public void setGraphic(final ERGraphic graphic) {
+		if (this.graphic != null) {
+			this.graphic.removeListener(this);
+			if (this.mouseLocationRunnable != null) {
+				this.mouseLocationRunnable.cancel();
+				this.mouseLocationRunnable= null;
+			}
+		}
+		this.graphic= graphic;
+		if (this.graphic != null) {
+			this.graphic.addListener(this);
+		}
+		
+		update();
+	}
+	
+	public void initActions(final IServiceLocator serviceLocator) {
+		this.handlerCollection= new HandlerCollection();
+		this.handlerCollection.add(LOCATOR_DONE_COMMAND_ID,
+				new StopLocatorHandler(ERGraphic.LOCATOR_DONE) );
+		this.handlerCollection.add(LOCATOR_CANCEL_COMMAND_ID,
+				new StopLocatorHandler(ERGraphic.LOCATOR_CANCEL) );
+		this.handlerCollection.add(RESIZE_FIT_COMMAND_ID,
+				new ResizeFitRHandler() );
+	}
+	
+	public void contributeToActionsBars(final IServiceLocator serviceLocator,
+			final IActionBars actionBars) {
+		this.actionBars.add(actionBars);
+		
+		final IToolBarManager toolBar= actionBars.getToolBarManager();
+		if (toolBar.find(CONTEXT_MENU_GROUP_ID) == null) {
+			toolBar.insertBefore(SharedUIResources.ADDITIONS_MENU_ID, new Separator(CONTEXT_MENU_GROUP_ID));
+		}
+		if (toolBar.find(SIZE_MENU_GROUP_ID) == null) {
+			toolBar.insertBefore(SharedUIResources.ADDITIONS_MENU_ID, new Separator(SIZE_MENU_GROUP_ID));
+		}
+		
+		final ImageRegistry rGraphicsImageRegistry= RGraphicsPlugin.getDefault().getImageRegistry();
+		
+		toolBar.appendToGroup(CONTEXT_MENU_GROUP_ID, new HandlerContributionItem(new CommandContributionItemParameter(
+				serviceLocator, null, HandlerContributionItem.NO_COMMAND_ID, null,
+				rGraphicsImageRegistry.getDescriptor(RGraphicsPlugin.IMG_LOCTOOL_LOCATOR_DONE), null, null,
+				"Stop Locator", null, null, HandlerContributionItem.STYLE_PUSH, null, true),
+				this.handlerCollection.get(LOCATOR_DONE_COMMAND_ID) ));
+		toolBar.appendToGroup(CONTEXT_MENU_GROUP_ID, new HandlerContributionItem(new CommandContributionItemParameter(
+				serviceLocator, null, HandlerContributionItem.NO_COMMAND_ID, null,
+				rGraphicsImageRegistry.getDescriptor(RGraphicsPlugin.IMG_LOCTOOL_LOCATOR_CANCEL), null, null,
+				"Cancel Locator", null, null, HandlerContributionItem.STYLE_PUSH, null, true),
+				this.handlerCollection.get(LOCATOR_CANCEL_COMMAND_ID) ));
+	}
+	
+	protected void addTestLocator(final IServiceLocator serviceLocator, final IActionBars actionBars) {
+		final IToolBarManager toolBar= actionBars.getToolBarManager();
+		
+		final IHandler2 handler= new AbstractHandler() {
+			@Override
+			public void setEnabled(final Object evaluationContext) {
+				setBaseEnabled(RGraphicCompositeActionSet.this.graphic != null && !RGraphicCompositeActionSet.this.graphic.isLocatorStarted());
+			}
+			@Override
+			public Object execute(final ExecutionEvent event) throws ExecutionException {
+				if (RGraphicCompositeActionSet.this.graphic == null || RGraphicCompositeActionSet.this.graphic.isLocatorStarted()) {
+					return null;
+				}
+				final AbstractLocalLocator locator= new AbstractLocalLocator(RGraphicCompositeActionSet.this.graphic) {
+					@Override
+					protected void finished(final List<double[]> graphic, final List<double[]> user) {
+						final StringBuilder sb= new StringBuilder();
+						for (int i= 0; i < user.size(); i++) {
+							sb.append(Arrays.toString(user.get(i))).append("\n");
+						}
+						Display.getDefault().asyncExec(new Runnable() {
+							@Override
+							public void run() {
+								MessageDialog.openInformation(null, "Locator Result",
+										sb.toString());
+							}
+						});
+					};
+					@Override
+					protected void canceled() {
+					};
+				};
+				locator.start();
+				return null;
+			}
+		};
+		this.handlerCollection.add(".locator.startTest", handler);
+		toolBar.appendToGroup(CONTEXT_MENU_GROUP_ID, new HandlerContributionItem(new CommandContributionItemParameter(
+				serviceLocator, null, HandlerContributionItem.NO_COMMAND_ID, null,
+				SharedUIResources.getImages().getDescriptor(SharedUIResources.LOCTOOL_SORT_SCORE_IMAGE_ID), null, null,
+				"Test Locator", null, null, HandlerContributionItem.STYLE_PUSH, null, false),
+				handler ));
+	}
+	
+	protected void addSizeActions(final IServiceLocator serviceLocator, final IActionBars actionBars) {
+		final IToolBarManager toolBar= actionBars.getToolBarManager();
+		
+		final ImageRegistry rGraphicsImageRegistry= RGraphicsPlugin.getDefault().getImageRegistry();
+		
+		toolBar.appendToGroup(SIZE_MENU_GROUP_ID, new HandlerContributionItem(new CommandContributionItemParameter(
+				serviceLocator, null, HandlerContributionItem.NO_COMMAND_ID, null,
+				rGraphicsImageRegistry.getDescriptor(RGraphicsPlugin.IMG_LOCTOOL_RESIZE_FIT_R), null, null,
+				"Resize Fit in R", null, null, HandlerContributionItem.STYLE_PUSH, null, false ),
+				this.handlerCollection.get(RESIZE_FIT_COMMAND_ID) ));
+		
+		update();
+	}
+	
+	protected void update() {
+		if (this.actionBars.isEmpty()) {
+			return;
+		}
+		
+		this.handlerCollection.update(null);
+		
+		for (final IActionBars actionBars : this.actionBars) {
+			actionBars.getToolBarManager().update(true);
+		}
+	}
+	
+	
+	@Override
+	public void activated() {
+	}
+	
+	@Override
+	public void deactivated() {
+	}
+	
+	@Override
+	public void drawingStarted() {
+	}
+	
+	@Override
+	public void drawingStopped() {
+	}
+	
+	@Override
+	public void locatorStarted() {
+		update();
+	}
+	
+	@Override
+	public void locatorStopped() {
+		update();
+	}
+	
+	
+	public void addMouseClickLocationListener(final LocationListener listener) {
+		this.mouseLocationListeners.add(listener);
+		if (this.mouseListenerListener == null) {
+			this.mouseListenerListener= new MouseLocationListener();
+			final Control widget= this.graphicComposite.getGraphicWidget();
+			widget.addListener(SWT.MouseDown, this.mouseListenerListener);
+		}
+	}
+	
+	public void removeMouseLocationListener(final LocationListener listener) {
+		this.mouseLocationListeners.remove(listener);
+	}
+	
+	private void notifyMouseLocationListeners(final double[] xy) {
+		final ImIdentityList<LocationListener> listeners= this.mouseLocationListeners.toList();
+		if (xy != null) {
+			for (final LocationListener listener : listeners) {
+				listener.located(xy[0], xy[1]);
+			}
+		}
+		else {
+			for (final LocationListener listener : listeners) {
+				listener.loading();
+			}
+		}
+	}
+	
+	
+	public void dispose(final IActionBars actionBars) {
+		this.actionBars.remove(actionBars);
+	}
+	
+	public void dispose() {
+		setGraphic(null);
+	}
+	
+}
diff --git a/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/rj/eclient/graphics/RGraphicPage.java b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/rj/eclient/graphics/RGraphicPage.java
new file mode 100644
index 0000000..33401f0
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/rj/eclient/graphics/RGraphicPage.java
@@ -0,0 +1,185 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.eclient.graphics;
+
+import java.text.DecimalFormat;
+import java.text.DecimalFormatSymbols;
+import java.util.Locale;
+
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.commands.IHandler2;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.jface.action.IToolBarManager;
+import org.eclipse.jface.action.Separator;
+import org.eclipse.jface.action.StatusLineContributionItem;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.ui.IActionBars;
+import org.eclipse.ui.IWorkbenchCommandConstants;
+import org.eclipse.ui.handlers.IHandlerService;
+import org.eclipse.ui.part.Page;
+import org.eclipse.ui.services.IServiceLocator;
+
+import org.eclipse.statet.ecommons.runtime.core.StatusChangeListener;
+import org.eclipse.statet.ecommons.ui.SharedUIResources;
+import org.eclipse.statet.ecommons.ui.util.UIAccess;
+
+import org.eclipse.statet.rj.eclient.graphics.RGraphicCompositeActionSet.LocationListener;
+
+
+/**
+ * Single graphic page for {@link PageBookRGraphicView}.
+ */
+public class RGraphicPage extends Page implements StatusChangeListener {
+	
+	
+	private final ERGraphic graphic;
+	
+	private RGraphicComposite control;
+	
+	private RGraphicCompositeActionSet actions;
+	
+	private StatusLineContributionItem locationStatusItem;
+	private String locationStatusText;
+	private LocationListener mouseLocationListener;
+	
+	
+	public RGraphicPage(final ERGraphic graphic) {
+		this.graphic= graphic;
+	}
+	
+	
+	protected ERGraphic getGraphic() {
+		return this.graphic;
+	}
+	
+	protected void init(final StatusLineContributionItem locationStatusItem) {
+		this.locationStatusItem= locationStatusItem;
+	}
+	
+	@Override
+	public void createControl(final Composite parent) {
+		this.control= new RGraphicComposite(parent, this.graphic);
+		
+		initActions(getSite(), getSite().getActionBars());
+		
+		this.graphic.addMessageListener(this);
+		statusChanged(this.graphic.getMessage());
+	}
+	
+	protected void initActions(final IServiceLocator serviceLocator, final IActionBars actionBars) {
+		final IHandlerService handlerService= serviceLocator.getService(IHandlerService.class);
+		
+		final IHandler2 refreshHandler= new AbstractHandler() {
+			@Override
+			public Object execute(final ExecutionEvent event) throws ExecutionException {
+				RGraphicPage.this.control.redrawGraphic();
+				return null;
+			}
+		};
+		handlerService.activateHandler(IWorkbenchCommandConstants.FILE_REFRESH, refreshHandler);
+		
+		final IToolBarManager toolBar= actionBars.getToolBarManager();
+		toolBar.insertBefore(SharedUIResources.ADDITIONS_MENU_ID, new Separator(RGraphicCompositeActionSet.CONTEXT_MENU_GROUP_ID));
+		toolBar.insertBefore(SharedUIResources.ADDITIONS_MENU_ID, new Separator(RGraphicCompositeActionSet.SIZE_MENU_GROUP_ID));
+		
+		this.actions= createActionSet();
+		this.actions.setGraphic(this.graphic);
+		this.actions.initActions(serviceLocator);
+		this.actions.contributeToActionsBars(serviceLocator, actionBars);
+		
+		// Can find wrong item from other view
+//		locationStatusItem= (StatusLineContributionItem) actionBars.getStatusLineManager().find(RGraphicCompositeActionSet.POSITION_STATUSLINE_ITEM_ID);
+		if (this.locationStatusItem != null) {
+			this.mouseLocationListener= new LocationListener() {
+				
+				final DecimalFormat format= new DecimalFormat("0.0####", new DecimalFormatSymbols(Locale.US)); //$NON-NLS-1$
+				
+				@Override
+				public void loading() {
+					if (RGraphicPage.this.locationStatusItem != null) {
+						RGraphicPage.this.locationStatusItem.setText("..."); //$NON-NLS-1$
+					}
+				}
+				
+				@Override
+				public void located(final double x, final double y) {
+					if (RGraphicPage.this.locationStatusItem != null && UIAccess.isOkToUse(RGraphicPage.this.control)) {
+						if (Double.isNaN(x) || Double.isInfinite(x)
+								|| Double.isNaN(y) || Double.isInfinite(y) ) {
+							RGraphicPage.this.locationStatusText= "NA"; //$NON-NLS-1$
+						}
+						else {
+							final StringBuilder sb= new StringBuilder(32);
+							sb.append('(');
+							sb.append(this.format.format(x));
+							sb.append(", "); //$NON-NLS-1$
+							sb.append(this.format.format(y));
+							sb.append(')');
+							RGraphicPage.this.locationStatusText= sb.toString();
+						}
+						RGraphicPage.this.locationStatusItem.setText(RGraphicPage.this.locationStatusText);
+					}
+				}
+			};
+			this.actions.addMouseClickLocationListener(this.mouseLocationListener);
+		}
+	}
+	
+	protected RGraphicCompositeActionSet createActionSet() {
+		return new RGraphicCompositeActionSet(this.control);
+	}
+	
+	@Override
+	public void statusChanged(final IStatus status) {
+		final String message;
+		if (status.getSeverity() > 0) {
+			message= status.getMessage();
+		}
+		else {
+			message= null;
+		}
+		getSite().getActionBars().getStatusLineManager().setMessage(message);
+	}
+	
+	@Override
+	public Control getControl() {
+		return this.control;
+	}
+	
+	protected RGraphicComposite getGraphicComposite() {
+		return this.control;
+	}
+	
+	@Override
+	public void setFocus() {
+		this.control.setFocus();
+	}
+	
+	@Override
+	public void dispose() {
+		if (this.actions != null) {
+			this.actions.dispose();
+			this.actions= null;
+		}
+		if (this.graphic != null) {
+			this.graphic.removeMessageListener(this);
+		}
+		super.dispose();
+	}
+	
+}
diff --git a/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/rj/eclient/graphics/RGraphics.java b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/rj/eclient/graphics/RGraphics.java
new file mode 100644
index 0000000..29b979c
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/rj/eclient/graphics/RGraphics.java
@@ -0,0 +1,59 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.eclient.graphics;
+
+
+public class RGraphics {
+	
+	
+	public static final String BUNDLE_ID= "org.eclipse.statet.rj.eclient.graphics"; //$NON-NLS-1$
+	
+	
+	public static final String PREF_DISPLAY_QUALIFIER= BUNDLE_ID + "/display"; //$NON-NLS-1$
+	
+	/**
+	 * Preference key: custom dpi setting (string "horizontal,vertical"), none/empty for default
+	 * 
+	 * @since 1.0
+	 */
+	public static final String PREF_DISPLAY_CUSTOM_DPI_KEY= "dpi.xy"; //$NON-NLS-1$
+	
+	
+	public static final String FONTS_PREF_QUALIFIER= BUNDLE_ID + "/fonts"; //$NON-NLS-1$
+	public static final String PREF_FONTS_SERIF_FONTNAME_KEY= "serif.name"; //$NON-NLS-1$
+	public static final String PREF_FONTS_SANS_FONTNAME_KEY= "sans.name"; //$NON-NLS-1$
+	public static final String PREF_FONTS_MONO_FONTNAME_KEY= "mono.name"; //$NON-NLS-1$
+	
+	/**
+	 * Preference key: if (boolean) a special symbol font should be used
+	 * 
+	 * @since 1.0
+	 */
+	public static final String PREF_FONTS_SYMBOL_USE_KEY= "symbol.use"; //$NON-NLS-1$
+	/**
+	 * Preference key: name (string) of the symbol font (if special symbol font is enabled)
+	 * 
+	 * @since 1.0
+	 */
+	public static final String PREF_FONTS_SYMBOL_FONTNAME_KEY= "symbol.name"; //$NON-NLS-1$
+	/**
+	 * Preference key: encoding (known key) of the symbol font (if special symbol font is enabled)
+	 * 
+	 * @since 1.0
+	 */
+	public static final String PREF_FONTS_SYMBOL_ENCODING_KEY= "symbol.enc"; //$NON-NLS-1$
+	
+	
+}
diff --git a/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/rj/eclient/graphics/RGraphicsPreferencePage.java b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/rj/eclient/graphics/RGraphicsPreferencePage.java
new file mode 100644
index 0000000..7829a05
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/rj/eclient/graphics/RGraphicsPreferencePage.java
@@ -0,0 +1,603 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.eclient.graphics;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.osgi.service.prefs.BackingStoreException;
+
+import org.eclipse.core.databinding.AggregateValidationStatus;
+import org.eclipse.core.databinding.DataBindingContext;
+import org.eclipse.core.databinding.UpdateValueStrategy;
+import org.eclipse.core.databinding.observable.Realm;
+import org.eclipse.core.databinding.observable.value.IValueChangeListener;
+import org.eclipse.core.databinding.observable.value.ValueChangeEvent;
+import org.eclipse.core.databinding.observable.value.WritableValue;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.preferences.DefaultScope;
+import org.eclipse.core.runtime.preferences.IEclipsePreferences;
+import org.eclipse.core.runtime.preferences.IScopeContext;
+import org.eclipse.core.runtime.preferences.InstanceScope;
+import org.eclipse.jface.databinding.swt.SWTObservables;
+import org.eclipse.jface.preference.PreferencePage;
+import org.eclipse.jface.resource.JFaceResources;
+import org.eclipse.jface.viewers.ArrayContentProvider;
+import org.eclipse.jface.viewers.ComboViewer;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.SWTError;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.graphics.Font;
+import org.eclipse.swt.graphics.FontData;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.FontDialog;
+import org.eclipse.swt.widgets.Group;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchPreferencePage;
+import org.eclipse.ui.statushandlers.StatusManager;
+
+import org.eclipse.statet.ecommons.databinding.DecimalValidator;
+import org.eclipse.statet.ecommons.ui.components.StatusInfo;
+import org.eclipse.statet.ecommons.ui.dialogs.DialogUtils;
+import org.eclipse.statet.ecommons.ui.util.LayoutUtil;
+
+
+/**
+ * Preference page with options to configure R graphic options:
+ * <ul>
+ *    <li>Default font families ('serif', 'sans', 'mono')</li>
+ * </ul>
+ * 
+ * The page is not registered by this plug-in.
+ */
+public class RGraphicsPreferencePage extends PreferencePage implements IWorkbenchPreferencePage {
+	
+	
+	public static double[] parseDPI(final String prefValue) {
+		if (prefValue != null) {
+			final String[] strings= prefValue.split(",");
+			if (strings.length == 2) {
+				try {
+					return new double[] {
+							Double.parseDouble(strings[0]),
+							Double.parseDouble(strings[1]),
+					};
+				}
+				catch (final Exception e) {}
+			}
+		}
+		return null;
+	}
+	
+	
+	private static class FontPref {
+		
+		final String prefKey;
+		
+		String defaultName;
+		String currentName;
+		
+		Font currentFont;
+		
+		Label valueLabel;
+		
+		
+		public FontPref(final String key) {
+			this.prefKey= key;
+		}
+		
+		
+		@Override
+		public int hashCode() {
+			return this.prefKey.hashCode();
+		}
+		
+		@Override
+		public boolean equals(final Object obj) {
+			return (this == obj
+					|| (obj instanceof FontPref
+							&& this.prefKey.equals(((FontPref) obj).prefKey) ));
+		}
+		
+	}
+	
+	private static class Encoding {
+		
+		final String label;
+		final String prefValue;
+		
+		
+		public Encoding(final String label, final String prefValue) {
+			this.label= label;
+			this.prefValue= prefValue;
+		}
+		
+		
+		@Override
+		public int hashCode() {
+			return this.prefValue.hashCode();
+		}
+		
+		@Override
+		public boolean equals(final Object obj) {
+			return (this == obj
+					|| (obj instanceof Encoding
+							&& this.prefValue.equals(((Encoding) obj).prefValue) ));
+		}
+		
+		@Override
+		public String toString() {
+			return this.label.toString();
+		};
+		
+	}
+	
+	private static final Encoding[] SYMBOL_ENCODINGS= new Encoding[] {
+			new Encoding("Unicode", "Unicode"),
+			new Encoding("Adobe Symbol", "AdobeSymbol"),
+	};
+	
+	private static final Encoding SYMBOL_ENCODING_DEFAULT= SYMBOL_ENCODINGS[1];
+	
+	
+	private DataBindingContext dbc;
+	
+	private FontPref serifPref;
+	private FontPref sansPref;
+	private FontPref monoPref;
+	private FontPref symbolFontPref;
+	private FontPref[] fontPrefs;
+	private Button symbolUseControl;
+	private ComboViewer symbolEncodingControl;
+	private Control[] symbolChildControls;
+	
+	private final int size= 10;
+	
+	private Button customDpiControl;
+	private Composite customDpiComposite;
+	private Text customHDpiControl;
+	private Text customVDpiControl;
+	
+	private boolean customEnabled;
+	private WritableValue customHDpiVisibleValue;
+	private WritableValue customVDpiVisibleValue;
+	private double customHDpiUserValue;
+	private double customVDpiUserValue;
+	
+	
+	/**
+	 * Created via extension point
+	 */
+	public RGraphicsPreferencePage() {
+	}
+	
+	
+	@Override
+	public void init(final IWorkbench workbench) {
+		this.serifPref= new FontPref(RGraphics.PREF_FONTS_SERIF_FONTNAME_KEY);
+		this.sansPref= new FontPref(RGraphics.PREF_FONTS_SANS_FONTNAME_KEY);
+		this.monoPref= new FontPref(RGraphics.PREF_FONTS_MONO_FONTNAME_KEY);
+		this.symbolFontPref= new FontPref(RGraphics.PREF_FONTS_SYMBOL_FONTNAME_KEY);
+		this.fontPrefs= new FontPref[] { this.serifPref, this.sansPref, this.monoPref, this.symbolFontPref };
+		
+		final IEclipsePreferences node= DefaultScope.INSTANCE.getNode(RGraphics.FONTS_PREF_QUALIFIER);
+		for (final FontPref pref : this.fontPrefs) {
+			pref.defaultName= (node != null) ? node.get(pref.prefKey, "") : "";
+		}
+	}
+	
+	@Override
+	protected Control createContents(final Composite parent) {
+		final Composite pageComposite= new Composite(parent, SWT.NONE);
+		pageComposite.setLayout(LayoutUtil.applyCompositeDefaults(new GridLayout(), 1));
+		
+		final Group displayGroup= createDisplayGroup(pageComposite);
+		displayGroup.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
+		
+		final Group fontGroup= createFontGroup(pageComposite);
+		fontGroup.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
+		
+		initBindings();
+		loadDisplayOptions();
+		loadFontOptions();
+		
+		applyDialogFont(pageComposite);
+		
+		return pageComposite;
+	}
+	
+	protected Group createDisplayGroup(final Composite parent) {
+		final Group group= new Group(parent, SWT.NONE);
+		group.setText("Display:");
+		group.setLayout(LayoutUtil.applyGroupDefaults(new GridLayout(), 2));
+		
+		this.customDpiControl= new Button(group, SWT.CHECK);
+		this.customDpiControl.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 2, 1));
+		this.customDpiControl.setText("Use custom DPI (instead of system setting):");
+		
+		this.customDpiComposite= new Composite(group, SWT.NONE);
+		
+		{	final GridData gd= new GridData(SWT.FILL, SWT.FILL, true, false);
+			gd.horizontalIndent= LayoutUtil.defaultIndent();
+			this.customDpiComposite.setLayoutData(gd);
+			this.customDpiComposite.setLayout(LayoutUtil.applyCompositeDefaults(new GridLayout(), 2));
+		}
+		
+		{	final Label label= new Label(this.customDpiComposite, SWT.LEFT);
+			label.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false));
+			label.setText("&Horizontal (x):");
+		}
+		{	final Text text= new Text(this.customDpiComposite, SWT.BORDER | SWT.RIGHT);
+			final GridData gd= new GridData(SWT.LEFT, SWT.CENTER, false, false);
+			gd.widthHint= LayoutUtil.hintWidth(text, 8);
+			text.setLayoutData(gd);
+			this.customHDpiControl= text;
+		}
+		{	final Label label= new Label(this.customDpiComposite, SWT.LEFT);
+			label.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false));
+			label.setText("&Vertical (y):");
+		}
+		{	final Text text= new Text(this.customDpiComposite, SWT.BORDER | SWT.RIGHT);
+			final GridData gd= new GridData(SWT.LEFT, SWT.CENTER, false, false);
+			gd.widthHint= LayoutUtil.hintWidth(text, 8);
+			text.setLayoutData(gd);
+			this.customVDpiControl= text;
+		}
+		
+		this.customDpiControl.addSelectionListener(new SelectionAdapter() {
+			@Override
+			public void widgetSelected(final SelectionEvent e) {
+				updateDisplayGroup();
+			}
+		});
+		
+		return group;
+	}
+	
+	private void updateDisplayGroup() {
+		this.customEnabled= this.customDpiControl.getSelection();
+		DialogUtils.setEnabled(this.customDpiComposite, null, this.customEnabled);
+		
+		final double hvalue;
+		final double vvalue;
+		if (!this.customEnabled || this.customHDpiUserValue <= 0 || this.customVDpiUserValue <= 0) {
+			final Point dpi= Display.getDefault().getDPI();
+			hvalue= dpi.x;
+			vvalue= dpi.y;
+			if (this.customEnabled) {
+				this.customHDpiUserValue= hvalue;
+				this.customVDpiUserValue= vvalue;
+			}
+		}
+		else {
+			hvalue= this.customHDpiUserValue;
+			vvalue= this.customVDpiUserValue;
+		}
+		this.customHDpiVisibleValue.setValue(hvalue);
+		this.customVDpiVisibleValue.setValue(vvalue);
+	}
+	
+	protected Group createFontGroup(final Composite parent) {
+		final Group group= new Group(parent, SWT.NONE);
+		group.setText("Fonts:");
+		group.setLayout(LayoutUtil.applyGroupDefaults(new GridLayout(), 3));
+		
+		addFont(group, this.serifPref, "Default &Serif Font ('serif'):");
+		addFont(group, this.sansPref, "Default S&ansserif Font ('sans'):");
+		addFont(group, this.monoPref, "Default &Monospace Font ('mono'):");
+		
+		LayoutUtil.addSmallFiller(group, false);
+		
+		this.symbolUseControl= new Button(group, SWT.CHECK);
+		this.symbolUseControl.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false, 3, 1));
+		this.symbolUseControl.setText("Use special S&ymbol Font");
+		final List<Control> symbolControls= new ArrayList<>();
+		addFont(group, this.symbolFontPref, "Symbol &Font:",
+				LayoutUtil.defaultIndent(), symbolControls );
+		{	final Label label= new Label(group, SWT.NONE);
+			final GridData gd= new GridData(SWT.FILL, SWT.CENTER, false, false);
+			gd.horizontalIndent= LayoutUtil.defaultIndent();
+			label.setLayoutData(gd);
+			label.setText("Encoding:");
+			symbolControls.add(label);
+		}
+		{	this.symbolEncodingControl= new ComboViewer(group, SWT.DROP_DOWN | SWT.READ_ONLY);
+			final GridData gd= new GridData(SWT.LEFT, SWT.CENTER, false, false, 2, 1);
+			gd.widthHint= LayoutUtil.hintWidth(this.symbolEncodingControl.getCombo(), 15);
+			this.symbolEncodingControl.getControl().setLayoutData(gd);
+			this.symbolEncodingControl.setContentProvider(new ArrayContentProvider());
+			this.symbolEncodingControl.setInput(SYMBOL_ENCODINGS);
+			symbolControls.add(this.symbolEncodingControl.getControl());
+		}
+		this.symbolChildControls= symbolControls.toArray(new Control[symbolControls.size()]);
+		this.symbolUseControl.addSelectionListener(new SelectionAdapter() {
+			@Override
+			public void widgetSelected(final SelectionEvent e) {
+				updateSymbolControls();
+			}
+		});
+		
+		return group;
+	}
+	
+	private void addFont(final Group group, final FontPref pref, final String text) {
+		addFont(group, pref, text, 0, null);
+	}
+	
+	private void addFont(final Group group, final FontPref pref, final String text,
+			final int indent, final List<Control> controls) {
+		final Label label= new Label(group, SWT.NONE);
+		final GridData gd= new GridData(SWT.FILL, SWT.CENTER, false, false);
+		gd.horizontalIndent= indent;
+		label.setLayoutData(gd);
+		label.setText(text);
+		
+		pref.valueLabel= new Label(group, SWT.BORDER);
+		pref.valueLabel.setBackground(label.getDisplay().getSystemColor(SWT.COLOR_WHITE));
+		pref.valueLabel.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+		
+		final Button button= new Button(group, SWT.PUSH);
+		button.setText("Edit...");
+		button.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false));
+		button.addSelectionListener(new SelectionListener() {
+			@Override
+			public void widgetSelected(final SelectionEvent e) {
+				final FontDialog dialog= new FontDialog(button.getShell(), SWT.NONE);
+				dialog.setFontList((pref.currentFont != null) ? pref.currentFont.getFontData() : null);
+				final FontData result= dialog.open();
+				if (result != null) {
+					set(pref, result.getName());
+				}
+			}
+			@Override
+			public void widgetDefaultSelected(final SelectionEvent e) {
+			}
+		});
+		
+		if (controls != null) {
+			controls.add(label);
+			controls.add(pref.valueLabel);
+			controls.add(button);
+		}
+	}
+	
+	protected void initBindings() {
+		final Realm realm= Realm.getDefault();
+		this.dbc= new DataBindingContext(realm);
+		addBindings(this.dbc, realm);
+		
+		final AggregateValidationStatus validationStatus= new AggregateValidationStatus(this.dbc, AggregateValidationStatus.MAX_SEVERITY);
+		validationStatus.addValueChangeListener(new IValueChangeListener() {
+			@Override
+			public void handleValueChange(final ValueChangeEvent event) {
+				final IStatus currentStatus= (IStatus) event.diff.getNewValue();
+				updateStatus(currentStatus);
+			}
+		});
+	}
+	
+	protected void addBindings(final DataBindingContext dbc, final Realm realm) {
+		this.customHDpiVisibleValue= new WritableValue(realm, 96.0, Double.class);
+		this.customVDpiVisibleValue= new WritableValue(realm, 96.0, Double.class);
+		
+		dbc.bindValue(SWTObservables.observeText(this.customHDpiControl, SWT.Modify),
+				this.customHDpiVisibleValue,
+				new UpdateValueStrategy().setAfterGetValidator(new DecimalValidator(10.0, 10000.0,
+						"The value for Horizontal (x) DPI is invalid (10-10000)." )), null);
+		dbc.bindValue(SWTObservables.observeText(this.customVDpiControl, SWT.Modify),
+				this.customVDpiVisibleValue,
+				new UpdateValueStrategy().setAfterGetValidator(new DecimalValidator(10.0, 10000.0,
+						"The value for Vertical (x) DPI is invalid (10-10000)." )), null);
+		
+		this.customHDpiVisibleValue.addValueChangeListener(new IValueChangeListener() {
+			@Override
+			public void handleValueChange(final ValueChangeEvent event) {
+				if (RGraphicsPreferencePage.this.customEnabled) {
+					RGraphicsPreferencePage.this.customHDpiUserValue= (Double) RGraphicsPreferencePage.this.customHDpiVisibleValue.getValue();
+				}
+			}
+		});
+		this.customVDpiVisibleValue.addValueChangeListener(new IValueChangeListener() {
+			@Override
+			public void handleValueChange(final ValueChangeEvent event) {
+				if (RGraphicsPreferencePage.this.customEnabled) {
+					RGraphicsPreferencePage.this.customVDpiUserValue= (Double) RGraphicsPreferencePage.this.customVDpiVisibleValue.getValue();
+				}
+			}
+		});
+	}
+	
+	protected void updateStatus(final IStatus status) {
+		setValid(!status.matches(IStatus.ERROR));
+		StatusInfo.applyToStatusLine(this, status);
+	}
+	
+	protected void setCustomDpi(final String prefValue) {
+		final double[] dpi= parseDPI(prefValue);
+		if (dpi != null) {
+			this.customHDpiUserValue= dpi[0];
+			this.customVDpiUserValue= dpi[1];
+			this.customDpiControl.setSelection(true);
+		}
+		else {
+			this.customDpiControl.setSelection(false);
+		}
+		updateDisplayGroup();
+	}
+	
+	protected void updateSymbolControls() {
+		DialogUtils.setEnabled(this.symbolChildControls, null, this.symbolUseControl.getSelection());
+	}
+	
+	protected void set(final FontPref pref, final String value) {
+		if (value.equals(pref.currentName)) {
+			return;
+		}
+		pref.valueLabel.setText("");
+		Font font;
+		try {
+			font= new Font(pref.valueLabel.getDisplay(), value, this.size, SWT.NONE);
+			if (pref != this.symbolFontPref) {
+				pref.valueLabel.setFont(font);
+			}
+			pref.valueLabel.setText(value);
+		}
+		catch (final SWTError e) {
+			font= JFaceResources.getDialogFont();
+			pref.valueLabel.setFont(font);
+			pref.valueLabel.setText(value + " (not available)");
+		}
+		if (pref.currentFont != null && !pref.currentFont.isDisposed()) {
+			pref.currentFont.dispose();
+		}
+		pref.currentName= value;
+		pref.currentFont= font;
+	}
+	
+	@Override
+	protected void performDefaults() {
+		setCustomDpi(null);
+		this.symbolUseControl.setSelection(true);
+		this.symbolEncodingControl.setSelection(new StructuredSelection(SYMBOL_ENCODING_DEFAULT));
+		for (final FontPref pref : this.fontPrefs) {
+			set(pref, pref.defaultName);
+		}
+		updateSymbolControls();
+		super.performDefaults();
+	}
+	
+	@Override
+	protected void performApply() {
+		saveDisplayOptions(true);
+		saveFontOptions(true);
+	}
+	
+	@Override
+	public boolean performOk() {
+		saveDisplayOptions(false);
+		saveFontOptions(false);
+		return true;
+	}
+	
+	
+	protected IScopeContext getScope() {
+		return InstanceScope.INSTANCE;
+	}
+	
+	protected void loadDisplayOptions() {
+		final IEclipsePreferences node= getScope().getNode(RGraphics.PREF_DISPLAY_QUALIFIER);
+		setCustomDpi(node.get(RGraphics.PREF_DISPLAY_CUSTOM_DPI_KEY, null));
+	}
+	
+	protected void saveDisplayOptions(final boolean flush) {
+		final IEclipsePreferences node= getScope().getNode(RGraphics.PREF_DISPLAY_QUALIFIER);
+		if (this.customEnabled) {
+			node.put(RGraphics.PREF_DISPLAY_CUSTOM_DPI_KEY,
+					Double.toString(this.customHDpiUserValue) + "," + Double.toString(this.customVDpiUserValue));
+		}
+		else {
+			node.remove(RGraphics.PREF_DISPLAY_CUSTOM_DPI_KEY);
+		}
+		if (flush) {
+			try {
+				node.flush();
+			}
+			catch (final BackingStoreException e) {
+				StatusManager.getManager().handle(new Status(IStatus.ERROR, RGraphics.BUNDLE_ID, -1,
+						"An error occurred when storing R graphics display preferences.", e));
+			}
+		}
+	}
+	
+	protected void loadFontOptions() {
+		if (this.fontPrefs != null) {
+			final IEclipsePreferences node= getScope().getNode(RGraphics.FONTS_PREF_QUALIFIER);
+			this.symbolUseControl.setSelection(node.getBoolean(RGraphics.PREF_FONTS_SYMBOL_USE_KEY, true));
+			final String s= node.get(RGraphics.PREF_FONTS_SYMBOL_ENCODING_KEY, (String) null);
+			this.symbolEncodingControl.setSelection(new StructuredSelection((s != null) ?
+					new Encoding(null, s) : SYMBOL_ENCODING_DEFAULT ));
+			for (final FontPref pref : this.fontPrefs) {
+				final String value= node.get(pref.prefKey, ""); //$NON-NLS-1$
+				set(pref, (value.length() > 0) ? value : pref.defaultName);
+			}
+			updateSymbolControls();
+		}
+	}
+	
+	protected void saveFontOptions(final boolean flush) {
+		if (this.fontPrefs != null) {
+			final IEclipsePreferences node= getScope().getNode(RGraphics.FONTS_PREF_QUALIFIER);
+			node.putBoolean(RGraphics.PREF_FONTS_SYMBOL_USE_KEY, this.symbolUseControl.getSelection());
+			final IStructuredSelection selection= (IStructuredSelection) this.symbolEncodingControl.getSelection();
+			if (selection.getFirstElement() instanceof Encoding
+					&& !SYMBOL_ENCODING_DEFAULT.equals(selection.getFirstElement())) {
+				node.put(RGraphics.PREF_FONTS_SYMBOL_ENCODING_KEY,
+						((Encoding) selection.getFirstElement()).prefValue );
+			}
+			else {
+				node.remove(RGraphics.PREF_FONTS_SYMBOL_ENCODING_KEY);
+			}
+			for (final FontPref pref : this.fontPrefs) {
+				if (pref.currentName == null || pref.currentName.equals(pref.defaultName)) {
+					node.remove(pref.prefKey);
+				}
+				else {
+					node.put(pref.prefKey, pref.currentName);
+				}
+			}
+			updateSymbolControls();
+			if (flush) {
+				try {
+					node.flush();
+				}
+				catch (final BackingStoreException e) {
+					StatusManager.getManager().handle(new Status(IStatus.ERROR, RGraphics.BUNDLE_ID, -1,
+							"An error occurred when storing R graphics font preferences.", e));
+				}
+			}
+		}
+	}
+	
+	@Override
+	public void dispose() {
+		if (this.dbc != null) {
+			this.dbc.dispose();
+			this.dbc= null;
+		}
+		if (this.fontPrefs != null) {
+			for (final FontPref pref : this.fontPrefs) {
+				if (pref.currentFont != null && !pref.currentFont.isDisposed()) {
+					pref.currentFont.dispose();
+					pref.currentFont= null;
+				}
+			}
+		}
+		super.dispose();
+	}
+	
+}
diff --git a/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/rj/eclient/graphics/comclient/ERClientGraphicActions.java b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/rj/eclient/graphics/comclient/ERClientGraphicActions.java
new file mode 100644
index 0000000..6d90c44
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/rj/eclient/graphics/comclient/ERClientGraphicActions.java
@@ -0,0 +1,155 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.eclient.graphics.comclient;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+
+import org.eclipse.statet.ecommons.collections.IntArrayMap;
+import org.eclipse.statet.ecommons.ts.core.SystemRunnable;
+import org.eclipse.statet.ecommons.ts.core.Tool;
+
+import org.eclipse.statet.rj.eclient.core.AbstractRToolRunnable;
+import org.eclipse.statet.rj.eclient.core.RToolService;
+import org.eclipse.statet.rj.server.client.AbstractRJComClient;
+import org.eclipse.statet.rj.server.client.AbstractRJComClientGraphicActions;
+
+
+public class ERClientGraphicActions extends AbstractRJComClientGraphicActions
+		implements ToolRClientGraphicActions {
+	
+	
+	private final Tool tool;
+	
+	private final IntArrayMap<Boolean> resizeTasks= new IntArrayMap<>();
+	private final IntArrayMap<Boolean> closeTasks= new IntArrayMap<>();
+	
+	
+	public ERClientGraphicActions(final AbstractRJComClient rjs, final Tool tool) {
+		super(rjs);
+		this.tool= tool;
+	}
+	
+	
+	private class ResizeRunnable extends AbstractRToolRunnable implements SystemRunnable {
+		
+		private final int devId;
+		private final Runnable beforeResize;
+		
+		public ResizeRunnable(final int devId, final Runnable beforeResize) {
+			super("r/rj/gd/resize", "Resize R Graphic"); //$NON-NLS-1$
+			this.devId= devId;
+			this.beforeResize= beforeResize;
+		}
+		
+		@Override
+		public boolean changed(final int event, final Tool process) {
+			switch (event) {
+			case MOVING_FROM:
+			case REMOVING_FROM:
+				return false;
+			case BEING_ABANDONED:
+				synchronized (ERClientGraphicActions.this.closeTasks) {
+					ERClientGraphicActions.this.resizeTasks.put(this.devId, Boolean.FALSE);
+				}
+				return true;
+			default:
+				return true;
+			}
+		}
+		
+		@Override
+		public void run(final RToolService r,
+				final IProgressMonitor monitor) throws CoreException {
+			synchronized (ERClientGraphicActions.this.closeTasks) {
+				ERClientGraphicActions.this.resizeTasks.put(this.devId, Boolean.FALSE);
+			}
+			this.beforeResize.run();
+			doResizeGraphic(this.devId, monitor);
+		}
+		
+	}
+	
+	private class CloseRunnable extends AbstractRToolRunnable implements SystemRunnable {
+		
+		
+		private final int devId;
+		
+		public CloseRunnable(final int devId) {
+			super("r/rj/gd/close", "Close R Graphic ("+(devId+1)+")"); //$NON-NLS-1$
+			this.devId= devId;
+		}
+		
+		@Override
+		public boolean changed(final int event, final Tool tool) {
+			switch (event) {
+			case MOVING_FROM:
+				return false;
+			case REMOVING_FROM:
+			case BEING_ABANDONED:
+			case FINISHING_OK:
+			case FINISHING_ERROR:
+			case FINISHING_CANCEL:
+				synchronized (ERClientGraphicActions.this.closeTasks) {
+					ERClientGraphicActions.this.closeTasks.put(this.devId, Boolean.FALSE);
+				}
+				return true;
+			default:
+				return true;
+			}
+		}
+		
+		@Override
+		public void run(final RToolService r,
+				final IProgressMonitor monitor) throws CoreException {
+			doCloseGraphic(this.devId, monitor);
+		}
+		
+	}
+	
+	
+	@Override
+	public Tool getRHandle() {
+		return this.tool;
+	}
+	
+	@Override
+	public String getRLabel() {
+		return this.tool.getLabel(Tool.DEFAULT_LABEL);
+	}
+	
+	@Override
+	public IStatus resizeGraphic(final int devId, final Runnable beforeResize) {
+		synchronized (this.resizeTasks) {
+			if (this.resizeTasks.put(devId, Boolean.TRUE) == Boolean.TRUE) {
+				return Status.OK_STATUS;
+			}
+		}
+		return this.tool.getQueue().add(new ResizeRunnable(devId, beforeResize));
+	}
+	
+	@Override
+	public IStatus closeGraphic(final int devId) {
+		synchronized (this.closeTasks) {
+			if (this.closeTasks.put(devId, Boolean.TRUE) == Boolean.TRUE) {
+				return Status.OK_STATUS;
+			}
+		}
+		return this.tool.getQueue().add(new CloseRunnable(devId));
+	}
+	
+}
diff --git a/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/rj/eclient/graphics/comclient/ERClientGraphicActionsFactory.java b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/rj/eclient/graphics/comclient/ERClientGraphicActionsFactory.java
new file mode 100644
index 0000000..812aa5a
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/rj/eclient/graphics/comclient/ERClientGraphicActionsFactory.java
@@ -0,0 +1,34 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.eclient.graphics.comclient;
+
+import org.eclipse.statet.ecommons.ts.core.Tool;
+
+import org.eclipse.statet.rj.server.client.AbstractRJComClient;
+import org.eclipse.statet.rj.server.client.AbstractRJComClientGraphicActions;
+
+
+public class ERClientGraphicActionsFactory implements AbstractRJComClientGraphicActions.Factory {
+	
+	
+	@Override
+	public AbstractRJComClientGraphicActions create(final AbstractRJComClient rjs, final Object rHandle) {
+		if (rHandle instanceof Tool) {
+			return new ERClientGraphicActions(rjs, (Tool) rHandle);
+		}
+		return null;
+	}
+	
+}
diff --git a/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/rj/eclient/graphics/comclient/ERGraphicFactory.java b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/rj/eclient/graphics/comclient/ERGraphicFactory.java
new file mode 100644
index 0000000..cf79821
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/rj/eclient/graphics/comclient/ERGraphicFactory.java
@@ -0,0 +1,27 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.eclient.graphics.comclient;
+
+import org.eclipse.statet.internal.rj.eclient.graphics.EclipseRGraphicFactory;
+import org.eclipse.statet.rj.eclient.graphics.ERGraphicsManager;
+
+
+/**
+ * Factory and manager for R graphics under Eclipse.
+ */
+public class ERGraphicFactory extends EclipseRGraphicFactory
+		implements ERGraphicsManager {
+	
+}
diff --git a/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/rj/eclient/graphics/comclient/ToolRClientGraphicActions.java b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/rj/eclient/graphics/comclient/ToolRClientGraphicActions.java
new file mode 100644
index 0000000..c5e5a52
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/rj/eclient/graphics/comclient/ToolRClientGraphicActions.java
@@ -0,0 +1,28 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.eclient.graphics.comclient;
+
+import org.eclipse.statet.ecommons.ts.core.Tool;
+
+import org.eclipse.statet.rj.server.client.RClientGraphicActions;
+
+
+public interface ToolRClientGraphicActions extends RClientGraphicActions {
+	
+	
+	@Override
+	Tool getRHandle();
+	
+}
diff --git a/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/rj/eclient/graphics/util/AbstractLocalLocator.java b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/rj/eclient/graphics/util/AbstractLocalLocator.java
new file mode 100644
index 0000000..17da038
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/rj/eclient/graphics/util/AbstractLocalLocator.java
@@ -0,0 +1,249 @@
+/*=============================================================================#
+ # Copyright (c) 2011, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.eclient.graphics.util;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+
+import org.eclipse.statet.jcommons.collections.ImCollections;
+import org.eclipse.statet.jcommons.collections.ImList;
+
+import org.eclipse.statet.ecommons.ts.core.SystemRunnable;
+import org.eclipse.statet.ecommons.ts.core.Tool;
+import org.eclipse.statet.ecommons.ts.core.ToolService;
+
+import org.eclipse.statet.rj.eclient.graphics.ERGraphic;
+import org.eclipse.statet.rj.eclient.graphics.LocatorCallback;
+
+
+/**
+ * Basic implementation for a local locator for R graphics.
+ * <p>
+ * Requests the user to locate point and converts the graphic coordinates to user coordinates.
+ * It uses the tool service API (org.eclipse.statet.ecommons.ts.core) to schedule the R job.</p>
+ */
+public abstract class AbstractLocalLocator extends LocatorCallback implements SystemRunnable {
+	
+	protected static final ImList<String> OK_CANCEL_STOP_TYPES= ImCollections.newList(
+			ERGraphic.LOCATOR_DONE, ERGraphic.LOCATOR_CANCEL );
+	
+	
+	private final ERGraphic graphic;
+	private final Tool tool;
+	
+	private boolean started;
+	private boolean graphicLocatorStarted;
+	private boolean runnableScheduled;
+	
+	private final List<double[]> toConvert= new ArrayList<>();
+	
+	private final List<double[]> locatedGraphic= new ArrayList<>();
+	private final List<double[]> locatedUser= new ArrayList<>();
+	
+	private volatile int counter;
+	
+	
+	public AbstractLocalLocator(final ERGraphic graphic) {
+		this.graphic= graphic;
+		this.tool= graphic.getRHandle();
+	}
+	
+	
+	@Override
+	public Collection<String> getStopTypes() {
+		return OK_CANCEL_STOP_TYPES;
+	}
+	
+	@Override
+	public String getMessage() {
+		return super.getMessage() + " (" + this.counter + " selected)";
+	}
+	
+	@Override
+	public int located(final double x, final double y) {
+		synchronized (this) {
+			this.counter++;
+			this.toConvert.add(new double[] { x, y });
+			if (!internalScheduleConversion()) {
+				internalStop(null);
+				return STOP;
+			}
+		}
+		return NEXT;
+	}
+	
+	@Override
+	public void stopped(final String type) {
+		synchronized (this) {
+			this.graphicLocatorStarted= false;
+			if (type == ERGraphic.LOCATOR_DONE) {
+				if (this.toConvert.isEmpty()) {
+					internalStop(ERGraphic.LOCATOR_DONE);
+					return;
+				}
+				else if (internalScheduleConversion()) {
+					return;
+				}
+				// scheduling failed
+			}
+			internalStop(null);
+			return;
+		}
+	}
+	
+	@Override
+	public String getTypeId() {
+		return "r/rjgd/locallocator"; //$NON-NLS-1$
+	}
+	
+	@Override
+	public String getLabel() {
+		return "Resolve Graphic Points";
+	}
+	
+	@Override
+	public boolean canRunIn(final Tool tool) {
+		return (tool == this.tool);
+	}
+	
+	@Override
+	public boolean changed(final int event, final Tool tool) {
+		switch (event) {
+		case REMOVING_FROM:
+			return false;
+		case BEING_ABANDONED:
+		case FINISHING_CANCEL:
+		case FINISHING_ERROR:
+			synchronized (this) {
+				this.runnableScheduled= false;
+				if (!this.graphicLocatorStarted) {
+					internalStop(null);
+					break;
+				}
+			}
+			this.graphic.stopLocator(null);
+			break;
+		case FINISHING_OK:
+			synchronized (this) {
+				if (!this.graphicLocatorStarted && this.toConvert.isEmpty()) {
+					internalStop(ERGraphic.LOCATOR_DONE);
+					break;
+				}
+			}
+		}
+		return true;
+	}
+	
+	@Override
+	public void run(final ToolService service,
+			final IProgressMonitor monitor) throws CoreException {
+		double[] graphic= null;
+		double[] user= null;
+		while (true) {
+			synchronized (this) {
+				if (graphic != null) {
+					if (user != null) {
+						this.locatedGraphic.add(graphic);
+						this.locatedUser.add(user);
+					}
+					else {
+						// invalid point?
+					}
+				}
+				if (this.toConvert.isEmpty()) {
+					this.counter= this.locatedGraphic.size();
+					this.runnableScheduled= false;
+					return;
+				}
+				graphic= this.toConvert.remove(0);
+				user= null;
+			}
+			user= this.graphic.convertGraphic2User(graphic, monitor);
+		}
+	}
+	
+	/**
+	 * synchronized
+	 */
+	protected boolean internalScheduleConversion() {
+		if (!this.runnableScheduled) {
+			if (this.tool.getQueue().addHot(this).isOK()) {
+				this.runnableScheduled= true;
+				return true;
+			}
+			return false;
+		}
+		return true;
+	}
+	
+	/**
+	 * synchronized
+	 * 
+	 * @param type the stop type
+	 */
+	protected void internalStop(final String type) {
+		assert (!this.graphicLocatorStarted);
+		if (this.runnableScheduled) {
+			this.tool.getQueue().removeHot(this);
+			this.runnableScheduled= false;
+		}
+		this.started= false;
+		if (type == ERGraphic.LOCATOR_DONE) {
+			finished(new ArrayList<>(this.locatedGraphic), new ArrayList<>(this.locatedUser));
+		}
+		else {
+			canceled();
+		}
+	}
+	
+	
+	public boolean start() {
+		synchronized (this) {
+			if (this.started) {
+				return false;
+			}
+			this.toConvert.clear();
+			this.locatedGraphic.clear();
+			this.locatedUser.clear();
+			this.started= this.graphicLocatorStarted= true;
+			this.counter= 0;
+			if (this.graphic.startLocalLocator(this).isOK()) {
+				return true;
+			}
+			else {
+				this.started= this.graphicLocatorStarted= false;
+				return false;
+			}
+		}
+	}
+	
+	/**
+	 * Is called if the locator and conversion is finished.
+	 * 
+	 * @param graphic the graphic coordinates
+	 * @param user the user coordinates
+	 */
+	protected abstract void finished(final List<double[]> graphic, final List<double[]> user);
+	
+	/**
+	 * Is called if the locator was canceled
+	 */
+	protected abstract void canceled();
+	
+}
diff --git a/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/rj/eclient/graphics/util/CopyToDevRunnable.java b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/rj/eclient/graphics/util/CopyToDevRunnable.java
new file mode 100644
index 0000000..419597a
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/rj/eclient/graphics/util/CopyToDevRunnable.java
@@ -0,0 +1,61 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.eclient.graphics.util;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+
+import org.eclipse.statet.ecommons.ts.core.Tool;
+
+import org.eclipse.statet.rj.eclient.core.AbstractRToolRunnable;
+import org.eclipse.statet.rj.eclient.core.RToolService;
+import org.eclipse.statet.rj.eclient.graphics.ERGraphic;
+
+
+public class CopyToDevRunnable extends AbstractRToolRunnable {
+	
+	
+	private final ERGraphic graphic;
+	private final String toDev;
+	private final String toDevFile;
+	private final String toDevArgs;
+	
+	
+	public CopyToDevRunnable(final ERGraphic graphic, final String toDev,
+			final String toDevFile, final String toDevArgs) {
+		super("r/rj/gd/copy", "Copy R Graphic ('" + toDev + "')"); //$NON-NLS-1$
+		this.graphic= graphic;
+		this.toDev= toDev;
+		this.toDevFile= toDevFile;
+		this.toDevArgs= toDevArgs;
+	}
+	
+	@Override
+	public boolean changed(final int event, final Tool tool) {
+		switch (event) {
+		case MOVING_FROM:
+			return false;
+		default:
+			return true;
+		}
+	}
+	
+	@Override
+	public void run(final RToolService r,
+			final IProgressMonitor monitor) throws CoreException {
+		this.graphic.copy(this.toDev, this.toDevFile, this.toDevArgs, monitor);
+	}
+	
+}
diff --git a/examples/org.eclipse.statet.rj.servi.demo/.classpath b/examples/org.eclipse.statet.rj.servi.demo/.classpath
new file mode 100644
index 0000000..eca7bdb
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.demo/.classpath
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
+	<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+	<classpathentry kind="src" path="src"/>
+	<classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/examples/org.eclipse.statet.rj.servi.demo/.gitignore b/examples/org.eclipse.statet.rj.servi.demo/.gitignore
new file mode 100644
index 0000000..5e56e04
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.demo/.gitignore
@@ -0,0 +1 @@
+/bin
diff --git a/examples/org.eclipse.statet.rj.servi.demo/.project b/examples/org.eclipse.statet.rj.servi.demo/.project
new file mode 100644
index 0000000..e001a87
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.demo/.project
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>org.eclipse.statet.rj.servi.demo</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.jdt.core.javabuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.pde.ManifestBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.pde.SchemaBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.pde.PluginNature</nature>
+		<nature>org.eclipse.jdt.core.javanature</nature>
+	</natures>
+</projectDescription>
diff --git a/examples/org.eclipse.statet.rj.servi.demo/.settings/org.eclipse.core.resources.prefs b/examples/org.eclipse.statet.rj.servi.demo/.settings/org.eclipse.core.resources.prefs
new file mode 100644
index 0000000..99f26c0
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.demo/.settings/org.eclipse.core.resources.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+encoding/<project>=UTF-8
diff --git a/examples/org.eclipse.statet.rj.servi.demo/.settings/org.eclipse.core.runtime.prefs b/examples/org.eclipse.statet.rj.servi.demo/.settings/org.eclipse.core.runtime.prefs
new file mode 100644
index 0000000..5a0ad22
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.demo/.settings/org.eclipse.core.runtime.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+line.separator=\n
diff --git a/examples/org.eclipse.statet.rj.servi.demo/.settings/org.eclipse.jdt.core.prefs b/examples/org.eclipse.statet.rj.servi.demo/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000..ccb1eaa
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.demo/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,325 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.codeComplete.argumentPrefixes=
+org.eclipse.jdt.core.codeComplete.argumentSuffixes=
+org.eclipse.jdt.core.codeComplete.fieldPrefixes=
+org.eclipse.jdt.core.codeComplete.fieldSuffixes=
+org.eclipse.jdt.core.codeComplete.localPrefixes=
+org.eclipse.jdt.core.codeComplete.localSuffixes=
+org.eclipse.jdt.core.codeComplete.staticFieldPrefixes=
+org.eclipse.jdt.core.codeComplete.staticFieldSuffixes=
+org.eclipse.jdt.core.codeComplete.staticFinalFieldPrefixes=
+org.eclipse.jdt.core.codeComplete.staticFinalFieldSuffixes=
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=1.8
+org.eclipse.jdt.core.compiler.debug.lineNumber=generate
+org.eclipse.jdt.core.compiler.debug.localVariable=generate
+org.eclipse.jdt.core.compiler.debug.sourceFile=generate
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.source=1.8
+org.eclipse.jdt.core.formatter.align_fields_grouping_blank_lines=2147483647
+org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_assignment=0
+org.eclipse.jdt.core.formatter.alignment_for_binary_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_compact_if=16
+org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=80
+org.eclipse.jdt.core.formatter.alignment_for_enum_constants=0
+org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16
+org.eclipse.jdt.core.formatter.alignment_for_expressions_in_for_loop_header=0
+org.eclipse.jdt.core.formatter.alignment_for_method_declaration=0
+org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16
+org.eclipse.jdt.core.formatter.alignment_for_parameterized_type_references=0
+org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_resources_in_try=85
+org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=16
+org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_type_arguments=0
+org.eclipse.jdt.core.formatter.alignment_for_type_parameters=0
+org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch=16
+org.eclipse.jdt.core.formatter.blank_lines_after_imports=2
+org.eclipse.jdt.core.formatter.blank_lines_after_package=1
+org.eclipse.jdt.core.formatter.blank_lines_before_field=0
+org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=1
+org.eclipse.jdt.core.formatter.blank_lines_before_imports=1
+org.eclipse.jdt.core.formatter.blank_lines_before_member_type=1
+org.eclipse.jdt.core.formatter.blank_lines_before_method=1
+org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=2
+org.eclipse.jdt.core.formatter.blank_lines_before_package=1
+org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=1
+org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=1
+org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_block=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_lambda_body=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=false
+org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=false
+org.eclipse.jdt.core.formatter.comment.format_block_comments=true
+org.eclipse.jdt.core.formatter.comment.format_header=false
+org.eclipse.jdt.core.formatter.comment.format_html=true
+org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=true
+org.eclipse.jdt.core.formatter.comment.format_line_comments=true
+org.eclipse.jdt.core.formatter.comment.format_source_code=true
+org.eclipse.jdt.core.formatter.comment.indent_parameter_description=false
+org.eclipse.jdt.core.formatter.comment.indent_root_tags=true
+org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert
+org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=do not insert
+org.eclipse.jdt.core.formatter.comment.line_length=100
+org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries=false
+org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries=true
+org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments=false
+org.eclipse.jdt.core.formatter.compact_else_if=true
+org.eclipse.jdt.core.formatter.continuation_indentation=2
+org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=2
+org.eclipse.jdt.core.formatter.disabling_tag=@formatter\:off
+org.eclipse.jdt.core.formatter.enabling_tag=@formatter\:on
+org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false
+org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true
+org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true
+org.eclipse.jdt.core.formatter.indent_empty_lines=true
+org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true
+org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true
+org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true
+org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=false
+org.eclipse.jdt.core.formatter.indentation.size=4
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_enum_constant=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_label=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_type_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert
+org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert
+org.eclipse.jdt.core.formatter.insert_space_after_lambda_arrow=insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources=insert
+org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert
+org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=insert
+org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert
+org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw=insert
+org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.join_lines_in_comments=true
+org.eclipse.jdt.core.formatter.join_wrapped_lines=true
+org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=false
+org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false
+org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=false
+org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false
+org.eclipse.jdt.core.formatter.lineSplit=100
+org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false
+org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=false
+org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0
+org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=1
+org.eclipse.jdt.core.formatter.parentheses_positions_in_annotation=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_catch_clause=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_enum_constant_declaration=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_for_statment=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_if_while_statement=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_lambda_declaration=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_method_delcaration=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_method_invocation=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_switch_statement=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_try_clause=common_lines
+org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=true
+org.eclipse.jdt.core.formatter.tabulation.char=tab
+org.eclipse.jdt.core.formatter.tabulation.size=4
+org.eclipse.jdt.core.formatter.use_on_off_tags=false
+org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false
+org.eclipse.jdt.core.formatter.wrap_before_assignment_operator=false
+org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true
+org.eclipse.jdt.core.formatter.wrap_before_conditional_operator=false
+org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch=true
+org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true
+org.eclipse.jdt.core.javaFormatter=org.eclipse.jdt.core.defaultJavaFormatter
diff --git a/examples/org.eclipse.statet.rj.servi.demo/.settings/org.eclipse.jdt.ui.prefs b/examples/org.eclipse.statet.rj.servi.demo/.settings/org.eclipse.jdt.ui.prefs
new file mode 100644
index 0000000..e62a4f5
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.demo/.settings/org.eclipse.jdt.ui.prefs
@@ -0,0 +1,131 @@
+cleanup.add_default_serial_version_id=true
+cleanup.add_generated_serial_version_id=false
+cleanup.add_missing_annotations=true
+cleanup.add_missing_deprecated_annotations=true
+cleanup.add_missing_methods=false
+cleanup.add_missing_nls_tags=false
+cleanup.add_missing_override_annotations=true
+cleanup.add_missing_override_annotations_interface_methods=true
+cleanup.add_serial_version_id=false
+cleanup.always_use_blocks=true
+cleanup.always_use_parentheses_in_expressions=true
+cleanup.always_use_this_for_non_static_field_access=true
+cleanup.always_use_this_for_non_static_method_access=false
+cleanup.convert_functional_interfaces=false
+cleanup.convert_to_enhanced_for_loop=false
+cleanup.correct_indentation=false
+cleanup.format_source_code=false
+cleanup.format_source_code_changes_only=false
+cleanup.insert_inferred_type_arguments=false
+cleanup.make_local_variable_final=true
+cleanup.make_parameters_final=true
+cleanup.make_private_fields_final=true
+cleanup.make_type_abstract_if_missing_method=false
+cleanup.make_variable_declarations_final=true
+cleanup.never_use_blocks=false
+cleanup.never_use_parentheses_in_expressions=false
+cleanup.organize_imports=true
+cleanup.qualify_static_field_accesses_with_declaring_class=false
+cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true
+cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=false
+cleanup.qualify_static_member_accesses_with_declaring_class=true
+cleanup.qualify_static_method_accesses_with_declaring_class=false
+cleanup.remove_private_constructors=true
+cleanup.remove_redundant_type_arguments=true
+cleanup.remove_trailing_whitespaces=false
+cleanup.remove_trailing_whitespaces_all=true
+cleanup.remove_trailing_whitespaces_ignore_empty=false
+cleanup.remove_unnecessary_casts=true
+cleanup.remove_unnecessary_nls_tags=true
+cleanup.remove_unused_imports=true
+cleanup.remove_unused_local_variables=false
+cleanup.remove_unused_private_fields=true
+cleanup.remove_unused_private_members=false
+cleanup.remove_unused_private_methods=true
+cleanup.remove_unused_private_types=true
+cleanup.sort_members=false
+cleanup.sort_members_all=false
+cleanup.use_anonymous_class_creation=false
+cleanup.use_blocks=true
+cleanup.use_blocks_only_for_return_and_throw=false
+cleanup.use_lambda=true
+cleanup.use_parentheses_in_expressions=false
+cleanup.use_this_for_non_static_field_access=true
+cleanup.use_this_for_non_static_field_access_only_if_necessary=false
+cleanup.use_this_for_non_static_method_access=true
+cleanup.use_this_for_non_static_method_access_only_if_necessary=true
+cleanup.use_type_arguments=false
+cleanup_profile=_StatET
+cleanup_settings_version=2
+eclipse.preferences.version=1
+editor_save_participant_org.eclipse.jdt.ui.postsavelistener.cleanup=true
+formatter_profile=_StatET
+formatter_settings_version=12
+org.eclipse.jdt.ui.exception.name=e
+org.eclipse.jdt.ui.gettersetter.use.is=true
+org.eclipse.jdt.ui.ignorelowercasenames=true
+org.eclipse.jdt.ui.importorder=\#;java;javax;com.ibm.icu;org.osgi;org.eclipse;;org.eclipse.statet.jcommons;org.eclipse.statet.ecommons;org.eclipse.statet;
+org.eclipse.jdt.ui.javadoc=true
+org.eclipse.jdt.ui.keywordthis=true
+org.eclipse.jdt.ui.ondemandthreshold=99
+org.eclipse.jdt.ui.overrideannotation=true
+org.eclipse.jdt.ui.staticondemandthreshold=99
+org.eclipse.jdt.ui.text.custom_code_templates=<?xml version\="1.0" encoding\="UTF-8" standalone\="no"?><templates><template autoinsert\="true" context\="gettercomment_context" deleted\="false" description\="Comment for getter method" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.gettercomment" name\="gettercomment">/**\n * @return the ${bare_field_name}\n */</template><template autoinsert\="true" context\="settercomment_context" deleted\="false" description\="Comment for setter method" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.settercomment" name\="settercomment">/**\n * @param ${param} the ${bare_field_name} to set\n */</template><template autoinsert\="true" context\="constructorcomment_context" deleted\="false" description\="Comment for created constructors" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.constructorcomment" name\="constructorcomment">/**\n * ${tags}\n */</template><template autoinsert\="false" context\="filecomment_context" deleted\="false" description\="Comment for created Java files" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.filecomment" name\="filecomment">/*\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\#\n \# Copyright (c) ${year} ${user} and others.\n # \n # This program and the accompanying materials are made available under the\n # terms of the Eclipse Public License 2.0 which is available at\n # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n # which is available at https://www.apache.org/licenses/LICENSE-2.0.\n # \n # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n # \n \# Contributors\:\n \#     ${user} - initial API and implementation\n \#\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=*/</template><template autoinsert\="false" context\="typecomment_context" deleted\="false" description\="Comment for created types" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.typecomment" name\="typecomment">/**\n * \n * ${tags}\n */</template><template autoinsert\="true" context\="fieldcomment_context" deleted\="false" description\="Comment for fields" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.fieldcomment" name\="fieldcomment">/**\n * \n */</template><template autoinsert\="true" context\="methodcomment_context" deleted\="false" description\="Comment for non-overriding methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.methodcomment" name\="methodcomment">/**\n * ${tags}\n */</template><template autoinsert\="false" context\="overridecomment_context" deleted\="false" description\="Comment for overriding methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.overridecomment" name\="overridecomment"/><template autoinsert\="true" context\="delegatecomment_context" deleted\="false" description\="Comment for delegate methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.delegatecomment" name\="delegatecomment">/**\n * ${tags}\n * ${see_to_target}\n */</template><template autoinsert\="false" context\="newtype_context" deleted\="false" description\="Newly created files" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.newtype" name\="newtype">${filecomment}\n\n${package_declaration}\n\n${typecomment}\n${type_declaration}</template><template autoinsert\="true" context\="classbody_context" deleted\="false" description\="Code in new class type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.classbody" name\="classbody">\n</template><template autoinsert\="true" context\="interfacebody_context" deleted\="false" description\="Code in new interface type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.interfacebody" name\="interfacebody">\n</template><template autoinsert\="true" context\="enumbody_context" deleted\="false" description\="Code in new enum type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.enumbody" name\="enumbody">\n</template><template autoinsert\="true" context\="annotationbody_context" deleted\="false" description\="Code in new annotation type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.annotationbody" name\="annotationbody">\n</template><template autoinsert\="true" context\="catchblock_context" deleted\="false" description\="Code in new catch blocks" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.catchblock" name\="catchblock">// ${todo} Auto-generated catch block\n${exception_var}.printStackTrace();</template><template autoinsert\="true" context\="methodbody_context" deleted\="false" description\="Code in created method stubs" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.methodbody" name\="methodbody">// ${todo} Auto-generated method stub\n${body_statement}</template><template autoinsert\="true" context\="constructorbody_context" deleted\="false" description\="Code in created constructor stubs" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.constructorbody" name\="constructorbody">${body_statement}\n// ${todo} Auto-generated constructor stub</template><template autoinsert\="true" context\="getterbody_context" deleted\="false" description\="Code in created getters" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.getterbody" name\="getterbody">return ${field};</template><template autoinsert\="true" context\="setterbody_context" deleted\="false" description\="Code in created setters" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.setterbody" name\="setterbody">${field} \= ${param};</template></templates>
+sp_cleanup.add_default_serial_version_id=true
+sp_cleanup.add_generated_serial_version_id=false
+sp_cleanup.add_missing_annotations=true
+sp_cleanup.add_missing_deprecated_annotations=true
+sp_cleanup.add_missing_methods=false
+sp_cleanup.add_missing_nls_tags=false
+sp_cleanup.add_missing_override_annotations=true
+sp_cleanup.add_missing_override_annotations_interface_methods=true
+sp_cleanup.add_serial_version_id=false
+sp_cleanup.always_use_blocks=true
+sp_cleanup.always_use_parentheses_in_expressions=true
+sp_cleanup.always_use_this_for_non_static_field_access=true
+sp_cleanup.always_use_this_for_non_static_method_access=false
+sp_cleanup.convert_functional_interfaces=false
+sp_cleanup.convert_to_enhanced_for_loop=false
+sp_cleanup.correct_indentation=false
+sp_cleanup.format_source_code=false
+sp_cleanup.format_source_code_changes_only=false
+sp_cleanup.insert_inferred_type_arguments=false
+sp_cleanup.make_local_variable_final=true
+sp_cleanup.make_parameters_final=true
+sp_cleanup.make_private_fields_final=true
+sp_cleanup.make_type_abstract_if_missing_method=false
+sp_cleanup.make_variable_declarations_final=false
+sp_cleanup.never_use_blocks=false
+sp_cleanup.never_use_parentheses_in_expressions=false
+sp_cleanup.on_save_use_additional_actions=true
+sp_cleanup.organize_imports=true
+sp_cleanup.qualify_static_field_accesses_with_declaring_class=false
+sp_cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true
+sp_cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=false
+sp_cleanup.qualify_static_member_accesses_with_declaring_class=true
+sp_cleanup.qualify_static_method_accesses_with_declaring_class=false
+sp_cleanup.remove_private_constructors=true
+sp_cleanup.remove_redundant_type_arguments=true
+sp_cleanup.remove_trailing_whitespaces=false
+sp_cleanup.remove_trailing_whitespaces_all=false
+sp_cleanup.remove_trailing_whitespaces_ignore_empty=true
+sp_cleanup.remove_unnecessary_casts=true
+sp_cleanup.remove_unnecessary_nls_tags=false
+sp_cleanup.remove_unused_imports=false
+sp_cleanup.remove_unused_local_variables=false
+sp_cleanup.remove_unused_private_fields=false
+sp_cleanup.remove_unused_private_members=false
+sp_cleanup.remove_unused_private_methods=false
+sp_cleanup.remove_unused_private_types=true
+sp_cleanup.sort_members=false
+sp_cleanup.sort_members_all=false
+sp_cleanup.use_anonymous_class_creation=false
+sp_cleanup.use_blocks=true
+sp_cleanup.use_blocks_only_for_return_and_throw=false
+sp_cleanup.use_lambda=false
+sp_cleanup.use_parentheses_in_expressions=false
+sp_cleanup.use_this_for_non_static_field_access=true
+sp_cleanup.use_this_for_non_static_field_access_only_if_necessary=false
+sp_cleanup.use_this_for_non_static_method_access=true
+sp_cleanup.use_this_for_non_static_method_access_only_if_necessary=true
+sp_cleanup.use_type_arguments=false
diff --git a/examples/org.eclipse.statet.rj.servi.demo/META-INF/MANIFEST.MF b/examples/org.eclipse.statet.rj.servi.demo/META-INF/MANIFEST.MF
new file mode 100644
index 0000000..00e705a
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.demo/META-INF/MANIFEST.MF
@@ -0,0 +1,15 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-SymbolicName: org.eclipse.statet.rj.servi.demo
+Bundle-Version: 2.1.0.qualifier
+Bundle-Vendor: Eclipse.org
+Bundle-Name: StatET RJ - RServi Demo
+Bundle-RequiredExecutionEnvironment: JavaSE-1.8
+Require-Bundle: org.eclipse.statet.rj.data;bundle-version="1.1.0",
+ org.eclipse.statet.rj.servi;bundle-version="1.1.0",
+ org.eclipse.swt;bundle-version="3.4.0",
+ org.eclipse.statet.ecommons.runtime.core
+Import-Package: org.eclipse.core.runtime,
+ org.eclipse.statet.jcommons.lang;version="1.0.0",
+ org.eclipse.statet.rj.services,
+ org.eclipse.statet.rj.services.util
diff --git a/examples/org.eclipse.statet.rj.servi.demo/about.html b/examples/org.eclipse.statet.rj.servi.demo/about.html
new file mode 100644
index 0000000..e71ae66
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.demo/about.html
@@ -0,0 +1,37 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+		"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+<title>About</title>
+</head>
+<body lang="EN-US">
+<h2>About This Content</h2>
+
+<p>December 1, 2017</p>
+<h3>License</h3>
+
+<p>
+	The Eclipse Foundation makes available all content in this plug-in
+	(&quot;Content&quot;). Unless otherwise indicated below, the Content
+	is provided to you under the terms and conditions of the Eclipse
+	Public License Version 2.0 (&quot;EPL&quot;), or the Apache License,
+	Version 2.0 (AL). A copy of the EPL is available at <a href="https://www.eclipse.org/legal/epl-2.0">https://www.eclipse.org/legal/epl-2.0</a>.
+	For purposes of the EPL, &quot;Program&quot; will mean the Content.
+	A copy of the AL is available at <a href="https://www.apache.org/licenses/LICENSE-2.0">https://www.apache.org/licenses/LICENSE-2.0</a>.
+</p>
+
+<p>
+	If you did not receive this Content directly from the Eclipse
+	Foundation, the Content is being redistributed by another party
+	(&quot;Redistributor&quot;) and different terms and conditions may
+	apply to your use of any object code in the Content. Check the
+	Redistributor's license that was provided with the Content. If no such
+	license exists, contact the Redistributor. Unless otherwise indicated
+	below, the terms and conditions of the EPL or AL still apply to any
+	source code in the Content and such source code may be obtained at <a
+	href="https://www.eclipse.org/">https://www.eclipse.org</a>.
+</p>
+
+</body>
+</html>
diff --git a/examples/org.eclipse.statet.rj.servi.demo/build.properties b/examples/org.eclipse.statet.rj.servi.demo/build.properties
new file mode 100644
index 0000000..9f02c9f
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.demo/build.properties
@@ -0,0 +1,8 @@
+source..= src/
+output..= bin/
+javacDefaultEncoding..= UTF-8
+
+bin.includes= META-INF/,\
+              .,\
+              about.html
+src.includes= .settings/org.eclipse.core.resources.prefs
diff --git a/examples/org.eclipse.statet.rj.servi.demo/src/org/eclipse/statet/rj/servi/demo/DemoApp.java b/examples/org.eclipse.statet.rj.servi.demo/src/org/eclipse/statet/rj/servi/demo/DemoApp.java
new file mode 100644
index 0000000..96f5940
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.demo/src/org/eclipse/statet/rj/servi/demo/DemoApp.java
@@ -0,0 +1,724 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.servi.demo;
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.SashForm;
+import org.eclipse.swt.events.DisposeEvent;
+import org.eclipse.swt.events.DisposeListener;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.ShellAdapter;
+import org.eclipse.swt.events.ShellEvent;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.program.Program;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.FileDialog;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.MessageBox;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Text;
+
+import org.eclipse.statet.rj.data.RObject;
+import org.eclipse.statet.rj.servi.RServi;
+import org.eclipse.statet.rj.servi.RServiUtil;
+import org.eclipse.statet.rj.services.FunctionCall;
+import org.eclipse.statet.rj.services.util.Graphic;
+import org.eclipse.statet.rj.services.util.PngGraphic;
+import org.eclipse.statet.rj.services.util.RPkgInstallation;
+
+
+public class DemoApp {
+	
+	
+	public static void main(String[] args) {
+		Display display= new Display();
+		Shell shell= new Shell(display);
+		shell.setText("(RJ) - RServi Demo/Test");
+		shell.setLayout(new FillLayout());
+		
+		new DemoApp(shell);
+		
+		shell.pack();
+		shell.open();
+		while (!shell.isDisposed()) {
+			if (!display.readAndDispatch()) { 
+				display.sleep();
+			}
+		}
+		display.dispose();
+	}
+	
+	
+	private Text fInitRemoteText;
+	private Button fInitRemoteButton;
+	private Text fInitLocalText;
+	private Button fInitLocalButton;
+	private Button fCloseButton;
+	private Text fLogText;
+	
+	private Text fEvalText;
+	private Button fEvalVoidButton;
+	private Button fEvalDataButton;
+	private Button fAssignDataButton;
+	
+	private Text fRemoteFileText;
+	private Button fUploadButton;
+	private Button fDownloadButton;
+	private Button fOpenButton;
+	
+	private Button fInstPkgButton;
+	
+	private FunctionCall fFunctionBuilder;
+	private Text fFunctionNameText;
+	private Button fFunctionNewButton;
+	private Text fFunctionArgumentText;
+	private Button fFunctionAddDataButton;
+	private Text fFunctionAddExpressionText;
+	private Button fFunctionAddExpressionButton;
+	private Button fFunctionEvalData;
+	
+	private Button fCombinedHistButton;
+	
+	private RServi fRServi;
+	
+	private RObject fData;
+	private File fFile;
+	
+	
+	public DemoApp(Composite parent) {
+		EAppEnvSWT eAppEnv= new EAppEnvSWT();
+		Control content= createContent(parent);
+		
+		parent.getShell().addDisposeListener(eAppEnv);
+		parent.getShell().addShellListener(new ShellAdapter() {
+			@Override
+			public void shellClosed(ShellEvent e) {
+				if (fRServi != null) {
+					close();
+				}
+			}
+		});
+		checkedEnabled();
+	}
+	
+	
+	private Control createContent(Composite parent) {
+		SashForm form= new SashForm(parent, SWT.HORIZONTAL);
+		
+		Composite composite= new Composite(form, SWT.NONE);
+		composite.setLayout(new GridLayout(2, false));
+		
+		{	Composite log= new Composite(form, SWT.NONE);
+			GridLayout layout= new GridLayout(1, false);
+			layout.marginRight+= layout.marginWidth;
+			layout.marginWidth= 0;
+			log.setLayout(layout);
+			
+			fLogText= new Text(log, SWT.MULTI | SWT.BORDER | SWT.V_SCROLL | SWT.H_SCROLL);
+			GridData gd= new GridData(SWT.FILL, SWT.FILL, true, true, 1, 20);
+			gd.widthHint= 300;
+			gd.heightHint= fLogText.getLineHeight()*10;
+			fLogText.setLayoutData(gd);
+		}
+		{	addLabel(composite, "Pool:");
+			fInitRemoteText= new Text(composite, SWT.SINGLE | SWT.BORDER);
+			fInitRemoteText.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
+			
+			addDummy(composite);
+			fInitRemoteButton= new Button(composite, SWT.PUSH);
+			GridData gd= new GridData(SWT.FILL, SWT.FILL, true, false);
+			gd.widthHint= 300;
+			fInitRemoteButton.setLayoutData(gd);
+			fInitRemoteButton.setText("Start - Connect Remote");
+			fInitRemoteButton.addSelectionListener(new SelectionAdapter() {
+				@Override
+				public void widgetSelected(SelectionEvent e) {
+					initRemote();
+				}
+			});
+			
+//			addLabel(composite, "R_HOME:");
+//			fInitLocalText= new Text(composite, SWT.SINGLE | SWT.BORDER);
+//			fInitLocalText.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
+//			
+//			addDummy(composite);
+//			fInitLocalButton= new Button(composite, SWT.PUSH);
+//			fInitLocalButton.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
+//			fInitLocalButton.setText("Start - Local");
+//			fInitLocalButton.addSelectionListener(new SelectionAdapter() {
+//				@Override
+//				public void widgetSelected(SelectionEvent e) {
+//					initLocal();
+//				}
+//			});
+			addDummy(composite);
+			fCloseButton= new Button(composite, SWT.PUSH);
+			fCloseButton.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
+			fCloseButton.setText("Close");
+			fCloseButton.addSelectionListener(new SelectionAdapter() {
+				@Override
+				public void widgetSelected(SelectionEvent e) {
+					close();
+				}
+			});
+		}
+		
+		new Label(composite, SWT.SEPARATOR | SWT.HORIZONTAL)
+				.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 2, 1));
+		
+		{	addLabel(composite, "Expression:");
+			fEvalText= new Text(composite, SWT.BORDER);
+			fEvalText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+			
+			addDummy(composite);
+			fEvalVoidButton= new Button(composite, SWT.PUSH);
+			fEvalVoidButton.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
+			fEvalVoidButton.setText("Execute #evalVoid");
+			fEvalVoidButton.addSelectionListener(new SelectionAdapter() {
+				@Override
+				public void widgetSelected(SelectionEvent e) {
+					evalVoid();
+				}
+			});
+			
+			addDummy(composite);
+			fEvalDataButton= new Button(composite, SWT.PUSH);
+			fEvalDataButton.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
+			fEvalDataButton.setText("Execute #evalData");
+			fEvalDataButton.addSelectionListener(new SelectionAdapter() {
+				@Override
+				public void widgetSelected(SelectionEvent e) {
+					evalData();
+				}
+			});
+			
+			addDummy(composite);
+			fAssignDataButton= new Button(composite, SWT.PUSH);
+			fAssignDataButton.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
+			fAssignDataButton.setText("Execute #assignData");
+			fAssignDataButton.addSelectionListener(new SelectionAdapter() {
+				@Override
+				public void widgetSelected(SelectionEvent e) {
+					assignData();
+				}
+			});
+		}
+		
+		new Label(composite, SWT.SEPARATOR | SWT.HORIZONTAL)
+				.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 2, 1));
+		
+		{	addLabel(composite, "Remote file:");
+			fRemoteFileText= new Text(composite, SWT.BORDER);
+			fRemoteFileText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+			
+			addDummy(composite);
+			fUploadButton= new Button(composite, SWT.PUSH);
+			fUploadButton.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
+			fUploadButton.setText("Upload File...");
+			fUploadButton.addSelectionListener(new SelectionAdapter() {
+				@Override
+				public void widgetSelected(SelectionEvent e) {
+					uploadFile();
+				}
+			});
+			
+			fOpenButton= new Button(composite, SWT.PUSH);
+			fOpenButton.setLayoutData(new GridData(SWT.RIGHT, SWT.FILL, false, false));
+			fOpenButton.setText("Open File <-");
+			fOpenButton.addSelectionListener(new SelectionAdapter() {
+				@Override
+				public void widgetSelected(SelectionEvent e) {
+					openFile();
+				}
+			});
+			fDownloadButton= new Button(composite, SWT.PUSH);
+			fDownloadButton.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
+			fDownloadButton.setText("Download File...");
+			fDownloadButton.addSelectionListener(new SelectionAdapter() {
+				@Override
+				public void widgetSelected(SelectionEvent e) {
+					downloadFile();
+				}
+			});
+			
+		}
+		
+		new Label(composite, SWT.SEPARATOR | SWT.HORIZONTAL)
+				.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 2, 1));
+		
+		{	addLabel(composite, "Package:");
+			fInstPkgButton= new Button(composite, SWT.PUSH);
+			fInstPkgButton.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
+			fInstPkgButton.setText("Install Package file...");
+			fInstPkgButton.addSelectionListener(new SelectionAdapter() {
+				@Override
+				public void widgetSelected(SelectionEvent e) {
+					instPkgFile();
+				}
+			});
+		}
+		
+		
+		new Label(composite, SWT.SEPARATOR | SWT.HORIZONTAL)
+				.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 2, 1));
+		
+		{	addLabel(composite, "Function:");
+			fFunctionNameText= new Text(composite, SWT.BORDER);
+			fFunctionNameText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+			
+			addDummy(composite);
+			fFunctionNewButton= new Button(composite, SWT.PUSH);
+			fFunctionNewButton.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
+			fFunctionNewButton.setText("New (Restart builder)");
+			fFunctionNewButton.addSelectionListener(new SelectionAdapter() {
+				@Override
+				public void widgetSelected(SelectionEvent event) {
+					try {
+						fFunctionBuilder= fRServi.createFunctionCall(fFunctionNameText.getText());
+					}
+					catch (Exception e) {
+						logError(e);
+					}
+					logFunction();
+					checkedEnabled();
+				}
+			});
+			
+			addLabel(composite, "Argument:");
+			fFunctionArgumentText= new Text(composite, SWT.BORDER);
+			fFunctionArgumentText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+			
+			addLabel(composite, "Expression:");
+			fFunctionAddExpressionText= new Text(composite, SWT.BORDER);
+			fFunctionAddExpressionText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+			
+			addDummy(composite);
+			fFunctionAddDataButton= new Button(composite, SWT.PUSH);
+			fFunctionAddDataButton.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
+			fFunctionAddDataButton.setText("Add data argument");
+			fFunctionAddDataButton.addSelectionListener(new SelectionAdapter() {
+				@Override
+				public void widgetSelected(SelectionEvent e) {
+					String arg= fFunctionArgumentText.getText();
+					fFunctionBuilder.add(arg.length() > 0 ? arg : null, fData);
+					logFunction();
+				}
+			});
+			
+			addDummy(composite);
+			fFunctionAddExpressionButton= new Button(composite, SWT.PUSH);
+			fFunctionAddExpressionButton.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
+			fFunctionAddExpressionButton.setText("Add expression argument");
+			fFunctionAddExpressionButton.addSelectionListener(new SelectionAdapter() {
+				@Override
+				public void widgetSelected(SelectionEvent e) {
+					String arg= fFunctionArgumentText.getText();
+					fFunctionBuilder.add(arg.length() > 0 ? arg : null, fFunctionAddExpressionText.getText());
+					logFunction();
+				}
+			});
+			
+			addDummy(composite);
+			fFunctionEvalData= new Button(composite, SWT.PUSH);
+			fFunctionEvalData.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
+			fFunctionEvalData.setText("Execute #evalData");
+			fFunctionEvalData.addSelectionListener(new SelectionAdapter() {
+				@Override
+				public void widgetSelected(SelectionEvent e) {
+					evalFunctionData();
+				}
+			});
+		}
+		
+		new Label(composite, SWT.SEPARATOR | SWT.HORIZONTAL)
+				.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 2, 1));
+		
+		{	fCombinedHistButton= new Button(composite, SWT.PUSH);
+			fCombinedHistButton.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, 2, 1));
+			fCombinedHistButton.setText("Create and Show 'hist(x)'");
+			fCombinedHistButton.addSelectionListener(new SelectionAdapter() {
+				@Override
+				public void widgetSelected(SelectionEvent e) {
+					showHist();
+				}
+			});
+		}
+			
+		form.setWeights(new int[] { 2, 3 });
+		
+		fInitRemoteText.setText("rmi://localhost/rservi-pool");
+		String rHome= System.getenv("R_HOME");
+		if (rHome != null) {
+			fInitLocalText.setText(rHome);
+		}
+		
+		return composite;
+	}
+	
+	private Label addLabel(Composite composite, String text) {
+		final Label label= new Label(composite, SWT.NONE);
+		label.setText(text);
+		label.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false));
+		return label;
+	}
+	
+	private void addDummy(Composite composite) {
+		final Label label= new Label(composite, SWT.NONE);
+		label.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false));
+	}
+	
+	private void logOK() {
+		fLogText.append(" OK\n");
+	}
+	
+	private void logCancelled() {
+		fLogText.append(" CANCELLED\n");
+	}
+	
+	private void logFailed() {
+		fLogText.append(" FAILED\n");
+	}
+	
+	private void logFunction() {
+		fLogText.append("Current Function:\n");
+		fLogText.append(fFunctionBuilder.toString());
+		fLogText.append("\n");
+	}
+	
+	private void logError(Throwable t) {
+		StringWriter sw= new StringWriter();
+		PrintWriter pw= new PrintWriter(sw, true);
+		t.printStackTrace(pw);
+		pw.flush();
+		sw.flush();
+		fLogText.append(" FAILED\n");
+		fLogText.append(sw.toString());
+		fLogText.append("\n");
+	}
+	
+	private void checkedEnabled() {
+		boolean ok= (fRServi != null);
+		fInitRemoteButton.setEnabled(!ok);
+		if (fInitLocalButton != null) {
+			fInitLocalButton.setEnabled(!ok);
+		}
+		fCloseButton.setEnabled(ok);
+		
+		fEvalVoidButton.setEnabled(ok);
+		fEvalDataButton.setEnabled(ok);
+		fAssignDataButton.setEnabled(ok && fData != null);
+		
+		fUploadButton.setEnabled(ok);
+		fDownloadButton.setEnabled(ok);
+		fOpenButton.setEnabled(fFile != null);
+		
+		fInstPkgButton.setEnabled(ok);
+		
+		fCombinedHistButton.setEnabled(ok);
+		
+		fFunctionNewButton.setEnabled(ok);
+		ok= ok && (fFunctionBuilder != null);
+		fFunctionAddDataButton.setEnabled(ok && fData != null);
+		fFunctionAddExpressionButton.setEnabled(ok);
+		fFunctionEvalData.setEnabled(ok);
+	}
+	
+	private void initRemote() {
+		fLogText.setText("");
+		fLogText.append("Requesting RServi instance...");
+		try {
+			fRServi= RServiUtil.getRServi(fInitRemoteText.getText(), "demo/test");
+			logOK();
+		}
+		catch (Exception e) {
+			fRServi= null;
+			logError(e);
+		}
+		checkedEnabled();
+	}
+	
+//	private void initLocal() {
+//		fLogText.setText("");
+//		fLogText.append("Requesting RServi instance...");
+//		try {
+//			TODO
+//			logOK();
+//		}
+//		catch (Exception e) {
+//			fRServi= null;
+//			logError(e);
+//		}
+//		checkedEnabled();
+//	}
+	
+	private void close() {
+		fLogText.append("Closing RServi instance...");
+		try {
+			fFunctionBuilder= null;
+			fRServi.close();
+			fRServi= null;
+			logOK();
+		}
+		catch (Exception e) {
+			fRServi= null;
+			logError(e);
+		}
+		checkedEnabled();
+	}
+	
+	private void evalVoid() {
+		fLogText.append("Executing #evalVoid:\n\t");
+		String command= fEvalText.getText();
+		fLogText.append(command);
+		try {
+			fRServi.evalVoid(command, null);
+			fLogText.append("\n----\n");
+		}
+		catch (Exception e) {
+			logError(e);
+		}
+		checkedEnabled();
+	}
+	
+	private void evalData() {
+		fLogText.append("Executing #evalData:\n\t");
+		final String command= fEvalText.getText();
+		fLogText.append(command);
+		try {
+			RObject data= fRServi.evalData(command, null);
+			fLogText.append("\n");
+			fLogText.append(data.toString());
+			fLogText.append("\n----\n");
+			fData= data;
+		}
+		catch (Exception e) {
+			logError(e);
+		}
+		checkedEnabled();
+	}
+	
+	private void evalFunctionData() {
+		fLogText.append("Executing FunctionCall#evalData:\n\t");
+		final String command= fEvalText.getText();
+		fLogText.append(command);
+		try {
+			RObject data= fFunctionBuilder.evalData(null);
+			fLogText.append("\n");
+			fLogText.append(data.toString());
+			fLogText.append("\n----\n");
+			fData= data;
+		}
+		catch (Exception e) {
+			logError(e);
+		}
+		checkedEnabled();
+	}
+	
+	private void assignData() {
+		fLogText.append("Executing #assignData:\n\t");
+		final String command= fEvalText.getText();
+		fLogText.append(command);
+		try {
+			fRServi.assignData(command, fData, null);
+			logOK();
+		}
+		catch (Exception e) {
+			logError(e);
+		}
+		checkedEnabled();
+	}
+	
+	private void uploadFile() {
+		fLogText.append("Uploading file...");
+		final FileDialog dialog= new FileDialog(fLogText.getShell(), SWT.OPEN);
+		final String local= dialog.open();
+		if (local == null) {
+			logCancelled();
+			return;
+		}
+		
+		final String remote= fRemoteFileText.getText();
+		fLogText.append("\n\t");
+		fLogText.append("local: ");
+		fLogText.append(local);
+		fLogText.append(" -> ");
+		fLogText.append("remote: ");
+		fLogText.append(remote);
+		fLogText.append("\n");
+		
+		FileInputStream in= null;
+		try {
+			File file= new File(local);
+			in= new FileInputStream(file);
+			fRServi.uploadFile(in, file.length(), remote, 0, null);
+			logOK();
+		}
+		catch (Exception e) {
+			logError(e);
+		}
+		finally {
+			if (in != null) {
+				try {
+					in.close();
+				}
+				catch (IOException e) {}
+			}
+		}
+		checkedEnabled();
+	}
+	
+	private void downloadFile() {
+		fLogText.append("Downloading file...");
+		final FileDialog dialog= new FileDialog(fLogText.getShell(), SWT.SAVE);
+		final String local= dialog.open();
+		if (local == null) {
+			logCancelled();
+			return;
+		}
+		
+		File file= new File(local);
+		if (file.exists()) {
+			MessageBox box= new MessageBox(fLogText.getShell(), SWT.YES | SWT.NO);
+			box.setText("Downloading File");
+			box.setMessage("Overwrite existing file '"+file.getName()+"'?");
+			if (box.open() != SWT.YES) {
+				logCancelled();
+				return;
+			}
+		}
+		final String remote= fRemoteFileText.getText();
+		fLogText.append("\n\t");
+		fLogText.append("local: ");
+		fLogText.append(local);
+		fLogText.append(" <- ");
+		fLogText.append("remote: ");
+		fLogText.append(remote);
+		fLogText.append("\n");
+		FileOutputStream out= null;
+		try {
+			out= new FileOutputStream(file);
+			fRServi.downloadFile(out, remote, 0, null);
+			logOK();
+			fFile= file;
+		}
+		catch (Exception e) {
+			fFile= null;
+			logError(e);
+		}
+		finally {
+			if (out != null) {
+				try {
+					out.close();
+				}
+				catch (IOException e) {}
+			}
+		}
+		checkedEnabled();
+	}
+	
+	private void openFile() {
+		String local= fFile.getPath();
+		fLogText.append("Opening file...\n\t");
+		fLogText.append(local);
+		fLogText.append("\n");
+		if (Program.launch(local)) {
+			logOK();
+		}
+		else {
+			logFailed();
+		}
+	}
+	
+	private void instPkgFile() {
+		fLogText.append("Install package file...");
+		final FileDialog dialog= new FileDialog(fLogText.getShell(), SWT.OPEN);
+		final String local= dialog.open();
+		if (local == null) {
+			logCancelled();
+			return;
+		}
+		
+		try {
+			File file= new File(local);
+			RPkgInstallation inst= new RPkgInstallation(file);
+			
+			fLogText.append("\n\t");
+			fLogText.append("local: ");
+			fLogText.append(local);
+			fLogText.append(" -> rpkg: ");
+			fLogText.append(inst.getPkg().toString());
+			fLogText.append("\n");
+			
+			inst.install(fRServi, null);
+			logOK();
+		}
+		catch (Exception e) {
+			logError(e);
+		}
+		checkedEnabled();
+	}
+	
+	private void showHist() {
+		fLogText.append("Create and Show 'hist(x)'...");
+		
+		try {
+			final PngGraphic pngGraphic= new PngGraphic();
+			pngGraphic.setSize(400, 500, Graphic.UNIT_PX);
+			
+			final FunctionCall hist= fRServi.createFunctionCall("hist");
+			hist.add("x");
+			
+			final byte[] plot= pngGraphic.create(hist, fRServi, null);
+			final Shell shell= new Shell(fLogText.getShell(), SWT.DIALOG_TRIM | SWT.RESIZE);
+			shell.setSize(500, 600);
+			shell.setText("PNG Graphic");
+			shell.setLayout(new GridLayout());
+			
+			final Image image= new Image(Display.getCurrent(), new ByteArrayInputStream(plot));
+			shell.addDisposeListener(new DisposeListener() {
+				@Override
+				public void widgetDisposed(DisposeEvent e) {
+					image.dispose();
+				}
+			});
+			final Label label= new Label(shell, SWT.NONE);
+			label.setImage(image);
+			label.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, true, true));
+			
+			shell.open();
+			logOK();
+		}
+		catch (Exception e) {
+			logError(e);
+		}
+		checkedEnabled();
+	}
+	
+}
diff --git a/examples/org.eclipse.statet.rj.servi.demo/src/org/eclipse/statet/rj/servi/demo/EAppEnvSWT.java b/examples/org.eclipse.statet.rj.servi.demo/src/org/eclipse/statet/rj/servi/demo/EAppEnvSWT.java
new file mode 100644
index 0000000..453d4a8
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.demo/src/org/eclipse/statet/rj/servi/demo/EAppEnvSWT.java
@@ -0,0 +1,67 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.servi.demo;
+
+import java.util.concurrent.CopyOnWriteArraySet;
+
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.swt.events.DisposeEvent;
+import org.eclipse.swt.events.DisposeListener;
+
+import org.eclipse.statet.jcommons.lang.Disposable;
+
+import org.eclipse.statet.ecommons.runtime.core.ECommonsRuntime;
+
+
+/** Replaces missing Eclipse environment */
+public class EAppEnvSWT implements ECommonsRuntime.AppEnvironment, DisposeListener {
+	
+	
+	private final CopyOnWriteArraySet<Disposable> stopListeners= new CopyOnWriteArraySet<>();
+	
+	
+	public EAppEnvSWT() {
+		ECommonsRuntime.init("org.eclipse.statet.rj.services.eruntime", this);
+	}
+	
+	
+	@Override
+	public void addStoppingListener(Disposable listener) {
+		stopListeners.add(listener);
+	}
+	
+	@Override
+	public void removeStoppingListener(Disposable listener) {
+		stopListeners.add(listener);
+	}
+	
+	@Override
+	public void log(IStatus status) {
+		System.out.println(status.toString());
+	}
+	
+	@Override
+	public void widgetDisposed(DisposeEvent e) {
+		try {
+			for (final Disposable listener : stopListeners) {
+				listener.dispose();
+			}
+		}
+		finally {
+			stopListeners.clear();
+		}
+	}
+	
+}
diff --git a/examples/org.eclipse.statet.rj.servi.demo/src/org/eclipse/statet/rj/servi/examples/CorrelationPlotter.java b/examples/org.eclipse.statet.rj.servi.demo/src/org/eclipse/statet/rj/servi/examples/CorrelationPlotter.java
new file mode 100644
index 0000000..8416634
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.demo/src/org/eclipse/statet/rj/servi/examples/CorrelationPlotter.java
@@ -0,0 +1,290 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Tobias Verbeke - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.servi.examples;
+
+import java.io.ByteArrayInputStream;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.events.MouseEvent;
+import org.eclipse.swt.events.MouseListener;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Scale;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Text;
+
+import org.eclipse.statet.rj.data.RObject;
+import org.eclipse.statet.rj.servi.RServi;
+import org.eclipse.statet.rj.servi.RServiUtil;
+import org.eclipse.statet.rj.servi.demo.EAppEnvSWT;
+import org.eclipse.statet.rj.services.FunctionCall;
+import org.eclipse.statet.rj.services.util.Graphic;
+import org.eclipse.statet.rj.services.util.PngGraphic;
+
+
+public class CorrelationPlotter {
+	
+	
+	Display display= new Display();
+	Shell shell= new Shell(display);
+	
+	Label nPointsLabel;
+	Text nPointsText;
+	Label correlationLabel;
+	Label correlationValueLabel; 
+	Scale correlationScale;
+	Label pngLabel;
+	Label messageLabel;
+	
+	RServi fRservi;
+	
+	RObject muObj;
+	RObject nObj;
+	RObject rObj;
+	double rValue= 1001; // corresponds to zero correlation
+	int nValue= 100; // initial number of points
+	
+	
+	public CorrelationPlotter(){
+		EAppEnvSWT eAppEnvSWT= new EAppEnvSWT();
+		shell.addDisposeListener(eAppEnvSWT);
+		
+		shell.setText("Correlation Plotter"); // set window title
+		GridLayout gridLayout= new GridLayout();
+		gridLayout.numColumns= 2;
+		shell.setLayout(gridLayout);
+		
+		nPointsLabel= new Label(shell, SWT.NULL);
+		nPointsLabel.setText("Number of points: ");
+		nPointsLabel.setVisible(true);
+		
+		nPointsText= new Text(shell, SWT.RIGHT | SWT.SINGLE | SWT.BORDER);
+		GridData gridDataNPointsText= new GridData(GridData.FILL_HORIZONTAL);
+		gridDataNPointsText.horizontalSpan= 1;
+		nPointsText.setLayoutData(gridDataNPointsText);
+		nPointsText.setSelection(nValue);
+		nPointsText.insert("" + nValue);
+		nPointsText.setVisible(true);
+		
+		correlationLabel= new Label(shell, SWT.NULL);
+		correlationLabel.setText("Correlation value: ");
+		GridData gridDataCorrelationLabel= new GridData(GridData.FILL_HORIZONTAL);
+		gridDataCorrelationLabel.horizontalSpan= 1;
+		correlationLabel.setLayoutData(gridDataCorrelationLabel);
+		correlationLabel.setVisible(true);
+		
+		correlationValueLabel= new Label(shell, SWT.NULL);
+		double labelValue= (double) ((int) ((rValue-1001) * 100.0))/100;
+		correlationValueLabel.setText("" + labelValue); // TODO remove hard-coded value
+		GridData gridDataCorrelationValueLabel= new GridData(GridData.FILL_HORIZONTAL);
+		gridDataCorrelationValueLabel.horizontalSpan= 1;
+		correlationValueLabel.setLayoutData(gridDataCorrelationValueLabel);
+		correlationValueLabel.setAlignment(SWT.RIGHT);
+		correlationValueLabel.setVisible(true);
+		
+		correlationScale= new Scale(shell, SWT.HORIZONTAL);
+		GridData gridDataCorrelationScale= new GridData(GridData.FILL_HORIZONTAL);
+		gridDataCorrelationScale.horizontalSpan= 2;
+		correlationScale.setLayoutData(gridDataCorrelationScale);
+		correlationScale.setMinimum(0);
+		correlationScale.setMaximum(2001);
+		correlationScale.setPageIncrement(10);
+		correlationScale.setSelection((int) rValue); // default value
+		correlationScale.setVisible(true);
+		
+		pngLabel= new Label(shell, SWT.IMAGE_PNG);
+		pngLabel.setSize(300, 300);
+		GridData gridDataPngLabel= new GridData(GridData.FILL_BOTH);
+		gridDataPngLabel.horizontalSpan= 2;
+		pngLabel.setLayoutData(gridDataPngLabel);
+		pngLabel.setToolTipText("Click to sample again");
+		pngLabel.setVisible(true);
+		
+		messageLabel= new Label(shell, SWT.BORDER);
+		GridData gridDataMessageLabel= new GridData(GridData.FILL_HORIZONTAL);
+		gridDataMessageLabel.horizontalSpan= 2;
+		messageLabel.setLayoutData(gridDataMessageLabel);
+		messageLabel.setVisible(true);
+		
+		ModifyListener nPointsListener= new ModifyListener() {
+			@Override
+			public void modifyText(ModifyEvent event) {
+				nPointsChanged();
+			}
+		};
+		
+		SelectionListener correlationListener= new SelectionListener() {
+			@Override
+			public void widgetSelected(SelectionEvent e) {
+				correlationValueChanged();
+			}
+			
+			@Override
+			public void widgetDefaultSelected(SelectionEvent e) {
+				// nothing is done
+				return;
+			}
+		};
+		
+		MouseListener clickListener= new MouseListener() {
+			@Override
+			public void mouseUp(MouseEvent e) {
+				return;
+			}
+			@Override
+			public void mouseDown(MouseEvent e) {
+				try {
+					makePlot();
+				} catch (Exception e2) {
+					e2.printStackTrace();
+				}
+			}
+			@Override
+			public void mouseDoubleClick(MouseEvent e) {
+				return;
+			}
+		};
+		
+		nPointsText.addModifyListener(nPointsListener);
+		correlationScale.addSelectionListener(correlationListener);
+		pngLabel.addMouseListener(clickListener);
+		
+		String URL= "rmi://127.0.0.1/rservi-pool";
+		try {
+			fRservi= RServiUtil.getRServi(URL, "CorrelationPlotter");
+		} catch (Exception e1) {
+			e1.printStackTrace();
+		}
+		try {
+			FunctionCall massCall= fRservi.createFunctionCall("library");
+			massCall.add("package", "MASS");
+			massCall.evalVoid(null);
+			fRservi.evalVoid("mu <- c(0,0)", null);   // does not change
+			fRservi.evalVoid("r <- " + (rValue-1001)/1001, null); // set default value, here: 0
+			fRservi.evalVoid("n <- " + nValue, null); // set default value
+			makePlot(); // initial plot
+		} catch (Exception e){
+			e.printStackTrace();
+		}
+		
+		shell.pack();
+		shell.open();
+		
+		while (!shell.isDisposed()){
+			if (!display.readAndDispatch()) {
+				display.sleep();
+			}
+		}
+		
+		try {
+			fRservi.close();	
+		} catch (Exception e) {
+			e.printStackTrace();
+		}
+		display.dispose();
+	}
+	
+	public void nPointsChanged(){
+		if (!nPointsText.isFocusControl()) {
+			return;
+		}
+		
+		double nPointsValue;
+		
+		try {
+			nPointsValue= Double.parseDouble(nPointsText.getText());
+			messageLabel.setText("Valid number of points: " + nPointsText.getText());
+			messageLabel.setForeground(display.getSystemColor(SWT.COLOR_BLACK));
+			try {
+				if (nPointsValue > 1){
+					fRservi.evalVoid("n <- " + nPointsValue, null);
+					makePlot();
+				} else {
+					messageLabel.setText("Invalid number of points: " + nPointsText.getText());
+					messageLabel.setForeground(display.getSystemColor(SWT.COLOR_RED));
+				}
+			} catch (Exception e) {
+				e.printStackTrace();
+			}
+			
+		} catch (NumberFormatException nfe) {
+			messageLabel.setText("Invalid number of points: " + nPointsText.getText());
+			messageLabel.setForeground(display.getSystemColor(SWT.COLOR_RED));
+		}
+		
+	}
+	
+	public void correlationValueChanged(){
+		double rValue= (double) correlationScale.getSelection() - 1001; // TODO replace with maximum of scale
+		if (rValue >= 0) {
+			rValue= rValue/1000;
+		} else {
+			rValue= rValue/1001;
+		}
+		rValue= (double) ((int) (rValue * 100.0))/100;
+		correlationValueLabel.setText("" + rValue);
+		// System.out.println("Correlation: " + rValue);
+		try {
+			fRservi.evalVoid("r <- " + rValue, null);
+			makePlot();
+			
+		} catch (Exception e) {
+			e.printStackTrace();
+		}
+	}
+	
+	public void makePlot(){
+		try {
+			FunctionCall mvrnormCall= fRservi.createFunctionCall("mvrnorm");
+			mvrnormCall.add("n", "n");
+			mvrnormCall.add("mu", "mu");
+			
+			fRservi.evalVoid("sigma <- matrix(rep(r, 4), ncol= 2)", null);
+			fRservi.evalVoid("diag(sigma) <- c(1,1)", null);
+			fRservi.evalVoid("xy <- mvrnorm(n= n, mu= mu, Sigma= sigma)", null);
+			
+			// plot(x= xy[,1], y= xy[,2], ylab= "", xlab= "")
+			
+			final PngGraphic pngGraphic= new PngGraphic();
+			pngGraphic.setSize(300, 300, Graphic.UNIT_PX);
+			
+			final FunctionCall plotFun= fRservi.createFunctionCall("eqscplot");
+			plotFun.add("x", "xy[,1]");
+			plotFun.add("y", "xy[,2]");
+			plotFun.addChar("xlab", "");
+			plotFun.addChar("ylab", "");
+			
+			final byte[] plot= pngGraphic.create(plotFun, fRservi, null);
+			final Image image= new Image(display, new ByteArrayInputStream(plot));
+			pngLabel.setImage(image);
+			
+		} catch (Exception e) {
+			e.printStackTrace();
+		}
+	}
+	
+	
+	public static void main(String[] args) {
+		new CorrelationPlotter();
+	}
+	
+}
diff --git a/examples/org.eclipse.statet.rj.servi.rcpdemo/.classpath b/examples/org.eclipse.statet.rj.servi.rcpdemo/.classpath
new file mode 100644
index 0000000..eca7bdb
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.rcpdemo/.classpath
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
+	<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+	<classpathentry kind="src" path="src"/>
+	<classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/examples/org.eclipse.statet.rj.servi.rcpdemo/.gitignore b/examples/org.eclipse.statet.rj.servi.rcpdemo/.gitignore
new file mode 100644
index 0000000..5e56e04
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.rcpdemo/.gitignore
@@ -0,0 +1 @@
+/bin
diff --git a/examples/org.eclipse.statet.rj.servi.rcpdemo/.project b/examples/org.eclipse.statet.rj.servi.rcpdemo/.project
new file mode 100644
index 0000000..c2fe9e6
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.rcpdemo/.project
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>org.eclipse.statet.rj.servi.rcpdemo</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.jdt.core.javabuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.pde.ManifestBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.pde.SchemaBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.pde.PluginNature</nature>
+		<nature>org.eclipse.jdt.core.javanature</nature>
+	</natures>
+</projectDescription>
diff --git a/examples/org.eclipse.statet.rj.servi.rcpdemo/.settings/org.eclipse.core.resources.prefs b/examples/org.eclipse.statet.rj.servi.rcpdemo/.settings/org.eclipse.core.resources.prefs
new file mode 100644
index 0000000..99f26c0
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.rcpdemo/.settings/org.eclipse.core.resources.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+encoding/<project>=UTF-8
diff --git a/examples/org.eclipse.statet.rj.servi.rcpdemo/.settings/org.eclipse.core.runtime.prefs b/examples/org.eclipse.statet.rj.servi.rcpdemo/.settings/org.eclipse.core.runtime.prefs
new file mode 100644
index 0000000..5a0ad22
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.rcpdemo/.settings/org.eclipse.core.runtime.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+line.separator=\n
diff --git a/examples/org.eclipse.statet.rj.servi.rcpdemo/.settings/org.eclipse.jdt.core.prefs b/examples/org.eclipse.statet.rj.servi.rcpdemo/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000..ccb1eaa
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.rcpdemo/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,325 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.codeComplete.argumentPrefixes=
+org.eclipse.jdt.core.codeComplete.argumentSuffixes=
+org.eclipse.jdt.core.codeComplete.fieldPrefixes=
+org.eclipse.jdt.core.codeComplete.fieldSuffixes=
+org.eclipse.jdt.core.codeComplete.localPrefixes=
+org.eclipse.jdt.core.codeComplete.localSuffixes=
+org.eclipse.jdt.core.codeComplete.staticFieldPrefixes=
+org.eclipse.jdt.core.codeComplete.staticFieldSuffixes=
+org.eclipse.jdt.core.codeComplete.staticFinalFieldPrefixes=
+org.eclipse.jdt.core.codeComplete.staticFinalFieldSuffixes=
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=1.8
+org.eclipse.jdt.core.compiler.debug.lineNumber=generate
+org.eclipse.jdt.core.compiler.debug.localVariable=generate
+org.eclipse.jdt.core.compiler.debug.sourceFile=generate
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.source=1.8
+org.eclipse.jdt.core.formatter.align_fields_grouping_blank_lines=2147483647
+org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_assignment=0
+org.eclipse.jdt.core.formatter.alignment_for_binary_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_compact_if=16
+org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=80
+org.eclipse.jdt.core.formatter.alignment_for_enum_constants=0
+org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16
+org.eclipse.jdt.core.formatter.alignment_for_expressions_in_for_loop_header=0
+org.eclipse.jdt.core.formatter.alignment_for_method_declaration=0
+org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16
+org.eclipse.jdt.core.formatter.alignment_for_parameterized_type_references=0
+org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_resources_in_try=85
+org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=16
+org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_type_arguments=0
+org.eclipse.jdt.core.formatter.alignment_for_type_parameters=0
+org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch=16
+org.eclipse.jdt.core.formatter.blank_lines_after_imports=2
+org.eclipse.jdt.core.formatter.blank_lines_after_package=1
+org.eclipse.jdt.core.formatter.blank_lines_before_field=0
+org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=1
+org.eclipse.jdt.core.formatter.blank_lines_before_imports=1
+org.eclipse.jdt.core.formatter.blank_lines_before_member_type=1
+org.eclipse.jdt.core.formatter.blank_lines_before_method=1
+org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=2
+org.eclipse.jdt.core.formatter.blank_lines_before_package=1
+org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=1
+org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=1
+org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_block=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_lambda_body=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=false
+org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=false
+org.eclipse.jdt.core.formatter.comment.format_block_comments=true
+org.eclipse.jdt.core.formatter.comment.format_header=false
+org.eclipse.jdt.core.formatter.comment.format_html=true
+org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=true
+org.eclipse.jdt.core.formatter.comment.format_line_comments=true
+org.eclipse.jdt.core.formatter.comment.format_source_code=true
+org.eclipse.jdt.core.formatter.comment.indent_parameter_description=false
+org.eclipse.jdt.core.formatter.comment.indent_root_tags=true
+org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert
+org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=do not insert
+org.eclipse.jdt.core.formatter.comment.line_length=100
+org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries=false
+org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries=true
+org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments=false
+org.eclipse.jdt.core.formatter.compact_else_if=true
+org.eclipse.jdt.core.formatter.continuation_indentation=2
+org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=2
+org.eclipse.jdt.core.formatter.disabling_tag=@formatter\:off
+org.eclipse.jdt.core.formatter.enabling_tag=@formatter\:on
+org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false
+org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true
+org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true
+org.eclipse.jdt.core.formatter.indent_empty_lines=true
+org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true
+org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true
+org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true
+org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=false
+org.eclipse.jdt.core.formatter.indentation.size=4
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_enum_constant=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_label=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_type_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert
+org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert
+org.eclipse.jdt.core.formatter.insert_space_after_lambda_arrow=insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources=insert
+org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert
+org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=insert
+org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert
+org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw=insert
+org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.join_lines_in_comments=true
+org.eclipse.jdt.core.formatter.join_wrapped_lines=true
+org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=false
+org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false
+org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=false
+org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false
+org.eclipse.jdt.core.formatter.lineSplit=100
+org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false
+org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=false
+org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0
+org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=1
+org.eclipse.jdt.core.formatter.parentheses_positions_in_annotation=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_catch_clause=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_enum_constant_declaration=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_for_statment=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_if_while_statement=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_lambda_declaration=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_method_delcaration=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_method_invocation=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_switch_statement=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_try_clause=common_lines
+org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=true
+org.eclipse.jdt.core.formatter.tabulation.char=tab
+org.eclipse.jdt.core.formatter.tabulation.size=4
+org.eclipse.jdt.core.formatter.use_on_off_tags=false
+org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false
+org.eclipse.jdt.core.formatter.wrap_before_assignment_operator=false
+org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true
+org.eclipse.jdt.core.formatter.wrap_before_conditional_operator=false
+org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch=true
+org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true
+org.eclipse.jdt.core.javaFormatter=org.eclipse.jdt.core.defaultJavaFormatter
diff --git a/examples/org.eclipse.statet.rj.servi.rcpdemo/.settings/org.eclipse.jdt.ui.prefs b/examples/org.eclipse.statet.rj.servi.rcpdemo/.settings/org.eclipse.jdt.ui.prefs
new file mode 100644
index 0000000..e62a4f5
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.rcpdemo/.settings/org.eclipse.jdt.ui.prefs
@@ -0,0 +1,131 @@
+cleanup.add_default_serial_version_id=true
+cleanup.add_generated_serial_version_id=false
+cleanup.add_missing_annotations=true
+cleanup.add_missing_deprecated_annotations=true
+cleanup.add_missing_methods=false
+cleanup.add_missing_nls_tags=false
+cleanup.add_missing_override_annotations=true
+cleanup.add_missing_override_annotations_interface_methods=true
+cleanup.add_serial_version_id=false
+cleanup.always_use_blocks=true
+cleanup.always_use_parentheses_in_expressions=true
+cleanup.always_use_this_for_non_static_field_access=true
+cleanup.always_use_this_for_non_static_method_access=false
+cleanup.convert_functional_interfaces=false
+cleanup.convert_to_enhanced_for_loop=false
+cleanup.correct_indentation=false
+cleanup.format_source_code=false
+cleanup.format_source_code_changes_only=false
+cleanup.insert_inferred_type_arguments=false
+cleanup.make_local_variable_final=true
+cleanup.make_parameters_final=true
+cleanup.make_private_fields_final=true
+cleanup.make_type_abstract_if_missing_method=false
+cleanup.make_variable_declarations_final=true
+cleanup.never_use_blocks=false
+cleanup.never_use_parentheses_in_expressions=false
+cleanup.organize_imports=true
+cleanup.qualify_static_field_accesses_with_declaring_class=false
+cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true
+cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=false
+cleanup.qualify_static_member_accesses_with_declaring_class=true
+cleanup.qualify_static_method_accesses_with_declaring_class=false
+cleanup.remove_private_constructors=true
+cleanup.remove_redundant_type_arguments=true
+cleanup.remove_trailing_whitespaces=false
+cleanup.remove_trailing_whitespaces_all=true
+cleanup.remove_trailing_whitespaces_ignore_empty=false
+cleanup.remove_unnecessary_casts=true
+cleanup.remove_unnecessary_nls_tags=true
+cleanup.remove_unused_imports=true
+cleanup.remove_unused_local_variables=false
+cleanup.remove_unused_private_fields=true
+cleanup.remove_unused_private_members=false
+cleanup.remove_unused_private_methods=true
+cleanup.remove_unused_private_types=true
+cleanup.sort_members=false
+cleanup.sort_members_all=false
+cleanup.use_anonymous_class_creation=false
+cleanup.use_blocks=true
+cleanup.use_blocks_only_for_return_and_throw=false
+cleanup.use_lambda=true
+cleanup.use_parentheses_in_expressions=false
+cleanup.use_this_for_non_static_field_access=true
+cleanup.use_this_for_non_static_field_access_only_if_necessary=false
+cleanup.use_this_for_non_static_method_access=true
+cleanup.use_this_for_non_static_method_access_only_if_necessary=true
+cleanup.use_type_arguments=false
+cleanup_profile=_StatET
+cleanup_settings_version=2
+eclipse.preferences.version=1
+editor_save_participant_org.eclipse.jdt.ui.postsavelistener.cleanup=true
+formatter_profile=_StatET
+formatter_settings_version=12
+org.eclipse.jdt.ui.exception.name=e
+org.eclipse.jdt.ui.gettersetter.use.is=true
+org.eclipse.jdt.ui.ignorelowercasenames=true
+org.eclipse.jdt.ui.importorder=\#;java;javax;com.ibm.icu;org.osgi;org.eclipse;;org.eclipse.statet.jcommons;org.eclipse.statet.ecommons;org.eclipse.statet;
+org.eclipse.jdt.ui.javadoc=true
+org.eclipse.jdt.ui.keywordthis=true
+org.eclipse.jdt.ui.ondemandthreshold=99
+org.eclipse.jdt.ui.overrideannotation=true
+org.eclipse.jdt.ui.staticondemandthreshold=99
+org.eclipse.jdt.ui.text.custom_code_templates=<?xml version\="1.0" encoding\="UTF-8" standalone\="no"?><templates><template autoinsert\="true" context\="gettercomment_context" deleted\="false" description\="Comment for getter method" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.gettercomment" name\="gettercomment">/**\n * @return the ${bare_field_name}\n */</template><template autoinsert\="true" context\="settercomment_context" deleted\="false" description\="Comment for setter method" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.settercomment" name\="settercomment">/**\n * @param ${param} the ${bare_field_name} to set\n */</template><template autoinsert\="true" context\="constructorcomment_context" deleted\="false" description\="Comment for created constructors" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.constructorcomment" name\="constructorcomment">/**\n * ${tags}\n */</template><template autoinsert\="false" context\="filecomment_context" deleted\="false" description\="Comment for created Java files" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.filecomment" name\="filecomment">/*\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\#\n \# Copyright (c) ${year} ${user} and others.\n # \n # This program and the accompanying materials are made available under the\n # terms of the Eclipse Public License 2.0 which is available at\n # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n # which is available at https://www.apache.org/licenses/LICENSE-2.0.\n # \n # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n # \n \# Contributors\:\n \#     ${user} - initial API and implementation\n \#\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=*/</template><template autoinsert\="false" context\="typecomment_context" deleted\="false" description\="Comment for created types" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.typecomment" name\="typecomment">/**\n * \n * ${tags}\n */</template><template autoinsert\="true" context\="fieldcomment_context" deleted\="false" description\="Comment for fields" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.fieldcomment" name\="fieldcomment">/**\n * \n */</template><template autoinsert\="true" context\="methodcomment_context" deleted\="false" description\="Comment for non-overriding methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.methodcomment" name\="methodcomment">/**\n * ${tags}\n */</template><template autoinsert\="false" context\="overridecomment_context" deleted\="false" description\="Comment for overriding methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.overridecomment" name\="overridecomment"/><template autoinsert\="true" context\="delegatecomment_context" deleted\="false" description\="Comment for delegate methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.delegatecomment" name\="delegatecomment">/**\n * ${tags}\n * ${see_to_target}\n */</template><template autoinsert\="false" context\="newtype_context" deleted\="false" description\="Newly created files" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.newtype" name\="newtype">${filecomment}\n\n${package_declaration}\n\n${typecomment}\n${type_declaration}</template><template autoinsert\="true" context\="classbody_context" deleted\="false" description\="Code in new class type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.classbody" name\="classbody">\n</template><template autoinsert\="true" context\="interfacebody_context" deleted\="false" description\="Code in new interface type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.interfacebody" name\="interfacebody">\n</template><template autoinsert\="true" context\="enumbody_context" deleted\="false" description\="Code in new enum type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.enumbody" name\="enumbody">\n</template><template autoinsert\="true" context\="annotationbody_context" deleted\="false" description\="Code in new annotation type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.annotationbody" name\="annotationbody">\n</template><template autoinsert\="true" context\="catchblock_context" deleted\="false" description\="Code in new catch blocks" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.catchblock" name\="catchblock">// ${todo} Auto-generated catch block\n${exception_var}.printStackTrace();</template><template autoinsert\="true" context\="methodbody_context" deleted\="false" description\="Code in created method stubs" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.methodbody" name\="methodbody">// ${todo} Auto-generated method stub\n${body_statement}</template><template autoinsert\="true" context\="constructorbody_context" deleted\="false" description\="Code in created constructor stubs" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.constructorbody" name\="constructorbody">${body_statement}\n// ${todo} Auto-generated constructor stub</template><template autoinsert\="true" context\="getterbody_context" deleted\="false" description\="Code in created getters" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.getterbody" name\="getterbody">return ${field};</template><template autoinsert\="true" context\="setterbody_context" deleted\="false" description\="Code in created setters" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.setterbody" name\="setterbody">${field} \= ${param};</template></templates>
+sp_cleanup.add_default_serial_version_id=true
+sp_cleanup.add_generated_serial_version_id=false
+sp_cleanup.add_missing_annotations=true
+sp_cleanup.add_missing_deprecated_annotations=true
+sp_cleanup.add_missing_methods=false
+sp_cleanup.add_missing_nls_tags=false
+sp_cleanup.add_missing_override_annotations=true
+sp_cleanup.add_missing_override_annotations_interface_methods=true
+sp_cleanup.add_serial_version_id=false
+sp_cleanup.always_use_blocks=true
+sp_cleanup.always_use_parentheses_in_expressions=true
+sp_cleanup.always_use_this_for_non_static_field_access=true
+sp_cleanup.always_use_this_for_non_static_method_access=false
+sp_cleanup.convert_functional_interfaces=false
+sp_cleanup.convert_to_enhanced_for_loop=false
+sp_cleanup.correct_indentation=false
+sp_cleanup.format_source_code=false
+sp_cleanup.format_source_code_changes_only=false
+sp_cleanup.insert_inferred_type_arguments=false
+sp_cleanup.make_local_variable_final=true
+sp_cleanup.make_parameters_final=true
+sp_cleanup.make_private_fields_final=true
+sp_cleanup.make_type_abstract_if_missing_method=false
+sp_cleanup.make_variable_declarations_final=false
+sp_cleanup.never_use_blocks=false
+sp_cleanup.never_use_parentheses_in_expressions=false
+sp_cleanup.on_save_use_additional_actions=true
+sp_cleanup.organize_imports=true
+sp_cleanup.qualify_static_field_accesses_with_declaring_class=false
+sp_cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true
+sp_cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=false
+sp_cleanup.qualify_static_member_accesses_with_declaring_class=true
+sp_cleanup.qualify_static_method_accesses_with_declaring_class=false
+sp_cleanup.remove_private_constructors=true
+sp_cleanup.remove_redundant_type_arguments=true
+sp_cleanup.remove_trailing_whitespaces=false
+sp_cleanup.remove_trailing_whitespaces_all=false
+sp_cleanup.remove_trailing_whitespaces_ignore_empty=true
+sp_cleanup.remove_unnecessary_casts=true
+sp_cleanup.remove_unnecessary_nls_tags=false
+sp_cleanup.remove_unused_imports=false
+sp_cleanup.remove_unused_local_variables=false
+sp_cleanup.remove_unused_private_fields=false
+sp_cleanup.remove_unused_private_members=false
+sp_cleanup.remove_unused_private_methods=false
+sp_cleanup.remove_unused_private_types=true
+sp_cleanup.sort_members=false
+sp_cleanup.sort_members_all=false
+sp_cleanup.use_anonymous_class_creation=false
+sp_cleanup.use_blocks=true
+sp_cleanup.use_blocks_only_for_return_and_throw=false
+sp_cleanup.use_lambda=false
+sp_cleanup.use_parentheses_in_expressions=false
+sp_cleanup.use_this_for_non_static_field_access=true
+sp_cleanup.use_this_for_non_static_field_access_only_if_necessary=false
+sp_cleanup.use_this_for_non_static_method_access=true
+sp_cleanup.use_this_for_non_static_method_access_only_if_necessary=true
+sp_cleanup.use_type_arguments=false
diff --git a/examples/org.eclipse.statet.rj.servi.rcpdemo/META-INF/MANIFEST.MF b/examples/org.eclipse.statet.rj.servi.rcpdemo/META-INF/MANIFEST.MF
new file mode 100644
index 0000000..13cfc64
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.rcpdemo/META-INF/MANIFEST.MF
@@ -0,0 +1,17 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-SymbolicName: org.eclipse.statet.rj.servi.rcpdemo;singleton:=true
+Bundle-Version: 2.1.0.qualifier
+Bundle-Vendor: Eclipse.org
+Bundle-Name: StatET RJ - RServi RCP Demo (1)
+Bundle-ActivationPolicy: lazy
+Bundle-Activator: org.eclipse.statet.internal.rj.servi.rcpdemo.Activator
+Bundle-RequiredExecutionEnvironment: JavaSE-1.8
+Require-Bundle: org.eclipse.core.runtime,
+ org.eclipse.statet.ecommons.rmi.core;bundle-version="1.5.0",
+ org.eclipse.statet.rj.data;bundle-version="2.1.0",
+ org.eclipse.statet.rj.server;bundle-version="2.1.0",
+ org.eclipse.statet.rj.client;bundle-version="2.1.0",
+ org.eclipse.statet.rj.servi;bundle-version="2.1.0",
+ org.eclipse.ui,
+ org.eclipse.statet.rj.eclient.graphics;bundle-version="2.1.0"
diff --git a/examples/org.eclipse.statet.rj.servi.rcpdemo/RServi RCP Demo.launch b/examples/org.eclipse.statet.rj.servi.rcpdemo/RServi RCP Demo.launch
new file mode 100644
index 0000000..da45f0a
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.rcpdemo/RServi RCP Demo.launch
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>

+<launchConfiguration type="org.eclipse.pde.ui.RuntimeWorkbench">

+<setAttribute key="additional_plugins"/>

+<booleanAttribute key="append.args" value="true"/>

+<stringAttribute key="application" value="org.eclipse.statet.rj.servi.rcpdemo.application"/>

+<booleanAttribute key="askclear" value="false"/>

+<booleanAttribute key="automaticAdd" value="false"/>

+<booleanAttribute key="automaticValidate" value="false"/>

+<stringAttribute key="bootstrap" value=""/>

+<stringAttribute key="checked" value="[NONE]"/>

+<booleanAttribute key="clearConfig" value="true"/>

+<booleanAttribute key="clearws" value="true"/>

+<booleanAttribute key="clearwslog" value="true"/>

+<stringAttribute key="configLocation" value="${workspace_loc}/.metadata/.plugins/org.eclipse.pde.core/RServi RCP Demo"/>

+<booleanAttribute key="default" value="false"/>

+<stringAttribute key="featureDefaultLocation" value="workspace"/>

+<stringAttribute key="featurePluginResolution" value="workspace"/>

+<booleanAttribute key="includeOptional" value="false"/>

+<stringAttribute key="location" value="${workspace_loc}/../runtime-org.eclipse.statet.rj.servi.rcpdemo.product"/>

+<stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>

+<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-os ${target.os} -ws ${target.ws} -arch ${target.arch} -nl ${target.nl} -consoleLog"/>

+<stringAttribute key="org.eclipse.jdt.launching.SOURCE_PATH_PROVIDER" value="org.eclipse.pde.ui.workbenchClasspathProvider"/>

+<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-Xms40m -Xmx512m"/>

+<booleanAttribute key="pde.generated.config" value="false"/>

+<stringAttribute key="pde.version" value="3.3"/>

+<stringAttribute key="product" value="org.eclipse.statet.rj.servi.rcpdemo.product"/>

+<stringAttribute key="productFile" value="\org.eclipse.statet.rj.servi.rcpdemo\org.eclipse.statet.rj.servi.rcpdemo.product"/>

+<setAttribute key="selected_features">

+<setEntry value="org.eclipse.e4.rcp:default"/>

+<setEntry value="org.eclipse.emf.common:default"/>

+<setEntry value="org.eclipse.emf.ecore:default"/>

+<setEntry value="org.eclipse.rcp:default"/>

+</setAttribute>

+<booleanAttribute key="show_selected_only" value="false"/>

+<booleanAttribute key="tracing" value="false"/>

+<booleanAttribute key="useCustomFeatures" value="true"/>

+<booleanAttribute key="useDefaultConfig" value="true"/>

+<booleanAttribute key="useDefaultConfigArea" value="true"/>

+<booleanAttribute key="useProduct" value="true"/>

+<booleanAttribute key="usefeatures" value="false"/>

+</launchConfiguration>

diff --git a/examples/org.eclipse.statet.rj.servi.rcpdemo/about.html b/examples/org.eclipse.statet.rj.servi.rcpdemo/about.html
new file mode 100644
index 0000000..7206cec
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.rcpdemo/about.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+		"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+<title>About</title>
+</head>
+<body lang="EN-US">
+<h2>About This Content</h2>
+
+<p>December 1, 2017</p>
+<h3>License</h3>
+
+<p>
+	The Eclipse Foundation makes available all content in this plug-in
+	(&quot;Content&quot;). Unless otherwise indicated below, the Content
+	is provided to you under the terms and conditions of the Eclipse
+	Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is
+	available at <a href="https://www.eclipse.org/legal/epl-2.0">https://www.eclipse.org/legal/epl-2.0</a>.
+	For purposes of the EPL, &quot;Program&quot; will mean the Content.
+</p>
+
+<p>
+	If you did not receive this Content directly from the Eclipse
+	Foundation, the Content is being redistributed by another party
+	(&quot;Redistributor&quot;) and different terms and conditions may
+	apply to your use of any object code in the Content. Check the
+	Redistributor's license that was provided with the Content. If no such
+	license exists, contact the Redistributor. Unless otherwise indicated
+	below, the terms and conditions of the EPL still apply to any source
+	code in the Content and such source code may be obtained at <a
+	href="https://www.eclipse.org/">https://www.eclipse.org</a>.
+</p>
+
+</body>
+</html>
diff --git a/examples/org.eclipse.statet.rj.servi.rcpdemo/build.properties b/examples/org.eclipse.statet.rj.servi.rcpdemo/build.properties
new file mode 100644
index 0000000..8f6690d
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.rcpdemo/build.properties
@@ -0,0 +1,11 @@
+source..= src/
+output..= bin/
+javacDefaultEncoding..= UTF-8
+
+bin.includes= META-INF/,\
+              plugin.xml,\
+              .,\
+              icons/,\
+              plugin_customization.ini,\
+              splash.bmp
+src.includes= .settings/org.eclipse.core.resources.prefs
diff --git a/examples/org.eclipse.statet.rj.servi.rcpdemo/icons/alt_about.gif b/examples/org.eclipse.statet.rj.servi.rcpdemo/icons/alt_about.gif
new file mode 100644
index 0000000..20d9ad2
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.rcpdemo/icons/alt_about.gif
Binary files differ
diff --git a/examples/org.eclipse.statet.rj.servi.rcpdemo/icons/alt_launcher.icns b/examples/org.eclipse.statet.rj.servi.rcpdemo/icons/alt_launcher.icns
new file mode 100644
index 0000000..b77a6a6
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.rcpdemo/icons/alt_launcher.icns
Binary files differ
diff --git a/examples/org.eclipse.statet.rj.servi.rcpdemo/icons/alt_launcher.ico b/examples/org.eclipse.statet.rj.servi.rcpdemo/icons/alt_launcher.ico
new file mode 100644
index 0000000..d548f71
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.rcpdemo/icons/alt_launcher.ico
Binary files differ
diff --git a/examples/org.eclipse.statet.rj.servi.rcpdemo/icons/alt_launcher.xpm b/examples/org.eclipse.statet.rj.servi.rcpdemo/icons/alt_launcher.xpm
new file mode 100644
index 0000000..d2918c1
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.rcpdemo/icons/alt_launcher.xpm
@@ -0,0 +1,307 @@
+/* XPM */

+static char * icon48_xpm[]= {

+"48 48 256 2",

+"  	c #4B4B3B3B9090",

+". 	c #0D0D0E0E5454",

+"X 	c #11110E0E5B5B",

+"o 	c #17170F0F6363",

+"O 	c #1D1D13136969",

+"+ 	c #212114146C6C",

+"@ 	c #252514147171",

+"# 	c #282811116C6C",

+"$ 	c #26260D0D6363",

+"% 	c #22220B0B5E5E",

+"& 	c #1C1C0B0B5A5A",

+"* 	c #1C1C0B0B5252",

+"= 	c #1B1B05055353",

+"- 	c #161606064D4D",

+"; 	c #161605054949",

+": 	c #111104044848",

+"> 	c #131304044545",

+", 	c #131305054242",

+"< 	c #141410105E5E",

+"1 	c #2C2C15157373",

+"2 	c #2B2B1B1B7575",

+"3 	c #343416167272",

+"4 	c #313113136E6E",

+"5 	c #222209095757",

+"6 	c #1B1B06064D4D",

+"7 	c #15150B0B4242",

+"8 	c #13130C0C5555",

+"9 	c #2E2E1B1B7878",

+"0 	c #33331F1F7C7C",

+"q 	c #343418187878",

+"w 	c #3B3B1C1C7575",

+"e 	c #2E2E10106767",

+"r 	c #1B1B07074747",

+"t 	c #18180B0B4646",

+"y 	c #151513136262",

+"u 	c #1A1A15156464",

+"i 	c #34341F1F7777",

+"p 	c #40401E1E8080",

+"a 	c #42421B1B7A7A",

+"s 	c #3B3B15157474",

+"d 	c #2B2B0B0B5B5B",

+"f 	c #222207075252",

+"g 	c #373727277A7A",

+"h 	c #474724248484",

+"j 	c #393915156E6E",

+"k 	c #373711116A6A",

+"l 	c #343413136363",

+"z 	c #232319196E6E",

+"x 	c #292919197070",

+"c 	c #3C3C2C2C8282",

+"v 	c #444431318585",

+"b 	c #494934348A8A",

+"n 	c #505026268A8A",

+"m 	c #3D3D1B1B6E6E",

+"M 	c #31310E0E5C5C",

+"N 	c #2B2B0D0D5353",

+"B 	c #222207074A4A",

+"V 	c #52523C3C9292",

+"C 	c #58583C3C9494",

+"Z 	c #5D5D44449797",

+"A 	c #5C5C2E2E9292",

+"S 	c #676733339595",

+"D 	c #424228287575",

+"F 	c #29290A0A4F4F",

+"G 	c #6C6C4A4A9E9E",

+"H 	c #72725454A7A7",

+"J 	c #8C8C6D6DB2B2",

+"K 	c #343424246E6E",

+"L 	c #3A3A23236A6A",

+"P 	c #3A3A1C1C6767",

+"I 	c #24240A0A4B4B",

+"U 	c #151518186161",

+"Y 	c #76766F6FA5A5",

+"T 	c #ADAD9191CCCC",

+"R 	c #98988989D3D3",

+"E 	c #45453B3B8686",

+"W 	c #3C3C35357979",

+"Q 	c #363631317575",

+"! 	c #32322D2D6B6B",

+"~ 	c #323229296363",

+"^ 	c #30301F1F6262",

+"/ 	c #323218185E5E",

+"( 	c #272707074B4B",

+") 	c #202028286C6C",

+"_ 	c #1E1E1D1D6868",

+"` 	c #9A9A8282BBBB",

+"' 	c #C8C8B3B3D3D3",

+"] 	c #B3B3AFAFE7E7",

+"[ 	c #84847272C6C6",

+"{ 	c #58585757A3A3",

+"} 	c #3F3F3C3C8A8A",

+"| 	c #3B3B3A3A8484",

+" .	c #414139397D7D",

+"..	c #3D3D39397A7A",

+"X.	c #37372E2E6E6E",

+"o.	c #2C2C21215A5A",

+"O.	c #2E2E1B1B5B5B",

+"+.	c #F5F5EFEFF5F5",

+"@.	c #656566669A9A",

+"#.	c #47474B4B8E8E",

+"$.	c #3C3C44447B7B",

+"%.	c #444442428080",

+"&.	c #45453E3E8181",

+"*.	c #40403C3C8181",

+"=.	c #3D3D33337474",

+"-.	c #3B3B30306E6E",

+";.	c #38382D2D6969",

+":.	c #303026265D5D",

+">.	c #2C2C15155A5A",

+",.	c #1F1F1C1C7070",

+"<.	c #25251E1E7171",

+"1.	c #59595C5C9191",

+"2.	c #4D4D53538989",

+"3.	c #4C4C49498484",

+"4.	c #484845458585",

+"5.	c #494941418585",

+"6.	c #494940408181",

+"7.	c #2F2F1C1C5353",

+"8.	c #2B2B28287676",

+"9.	c #323231317F7F",

+"0.	c #545452528B8B",

+"q.	c #51514E4E8989",

+"w.	c #4E4E4B4B8C8C",

+"e.	c #4C4C47478686",

+"r.	c #46463D3D7E7E",

+"t.	c #434336367A7A",

+"y.	c #2B2B13135555",

+"u.	c #47473D3D8D8D",

+"i.	c #575757578E8E",

+"p.	c #48483E3E7F7F",

+"a.	c #46463A3A7D7D",

+"s.	c #424235357575",

+"d.	c #404034347171",

+"f.	c #BFBFCBCBFAFA",

+"g.	c #B8B8A8A8DDDD",

+"h.	c #5E5E60609292",

+"j.	c #565655558C8C",

+"k.	c #4B4B44448282",

+"l.	c #454539397B7B",

+"z.	c #434338387878",

+"x.	c #3F3F32326D6D",

+"c.	c #3D3D30306969",

+"v.	c #3A3A2E2E6363",

+"b.	c #36362A2A5C5C",

+"n.	c #343424245555",

+"m.	c #30301E1E4D4D",

+"M.	c #49493C3C8282",

+"N.	c #5E5E4F4F8C8C",

+"B.	c #56563B3B8B8B",

+"V.	c #545407078585",

+"C.	c #424234347272",

+"Z.	c #9797A4A4F7F7",

+"A.	c #444436367676",

+"S.	c #7D7D7979D5D5",

+"D.	c #464640408A8A",

+"F.	c #44444B4B8282",

+"G.	c #414107077777",

+"H.	c #71716161C1C1",

+"J.	c #303039397979",

+"K.	c #8E8E8E8EE6E6",

+"L.	c #404033338B8B",

+"P.	c #4A4A45458C8C",

+"I.	c #46463A3A8080",

+"U.	c #363629295454",

+"Y.	c #303022224848",

+"T.	c #424237377575",

+"R.	c #2E2E1D1D6363",

+"E.	c #79798383EAEA",

+"W.	c #74747B7BE4E4",

+"Q.	c #6D6D7676D6D6",

+"!.	c #6A6A7171CECE",

+"~.	c #66666969C6C6",

+"^.	c #62626565BCBC",

+"/.	c #5F5F6060B5B5",

+"(.	c #5B5B5B5BACAC",

+").	c #535353539898",

+"_.	c #4F4F4F4FA4A4",

+"`.	c #54544D4DA4A4",

+"'.	c #323204046B6B",

+"].	c #303035357979",

+"[.	c #313122224343",

+"{.	c #5A5A5B5BB7B7",

+"}.	c #484846468080",

+"|.	c #454541417575",

+" X	c #4B4B31318282",

+".X	c #47473C3C8484",

+"XX	c #3E3E35356E6E",

+"oX	c #2F2F26264040",

+"OX	c #2B2B23233A3A",

+"+X	c #262619195C5C",

+"@X	c #252515155A5A",

+"#X	c #55555151B3B3",

+"$X	c #3C3C2D2D5D5D",

+"%X	c #39392F2F5656",

+"&X	c #37372D2D5050",

+"*X	c #25251F1F3030",

+"=X	c #24241D1D4343",

+"-X	c #202013135656",

+";X	c #41413B3B6C6C",

+":X	c #444442429696",

+">X	c #212100005E5E",

+",X	c #444436367272",

+"<X	c #444436366F6F",

+"1X	c #424236366868",

+"2X	c #3F3F34346161",

+"3X	c #3C3C32325A5A",

+"4X	c #34342A2A4A4A",

+"5X	c #21211B1B2121",

+"6X	c #22221C1C6363",

+"7X	c #2D2D01015E5E",

+"8X	c #20201B1B2525",

+"9X	c #49492F2F7B7B",

+"0X	c #434334346C6C",

+"qX	c #323229294545",

+"wX	c #1C1C10104F4F",

+"eX	c #222217176363",

+"rX	c #37371E1E6B6B",

+"tX	c #424232326E6E",

+"yX	c #444433336969",

+"uX	c #424233336565",

+"iX	c #1E1E1A1A1E1E",

+"pX	c #161601014C4C",

+"aX	c #1C1C11115454",

+"sX	c #252503035B5B",

+"dX	c #414131316A6A",

+"fX	c #22221F1F7878",

+"gX	c #272724246767",

+"hX	c #1D1D16165E5E",

+"jX	c #131305055151",

+"kX	c #40402F2F6464",

+"lX	c #111107074E4E",

+"zX	c #0C0C05054B4B",

+"xX	c #22221E1E5757",

+"cX	c #1A1A0D0D4D4D",

+"vX	c #16160B0B4D4D",

+"bX	c #060604044747",

+"nX	c #040403034343",

+"mX	c #3B3B27276565",

+"MX	c #0E0E03034141",

+"NX	c #111106064A4A",

+"BX	c #0E0E04044646",

+"VX	c #111105053B3B",

+"CX	c #0D0D01013A3A",

+"ZX	c #030305053F3F",

+"AX	c #0F0F0F0F4C4C",

+"SX	c #020207073B3B",

+"DX	c #0D0D03034646",

+"FX	c #0B0B02023F3F",

+"GX	c #0D0D02023434",

+"HX	c #0A0A0E0E4444",

+"JX	c #161614145252",

+"KX	c #0B0B04044646",

+"LX	c #0A0A03034444",

+"PX	c #1D1D21215757",

+"IX	c #090910104040",

+"UX	c #18181E1E5353",

+"                                                                                                ",

+"  . . . . X X o o o o O + + @ @ @ @ @ @ @ # # # # # # $ $ % % & & & & *= - - - ; : > > , , ,   ",

+"  . . X X < < o o O O + @ 1 2 2 1 1 1 1 1 1 1 1 3 4 # # $ $ $ % % % 5= = 6 6 - ; ; > > , , 7   ",

+"  . 8 < < < o O O + @ @ 2 9 9 0 0 q q q q q q q w 3 4 4 e e $ $ $ $ % 5= = 6 6 6 ; ; > > r t   ",

+"  . X < y u O O + @ 1 2 i 0 0 p p p p p p p a a p a s 3 4 4 e e e e d 5 5 f f 6 6 6 ; ; r r t   ",

+"  X < y u O + + @ 2 9 0 g p p h h h h h h h p h h a a s s j k k j l d d 5 5 f f 6 6 r r r r r   ",

+"  X < y O z x x 9 0 g c v b n n n n n n n n n n n h a a s s j j m l M d d N f f B B B B r r r   ",

+"  < y u + z 2 0 c c b V C Z C C A A A A A S S S n h D w w m m m m k l M d d N f F F F B r r r   ",

+"  < y O z z 9 c b V Z G H H H G S G G J J H V v c g g K K K K L P l l l M M N N N N I B B r r   ",

+"  U u + z x i v C H Y J J J J H J T R H V E W W Q Q Q Q ! ! ! ~ ^ ^ / / M M M M M N ( B B r r   ",

+"  ) _ z x 9 g b Z Y ` ' ' ' T T ] [ { } |  .........W W Q Q X.! ~ ~ o.O./ / / / N F ( B B B r   ",

+"  ) ) z x i c V G J ' +.+.+.+.] [ @.#.$.%.%.%.&.*. . .....W =.-.X.;.~ :.o.O.^ >.N F ( B B B B   ",

+"  ) ,.<.2 g v C H J ' +.+.+.+.T Y 1.2.3.4.4.4.5.6.&.&. . ...W =.=.-.;.~ :.o.7.>.N F F ( B I I   ",

+"  ) ,.<.8.9.b C H J T +.+.+.' J @.1.0.q.q.w.e.4.5.6.&.r. . .t.W =.=.-.;.~ :.o.7.y.N F ( ( I I   ",

+"  8.8.8.9.| u.C G J T +.+.' ` Y @.1.i.0.q.q.e.e.5.6.p.r.a. .t.t.s.d.d.-.;.~ :.7.7.y.F F ( I I   ",

+"  9.c c c v b A S H ' f.g.` Y @.h.1.i.j.0.q.q.e.k.6.p.r.a.l.t.z.s.s.d.x.c.v.b.n.m.7.N F F F I   ",

+"  <.g M.N.B.B.n V.J f.R J @.h.h.1.i.i.j.j.0.q.3.k.6.p.r.a.l.l.z.s.C.d.x.x.c.v.b.n.m.y.N F F F   ",

+"  + x i v B.Z Z G g.Z.[ @.2.i.i.j.j.j.j.j.0.q.3.k.6.p.p.a.l.l.A.s.C.C.d.x.c.v.b.n.m.7.y.N N y.  ",

+"  O # 3 w p n Z ` f.S.H D.F.q.0.0.0.0.j.0.q.q.3.k.6.p.r.a.a.l.A.s.s.C.d.x.x.c.v.b.n.m.y.y.y.y.  ",

+"  O # 4 s a G.V.T Z.H.V J.%.e.w.q.0.0.0.0.q.q.e.k.6.p.r.a.a.l.z.A.s.C.d.d.x.c.v.b.n.m.7.>.y.y.  ",

+"  O # 4 s w G.A f.K.H L...4.P.w.w.w.q.q.q.q.e.e.5.6.M.I.I.a.a.l.z.A.s.d.d.x.c.v.v.U.Y.7.O.>.y.  ",

+"  $ # 4 3 s G.G f.S.Z 9.*.D.P.P.w.w.w.w.w.e.e.5.5.M.M.I.I.a.a.l.z.T.s.d.d.x.x.c.v.U.Y.m.R.>.>.  ",

+"  E.E.W.W.W.W.E.Z.E.W.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.!.!.!.!.!.~.~.~.~.~.~.^.^.^.^.^./././.(.{ { )._.`._.  ",

+"  + # 3 w s '.` f.H.V ].*.D.P.P.P.P.P.P.P.5.5.5.M.M.M.I.I.a.l.z.z.T.T.s.d.d.x.c.v.U.Y.[.^ O.>.  ",

+"  ~.~.~.~.~.~.K.Z.S.~.{.^.^.^.^.^.^.^.^././././././.(.(.(.(.(.(.{ { { { { ).).).w.w.}.|.P.u.}   ",

+"   .I.6. X X XT f.H.b ].*.E D.D.D.D.5.5..X.XM.M.I.I.a.a.l.l.z.z.T.T.T.d.XXx.c.v.b.U.oXOXR.+X@X  ",

+"  E.E.E.W.W.W.K.Z.E.W.Q.Q.Q.Q.Q.Q.Q.Q.!.!.!.!.!.!.~.~.~.~.~.~.^.^.^.^.^./././.(.{ { ).).#X_._.  ",

+"  & % $ e '.= H f.H.b 8.W *.E E E .X.X.XI.I.I.I.a.a.l.l.z.z.T.T.T.C.XXXXc.v.$X%X&XY.*X=X2 @X-X  ",

+"  {.{.{.{.{.#X~.Z.W.~.{.{./././././././././.(.(.(.(.(.(.(.{ { { { { { ).).).w.w.3.}.;X%.:X} }   ",

+"  & & % $ e >XV.f.S.C K X.W t. . .l.l.t.t.t.t.A.A.A.,X,X,X,X,X<X;X1X1X2X3X%X&X4XoX*X5Xo.6X-X-X  ",

+"  & & % $ $ >X7X` Z.Z D ! =.=.s.t.t.t.A.A.s.A.,X,X,X,X<X<X<X<X;X1X2X2X3X%X&X4XoXOX8X5X<.@X-X-X  ",

+"  8 & & $ e K 9XJ f.^. XK X.=.=.s.s.s.s.s.C.C.C.C.<X0X0X0X1X1X1X2X2X3X%X&X4XqXOX*X8X=X<.-X-XwX  ",

+"  8 & eXK k.@.M. Xg.E.B.rX~ -.d.d.C.C.C.C.C.tX0X0X0XyXyX1X1XuX2X2X3X%X&X4XqXoXOX8XiX6XeX-X-XwX  ",

+"  6XQ h.Y N.K e pXB.f./.9Xo.;.-.x.d.tXtXtXtXtX0X0XyXyXyXuXuX2X2X3X%X&X4XqXoXOX*XiX=X_ aX-XaXwX  ",

+"  Y Y  .R.@X% sX= 7XT Z.V P :.;.c.x.x.x.tXdXdXdXyXyXuXuX2X2X3X3X%X&X4XqXoXOX*X8X*XfXaXaXaXwXwX  ",

+"  gXhX& * & 5 5 sXjXa ] S.9X/ ~ v.c.dXdXdXdXdXuXuXuXkX2X2X3X%X%X&X4XqXoXOX*X8XiX<.hXwXwXaXwXwX  ",

+"  8 lXlXjX= * 5 5= zX9X] H.D 7.b.v.v.kXc.kXkXkXkXkX2X$X3X%X&X&X4XqXoXOX*X8XiXxXhXwXcXcXwXwXwX  ",

+"  zXzXlXlXjX== f f sXD Y ] ~.D 7.n.b.v.v.kXkXkXkX$X$X%X%X&X4XqXoXoXOX*X8X5XgXu cXvXvXcXcXwXwX  ",

+"  bXbXzXlXlX-= * @XX.h.e D T S.D n.m.b.$X$X$X$X$X%X%X&X&X4XqXoXOX*X8X8X*X<.hXvX; ; vXvXvXcXwX  ",

+"  nXbXzXzXlXlX- -XX.Y R.pXpXP J K.Z mXm.n.U.U.U.U.U.4X4XY.oXOX*X8X8X8X=X,.aXvX; > > > t t t cX  ",

+"  nXbXbXzXzXlXaXXXY +Xf= f= 7XtXR R   mXn.Y.[.[.[.[.OX*X*X8X5X*X=X,.u vXvX; > > MXMX, 7 t t   ",

+"  nXnXnXbXzXvX-.Y +XcX6 6= == d L B.G H `.X.:.7.m.=X=X=X=X=X6X,.u cXvXNX: BX> MXVXCXVX7 7 7   ",

+"  ZXZXnXbXAXgX@.+XvX; - - - - * @XR.>.sX>.R.i 0 x eXeXeXeXO hXaXcXvXNX: BXMXMXMXVXCXCXCXVX7 7   ",

+"  SXZXZXAXgXN.aXNX: : NXNXNX- * +X+X* 6 6 6 * * * * * * * vXvX- NX: DXBXMXMXFXCXCXCXCXGXVXVX7   ",

+"  SXSXHXgX0.JXKXLXKXKXDX: : NX* @X-X- - - - - - - - - - - NX: DXDXDXMXMXFXFXCXCXCXCXGXGXGXVXVX  ",

+"  SXHXPX3.JXnXnXnXnXbXLXKXKXNXaX-XvX: : NX: : : : : : : BXDXDXLXMXMXFXFXCXCXCXCXGXGXGXGXGXGXGX  ",

+"  IXUX$.AXZXZXZXZXnXnXnXLXLXNXJXvXBXDXBXBXBXBXDXDXDXDXLXDXLXLXFXFXFXFXCXCXCXCXGXGXGXGXGXGXGXGX  ",

+"                                                                                                "};

diff --git a/examples/org.eclipse.statet.rj.servi.rcpdemo/icons/alt_window_16.gif b/examples/org.eclipse.statet.rj.servi.rcpdemo/icons/alt_window_16.gif
new file mode 100644
index 0000000..05626b1
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.rcpdemo/icons/alt_window_16.gif
Binary files differ
diff --git a/examples/org.eclipse.statet.rj.servi.rcpdemo/icons/alt_window_32.gif b/examples/org.eclipse.statet.rj.servi.rcpdemo/icons/alt_window_32.gif
new file mode 100644
index 0000000..b432f88
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.rcpdemo/icons/alt_window_32.gif
Binary files differ
diff --git a/examples/org.eclipse.statet.rj.servi.rcpdemo/org.eclipse.statet.rj.servi.rcpdemo.product b/examples/org.eclipse.statet.rj.servi.rcpdemo/org.eclipse.statet.rj.servi.rcpdemo.product
new file mode 100644
index 0000000..edb4e62
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.rcpdemo/org.eclipse.statet.rj.servi.rcpdemo.product
@@ -0,0 +1,129 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<?pde version="3.5"?>
+
+<product name="RServi RCP Demo" id="org.eclipse.statet.rj.servi.rcpdemo.product" application="org.eclipse.statet.rj.servi.rcpdemo.application" version="0.4.0.qualifier" useFeatures="false" includeLaunchers="true">
+
+   <configIni use="default">
+   </configIni>
+
+   <launcherArgs>
+      <vmArgs>-Xms40m -Xmx512m
+      </vmArgs>
+      <vmArgsMac>-XstartOnFirstThread -Dorg.eclipse.swt.internal.carbon.smallFonts
+      </vmArgsMac>
+   </launcherArgs>
+
+   <windowImages i16="icons/alt_window_16.gif" i32="icons/alt_window_32.gif"/>
+
+   <splash
+      location="org.eclipse.statet.rj.servi.rcpdemo"
+      startupProgressRect="20,190,415,15"
+      startupMessageRect="20,210,415,20"
+      startupForegroundColor="000000" />
+   <launcher>
+      <solaris/>
+      <win useIco="false">
+         <bmp/>
+      </win>
+   </launcher>
+
+   <vm>
+   </vm>
+
+   <plugins>
+      <plugin id="com.ibm.icu"/>
+      <plugin id="org.eclipse.statet.ecommons.rmi.core"/>
+      <plugin id="org.eclipse.statet.ecommons.coremisc"/>
+      <plugin id="org.eclipse.statet.ecommons.uimisc"/>
+      <plugin id="org.eclipse.statet.rj.data"/>
+      <plugin id="org.eclipse.statet.rj.client"/>
+      <plugin id="org.eclipse.statet.rj.services.core"/>
+      <plugin id="org.eclipse.statet.rj.eclient.core"/>
+      <plugin id="org.eclipse.statet.rj.eclient.graphics"/>
+      <plugin id="org.eclipse.statet.rj.server"/>
+      <plugin id="org.eclipse.statet.rj.servi"/>
+      <plugin id="org.eclipse.statet.rj.servi.rcpdemo"/>
+      <plugin id="javax.annotation"/>
+      <plugin id="javax.inject"/>
+      <plugin id="javax.xml"/>
+      <plugin id="org.apache.batik.css"/>
+      <plugin id="org.apache.batik.util"/>
+      <plugin id="org.apache.batik.util.gui"/>
+      <plugin id="org.apache.commons.jxpath"/>
+      <plugin id="org.eclipse.core.commands"/>
+      <plugin id="org.eclipse.core.contenttype"/>
+      <plugin id="org.eclipse.core.databinding"/>
+      <plugin id="org.eclipse.core.databinding.observable"/>
+      <plugin id="org.eclipse.core.databinding.property"/>
+      <plugin id="org.eclipse.core.expressions"/>
+      <plugin id="org.eclipse.core.jobs"/>
+      <plugin id="org.eclipse.core.runtime"/>
+      <plugin id="org.eclipse.core.runtime.compatibility.registry" fragment="true"/>
+      <plugin id="org.eclipse.e4.core.commands"/>
+      <plugin id="org.eclipse.e4.core.contexts"/>
+      <plugin id="org.eclipse.e4.core.di"/>
+      <plugin id="org.eclipse.e4.core.di.annotations"/>
+      <plugin id="org.eclipse.e4.core.di.extensions"/>
+      <plugin id="org.eclipse.e4.core.services"/>
+      <plugin id="org.eclipse.e4.emf.xpath"/>
+      <plugin id="org.eclipse.e4.ui.bindings"/>
+      <plugin id="org.eclipse.e4.ui.css.core"/>
+      <plugin id="org.eclipse.e4.ui.css.swt"/>
+      <plugin id="org.eclipse.e4.ui.css.swt.theme"/>
+      <plugin id="org.eclipse.e4.ui.di"/>
+      <plugin id="org.eclipse.e4.ui.model.workbench"/>
+      <plugin id="org.eclipse.e4.ui.services"/>
+      <plugin id="org.eclipse.e4.ui.widgets"/>
+      <plugin id="org.eclipse.e4.ui.workbench"/>
+      <plugin id="org.eclipse.e4.ui.workbench.addons.swt"/>
+      <plugin id="org.eclipse.e4.ui.workbench.renderers.swt"/>
+      <plugin id="org.eclipse.e4.ui.workbench.swt"/>
+      <plugin id="org.eclipse.e4.ui.workbench3"/>
+      <plugin id="org.eclipse.emf.common"/>
+      <plugin id="org.eclipse.emf.ecore"/>
+      <plugin id="org.eclipse.emf.ecore.change"/>
+      <plugin id="org.eclipse.emf.ecore.xmi"/>
+      <plugin id="org.eclipse.equinox.app"/>
+      <plugin id="org.eclipse.equinox.common"/>
+      <plugin id="org.eclipse.equinox.ds"/>
+      <plugin id="org.eclipse.equinox.event"/>
+      <plugin id="org.eclipse.equinox.preferences"/>
+      <plugin id="org.eclipse.equinox.registry"/>
+      <plugin id="org.eclipse.equinox.util"/>
+      <plugin id="org.eclipse.help"/>
+      <plugin id="org.eclipse.jface"/>
+      <plugin id="org.eclipse.jface.databinding"/>
+      <plugin id="org.eclipse.osgi"/>
+      <plugin id="org.eclipse.osgi.compatibility.state" fragment="true"/>
+      <plugin id="org.eclipse.osgi.services"/>
+      <plugin id="org.eclipse.swt"/>
+      <plugin id="org.eclipse.swt.cocoa.macosx" fragment="true"/>
+      <plugin id="org.eclipse.swt.cocoa.macosx.x86_64" fragment="true"/>
+      <plugin id="org.eclipse.swt.gtk.aix.ppc" fragment="true"/>
+      <plugin id="org.eclipse.swt.gtk.aix.ppc64" fragment="true"/>
+      <plugin id="org.eclipse.swt.gtk.hpux.ia64_32" fragment="true"/>
+      <plugin id="org.eclipse.swt.gtk.linux.ppc64" fragment="true"/>
+      <plugin id="org.eclipse.swt.gtk.linux.s390" fragment="true"/>
+      <plugin id="org.eclipse.swt.gtk.linux.s390x" fragment="true"/>
+      <plugin id="org.eclipse.swt.gtk.linux.x86" fragment="true"/>
+      <plugin id="org.eclipse.swt.gtk.linux.x86_64" fragment="true"/>
+      <plugin id="org.eclipse.swt.gtk.solaris.sparc" fragment="true"/>
+      <plugin id="org.eclipse.swt.gtk.solaris.x86" fragment="true"/>
+      <plugin id="org.eclipse.swt.win32.win32.x86" fragment="true"/>
+      <plugin id="org.eclipse.swt.win32.win32.x86_64" fragment="true"/>
+      <plugin id="org.eclipse.ui"/>
+      <plugin id="org.eclipse.ui.workbench"/>
+      <plugin id="org.w3c.css.sac"/>
+      <plugin id="org.w3c.dom.events"/>
+      <plugin id="org.w3c.dom.smil"/>
+      <plugin id="org.w3c.dom.svg"/>
+   </plugins>
+
+   <configurations>
+      <plugin id="org.eclipse.core.runtime" autoStart="true" startLevel="0" />
+      <plugin id="org.eclipse.equinox.common" autoStart="true" startLevel="2" />
+      <plugin id="org.eclipse.equinox.ds" autoStart="true" startLevel="1" />
+      <plugin id="org.eclipse.osgi" autoStart="true" startLevel="-1" />
+   </configurations>
+
+</product>
diff --git a/examples/org.eclipse.statet.rj.servi.rcpdemo/plugin.xml b/examples/org.eclipse.statet.rj.servi.rcpdemo/plugin.xml
new file mode 100644
index 0000000..c002914
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.rcpdemo/plugin.xml
@@ -0,0 +1,127 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<?eclipse version="3.4"?>
+<plugin>
+
+   <extension
+         id="org.eclipse.statet.rj.servi.rcpdemo.application"
+         point="org.eclipse.core.runtime.applications">
+      <application>
+         <run
+               class="org.eclipse.statet.internal.rj.servi.rcpdemo.Application">
+         </run>
+      </application>
+   </extension>
+   <extension
+         id="product"
+         point="org.eclipse.core.runtime.products">
+      <product
+            application="org.eclipse.statet.rj.servi.rcpdemo.application"
+            name="RServi RCP Demo">
+         <property
+               name="windowImages"
+               value="icons/alt_window_16.gif,icons/alt_window_32.gif">
+         </property>
+         <property
+               name="appName"
+               value="RServi RCP Demo">
+         </property>
+         <property
+               name="startupProgressRect"
+               value="20,190,415,15">
+         </property>
+         <property
+               name="startupForegroundColor"
+               value="000000">
+         </property>
+         <property
+               name="startupMessageRect"
+               value="20,210,415,20">
+         </property>
+         <property
+               name="preferenceCustomization"
+               value="plugin_customization.ini">
+         </property>
+      </product>
+   </extension>
+   
+   <extension
+         point="org.eclipse.ui.perspectives">
+      <perspective
+            name="RCP Perspective"
+            class="org.eclipse.statet.internal.rj.servi.rcpdemo.Perspective"
+            id="org.eclipse.statet.rj.servi.rcpdemo.perspective">
+      </perspective>
+   </extension>
+   <extension
+         point="org.eclipse.ui.menus">
+      <menuContribution
+            locationURI="menu:org.eclipse.ui.main.menu">
+         <menu id="file"
+               label="&amp;File">
+         </menu>
+      </menuContribution>
+      <menuContribution
+            locationURI="menu:file">
+         <command
+               commandId="org.eclipse.ui.file.exit"
+               style="push">
+         </command>
+      </menuContribution>
+   </extension>
+   
+   <extension
+         point="org.eclipse.ui.views">
+      <view
+            allowMultiple="false"
+            class="org.eclipse.statet.internal.rj.servi.rcpdemo.views.RServiConfigView"
+            id="org.eclipse.statet.rj.servi.rcpdemo.views.RServiConfig"
+            name="Config"
+            restorable="true">
+      </view>
+      <view
+            allowMultiple="true"
+            class="org.eclipse.statet.internal.rj.servi.rcpdemo.views.GraphDemoView"
+            id="org.eclipse.statet.rj.servi.rcpdemo.views.GraphDemo"
+            name="Graph"
+            restorable="true">
+      </view>
+      <view
+            id="org.eclipse.ui.views.ProgressView"
+            class="org.eclipse.ui.ExtensionFactory:progressView"
+            name="Progress">
+      </view>
+   </extension>
+   <extension
+         point="org.eclipse.ui.perspectiveExtensions">
+      <perspectiveExtension
+            targetID="*">
+         <view
+               id="org.eclipse.statet.rj.servi.rcpdemo.views.GraphDemo"
+               closeable="false"
+               minimized="false"
+               relative="org.eclipse.ui.editorss"
+               relationship="left"
+               visible="true">
+         </view>
+         <view
+               id="org.eclipse.statet.rj.servi.rcpdemo.views.RServiConfig"
+               closeable="false"
+               minimized="false"
+               ratio="0.3f"
+               relative="org.eclipse.statet.rj.servi.rcpdemo.views.GraphDemo"
+               relationship="left"
+               visible="true">
+         </view>
+         <view
+               id="org.eclipse.ui.views.ProgressView"
+               closeable="true"
+               minimized="false"
+               ratio="0.75"
+               relative="org.eclipse.statet.rj.servi.rcpdemo.views.RServiConfig"
+               relationship="bottom"
+               visible="false">
+         </view>
+      </perspectiveExtension>
+   </extension>
+
+</plugin>
diff --git a/examples/org.eclipse.statet.rj.servi.rcpdemo/plugin_customization.ini b/examples/org.eclipse.statet.rj.servi.rcpdemo/plugin_customization.ini
new file mode 100644
index 0000000..61d5abf
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.rcpdemo/plugin_customization.ini
@@ -0,0 +1 @@
+org.eclipse.ui/SHOW_PROGRESS_ON_STARTUP= true
diff --git a/examples/org.eclipse.statet.rj.servi.rcpdemo/splash.bmp b/examples/org.eclipse.statet.rj.servi.rcpdemo/splash.bmp
new file mode 100644
index 0000000..fbcd619
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.rcpdemo/splash.bmp
Binary files differ
diff --git a/examples/org.eclipse.statet.rj.servi.rcpdemo/src/org/eclipse/statet/internal/rj/servi/rcpdemo/Activator.java b/examples/org.eclipse.statet.rj.servi.rcpdemo/src/org/eclipse/statet/internal/rj/servi/rcpdemo/Activator.java
new file mode 100644
index 0000000..ef8a779
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.rcpdemo/src/org/eclipse/statet/internal/rj/servi/rcpdemo/Activator.java
@@ -0,0 +1,85 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.internal.rj.servi.rcpdemo;
+
+import org.osgi.framework.BundleContext;
+
+import org.eclipse.ui.plugin.AbstractUIPlugin;
+
+import org.eclipse.statet.rj.eclient.graphics.comclient.ERGraphicFactory;
+import org.eclipse.statet.rj.servi.rcpdemo.RServiManager;
+
+
+/**
+ * The activator class controls the plug-in life cycle
+ */
+public class Activator extends AbstractUIPlugin {
+	
+	
+	public static final String BUNDLE_ID= "org.eclipse.statet.rj.servi.rcpdemo";
+	
+	
+	private static Activator instance;
+	
+	/**
+	 * Returns the shared plug-in instance
+	 *
+	 * @return the shared instance
+	 */
+	public static Activator getInstance() {
+		return instance;
+	}
+	
+	
+	private RServiManager rserviManager;
+	
+	private ERGraphicFactory graphicFactory;
+	
+	
+	/**
+	 * The constructor
+	 */
+	public Activator() {
+	}
+	
+	
+	@Override
+	public void start(final BundleContext context) throws Exception {
+		super.start(context);
+		instance= this;
+	}
+	
+	@Override
+	public void stop(final BundleContext context) throws Exception {
+		instance= null;
+		super.stop(context);
+	}
+	
+	
+	public synchronized RServiManager getRServiManager() {
+		if (this.rserviManager == null) {
+			this.rserviManager= new RServiManager("RCPDemo", getRGraphicFactory());
+		}
+		return this.rserviManager;
+	}
+	
+	public synchronized ERGraphicFactory getRGraphicFactory() {
+		if (this.graphicFactory == null) {
+			this.graphicFactory= new ERGraphicFactory();
+		}
+		return this.graphicFactory;
+	}
+	
+}
diff --git a/examples/org.eclipse.statet.rj.servi.rcpdemo/src/org/eclipse/statet/internal/rj/servi/rcpdemo/Application.java b/examples/org.eclipse.statet.rj.servi.rcpdemo/src/org/eclipse/statet/internal/rj/servi/rcpdemo/Application.java
new file mode 100644
index 0000000..f599e90
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.rcpdemo/src/org/eclipse/statet/internal/rj/servi/rcpdemo/Application.java
@@ -0,0 +1,67 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.internal.rj.servi.rcpdemo;
+
+import org.eclipse.equinox.app.IApplication;
+import org.eclipse.equinox.app.IApplicationContext;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.PlatformUI;
+
+
+/**
+ * This class controls all aspects of the application's execution
+ */
+public class Application implements IApplication {
+	
+	
+	public Application() {
+	}
+	
+	
+	@Override
+	public Object start(final IApplicationContext context) throws Exception {
+		final Display display= PlatformUI.createDisplay();
+		try {
+			final int returnCode= PlatformUI.createAndRunWorkbench(display, new ApplicationWorkbenchAdvisor());
+			if (returnCode == PlatformUI.RETURN_RESTART) {
+				return IApplication.EXIT_RESTART;
+			} else {
+				return IApplication.EXIT_OK;
+			}
+		}
+		finally {
+			display.dispose();
+		}
+	}
+	
+	@Override
+	public void stop() {
+		final IWorkbench workbench= PlatformUI.getWorkbench();
+		if (workbench == null) {
+			return;
+		}
+		final Display display= workbench.getDisplay();
+		display.syncExec(new Runnable() {
+			@Override
+			public void run() {
+				if (!display.isDisposed()) {
+					workbench.close();
+				}
+			}
+		});
+	}
+	
+}
diff --git a/examples/org.eclipse.statet.rj.servi.rcpdemo/src/org/eclipse/statet/internal/rj/servi/rcpdemo/ApplicationActionBarAdvisor.java b/examples/org.eclipse.statet.rj.servi.rcpdemo/src/org/eclipse/statet/internal/rj/servi/rcpdemo/ApplicationActionBarAdvisor.java
new file mode 100644
index 0000000..7dc61c3
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.rcpdemo/src/org/eclipse/statet/internal/rj/servi/rcpdemo/ApplicationActionBarAdvisor.java
@@ -0,0 +1,34 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.internal.rj.servi.rcpdemo;
+
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.application.ActionBarAdvisor;
+import org.eclipse.ui.application.IActionBarConfigurer;
+
+
+public class ApplicationActionBarAdvisor extends ActionBarAdvisor {
+	
+	
+	public ApplicationActionBarAdvisor(final IActionBarConfigurer configurer) {
+		super(configurer);
+	}
+	
+	
+	@Override
+	protected void makeActions(final IWorkbenchWindow window) {
+	}
+	
+}
diff --git a/examples/org.eclipse.statet.rj.servi.rcpdemo/src/org/eclipse/statet/internal/rj/servi/rcpdemo/ApplicationWorkbenchAdvisor.java b/examples/org.eclipse.statet.rj.servi.rcpdemo/src/org/eclipse/statet/internal/rj/servi/rcpdemo/ApplicationWorkbenchAdvisor.java
new file mode 100644
index 0000000..a82f86a
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.rcpdemo/src/org/eclipse/statet/internal/rj/servi/rcpdemo/ApplicationWorkbenchAdvisor.java
@@ -0,0 +1,36 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.internal.rj.servi.rcpdemo;
+
+import org.eclipse.ui.application.IWorkbenchWindowConfigurer;
+import org.eclipse.ui.application.WorkbenchAdvisor;
+import org.eclipse.ui.application.WorkbenchWindowAdvisor;
+
+public class ApplicationWorkbenchAdvisor extends WorkbenchAdvisor {
+	
+	private static final String PERSPECTIVE_ID= "org.eclipse.statet.rj.servi.rcpdemo.perspective";
+	
+	
+	@Override
+	public WorkbenchWindowAdvisor createWorkbenchWindowAdvisor(final IWorkbenchWindowConfigurer configurer) {
+		return new ApplicationWorkbenchWindowAdvisor(configurer);
+	}
+	
+	@Override
+	public String getInitialWindowPerspectiveId() {
+		return PERSPECTIVE_ID;
+	}
+	
+}
diff --git a/examples/org.eclipse.statet.rj.servi.rcpdemo/src/org/eclipse/statet/internal/rj/servi/rcpdemo/ApplicationWorkbenchWindowAdvisor.java b/examples/org.eclipse.statet.rj.servi.rcpdemo/src/org/eclipse/statet/internal/rj/servi/rcpdemo/ApplicationWorkbenchWindowAdvisor.java
new file mode 100644
index 0000000..74507c6
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.rcpdemo/src/org/eclipse/statet/internal/rj/servi/rcpdemo/ApplicationWorkbenchWindowAdvisor.java
@@ -0,0 +1,46 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.internal.rj.servi.rcpdemo;
+
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.ui.application.ActionBarAdvisor;
+import org.eclipse.ui.application.IActionBarConfigurer;
+import org.eclipse.ui.application.IWorkbenchWindowConfigurer;
+import org.eclipse.ui.application.WorkbenchWindowAdvisor;
+
+
+public class ApplicationWorkbenchWindowAdvisor extends WorkbenchWindowAdvisor {
+	
+	
+	public ApplicationWorkbenchWindowAdvisor(final IWorkbenchWindowConfigurer configurer) {
+		super(configurer);
+	}
+	
+	
+	@Override
+	public ActionBarAdvisor createActionBarAdvisor(final IActionBarConfigurer configurer) {
+		return new ApplicationActionBarAdvisor(configurer);
+	}
+	
+	@Override
+	public void preWindowOpen() {
+		final IWorkbenchWindowConfigurer configurer= getWindowConfigurer();
+		configurer.setInitialSize(new Point(760, 600));
+		configurer.setShowCoolBar(false);
+		configurer.setShowStatusLine(true);
+		configurer.setShowProgressIndicator(true);
+	}
+	
+}
diff --git a/examples/org.eclipse.statet.rj.servi.rcpdemo/src/org/eclipse/statet/internal/rj/servi/rcpdemo/Perspective.java b/examples/org.eclipse.statet.rj.servi.rcpdemo/src/org/eclipse/statet/internal/rj/servi/rcpdemo/Perspective.java
new file mode 100644
index 0000000..39e2966
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.rcpdemo/src/org/eclipse/statet/internal/rj/servi/rcpdemo/Perspective.java
@@ -0,0 +1,33 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.internal.rj.servi.rcpdemo;
+
+import org.eclipse.ui.IPageLayout;
+import org.eclipse.ui.IPerspectiveFactory;
+
+
+public class Perspective implements IPerspectiveFactory {
+	
+	
+	public Perspective() {
+	}
+	
+	
+	@Override
+	public void createInitialLayout(final IPageLayout layout) {
+		layout.setEditorAreaVisible(false);
+	}
+	
+}
diff --git a/examples/org.eclipse.statet.rj.servi.rcpdemo/src/org/eclipse/statet/internal/rj/servi/rcpdemo/views/GraphDemoView.java b/examples/org.eclipse.statet.rj.servi.rcpdemo/src/org/eclipse/statet/internal/rj/servi/rcpdemo/views/GraphDemoView.java
new file mode 100644
index 0000000..d296cfc
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.rcpdemo/src/org/eclipse/statet/internal/rj/servi/rcpdemo/views/GraphDemoView.java
@@ -0,0 +1,142 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.internal.rj.servi.rcpdemo.views;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.part.ViewPart;
+
+import org.eclipse.statet.rj.eclient.graphics.ERGraphic;
+import org.eclipse.statet.rj.eclient.graphics.RGraphicComposite;
+import org.eclipse.statet.rj.graphic.core.RGraphic;
+import org.eclipse.statet.rj.servi.rcpdemo.RJob;
+import org.eclipse.statet.rj.services.RGraphicCreator;
+import org.eclipse.statet.rj.services.RService;
+
+
+public class GraphDemoView extends ViewPart {
+	
+	
+	public static final String VIEW_ID= "org.eclipse.statet.rj.servi.rcpdemo.views.GraphDemo";
+	
+	
+	private Text commandControl;
+	
+	private RGraphicComposite imageControl;
+	
+	private ERGraphic currentPlot;
+	
+	
+	public GraphDemoView() {
+	}
+	
+	
+	@Override
+	public void createPartControl(final Composite parent) {
+		final Composite composite= new Composite(parent, SWT.NONE);
+		composite.setLayout(new GridLayout(3, false));
+		
+		final Label label= new Label(composite, SWT.LEFT);
+		label.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false));
+		label.setText("Graphic &command:");
+		
+		this.commandControl= new Text(composite, SWT.BORDER);
+		this.commandControl.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+		
+		final Button button= new Button(composite, SWT.PUSH);
+		button.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false));
+		button.setText("Run");
+		button.addSelectionListener(new SelectionAdapter() {
+			@Override
+			public void widgetSelected(final SelectionEvent e) {
+				run();
+			}
+		});
+		
+		this.commandControl.setText("hist(rnorm(1e+07))");
+		
+		this.imageControl= new RGraphicComposite(composite, null);
+		this.imageControl.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 3, 1));
+	}
+	
+	protected void setGraphic(final ERGraphic graphic) {
+		this.imageControl.setGraphic(graphic);
+		
+		if (this.currentPlot != null) {
+			this.currentPlot.close();
+			this.currentPlot= null;
+		}
+		this.currentPlot= graphic;
+	}
+	
+	@Override
+	public void dispose() {
+		super.dispose();
+		if (this.currentPlot != null) {
+			this.currentPlot.close();
+			this.currentPlot= null;
+		}
+	}
+	
+	@Override
+	public void setFocus() {
+		this.commandControl.setFocus();
+	}
+	
+	private void run() {
+		final Point size= this.imageControl.getSize();
+		final String command= this.commandControl.getText();
+		final RJob job= new RJob("GraphDemo") {
+			@Override
+			protected void runRTask(final RService r, final IProgressMonitor monitor) throws CoreException {
+				monitor.beginTask("Creating graphic in R...", 100);
+				
+				final RGraphicCreator rGraphicCreator= r.createRGraphicCreator(0);
+				rGraphicCreator.setSize(size.x, size.y);
+				final RGraphic plot= rGraphicCreator.create(command, monitor);
+				
+				monitor.worked(90);
+				
+				if (plot instanceof ERGraphic) {
+					final ERGraphic erPlot= (ERGraphic) plot;
+					PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() {
+						@Override
+						public void run() {
+							if (GraphDemoView.this.imageControl.isDisposed()) {
+								erPlot.close();
+								return;
+							}
+							setGraphic(erPlot);
+						}
+					});
+				}
+				return;
+			}
+		};
+		job.schedule();
+	}
+	
+}
diff --git a/examples/org.eclipse.statet.rj.servi.rcpdemo/src/org/eclipse/statet/internal/rj/servi/rcpdemo/views/RServiConfigView.java b/examples/org.eclipse.statet.rj.servi.rcpdemo/src/org/eclipse/statet/internal/rj/servi/rcpdemo/views/RServiConfigView.java
new file mode 100644
index 0000000..4f61d7d
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.rcpdemo/src/org/eclipse/statet/internal/rj/servi/rcpdemo/views/RServiConfigView.java
@@ -0,0 +1,154 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.internal.rj.servi.rcpdemo.views;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.DirectoryDialog;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.part.ViewPart;
+import org.eclipse.ui.statushandlers.StatusManager;
+
+import org.eclipse.statet.internal.rj.servi.rcpdemo.Activator;
+import org.eclipse.statet.rj.servi.rcpdemo.RServiManager;
+
+
+public class RServiConfigView extends ViewPart {
+	
+	
+	public static final String VIEW_ID= "org.eclipse.statet.rj.servi.rcpdemo.views.RServiConfig";
+	
+	
+	private Button remoteSelectControl;
+	private Text remoteAddressControl;
+	private Button localSelectControl;
+	private Text localRhomeControl;
+	private Button rsetupSelectControl;
+	private Text rsetupIdControl;
+	
+	
+	public RServiConfigView() {
+	}
+	
+	
+	@Override
+	public void createPartControl(final Composite parent) {
+		final Composite composite= new Composite(parent, SWT.NONE);
+		composite.setLayout(new GridLayout());
+		
+		this.remoteSelectControl= new Button(composite, SWT.RADIO);
+		this.remoteSelectControl.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+		this.remoteSelectControl.setText("Remote/Pool - RMI pool address:");
+		
+		{	this.remoteAddressControl= new Text(composite, SWT.BORDER);
+			final GridData gd= new GridData(SWT.FILL, SWT.CENTER, true, false);
+			gd.horizontalIndent= 10; 
+			this.remoteAddressControl.setLayoutData(gd);
+		}
+		
+		this.localSelectControl= new Button(composite, SWT.RADIO);
+		this.localSelectControl.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+		this.localSelectControl.setText("Local - R_HOME:");
+		
+		{	this.localRhomeControl= new Text(composite, SWT.BORDER);
+			final GridData gd= new GridData(SWT.FILL, SWT.CENTER, true, false);
+			gd.horizontalIndent= 10; 
+			this.localRhomeControl.setLayoutData(gd);
+		}
+		
+		{	final Button button= new Button(composite, SWT.PUSH);
+			button.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+			button.setText("Select...");
+			button.addSelectionListener(new SelectionAdapter() {
+				@Override
+				public void widgetSelected(final SelectionEvent e) {
+					final DirectoryDialog dialog= new DirectoryDialog(button.getShell());
+					dialog.setMessage("Select R_HOME directory:");
+					final String path= dialog.open();
+					if (path != null) {
+						RServiConfigView.this.localRhomeControl.setText(path);
+					}
+				}
+			});
+		}
+		
+		this.rsetupSelectControl= new Button(composite, SWT.RADIO);
+		this.rsetupSelectControl.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+		this.rsetupSelectControl.setText("Supplied R Setup - Id:");
+		
+		{	this.rsetupIdControl= new Text(composite, SWT.BORDER);
+			final GridData gd= new GridData(SWT.FILL, SWT.CENTER, true, false);
+			gd.horizontalIndent= 10; 
+			this.rsetupIdControl.setLayoutData(gd);
+		}
+		
+		final Label label= new Label(composite, SWT.NONE);
+		label.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
+		
+		final Button applyControl= new Button(composite, SWT.PUSH);
+		applyControl.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+		applyControl.setText("Apply");
+		applyControl.addSelectionListener(new SelectionAdapter() {
+			@Override
+			public void widgetSelected(final SelectionEvent e) {
+				applyConfig();
+			}
+		});
+		
+		this.remoteSelectControl.setSelection(true);
+		this.remoteAddressControl.setText("rmi://localhost/rservi-pool");
+		final String rhome= System.getenv("R_HOME");
+		this.localRhomeControl.setText((rhome != null) ? rhome : "");
+		this.rsetupIdControl.setText("org.rproject.r.DefaultSetup");
+	}
+	
+	@Override
+	public void setFocus() {
+	}
+	
+	private void applyConfig() {
+		try {
+			final RServiManager manager= Activator.getInstance().getRServiManager();
+			if (this.remoteSelectControl.getSelection()) {
+				manager.setPool(this.remoteAddressControl.getText());
+				return;
+			}
+			if (this.localSelectControl.getSelection()) {
+				manager.setLocalInst(this.localRhomeControl.getText());
+				return;
+			}
+			if (this.rsetupSelectControl.getSelection()) {
+				manager.setRSetup(this.rsetupIdControl.getText());
+				return;
+			}
+		}
+		catch (final CoreException e) {
+			StatusManager.getManager().handle(new Status(IStatus.ERROR, Activator.BUNDLE_ID,
+					"Could not apply RServi configuration.", e),
+					StatusManager.SHOW | StatusManager.LOG);
+		}
+		return;
+	}
+	
+}
diff --git a/examples/org.eclipse.statet.rj.servi.rcpdemo/src/org/eclipse/statet/rj/servi/rcpdemo/RJob.java b/examples/org.eclipse.statet.rj.servi.rcpdemo/src/org/eclipse/statet/rj/servi/rcpdemo/RJob.java
new file mode 100644
index 0000000..9cb4073
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.rcpdemo/src/org/eclipse/statet/rj/servi/rcpdemo/RJob.java
@@ -0,0 +1,72 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.servi.rcpdemo;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.jobs.Job;
+
+import org.eclipse.statet.internal.rj.servi.rcpdemo.Activator;
+import org.eclipse.statet.rj.servi.RServi;
+import org.eclipse.statet.rj.services.RService;
+
+
+public abstract class RJob extends Job {
+	
+	
+	private final RServiManager rServiManager;
+	
+	
+	public RJob(final String name) {
+		super(name);
+		this.rServiManager= Activator.getInstance().getRServiManager();
+		setRule(this.rServiManager.getSchedulingRule());
+	}
+	
+	
+	@Override
+	protected IStatus run(final IProgressMonitor monitor) {
+		RServi servi= null;
+		try {
+			servi= this.rServiManager.getRServi(getName());
+			runRTask(servi, monitor);
+		}
+		catch (final CoreException e) {
+			return new Status(IStatus.ERROR, Activator.BUNDLE_ID,
+					"An error occurred when running " + getName() + ".", e);
+		}
+		finally {
+			if (servi != null) {
+				try {
+					servi.close();
+				} catch (final CoreException e) {
+					// TODO Auto-generated catch block
+					e.printStackTrace();
+				}
+			}
+		}
+		return Status.OK_STATUS;
+	}
+	
+	@Override
+	public boolean belongsTo(final Object family) {
+		return this.rServiManager == family;
+	}
+	
+	protected abstract void runRTask(RService r, IProgressMonitor monitor) throws CoreException;
+	
+}
diff --git a/examples/org.eclipse.statet.rj.servi.rcpdemo/src/org/eclipse/statet/rj/servi/rcpdemo/RServiManager.java b/examples/org.eclipse.statet.rj.servi.rcpdemo/src/org/eclipse/statet/rj/servi/rcpdemo/RServiManager.java
new file mode 100644
index 0000000..5782843
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.rcpdemo/src/org/eclipse/statet/rj/servi/rcpdemo/RServiManager.java
@@ -0,0 +1,216 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.servi.rcpdemo;
+
+import java.io.File;
+import java.util.List;
+import java.util.NoSuchElementException;
+
+import javax.security.auth.login.LoginException;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.jobs.ISchedulingRule;
+
+import org.eclipse.statet.ecommons.rmi.core.RMIRegistry;
+import org.eclipse.statet.ecommons.rmi.core.RMIRegistryManager;
+
+import org.eclipse.statet.internal.rj.servi.rcpdemo.Activator;
+import org.eclipse.statet.rj.RjException;
+import org.eclipse.statet.rj.eclient.graphics.comclient.ERClientGraphicActionsFactory;
+import org.eclipse.statet.rj.rsetups.RSetup;
+import org.eclipse.statet.rj.rsetups.RSetupUtil;
+import org.eclipse.statet.rj.server.RjsComConfig;
+import org.eclipse.statet.rj.server.client.RClientGraphicFactory;
+import org.eclipse.statet.rj.server.osgi.ERJContext;
+import org.eclipse.statet.rj.servi.RServi;
+import org.eclipse.statet.rj.servi.RServiUtil;
+import org.eclipse.statet.rj.servi.node.RServiImpl;
+import org.eclipse.statet.rj.servi.node.RServiNodeConfig;
+import org.eclipse.statet.rj.servi.node.RServiNodeFactory;
+import org.eclipse.statet.rj.servi.node.RServiNodeManager;
+
+
+public class RServiManager {
+	
+	
+	private static final int LOCAL_INST= 1;
+	private static final int LOCAL_RSETUP= 2;
+	private static final int POOL= 3;
+	
+	private static class Config {
+		
+		private int mode;
+		private String address;
+		
+	}
+	
+	
+	private final String name;
+	
+	private Config config= new Config();
+	
+	private RServiNodeManager localR;
+	
+	private final ISchedulingRule schedulingRule= new ISchedulingRule() {
+		@Override
+		public boolean contains(final ISchedulingRule rule) {
+			return (rule == this);
+		}
+		@Override
+		public boolean isConflicting(final ISchedulingRule rule) {
+			// if concurrent remote instances are desired, return false here
+			return (rule == this);
+		}
+	};
+	
+	
+	public RServiManager(final String appId, final RClientGraphicFactory graphicFactory) {
+		this.name= appId;
+		
+		RjsComConfig.setProperty("rj.servi.graphicFactory", graphicFactory);
+		RjsComConfig.setProperty("rj.servi.comClientGraphicActionsFactory",
+				new ERClientGraphicActionsFactory() );
+	}
+	
+	
+	public ISchedulingRule getSchedulingRule() {
+		return this.schedulingRule;
+	}
+	
+	public void setLocalInst(final String rHome) throws CoreException {
+		final Config config= new Config();
+		config.mode= LOCAL_INST;
+		config.address= rHome;
+		this.config= config;
+		
+		final RServiNodeConfig rConfig= new RServiNodeConfig();
+		rConfig.setRHome(rHome);
+		rConfig.setEnableVerbose(true);
+		
+		startLocal(rConfig);
+	}
+	
+	public void setRSetup(final String setupId) throws CoreException {
+		final Config config= new Config();
+		config.mode= LOCAL_RSETUP;
+		config.address= setupId;
+		this.config= config;
+		
+		final RSetup setup= RSetupUtil.loadSetup(setupId, null);
+		if (setup == null) {
+			throw new CoreException(new Status(IStatus.ERROR, Activator.BUNDLE_ID, "No R setup with specified id found."));
+		}
+		
+		final RServiNodeConfig rConfig= new RServiNodeConfig();
+		rConfig.setRHome(setup.getRHome());
+		setLibs(setup.getRLibsSite(), rConfig, "R_LIBS_SITE");
+		setLibs(setup.getRLibs(), rConfig, "R_LIBS");
+		setLibs(setup.getRLibsUser(), rConfig, "R_LIBS_USER");
+		rConfig.setEnableVerbose(true);
+		
+		startLocal(rConfig);
+	}
+	
+	public void setPool(final String poolAddress) {
+		final Config config= new Config();
+		config.mode= POOL;
+		config.address= poolAddress;
+		this.config= config;
+	}
+	
+	
+	private void setLibs(final List<String> locations, final RServiNodeConfig rConfig, final String varName) {
+		if (locations != null && locations.size() > 0) {
+			final StringBuilder sb= new StringBuilder(locations.get(0));
+			for (int i= 0; i < locations.size(); i++) {
+				sb.append(File.pathSeparatorChar);
+				sb.append(locations.get(i));
+			}
+			rConfig.getEnvironmentVariables().put(varName, sb.toString());
+		}
+	}
+	
+	private void startLocal(final RServiNodeConfig rConfig) throws CoreException {
+		startLocal(rConfig, new NullProgressMonitor()); // TODO real monitor, e.g. in a Job
+	}
+	
+	private void startLocal(final RServiNodeConfig rConfig,
+			final IProgressMonitor monitor) throws CoreException {
+		if (rConfig == null) {
+			throw new NullPointerException("rConfig");
+		}
+		if (monitor == null) {
+			throw new NullPointerException("monitor");
+		}
+		try {
+			final ERJContext context= new ERJContext();
+			if (System.getSecurityManager() == null) {
+				if (System.getProperty("java.security.policy") == null) {
+					final String policyFile= context.getServerPolicyFilePath();
+					System.setProperty("java.security.policy", policyFile);
+				}
+				System.setSecurityManager(new SecurityManager());
+			}
+			
+			final RMIRegistry registry= RMIRegistryManager.INSTANCE.getEmbeddedPrivateRegistry(monitor);
+			
+			final RServiNodeFactory nodeFactory= RServiImpl.createLocalNodeFactory(this.name, context);
+			nodeFactory.setRegistry(registry);
+			nodeFactory.setConfig(rConfig);
+			
+			final RServiNodeManager newLocalR= RServiImpl.createNodeManager(this.name, registry, nodeFactory);
+			newLocalR.start();
+			if (this.localR != null) {
+				this.localR.stop();
+				this.localR= null;
+			}
+			this.localR= newLocalR;
+		}
+		catch (final RjException e) {
+			throw new CoreException(new Status(IStatus.ERROR, Activator.BUNDLE_ID, "Local R instance could not created.", e));
+		}
+	}
+	
+	
+	public RServi getRServi(final String task) throws CoreException {
+		final Config config= this.config;
+		final String key= this.name + "-" + task;
+		
+		try {
+			switch (config.mode) {
+			case LOCAL_INST:
+			case LOCAL_RSETUP:
+				return RServiUtil.getRServi(this.localR, key);
+			case POOL:
+				return RServiUtil.getRServi(config.address, key);
+			}
+		}
+		catch (final CoreException e) {
+			throw new CoreException(new Status(IStatus.ERROR, Activator.BUNDLE_ID, "R not available, please check the configuration.", e));
+		}
+		catch (final LoginException e) {
+			throw new CoreException(new Status(IStatus.ERROR, Activator.BUNDLE_ID, "R not available, please check the configuration.", e));
+		}
+		catch (final NoSuchElementException e) {
+			throw new CoreException(new Status(IStatus.INFO, Activator.BUNDLE_ID, "R currently not available, please try again later.", e));
+		}
+		throw new CoreException(new Status(IStatus.ERROR, Activator.BUNDLE_ID, "R is not configured, please check the configuration."));
+	}
+	
+}
diff --git a/examples/org.eclipse.statet.rj.servi.rcpdemo2/.classpath b/examples/org.eclipse.statet.rj.servi.rcpdemo2/.classpath
new file mode 100644
index 0000000..eca7bdb
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.rcpdemo2/.classpath
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
+	<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+	<classpathentry kind="src" path="src"/>
+	<classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/examples/org.eclipse.statet.rj.servi.rcpdemo2/.gitignore b/examples/org.eclipse.statet.rj.servi.rcpdemo2/.gitignore
new file mode 100644
index 0000000..5e56e04
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.rcpdemo2/.gitignore
@@ -0,0 +1 @@
+/bin
diff --git a/examples/org.eclipse.statet.rj.servi.rcpdemo2/.project b/examples/org.eclipse.statet.rj.servi.rcpdemo2/.project
new file mode 100644
index 0000000..af023be
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.rcpdemo2/.project
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>org.eclipse.statet.rj.servi.rcpdemo2</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.jdt.core.javabuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.pde.ManifestBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.pde.SchemaBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.pde.PluginNature</nature>
+		<nature>org.eclipse.jdt.core.javanature</nature>
+	</natures>
+</projectDescription>
diff --git a/examples/org.eclipse.statet.rj.servi.rcpdemo2/.settings/org.eclipse.core.resources.prefs b/examples/org.eclipse.statet.rj.servi.rcpdemo2/.settings/org.eclipse.core.resources.prefs
new file mode 100644
index 0000000..99f26c0
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.rcpdemo2/.settings/org.eclipse.core.resources.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+encoding/<project>=UTF-8
diff --git a/examples/org.eclipse.statet.rj.servi.rcpdemo2/.settings/org.eclipse.core.runtime.prefs b/examples/org.eclipse.statet.rj.servi.rcpdemo2/.settings/org.eclipse.core.runtime.prefs
new file mode 100644
index 0000000..5a0ad22
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.rcpdemo2/.settings/org.eclipse.core.runtime.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+line.separator=\n
diff --git a/examples/org.eclipse.statet.rj.servi.rcpdemo2/.settings/org.eclipse.jdt.core.prefs b/examples/org.eclipse.statet.rj.servi.rcpdemo2/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000..ccb1eaa
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.rcpdemo2/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,325 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.codeComplete.argumentPrefixes=
+org.eclipse.jdt.core.codeComplete.argumentSuffixes=
+org.eclipse.jdt.core.codeComplete.fieldPrefixes=
+org.eclipse.jdt.core.codeComplete.fieldSuffixes=
+org.eclipse.jdt.core.codeComplete.localPrefixes=
+org.eclipse.jdt.core.codeComplete.localSuffixes=
+org.eclipse.jdt.core.codeComplete.staticFieldPrefixes=
+org.eclipse.jdt.core.codeComplete.staticFieldSuffixes=
+org.eclipse.jdt.core.codeComplete.staticFinalFieldPrefixes=
+org.eclipse.jdt.core.codeComplete.staticFinalFieldSuffixes=
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=1.8
+org.eclipse.jdt.core.compiler.debug.lineNumber=generate
+org.eclipse.jdt.core.compiler.debug.localVariable=generate
+org.eclipse.jdt.core.compiler.debug.sourceFile=generate
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.source=1.8
+org.eclipse.jdt.core.formatter.align_fields_grouping_blank_lines=2147483647
+org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_assignment=0
+org.eclipse.jdt.core.formatter.alignment_for_binary_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_compact_if=16
+org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=80
+org.eclipse.jdt.core.formatter.alignment_for_enum_constants=0
+org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16
+org.eclipse.jdt.core.formatter.alignment_for_expressions_in_for_loop_header=0
+org.eclipse.jdt.core.formatter.alignment_for_method_declaration=0
+org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16
+org.eclipse.jdt.core.formatter.alignment_for_parameterized_type_references=0
+org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_resources_in_try=85
+org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=16
+org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_type_arguments=0
+org.eclipse.jdt.core.formatter.alignment_for_type_parameters=0
+org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch=16
+org.eclipse.jdt.core.formatter.blank_lines_after_imports=2
+org.eclipse.jdt.core.formatter.blank_lines_after_package=1
+org.eclipse.jdt.core.formatter.blank_lines_before_field=0
+org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=1
+org.eclipse.jdt.core.formatter.blank_lines_before_imports=1
+org.eclipse.jdt.core.formatter.blank_lines_before_member_type=1
+org.eclipse.jdt.core.formatter.blank_lines_before_method=1
+org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=2
+org.eclipse.jdt.core.formatter.blank_lines_before_package=1
+org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=1
+org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=1
+org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_block=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_lambda_body=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=false
+org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=false
+org.eclipse.jdt.core.formatter.comment.format_block_comments=true
+org.eclipse.jdt.core.formatter.comment.format_header=false
+org.eclipse.jdt.core.formatter.comment.format_html=true
+org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=true
+org.eclipse.jdt.core.formatter.comment.format_line_comments=true
+org.eclipse.jdt.core.formatter.comment.format_source_code=true
+org.eclipse.jdt.core.formatter.comment.indent_parameter_description=false
+org.eclipse.jdt.core.formatter.comment.indent_root_tags=true
+org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert
+org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=do not insert
+org.eclipse.jdt.core.formatter.comment.line_length=100
+org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries=false
+org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries=true
+org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments=false
+org.eclipse.jdt.core.formatter.compact_else_if=true
+org.eclipse.jdt.core.formatter.continuation_indentation=2
+org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=2
+org.eclipse.jdt.core.formatter.disabling_tag=@formatter\:off
+org.eclipse.jdt.core.formatter.enabling_tag=@formatter\:on
+org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false
+org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true
+org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true
+org.eclipse.jdt.core.formatter.indent_empty_lines=true
+org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true
+org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true
+org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true
+org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=false
+org.eclipse.jdt.core.formatter.indentation.size=4
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_enum_constant=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_label=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_type_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert
+org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert
+org.eclipse.jdt.core.formatter.insert_space_after_lambda_arrow=insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources=insert
+org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert
+org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=insert
+org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert
+org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw=insert
+org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.join_lines_in_comments=true
+org.eclipse.jdt.core.formatter.join_wrapped_lines=true
+org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=false
+org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false
+org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=false
+org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false
+org.eclipse.jdt.core.formatter.lineSplit=100
+org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false
+org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=false
+org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0
+org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=1
+org.eclipse.jdt.core.formatter.parentheses_positions_in_annotation=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_catch_clause=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_enum_constant_declaration=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_for_statment=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_if_while_statement=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_lambda_declaration=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_method_delcaration=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_method_invocation=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_switch_statement=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_try_clause=common_lines
+org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=true
+org.eclipse.jdt.core.formatter.tabulation.char=tab
+org.eclipse.jdt.core.formatter.tabulation.size=4
+org.eclipse.jdt.core.formatter.use_on_off_tags=false
+org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false
+org.eclipse.jdt.core.formatter.wrap_before_assignment_operator=false
+org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true
+org.eclipse.jdt.core.formatter.wrap_before_conditional_operator=false
+org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch=true
+org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true
+org.eclipse.jdt.core.javaFormatter=org.eclipse.jdt.core.defaultJavaFormatter
diff --git a/examples/org.eclipse.statet.rj.servi.rcpdemo2/.settings/org.eclipse.jdt.ui.prefs b/examples/org.eclipse.statet.rj.servi.rcpdemo2/.settings/org.eclipse.jdt.ui.prefs
new file mode 100644
index 0000000..e62a4f5
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.rcpdemo2/.settings/org.eclipse.jdt.ui.prefs
@@ -0,0 +1,131 @@
+cleanup.add_default_serial_version_id=true
+cleanup.add_generated_serial_version_id=false
+cleanup.add_missing_annotations=true
+cleanup.add_missing_deprecated_annotations=true
+cleanup.add_missing_methods=false
+cleanup.add_missing_nls_tags=false
+cleanup.add_missing_override_annotations=true
+cleanup.add_missing_override_annotations_interface_methods=true
+cleanup.add_serial_version_id=false
+cleanup.always_use_blocks=true
+cleanup.always_use_parentheses_in_expressions=true
+cleanup.always_use_this_for_non_static_field_access=true
+cleanup.always_use_this_for_non_static_method_access=false
+cleanup.convert_functional_interfaces=false
+cleanup.convert_to_enhanced_for_loop=false
+cleanup.correct_indentation=false
+cleanup.format_source_code=false
+cleanup.format_source_code_changes_only=false
+cleanup.insert_inferred_type_arguments=false
+cleanup.make_local_variable_final=true
+cleanup.make_parameters_final=true
+cleanup.make_private_fields_final=true
+cleanup.make_type_abstract_if_missing_method=false
+cleanup.make_variable_declarations_final=true
+cleanup.never_use_blocks=false
+cleanup.never_use_parentheses_in_expressions=false
+cleanup.organize_imports=true
+cleanup.qualify_static_field_accesses_with_declaring_class=false
+cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true
+cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=false
+cleanup.qualify_static_member_accesses_with_declaring_class=true
+cleanup.qualify_static_method_accesses_with_declaring_class=false
+cleanup.remove_private_constructors=true
+cleanup.remove_redundant_type_arguments=true
+cleanup.remove_trailing_whitespaces=false
+cleanup.remove_trailing_whitespaces_all=true
+cleanup.remove_trailing_whitespaces_ignore_empty=false
+cleanup.remove_unnecessary_casts=true
+cleanup.remove_unnecessary_nls_tags=true
+cleanup.remove_unused_imports=true
+cleanup.remove_unused_local_variables=false
+cleanup.remove_unused_private_fields=true
+cleanup.remove_unused_private_members=false
+cleanup.remove_unused_private_methods=true
+cleanup.remove_unused_private_types=true
+cleanup.sort_members=false
+cleanup.sort_members_all=false
+cleanup.use_anonymous_class_creation=false
+cleanup.use_blocks=true
+cleanup.use_blocks_only_for_return_and_throw=false
+cleanup.use_lambda=true
+cleanup.use_parentheses_in_expressions=false
+cleanup.use_this_for_non_static_field_access=true
+cleanup.use_this_for_non_static_field_access_only_if_necessary=false
+cleanup.use_this_for_non_static_method_access=true
+cleanup.use_this_for_non_static_method_access_only_if_necessary=true
+cleanup.use_type_arguments=false
+cleanup_profile=_StatET
+cleanup_settings_version=2
+eclipse.preferences.version=1
+editor_save_participant_org.eclipse.jdt.ui.postsavelistener.cleanup=true
+formatter_profile=_StatET
+formatter_settings_version=12
+org.eclipse.jdt.ui.exception.name=e
+org.eclipse.jdt.ui.gettersetter.use.is=true
+org.eclipse.jdt.ui.ignorelowercasenames=true
+org.eclipse.jdt.ui.importorder=\#;java;javax;com.ibm.icu;org.osgi;org.eclipse;;org.eclipse.statet.jcommons;org.eclipse.statet.ecommons;org.eclipse.statet;
+org.eclipse.jdt.ui.javadoc=true
+org.eclipse.jdt.ui.keywordthis=true
+org.eclipse.jdt.ui.ondemandthreshold=99
+org.eclipse.jdt.ui.overrideannotation=true
+org.eclipse.jdt.ui.staticondemandthreshold=99
+org.eclipse.jdt.ui.text.custom_code_templates=<?xml version\="1.0" encoding\="UTF-8" standalone\="no"?><templates><template autoinsert\="true" context\="gettercomment_context" deleted\="false" description\="Comment for getter method" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.gettercomment" name\="gettercomment">/**\n * @return the ${bare_field_name}\n */</template><template autoinsert\="true" context\="settercomment_context" deleted\="false" description\="Comment for setter method" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.settercomment" name\="settercomment">/**\n * @param ${param} the ${bare_field_name} to set\n */</template><template autoinsert\="true" context\="constructorcomment_context" deleted\="false" description\="Comment for created constructors" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.constructorcomment" name\="constructorcomment">/**\n * ${tags}\n */</template><template autoinsert\="false" context\="filecomment_context" deleted\="false" description\="Comment for created Java files" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.filecomment" name\="filecomment">/*\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\#\n \# Copyright (c) ${year} ${user} and others.\n # \n # This program and the accompanying materials are made available under the\n # terms of the Eclipse Public License 2.0 which is available at\n # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n # which is available at https://www.apache.org/licenses/LICENSE-2.0.\n # \n # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n # \n \# Contributors\:\n \#     ${user} - initial API and implementation\n \#\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=*/</template><template autoinsert\="false" context\="typecomment_context" deleted\="false" description\="Comment for created types" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.typecomment" name\="typecomment">/**\n * \n * ${tags}\n */</template><template autoinsert\="true" context\="fieldcomment_context" deleted\="false" description\="Comment for fields" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.fieldcomment" name\="fieldcomment">/**\n * \n */</template><template autoinsert\="true" context\="methodcomment_context" deleted\="false" description\="Comment for non-overriding methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.methodcomment" name\="methodcomment">/**\n * ${tags}\n */</template><template autoinsert\="false" context\="overridecomment_context" deleted\="false" description\="Comment for overriding methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.overridecomment" name\="overridecomment"/><template autoinsert\="true" context\="delegatecomment_context" deleted\="false" description\="Comment for delegate methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.delegatecomment" name\="delegatecomment">/**\n * ${tags}\n * ${see_to_target}\n */</template><template autoinsert\="false" context\="newtype_context" deleted\="false" description\="Newly created files" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.newtype" name\="newtype">${filecomment}\n\n${package_declaration}\n\n${typecomment}\n${type_declaration}</template><template autoinsert\="true" context\="classbody_context" deleted\="false" description\="Code in new class type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.classbody" name\="classbody">\n</template><template autoinsert\="true" context\="interfacebody_context" deleted\="false" description\="Code in new interface type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.interfacebody" name\="interfacebody">\n</template><template autoinsert\="true" context\="enumbody_context" deleted\="false" description\="Code in new enum type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.enumbody" name\="enumbody">\n</template><template autoinsert\="true" context\="annotationbody_context" deleted\="false" description\="Code in new annotation type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.annotationbody" name\="annotationbody">\n</template><template autoinsert\="true" context\="catchblock_context" deleted\="false" description\="Code in new catch blocks" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.catchblock" name\="catchblock">// ${todo} Auto-generated catch block\n${exception_var}.printStackTrace();</template><template autoinsert\="true" context\="methodbody_context" deleted\="false" description\="Code in created method stubs" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.methodbody" name\="methodbody">// ${todo} Auto-generated method stub\n${body_statement}</template><template autoinsert\="true" context\="constructorbody_context" deleted\="false" description\="Code in created constructor stubs" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.constructorbody" name\="constructorbody">${body_statement}\n// ${todo} Auto-generated constructor stub</template><template autoinsert\="true" context\="getterbody_context" deleted\="false" description\="Code in created getters" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.getterbody" name\="getterbody">return ${field};</template><template autoinsert\="true" context\="setterbody_context" deleted\="false" description\="Code in created setters" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.setterbody" name\="setterbody">${field} \= ${param};</template></templates>
+sp_cleanup.add_default_serial_version_id=true
+sp_cleanup.add_generated_serial_version_id=false
+sp_cleanup.add_missing_annotations=true
+sp_cleanup.add_missing_deprecated_annotations=true
+sp_cleanup.add_missing_methods=false
+sp_cleanup.add_missing_nls_tags=false
+sp_cleanup.add_missing_override_annotations=true
+sp_cleanup.add_missing_override_annotations_interface_methods=true
+sp_cleanup.add_serial_version_id=false
+sp_cleanup.always_use_blocks=true
+sp_cleanup.always_use_parentheses_in_expressions=true
+sp_cleanup.always_use_this_for_non_static_field_access=true
+sp_cleanup.always_use_this_for_non_static_method_access=false
+sp_cleanup.convert_functional_interfaces=false
+sp_cleanup.convert_to_enhanced_for_loop=false
+sp_cleanup.correct_indentation=false
+sp_cleanup.format_source_code=false
+sp_cleanup.format_source_code_changes_only=false
+sp_cleanup.insert_inferred_type_arguments=false
+sp_cleanup.make_local_variable_final=true
+sp_cleanup.make_parameters_final=true
+sp_cleanup.make_private_fields_final=true
+sp_cleanup.make_type_abstract_if_missing_method=false
+sp_cleanup.make_variable_declarations_final=false
+sp_cleanup.never_use_blocks=false
+sp_cleanup.never_use_parentheses_in_expressions=false
+sp_cleanup.on_save_use_additional_actions=true
+sp_cleanup.organize_imports=true
+sp_cleanup.qualify_static_field_accesses_with_declaring_class=false
+sp_cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true
+sp_cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=false
+sp_cleanup.qualify_static_member_accesses_with_declaring_class=true
+sp_cleanup.qualify_static_method_accesses_with_declaring_class=false
+sp_cleanup.remove_private_constructors=true
+sp_cleanup.remove_redundant_type_arguments=true
+sp_cleanup.remove_trailing_whitespaces=false
+sp_cleanup.remove_trailing_whitespaces_all=false
+sp_cleanup.remove_trailing_whitespaces_ignore_empty=true
+sp_cleanup.remove_unnecessary_casts=true
+sp_cleanup.remove_unnecessary_nls_tags=false
+sp_cleanup.remove_unused_imports=false
+sp_cleanup.remove_unused_local_variables=false
+sp_cleanup.remove_unused_private_fields=false
+sp_cleanup.remove_unused_private_members=false
+sp_cleanup.remove_unused_private_methods=false
+sp_cleanup.remove_unused_private_types=true
+sp_cleanup.sort_members=false
+sp_cleanup.sort_members_all=false
+sp_cleanup.use_anonymous_class_creation=false
+sp_cleanup.use_blocks=true
+sp_cleanup.use_blocks_only_for_return_and_throw=false
+sp_cleanup.use_lambda=false
+sp_cleanup.use_parentheses_in_expressions=false
+sp_cleanup.use_this_for_non_static_field_access=true
+sp_cleanup.use_this_for_non_static_field_access_only_if_necessary=false
+sp_cleanup.use_this_for_non_static_method_access=true
+sp_cleanup.use_this_for_non_static_method_access_only_if_necessary=true
+sp_cleanup.use_type_arguments=false
diff --git a/examples/org.eclipse.statet.rj.servi.rcpdemo2/META-INF/MANIFEST.MF b/examples/org.eclipse.statet.rj.servi.rcpdemo2/META-INF/MANIFEST.MF
new file mode 100644
index 0000000..62dcbf1
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.rcpdemo2/META-INF/MANIFEST.MF
@@ -0,0 +1,20 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-SymbolicName: org.eclipse.statet.rj.servi.rcpdemo2;singleton:=true
+Bundle-Version: 2.1.0.qualifier
+Bundle-Vendor: Eclipse.org
+Bundle-Name: StatET RJ - RServi RCP Demo (2)
+Bundle-ActivationPolicy: lazy
+Bundle-Activator: org.eclipse.statet.internal.rj.servi.rcpdemo.Activator
+Bundle-RequiredExecutionEnvironment: JavaSE-1.8
+Require-Bundle: org.eclipse.statet.ecommons.runtime.core;bundle-version="1.1.0";visibility:=reexport,
+ org.eclipse.core.runtime,
+ org.eclipse.statet.ecommons.rmi.core;bundle-version="1.5.0",
+ org.eclipse.statet.rj.data;bundle-version="2.1.0",
+ org.eclipse.statet.rj.server;bundle-version="2.1.0",
+ org.eclipse.statet.rj.client;bundle-version="2.1.0",
+ org.eclipse.statet.rj.servi;bundle-version="2.1.0",
+ org.eclipse.ui,
+ org.eclipse.statet.rj.eclient.core;bundle-version="2.1.0",
+ org.eclipse.statet.rj.eclient.graphics;bundle-version="2.1.0"
+Import-Package: org.eclipse.statet.jcommons.lang;version="1.0.0"
diff --git a/examples/org.eclipse.statet.rj.servi.rcpdemo2/RServi RCP Demo2.launch b/examples/org.eclipse.statet.rj.servi.rcpdemo2/RServi RCP Demo2.launch
new file mode 100644
index 0000000..d38a114
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.rcpdemo2/RServi RCP Demo2.launch
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>

+<launchConfiguration type="org.eclipse.pde.ui.RuntimeWorkbench">

+<setAttribute key="additional_plugins"/>

+<booleanAttribute key="append.args" value="true"/>

+<stringAttribute key="application" value="org.eclipse.statet.rj.servi.rcpdemo.application"/>

+<booleanAttribute key="askclear" value="false"/>

+<booleanAttribute key="automaticAdd" value="false"/>

+<booleanAttribute key="automaticValidate" value="false"/>

+<stringAttribute key="bootstrap" value=""/>

+<stringAttribute key="checked" value="[NONE]"/>

+<booleanAttribute key="clearConfig" value="true"/>

+<booleanAttribute key="clearws" value="true"/>

+<booleanAttribute key="clearwslog" value="true"/>

+<stringAttribute key="configLocation" value="${workspace_loc}/.metadata/.plugins/org.eclipse.pde.core/RServi RCP Demo2"/>

+<booleanAttribute key="default" value="false"/>

+<stringAttribute key="featureDefaultLocation" value="workspace"/>

+<stringAttribute key="featurePluginResolution" value="workspace"/>

+<booleanAttribute key="includeOptional" value="false"/>

+<stringAttribute key="location" value="${workspace_loc}/../runtime-org.eclipse.statet.rj.servi.rcpdemo.product"/>

+<stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>

+<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-os ${target.os} -ws ${target.ws} -arch ${target.arch} -nl ${target.nl} -consoleLog"/>

+<stringAttribute key="org.eclipse.jdt.launching.SOURCE_PATH_PROVIDER" value="org.eclipse.pde.ui.workbenchClasspathProvider"/>

+<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-Xms40m -Xmx512m"/>

+<booleanAttribute key="pde.generated.config" value="false"/>

+<stringAttribute key="pde.version" value="3.3"/>

+<stringAttribute key="product" value="org.eclipse.statet.rj.servi.rcpdemo2.product"/>

+<stringAttribute key="productFile" value="\org.eclipse.statet.rj.servi.rcpdemo2\org.eclipse.statet.rj.servi.rcpdemo.product"/>

+<setAttribute key="selected_features">

+<setEntry value="org.eclipse.statet.rj.servi.e:default"/>

+<setEntry value="org.eclipse.e4.rcp:default"/>

+<setEntry value="org.eclipse.emf.common:default"/>

+<setEntry value="org.eclipse.emf.ecore:default"/>

+<setEntry value="org.eclipse.rcp:default"/>

+</setAttribute>

+<booleanAttribute key="show_selected_only" value="false"/>

+<booleanAttribute key="tracing" value="false"/>

+<booleanAttribute key="useCustomFeatures" value="true"/>

+<booleanAttribute key="useDefaultConfig" value="true"/>

+<booleanAttribute key="useDefaultConfigArea" value="true"/>

+<booleanAttribute key="useProduct" value="true"/>

+<booleanAttribute key="usefeatures" value="false"/>

+</launchConfiguration>

diff --git a/examples/org.eclipse.statet.rj.servi.rcpdemo2/about.html b/examples/org.eclipse.statet.rj.servi.rcpdemo2/about.html
new file mode 100644
index 0000000..7206cec
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.rcpdemo2/about.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+		"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+<title>About</title>
+</head>
+<body lang="EN-US">
+<h2>About This Content</h2>
+
+<p>December 1, 2017</p>
+<h3>License</h3>
+
+<p>
+	The Eclipse Foundation makes available all content in this plug-in
+	(&quot;Content&quot;). Unless otherwise indicated below, the Content
+	is provided to you under the terms and conditions of the Eclipse
+	Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is
+	available at <a href="https://www.eclipse.org/legal/epl-2.0">https://www.eclipse.org/legal/epl-2.0</a>.
+	For purposes of the EPL, &quot;Program&quot; will mean the Content.
+</p>
+
+<p>
+	If you did not receive this Content directly from the Eclipse
+	Foundation, the Content is being redistributed by another party
+	(&quot;Redistributor&quot;) and different terms and conditions may
+	apply to your use of any object code in the Content. Check the
+	Redistributor's license that was provided with the Content. If no such
+	license exists, contact the Redistributor. Unless otherwise indicated
+	below, the terms and conditions of the EPL still apply to any source
+	code in the Content and such source code may be obtained at <a
+	href="https://www.eclipse.org/">https://www.eclipse.org</a>.
+</p>
+
+</body>
+</html>
diff --git a/examples/org.eclipse.statet.rj.servi.rcpdemo2/build.properties b/examples/org.eclipse.statet.rj.servi.rcpdemo2/build.properties
new file mode 100644
index 0000000..8f6690d
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.rcpdemo2/build.properties
@@ -0,0 +1,11 @@
+source..= src/
+output..= bin/
+javacDefaultEncoding..= UTF-8
+
+bin.includes= META-INF/,\
+              plugin.xml,\
+              .,\
+              icons/,\
+              plugin_customization.ini,\
+              splash.bmp
+src.includes= .settings/org.eclipse.core.resources.prefs
diff --git a/examples/org.eclipse.statet.rj.servi.rcpdemo2/icons/alt_about.gif b/examples/org.eclipse.statet.rj.servi.rcpdemo2/icons/alt_about.gif
new file mode 100644
index 0000000..20d9ad2
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.rcpdemo2/icons/alt_about.gif
Binary files differ
diff --git a/examples/org.eclipse.statet.rj.servi.rcpdemo2/icons/alt_launcher.icns b/examples/org.eclipse.statet.rj.servi.rcpdemo2/icons/alt_launcher.icns
new file mode 100644
index 0000000..b77a6a6
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.rcpdemo2/icons/alt_launcher.icns
Binary files differ
diff --git a/examples/org.eclipse.statet.rj.servi.rcpdemo2/icons/alt_launcher.ico b/examples/org.eclipse.statet.rj.servi.rcpdemo2/icons/alt_launcher.ico
new file mode 100644
index 0000000..d548f71
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.rcpdemo2/icons/alt_launcher.ico
Binary files differ
diff --git a/examples/org.eclipse.statet.rj.servi.rcpdemo2/icons/alt_launcher.xpm b/examples/org.eclipse.statet.rj.servi.rcpdemo2/icons/alt_launcher.xpm
new file mode 100644
index 0000000..d2918c1
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.rcpdemo2/icons/alt_launcher.xpm
@@ -0,0 +1,307 @@
+/* XPM */

+static char * icon48_xpm[]= {

+"48 48 256 2",

+"  	c #4B4B3B3B9090",

+". 	c #0D0D0E0E5454",

+"X 	c #11110E0E5B5B",

+"o 	c #17170F0F6363",

+"O 	c #1D1D13136969",

+"+ 	c #212114146C6C",

+"@ 	c #252514147171",

+"# 	c #282811116C6C",

+"$ 	c #26260D0D6363",

+"% 	c #22220B0B5E5E",

+"& 	c #1C1C0B0B5A5A",

+"* 	c #1C1C0B0B5252",

+"= 	c #1B1B05055353",

+"- 	c #161606064D4D",

+"; 	c #161605054949",

+": 	c #111104044848",

+"> 	c #131304044545",

+", 	c #131305054242",

+"< 	c #141410105E5E",

+"1 	c #2C2C15157373",

+"2 	c #2B2B1B1B7575",

+"3 	c #343416167272",

+"4 	c #313113136E6E",

+"5 	c #222209095757",

+"6 	c #1B1B06064D4D",

+"7 	c #15150B0B4242",

+"8 	c #13130C0C5555",

+"9 	c #2E2E1B1B7878",

+"0 	c #33331F1F7C7C",

+"q 	c #343418187878",

+"w 	c #3B3B1C1C7575",

+"e 	c #2E2E10106767",

+"r 	c #1B1B07074747",

+"t 	c #18180B0B4646",

+"y 	c #151513136262",

+"u 	c #1A1A15156464",

+"i 	c #34341F1F7777",

+"p 	c #40401E1E8080",

+"a 	c #42421B1B7A7A",

+"s 	c #3B3B15157474",

+"d 	c #2B2B0B0B5B5B",

+"f 	c #222207075252",

+"g 	c #373727277A7A",

+"h 	c #474724248484",

+"j 	c #393915156E6E",

+"k 	c #373711116A6A",

+"l 	c #343413136363",

+"z 	c #232319196E6E",

+"x 	c #292919197070",

+"c 	c #3C3C2C2C8282",

+"v 	c #444431318585",

+"b 	c #494934348A8A",

+"n 	c #505026268A8A",

+"m 	c #3D3D1B1B6E6E",

+"M 	c #31310E0E5C5C",

+"N 	c #2B2B0D0D5353",

+"B 	c #222207074A4A",

+"V 	c #52523C3C9292",

+"C 	c #58583C3C9494",

+"Z 	c #5D5D44449797",

+"A 	c #5C5C2E2E9292",

+"S 	c #676733339595",

+"D 	c #424228287575",

+"F 	c #29290A0A4F4F",

+"G 	c #6C6C4A4A9E9E",

+"H 	c #72725454A7A7",

+"J 	c #8C8C6D6DB2B2",

+"K 	c #343424246E6E",

+"L 	c #3A3A23236A6A",

+"P 	c #3A3A1C1C6767",

+"I 	c #24240A0A4B4B",

+"U 	c #151518186161",

+"Y 	c #76766F6FA5A5",

+"T 	c #ADAD9191CCCC",

+"R 	c #98988989D3D3",

+"E 	c #45453B3B8686",

+"W 	c #3C3C35357979",

+"Q 	c #363631317575",

+"! 	c #32322D2D6B6B",

+"~ 	c #323229296363",

+"^ 	c #30301F1F6262",

+"/ 	c #323218185E5E",

+"( 	c #272707074B4B",

+") 	c #202028286C6C",

+"_ 	c #1E1E1D1D6868",

+"` 	c #9A9A8282BBBB",

+"' 	c #C8C8B3B3D3D3",

+"] 	c #B3B3AFAFE7E7",

+"[ 	c #84847272C6C6",

+"{ 	c #58585757A3A3",

+"} 	c #3F3F3C3C8A8A",

+"| 	c #3B3B3A3A8484",

+" .	c #414139397D7D",

+"..	c #3D3D39397A7A",

+"X.	c #37372E2E6E6E",

+"o.	c #2C2C21215A5A",

+"O.	c #2E2E1B1B5B5B",

+"+.	c #F5F5EFEFF5F5",

+"@.	c #656566669A9A",

+"#.	c #47474B4B8E8E",

+"$.	c #3C3C44447B7B",

+"%.	c #444442428080",

+"&.	c #45453E3E8181",

+"*.	c #40403C3C8181",

+"=.	c #3D3D33337474",

+"-.	c #3B3B30306E6E",

+";.	c #38382D2D6969",

+":.	c #303026265D5D",

+">.	c #2C2C15155A5A",

+",.	c #1F1F1C1C7070",

+"<.	c #25251E1E7171",

+"1.	c #59595C5C9191",

+"2.	c #4D4D53538989",

+"3.	c #4C4C49498484",

+"4.	c #484845458585",

+"5.	c #494941418585",

+"6.	c #494940408181",

+"7.	c #2F2F1C1C5353",

+"8.	c #2B2B28287676",

+"9.	c #323231317F7F",

+"0.	c #545452528B8B",

+"q.	c #51514E4E8989",

+"w.	c #4E4E4B4B8C8C",

+"e.	c #4C4C47478686",

+"r.	c #46463D3D7E7E",

+"t.	c #434336367A7A",

+"y.	c #2B2B13135555",

+"u.	c #47473D3D8D8D",

+"i.	c #575757578E8E",

+"p.	c #48483E3E7F7F",

+"a.	c #46463A3A7D7D",

+"s.	c #424235357575",

+"d.	c #404034347171",

+"f.	c #BFBFCBCBFAFA",

+"g.	c #B8B8A8A8DDDD",

+"h.	c #5E5E60609292",

+"j.	c #565655558C8C",

+"k.	c #4B4B44448282",

+"l.	c #454539397B7B",

+"z.	c #434338387878",

+"x.	c #3F3F32326D6D",

+"c.	c #3D3D30306969",

+"v.	c #3A3A2E2E6363",

+"b.	c #36362A2A5C5C",

+"n.	c #343424245555",

+"m.	c #30301E1E4D4D",

+"M.	c #49493C3C8282",

+"N.	c #5E5E4F4F8C8C",

+"B.	c #56563B3B8B8B",

+"V.	c #545407078585",

+"C.	c #424234347272",

+"Z.	c #9797A4A4F7F7",

+"A.	c #444436367676",

+"S.	c #7D7D7979D5D5",

+"D.	c #464640408A8A",

+"F.	c #44444B4B8282",

+"G.	c #414107077777",

+"H.	c #71716161C1C1",

+"J.	c #303039397979",

+"K.	c #8E8E8E8EE6E6",

+"L.	c #404033338B8B",

+"P.	c #4A4A45458C8C",

+"I.	c #46463A3A8080",

+"U.	c #363629295454",

+"Y.	c #303022224848",

+"T.	c #424237377575",

+"R.	c #2E2E1D1D6363",

+"E.	c #79798383EAEA",

+"W.	c #74747B7BE4E4",

+"Q.	c #6D6D7676D6D6",

+"!.	c #6A6A7171CECE",

+"~.	c #66666969C6C6",

+"^.	c #62626565BCBC",

+"/.	c #5F5F6060B5B5",

+"(.	c #5B5B5B5BACAC",

+").	c #535353539898",

+"_.	c #4F4F4F4FA4A4",

+"`.	c #54544D4DA4A4",

+"'.	c #323204046B6B",

+"].	c #303035357979",

+"[.	c #313122224343",

+"{.	c #5A5A5B5BB7B7",

+"}.	c #484846468080",

+"|.	c #454541417575",

+" X	c #4B4B31318282",

+".X	c #47473C3C8484",

+"XX	c #3E3E35356E6E",

+"oX	c #2F2F26264040",

+"OX	c #2B2B23233A3A",

+"+X	c #262619195C5C",

+"@X	c #252515155A5A",

+"#X	c #55555151B3B3",

+"$X	c #3C3C2D2D5D5D",

+"%X	c #39392F2F5656",

+"&X	c #37372D2D5050",

+"*X	c #25251F1F3030",

+"=X	c #24241D1D4343",

+"-X	c #202013135656",

+";X	c #41413B3B6C6C",

+":X	c #444442429696",

+">X	c #212100005E5E",

+",X	c #444436367272",

+"<X	c #444436366F6F",

+"1X	c #424236366868",

+"2X	c #3F3F34346161",

+"3X	c #3C3C32325A5A",

+"4X	c #34342A2A4A4A",

+"5X	c #21211B1B2121",

+"6X	c #22221C1C6363",

+"7X	c #2D2D01015E5E",

+"8X	c #20201B1B2525",

+"9X	c #49492F2F7B7B",

+"0X	c #434334346C6C",

+"qX	c #323229294545",

+"wX	c #1C1C10104F4F",

+"eX	c #222217176363",

+"rX	c #37371E1E6B6B",

+"tX	c #424232326E6E",

+"yX	c #444433336969",

+"uX	c #424233336565",

+"iX	c #1E1E1A1A1E1E",

+"pX	c #161601014C4C",

+"aX	c #1C1C11115454",

+"sX	c #252503035B5B",

+"dX	c #414131316A6A",

+"fX	c #22221F1F7878",

+"gX	c #272724246767",

+"hX	c #1D1D16165E5E",

+"jX	c #131305055151",

+"kX	c #40402F2F6464",

+"lX	c #111107074E4E",

+"zX	c #0C0C05054B4B",

+"xX	c #22221E1E5757",

+"cX	c #1A1A0D0D4D4D",

+"vX	c #16160B0B4D4D",

+"bX	c #060604044747",

+"nX	c #040403034343",

+"mX	c #3B3B27276565",

+"MX	c #0E0E03034141",

+"NX	c #111106064A4A",

+"BX	c #0E0E04044646",

+"VX	c #111105053B3B",

+"CX	c #0D0D01013A3A",

+"ZX	c #030305053F3F",

+"AX	c #0F0F0F0F4C4C",

+"SX	c #020207073B3B",

+"DX	c #0D0D03034646",

+"FX	c #0B0B02023F3F",

+"GX	c #0D0D02023434",

+"HX	c #0A0A0E0E4444",

+"JX	c #161614145252",

+"KX	c #0B0B04044646",

+"LX	c #0A0A03034444",

+"PX	c #1D1D21215757",

+"IX	c #090910104040",

+"UX	c #18181E1E5353",

+"                                                                                                ",

+"  . . . . X X o o o o O + + @ @ @ @ @ @ @ # # # # # # $ $ % % & & & & *= - - - ; : > > , , ,   ",

+"  . . X X < < o o O O + @ 1 2 2 1 1 1 1 1 1 1 1 3 4 # # $ $ $ % % % 5= = 6 6 - ; ; > > , , 7   ",

+"  . 8 < < < o O O + @ @ 2 9 9 0 0 q q q q q q q w 3 4 4 e e $ $ $ $ % 5= = 6 6 6 ; ; > > r t   ",

+"  . X < y u O O + @ 1 2 i 0 0 p p p p p p p a a p a s 3 4 4 e e e e d 5 5 f f 6 6 6 ; ; r r t   ",

+"  X < y u O + + @ 2 9 0 g p p h h h h h h h p h h a a s s j k k j l d d 5 5 f f 6 6 r r r r r   ",

+"  X < y O z x x 9 0 g c v b n n n n n n n n n n n h a a s s j j m l M d d N f f B B B B r r r   ",

+"  < y u + z 2 0 c c b V C Z C C A A A A A S S S n h D w w m m m m k l M d d N f F F F B r r r   ",

+"  < y O z z 9 c b V Z G H H H G S G G J J H V v c g g K K K K L P l l l M M N N N N I B B r r   ",

+"  U u + z x i v C H Y J J J J H J T R H V E W W Q Q Q Q ! ! ! ~ ^ ^ / / M M M M M N ( B B r r   ",

+"  ) _ z x 9 g b Z Y ` ' ' ' T T ] [ { } |  .........W W Q Q X.! ~ ~ o.O./ / / / N F ( B B B r   ",

+"  ) ) z x i c V G J ' +.+.+.+.] [ @.#.$.%.%.%.&.*. . .....W =.-.X.;.~ :.o.O.^ >.N F ( B B B B   ",

+"  ) ,.<.2 g v C H J ' +.+.+.+.T Y 1.2.3.4.4.4.5.6.&.&. . ...W =.=.-.;.~ :.o.7.>.N F F ( B I I   ",

+"  ) ,.<.8.9.b C H J T +.+.+.' J @.1.0.q.q.w.e.4.5.6.&.r. . .t.W =.=.-.;.~ :.o.7.y.N F ( ( I I   ",

+"  8.8.8.9.| u.C G J T +.+.' ` Y @.1.i.0.q.q.e.e.5.6.p.r.a. .t.t.s.d.d.-.;.~ :.7.7.y.F F ( I I   ",

+"  9.c c c v b A S H ' f.g.` Y @.h.1.i.j.0.q.q.e.k.6.p.r.a.l.t.z.s.s.d.x.c.v.b.n.m.7.N F F F I   ",

+"  <.g M.N.B.B.n V.J f.R J @.h.h.1.i.i.j.j.0.q.3.k.6.p.r.a.l.l.z.s.C.d.x.x.c.v.b.n.m.y.N F F F   ",

+"  + x i v B.Z Z G g.Z.[ @.2.i.i.j.j.j.j.j.0.q.3.k.6.p.p.a.l.l.A.s.C.C.d.x.c.v.b.n.m.7.y.N N y.  ",

+"  O # 3 w p n Z ` f.S.H D.F.q.0.0.0.0.j.0.q.q.3.k.6.p.r.a.a.l.A.s.s.C.d.x.x.c.v.b.n.m.y.y.y.y.  ",

+"  O # 4 s a G.V.T Z.H.V J.%.e.w.q.0.0.0.0.q.q.e.k.6.p.r.a.a.l.z.A.s.C.d.d.x.c.v.b.n.m.7.>.y.y.  ",

+"  O # 4 s w G.A f.K.H L...4.P.w.w.w.q.q.q.q.e.e.5.6.M.I.I.a.a.l.z.A.s.d.d.x.c.v.v.U.Y.7.O.>.y.  ",

+"  $ # 4 3 s G.G f.S.Z 9.*.D.P.P.w.w.w.w.w.e.e.5.5.M.M.I.I.a.a.l.z.T.s.d.d.x.x.c.v.U.Y.m.R.>.>.  ",

+"  E.E.W.W.W.W.E.Z.E.W.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.!.!.!.!.!.~.~.~.~.~.~.^.^.^.^.^./././.(.{ { )._.`._.  ",

+"  + # 3 w s '.` f.H.V ].*.D.P.P.P.P.P.P.P.5.5.5.M.M.M.I.I.a.l.z.z.T.T.s.d.d.x.c.v.U.Y.[.^ O.>.  ",

+"  ~.~.~.~.~.~.K.Z.S.~.{.^.^.^.^.^.^.^.^././././././.(.(.(.(.(.(.{ { { { { ).).).w.w.}.|.P.u.}   ",

+"   .I.6. X X XT f.H.b ].*.E D.D.D.D.5.5..X.XM.M.I.I.a.a.l.l.z.z.T.T.T.d.XXx.c.v.b.U.oXOXR.+X@X  ",

+"  E.E.E.W.W.W.K.Z.E.W.Q.Q.Q.Q.Q.Q.Q.Q.!.!.!.!.!.!.~.~.~.~.~.~.^.^.^.^.^./././.(.{ { ).).#X_._.  ",

+"  & % $ e '.= H f.H.b 8.W *.E E E .X.X.XI.I.I.I.a.a.l.l.z.z.T.T.T.C.XXXXc.v.$X%X&XY.*X=X2 @X-X  ",

+"  {.{.{.{.{.#X~.Z.W.~.{.{./././././././././.(.(.(.(.(.(.(.{ { { { { { ).).).w.w.3.}.;X%.:X} }   ",

+"  & & % $ e >XV.f.S.C K X.W t. . .l.l.t.t.t.t.A.A.A.,X,X,X,X,X<X;X1X1X2X3X%X&X4XoX*X5Xo.6X-X-X  ",

+"  & & % $ $ >X7X` Z.Z D ! =.=.s.t.t.t.A.A.s.A.,X,X,X,X<X<X<X<X;X1X2X2X3X%X&X4XoXOX8X5X<.@X-X-X  ",

+"  8 & & $ e K 9XJ f.^. XK X.=.=.s.s.s.s.s.C.C.C.C.<X0X0X0X1X1X1X2X2X3X%X&X4XqXOX*X8X=X<.-X-XwX  ",

+"  8 & eXK k.@.M. Xg.E.B.rX~ -.d.d.C.C.C.C.C.tX0X0X0XyXyX1X1XuX2X2X3X%X&X4XqXoXOX8XiX6XeX-X-XwX  ",

+"  6XQ h.Y N.K e pXB.f./.9Xo.;.-.x.d.tXtXtXtXtX0X0XyXyXyXuXuX2X2X3X%X&X4XqXoXOX*XiX=X_ aX-XaXwX  ",

+"  Y Y  .R.@X% sX= 7XT Z.V P :.;.c.x.x.x.tXdXdXdXyXyXuXuX2X2X3X3X%X&X4XqXoXOX*X8X*XfXaXaXaXwXwX  ",

+"  gXhX& * & 5 5 sXjXa ] S.9X/ ~ v.c.dXdXdXdXdXuXuXuXkX2X2X3X%X%X&X4XqXoXOX*X8XiX<.hXwXwXaXwXwX  ",

+"  8 lXlXjX= * 5 5= zX9X] H.D 7.b.v.v.kXc.kXkXkXkXkX2X$X3X%X&X&X4XqXoXOX*X8XiXxXhXwXcXcXwXwXwX  ",

+"  zXzXlXlXjX== f f sXD Y ] ~.D 7.n.b.v.v.kXkXkXkX$X$X%X%X&X4XqXoXoXOX*X8X5XgXu cXvXvXcXcXwXwX  ",

+"  bXbXzXlXlX-= * @XX.h.e D T S.D n.m.b.$X$X$X$X$X%X%X&X&X4XqXoXOX*X8X8X*X<.hXvX; ; vXvXvXcXwX  ",

+"  nXbXzXzXlXlX- -XX.Y R.pXpXP J K.Z mXm.n.U.U.U.U.U.4X4XY.oXOX*X8X8X8X=X,.aXvX; > > > t t t cX  ",

+"  nXbXbXzXzXlXaXXXY +Xf= f= 7XtXR R   mXn.Y.[.[.[.[.OX*X*X8X5X*X=X,.u vXvX; > > MXMX, 7 t t   ",

+"  nXnXnXbXzXvX-.Y +XcX6 6= == d L B.G H `.X.:.7.m.=X=X=X=X=X6X,.u cXvXNX: BX> MXVXCXVX7 7 7   ",

+"  ZXZXnXbXAXgX@.+XvX; - - - - * @XR.>.sX>.R.i 0 x eXeXeXeXO hXaXcXvXNX: BXMXMXMXVXCXCXCXVX7 7   ",

+"  SXZXZXAXgXN.aXNX: : NXNXNX- * +X+X* 6 6 6 * * * * * * * vXvX- NX: DXBXMXMXFXCXCXCXCXGXVXVX7   ",

+"  SXSXHXgX0.JXKXLXKXKXDX: : NX* @X-X- - - - - - - - - - - NX: DXDXDXMXMXFXFXCXCXCXCXGXGXGXVXVX  ",

+"  SXHXPX3.JXnXnXnXnXbXLXKXKXNXaX-XvX: : NX: : : : : : : BXDXDXLXMXMXFXFXCXCXCXCXGXGXGXGXGXGXGX  ",

+"  IXUX$.AXZXZXZXZXnXnXnXLXLXNXJXvXBXDXBXBXBXBXDXDXDXDXLXDXLXLXFXFXFXFXCXCXCXCXGXGXGXGXGXGXGXGX  ",

+"                                                                                                "};

diff --git a/examples/org.eclipse.statet.rj.servi.rcpdemo2/icons/alt_window_16.gif b/examples/org.eclipse.statet.rj.servi.rcpdemo2/icons/alt_window_16.gif
new file mode 100644
index 0000000..05626b1
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.rcpdemo2/icons/alt_window_16.gif
Binary files differ
diff --git a/examples/org.eclipse.statet.rj.servi.rcpdemo2/icons/alt_window_32.gif b/examples/org.eclipse.statet.rj.servi.rcpdemo2/icons/alt_window_32.gif
new file mode 100644
index 0000000..b432f88
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.rcpdemo2/icons/alt_window_32.gif
Binary files differ
diff --git a/examples/org.eclipse.statet.rj.servi.rcpdemo2/org.eclipse.statet.rj.servi.rcpdemo.product b/examples/org.eclipse.statet.rj.servi.rcpdemo2/org.eclipse.statet.rj.servi.rcpdemo.product
new file mode 100644
index 0000000..836d481
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.rcpdemo2/org.eclipse.statet.rj.servi.rcpdemo.product
@@ -0,0 +1,130 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<?pde version="3.5"?>
+
+<product name="RServi RCP Demo" id="org.eclipse.statet.rj.servi.rcpdemo2.product" application="org.eclipse.statet.rj.servi.rcpdemo.application" version="0.4.0.qualifier" useFeatures="false" includeLaunchers="true">
+
+   <configIni use="default">
+   </configIni>
+
+   <launcherArgs>
+      <vmArgs>-Xms40m -Xmx512m
+      </vmArgs>
+      <vmArgsMac>-XstartOnFirstThread -Dorg.eclipse.swt.internal.carbon.smallFonts
+      </vmArgsMac>
+   </launcherArgs>
+
+   <windowImages i16="icons/alt_window_16.gif" i32="icons/alt_window_32.gif"/>
+
+   <splash
+      location="org.eclipse.statet.rj.servi.rcpdemo2"
+      startupProgressRect="20,190,415,15"
+      startupMessageRect="20,210,415,20"
+      startupForegroundColor="000000" />
+   <launcher>
+      <solaris/>
+      <win useIco="false">
+         <bmp/>
+      </win>
+   </launcher>
+
+   <vm>
+   </vm>
+
+   <plugins>
+      <plugin id="com.ibm.icu"/>
+      <plugin id="org.eclipse.statet.ecommons.runtime.core"/>
+      <plugin id="org.eclipse.statet.ecommons.rmi.core"/>
+      <plugin id="org.eclipse.statet.ecommons.coremisc"/>
+      <plugin id="org.eclipse.statet.ecommons.uimisc"/>
+      <plugin id="org.eclipse.statet.rj.data"/>
+      <plugin id="org.eclipse.statet.rj.client"/>
+      <plugin id="org.eclipse.statet.rj.services.core"/>
+      <plugin id="org.eclipse.statet.rj.eclient.core"/>
+      <plugin id="org.eclipse.statet.rj.eclient.graphics"/>
+      <plugin id="org.eclipse.statet.rj.server"/>
+      <plugin id="org.eclipse.statet.rj.servi"/>
+      <plugin id="org.eclipse.statet.rj.servi.rcpdemo2"/>
+      <plugin id="javax.annotation"/>
+      <plugin id="javax.inject"/>
+      <plugin id="javax.xml"/>
+      <plugin id="org.apache.batik.css"/>
+      <plugin id="org.apache.batik.util"/>
+      <plugin id="org.apache.batik.util.gui"/>
+      <plugin id="org.apache.commons.jxpath"/>
+      <plugin id="org.eclipse.core.commands"/>
+      <plugin id="org.eclipse.core.contenttype"/>
+      <plugin id="org.eclipse.core.databinding"/>
+      <plugin id="org.eclipse.core.databinding.observable"/>
+      <plugin id="org.eclipse.core.databinding.property"/>
+      <plugin id="org.eclipse.core.expressions"/>
+      <plugin id="org.eclipse.core.jobs"/>
+      <plugin id="org.eclipse.core.runtime"/>
+      <plugin id="org.eclipse.core.runtime.compatibility.registry" fragment="true"/>
+      <plugin id="org.eclipse.e4.core.commands"/>
+      <plugin id="org.eclipse.e4.core.contexts"/>
+      <plugin id="org.eclipse.e4.core.di"/>
+      <plugin id="org.eclipse.e4.core.di.annotations"/>
+      <plugin id="org.eclipse.e4.core.di.extensions"/>
+      <plugin id="org.eclipse.e4.core.services"/>
+      <plugin id="org.eclipse.e4.emf.xpath"/>
+      <plugin id="org.eclipse.e4.ui.bindings"/>
+      <plugin id="org.eclipse.e4.ui.css.core"/>
+      <plugin id="org.eclipse.e4.ui.css.swt"/>
+      <plugin id="org.eclipse.e4.ui.css.swt.theme"/>
+      <plugin id="org.eclipse.e4.ui.di"/>
+      <plugin id="org.eclipse.e4.ui.model.workbench"/>
+      <plugin id="org.eclipse.e4.ui.services"/>
+      <plugin id="org.eclipse.e4.ui.widgets"/>
+      <plugin id="org.eclipse.e4.ui.workbench"/>
+      <plugin id="org.eclipse.e4.ui.workbench.addons.swt"/>
+      <plugin id="org.eclipse.e4.ui.workbench.renderers.swt"/>
+      <plugin id="org.eclipse.e4.ui.workbench.swt"/>
+      <plugin id="org.eclipse.e4.ui.workbench3"/>
+      <plugin id="org.eclipse.emf.common"/>
+      <plugin id="org.eclipse.emf.ecore"/>
+      <plugin id="org.eclipse.emf.ecore.change"/>
+      <plugin id="org.eclipse.emf.ecore.xmi"/>
+      <plugin id="org.eclipse.equinox.app"/>
+      <plugin id="org.eclipse.equinox.common"/>
+      <plugin id="org.eclipse.equinox.ds"/>
+      <plugin id="org.eclipse.equinox.event"/>
+      <plugin id="org.eclipse.equinox.preferences"/>
+      <plugin id="org.eclipse.equinox.registry"/>
+      <plugin id="org.eclipse.equinox.util"/>
+      <plugin id="org.eclipse.help"/>
+      <plugin id="org.eclipse.jface"/>
+      <plugin id="org.eclipse.jface.databinding"/>
+      <plugin id="org.eclipse.osgi"/>
+      <plugin id="org.eclipse.osgi.compatibility.state" fragment="true"/>
+      <plugin id="org.eclipse.osgi.services"/>
+      <plugin id="org.eclipse.swt"/>
+      <plugin id="org.eclipse.swt.cocoa.macosx" fragment="true"/>
+      <plugin id="org.eclipse.swt.cocoa.macosx.x86_64" fragment="true"/>
+      <plugin id="org.eclipse.swt.gtk.aix.ppc" fragment="true"/>
+      <plugin id="org.eclipse.swt.gtk.aix.ppc64" fragment="true"/>
+      <plugin id="org.eclipse.swt.gtk.hpux.ia64_32" fragment="true"/>
+      <plugin id="org.eclipse.swt.gtk.linux.ppc64" fragment="true"/>
+      <plugin id="org.eclipse.swt.gtk.linux.s390" fragment="true"/>
+      <plugin id="org.eclipse.swt.gtk.linux.s390x" fragment="true"/>
+      <plugin id="org.eclipse.swt.gtk.linux.x86" fragment="true"/>
+      <plugin id="org.eclipse.swt.gtk.linux.x86_64" fragment="true"/>
+      <plugin id="org.eclipse.swt.gtk.solaris.sparc" fragment="true"/>
+      <plugin id="org.eclipse.swt.gtk.solaris.x86" fragment="true"/>
+      <plugin id="org.eclipse.swt.win32.win32.x86" fragment="true"/>
+      <plugin id="org.eclipse.swt.win32.win32.x86_64" fragment="true"/>
+      <plugin id="org.eclipse.ui"/>
+      <plugin id="org.eclipse.ui.workbench"/>
+      <plugin id="org.w3c.css.sac"/>
+      <plugin id="org.w3c.dom.events"/>
+      <plugin id="org.w3c.dom.smil"/>
+      <plugin id="org.w3c.dom.svg"/>
+   </plugins>
+
+   <configurations>
+      <plugin id="org.eclipse.core.runtime" autoStart="true" startLevel="0" />
+      <plugin id="org.eclipse.equinox.common" autoStart="true" startLevel="2" />
+      <plugin id="org.eclipse.equinox.ds" autoStart="true" startLevel="1" />
+      <plugin id="org.eclipse.osgi" autoStart="true" startLevel="-1" />
+   </configurations>
+
+</product>
diff --git a/examples/org.eclipse.statet.rj.servi.rcpdemo2/plugin.xml b/examples/org.eclipse.statet.rj.servi.rcpdemo2/plugin.xml
new file mode 100644
index 0000000..c002914
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.rcpdemo2/plugin.xml
@@ -0,0 +1,127 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<?eclipse version="3.4"?>
+<plugin>
+
+   <extension
+         id="org.eclipse.statet.rj.servi.rcpdemo.application"
+         point="org.eclipse.core.runtime.applications">
+      <application>
+         <run
+               class="org.eclipse.statet.internal.rj.servi.rcpdemo.Application">
+         </run>
+      </application>
+   </extension>
+   <extension
+         id="product"
+         point="org.eclipse.core.runtime.products">
+      <product
+            application="org.eclipse.statet.rj.servi.rcpdemo.application"
+            name="RServi RCP Demo">
+         <property
+               name="windowImages"
+               value="icons/alt_window_16.gif,icons/alt_window_32.gif">
+         </property>
+         <property
+               name="appName"
+               value="RServi RCP Demo">
+         </property>
+         <property
+               name="startupProgressRect"
+               value="20,190,415,15">
+         </property>
+         <property
+               name="startupForegroundColor"
+               value="000000">
+         </property>
+         <property
+               name="startupMessageRect"
+               value="20,210,415,20">
+         </property>
+         <property
+               name="preferenceCustomization"
+               value="plugin_customization.ini">
+         </property>
+      </product>
+   </extension>
+   
+   <extension
+         point="org.eclipse.ui.perspectives">
+      <perspective
+            name="RCP Perspective"
+            class="org.eclipse.statet.internal.rj.servi.rcpdemo.Perspective"
+            id="org.eclipse.statet.rj.servi.rcpdemo.perspective">
+      </perspective>
+   </extension>
+   <extension
+         point="org.eclipse.ui.menus">
+      <menuContribution
+            locationURI="menu:org.eclipse.ui.main.menu">
+         <menu id="file"
+               label="&amp;File">
+         </menu>
+      </menuContribution>
+      <menuContribution
+            locationURI="menu:file">
+         <command
+               commandId="org.eclipse.ui.file.exit"
+               style="push">
+         </command>
+      </menuContribution>
+   </extension>
+   
+   <extension
+         point="org.eclipse.ui.views">
+      <view
+            allowMultiple="false"
+            class="org.eclipse.statet.internal.rj.servi.rcpdemo.views.RServiConfigView"
+            id="org.eclipse.statet.rj.servi.rcpdemo.views.RServiConfig"
+            name="Config"
+            restorable="true">
+      </view>
+      <view
+            allowMultiple="true"
+            class="org.eclipse.statet.internal.rj.servi.rcpdemo.views.GraphDemoView"
+            id="org.eclipse.statet.rj.servi.rcpdemo.views.GraphDemo"
+            name="Graph"
+            restorable="true">
+      </view>
+      <view
+            id="org.eclipse.ui.views.ProgressView"
+            class="org.eclipse.ui.ExtensionFactory:progressView"
+            name="Progress">
+      </view>
+   </extension>
+   <extension
+         point="org.eclipse.ui.perspectiveExtensions">
+      <perspectiveExtension
+            targetID="*">
+         <view
+               id="org.eclipse.statet.rj.servi.rcpdemo.views.GraphDemo"
+               closeable="false"
+               minimized="false"
+               relative="org.eclipse.ui.editorss"
+               relationship="left"
+               visible="true">
+         </view>
+         <view
+               id="org.eclipse.statet.rj.servi.rcpdemo.views.RServiConfig"
+               closeable="false"
+               minimized="false"
+               ratio="0.3f"
+               relative="org.eclipse.statet.rj.servi.rcpdemo.views.GraphDemo"
+               relationship="left"
+               visible="true">
+         </view>
+         <view
+               id="org.eclipse.ui.views.ProgressView"
+               closeable="true"
+               minimized="false"
+               ratio="0.75"
+               relative="org.eclipse.statet.rj.servi.rcpdemo.views.RServiConfig"
+               relationship="bottom"
+               visible="false">
+         </view>
+      </perspectiveExtension>
+   </extension>
+
+</plugin>
diff --git a/examples/org.eclipse.statet.rj.servi.rcpdemo2/plugin_customization.ini b/examples/org.eclipse.statet.rj.servi.rcpdemo2/plugin_customization.ini
new file mode 100644
index 0000000..61d5abf
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.rcpdemo2/plugin_customization.ini
@@ -0,0 +1 @@
+org.eclipse.ui/SHOW_PROGRESS_ON_STARTUP= true
diff --git a/examples/org.eclipse.statet.rj.servi.rcpdemo2/splash.bmp b/examples/org.eclipse.statet.rj.servi.rcpdemo2/splash.bmp
new file mode 100644
index 0000000..fbcd619
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.rcpdemo2/splash.bmp
Binary files differ
diff --git a/examples/org.eclipse.statet.rj.servi.rcpdemo2/src/org/eclipse/statet/internal/rj/servi/rcpdemo/Activator.java b/examples/org.eclipse.statet.rj.servi.rcpdemo2/src/org/eclipse/statet/internal/rj/servi/rcpdemo/Activator.java
new file mode 100644
index 0000000..941c0b4
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.rcpdemo2/src/org/eclipse/statet/internal/rj/servi/rcpdemo/Activator.java
@@ -0,0 +1,96 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.internal.rj.servi.rcpdemo;
+
+import org.osgi.framework.BundleContext;
+
+import org.eclipse.ui.plugin.AbstractUIPlugin;
+
+import org.eclipse.statet.jcommons.lang.Disposable;
+
+import org.eclipse.statet.rj.eclient.graphics.comclient.ERGraphicFactory;
+import org.eclipse.statet.rj.servi.rcpdemo.RServiManager;
+
+
+/**
+ * The activator class controls the plug-in life cycle
+ */
+public class Activator extends AbstractUIPlugin {
+	
+	
+	public static final String BUNDLE_ID= "org.eclipse.statet.rj.servi.rcpdemo2";
+	
+	
+	private static Activator instance;
+	
+	/**
+	 * Returns the shared plug-in instance
+	 *
+	 * @return the shared instance
+	 */
+	public static Activator getInstance() {
+		return instance;
+	}
+	
+	
+	private RServiManager rserviManager;
+	
+	private ERGraphicFactory graphicFactory;
+	
+	
+	/**
+	 * The constructor
+	 */
+	public Activator() {
+	}
+	
+	
+	@Override
+	public void start(final BundleContext context) throws Exception {
+		super.start(context);
+		instance= this;
+	}
+	
+	@Override
+	public void stop(final BundleContext context) throws Exception {
+		Disposable disposable;
+		synchronized (this) {
+			disposable= this.rserviManager;
+			this.rserviManager= null;
+		}
+		if (disposable != null) {
+			disposable.dispose();
+		}
+		
+		instance= null;
+		super.stop(context);
+	}
+	
+	
+	public synchronized RServiManager getRServiManager() {
+		if (this.rserviManager == null) {
+			this.rserviManager= new RServiManager("RCPDemo", getRGraphicFactory());
+		}
+		return this.rserviManager;
+	}
+	
+	public synchronized ERGraphicFactory getRGraphicFactory() {
+		if (this.graphicFactory == null) {
+			this.graphicFactory= new ERGraphicFactory();
+		}
+		return this.graphicFactory;
+	}
+	
+}
diff --git a/examples/org.eclipse.statet.rj.servi.rcpdemo2/src/org/eclipse/statet/internal/rj/servi/rcpdemo/Application.java b/examples/org.eclipse.statet.rj.servi.rcpdemo2/src/org/eclipse/statet/internal/rj/servi/rcpdemo/Application.java
new file mode 100644
index 0000000..f599e90
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.rcpdemo2/src/org/eclipse/statet/internal/rj/servi/rcpdemo/Application.java
@@ -0,0 +1,67 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.internal.rj.servi.rcpdemo;
+
+import org.eclipse.equinox.app.IApplication;
+import org.eclipse.equinox.app.IApplicationContext;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.PlatformUI;
+
+
+/**
+ * This class controls all aspects of the application's execution
+ */
+public class Application implements IApplication {
+	
+	
+	public Application() {
+	}
+	
+	
+	@Override
+	public Object start(final IApplicationContext context) throws Exception {
+		final Display display= PlatformUI.createDisplay();
+		try {
+			final int returnCode= PlatformUI.createAndRunWorkbench(display, new ApplicationWorkbenchAdvisor());
+			if (returnCode == PlatformUI.RETURN_RESTART) {
+				return IApplication.EXIT_RESTART;
+			} else {
+				return IApplication.EXIT_OK;
+			}
+		}
+		finally {
+			display.dispose();
+		}
+	}
+	
+	@Override
+	public void stop() {
+		final IWorkbench workbench= PlatformUI.getWorkbench();
+		if (workbench == null) {
+			return;
+		}
+		final Display display= workbench.getDisplay();
+		display.syncExec(new Runnable() {
+			@Override
+			public void run() {
+				if (!display.isDisposed()) {
+					workbench.close();
+				}
+			}
+		});
+	}
+	
+}
diff --git a/examples/org.eclipse.statet.rj.servi.rcpdemo2/src/org/eclipse/statet/internal/rj/servi/rcpdemo/ApplicationActionBarAdvisor.java b/examples/org.eclipse.statet.rj.servi.rcpdemo2/src/org/eclipse/statet/internal/rj/servi/rcpdemo/ApplicationActionBarAdvisor.java
new file mode 100644
index 0000000..7dc61c3
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.rcpdemo2/src/org/eclipse/statet/internal/rj/servi/rcpdemo/ApplicationActionBarAdvisor.java
@@ -0,0 +1,34 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.internal.rj.servi.rcpdemo;
+
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.application.ActionBarAdvisor;
+import org.eclipse.ui.application.IActionBarConfigurer;
+
+
+public class ApplicationActionBarAdvisor extends ActionBarAdvisor {
+	
+	
+	public ApplicationActionBarAdvisor(final IActionBarConfigurer configurer) {
+		super(configurer);
+	}
+	
+	
+	@Override
+	protected void makeActions(final IWorkbenchWindow window) {
+	}
+	
+}
diff --git a/examples/org.eclipse.statet.rj.servi.rcpdemo2/src/org/eclipse/statet/internal/rj/servi/rcpdemo/ApplicationWorkbenchAdvisor.java b/examples/org.eclipse.statet.rj.servi.rcpdemo2/src/org/eclipse/statet/internal/rj/servi/rcpdemo/ApplicationWorkbenchAdvisor.java
new file mode 100644
index 0000000..a82f86a
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.rcpdemo2/src/org/eclipse/statet/internal/rj/servi/rcpdemo/ApplicationWorkbenchAdvisor.java
@@ -0,0 +1,36 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.internal.rj.servi.rcpdemo;
+
+import org.eclipse.ui.application.IWorkbenchWindowConfigurer;
+import org.eclipse.ui.application.WorkbenchAdvisor;
+import org.eclipse.ui.application.WorkbenchWindowAdvisor;
+
+public class ApplicationWorkbenchAdvisor extends WorkbenchAdvisor {
+	
+	private static final String PERSPECTIVE_ID= "org.eclipse.statet.rj.servi.rcpdemo.perspective";
+	
+	
+	@Override
+	public WorkbenchWindowAdvisor createWorkbenchWindowAdvisor(final IWorkbenchWindowConfigurer configurer) {
+		return new ApplicationWorkbenchWindowAdvisor(configurer);
+	}
+	
+	@Override
+	public String getInitialWindowPerspectiveId() {
+		return PERSPECTIVE_ID;
+	}
+	
+}
diff --git a/examples/org.eclipse.statet.rj.servi.rcpdemo2/src/org/eclipse/statet/internal/rj/servi/rcpdemo/ApplicationWorkbenchWindowAdvisor.java b/examples/org.eclipse.statet.rj.servi.rcpdemo2/src/org/eclipse/statet/internal/rj/servi/rcpdemo/ApplicationWorkbenchWindowAdvisor.java
new file mode 100644
index 0000000..74507c6
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.rcpdemo2/src/org/eclipse/statet/internal/rj/servi/rcpdemo/ApplicationWorkbenchWindowAdvisor.java
@@ -0,0 +1,46 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.internal.rj.servi.rcpdemo;
+
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.ui.application.ActionBarAdvisor;
+import org.eclipse.ui.application.IActionBarConfigurer;
+import org.eclipse.ui.application.IWorkbenchWindowConfigurer;
+import org.eclipse.ui.application.WorkbenchWindowAdvisor;
+
+
+public class ApplicationWorkbenchWindowAdvisor extends WorkbenchWindowAdvisor {
+	
+	
+	public ApplicationWorkbenchWindowAdvisor(final IWorkbenchWindowConfigurer configurer) {
+		super(configurer);
+	}
+	
+	
+	@Override
+	public ActionBarAdvisor createActionBarAdvisor(final IActionBarConfigurer configurer) {
+		return new ApplicationActionBarAdvisor(configurer);
+	}
+	
+	@Override
+	public void preWindowOpen() {
+		final IWorkbenchWindowConfigurer configurer= getWindowConfigurer();
+		configurer.setInitialSize(new Point(760, 600));
+		configurer.setShowCoolBar(false);
+		configurer.setShowStatusLine(true);
+		configurer.setShowProgressIndicator(true);
+	}
+	
+}
diff --git a/examples/org.eclipse.statet.rj.servi.rcpdemo2/src/org/eclipse/statet/internal/rj/servi/rcpdemo/Perspective.java b/examples/org.eclipse.statet.rj.servi.rcpdemo2/src/org/eclipse/statet/internal/rj/servi/rcpdemo/Perspective.java
new file mode 100644
index 0000000..39e2966
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.rcpdemo2/src/org/eclipse/statet/internal/rj/servi/rcpdemo/Perspective.java
@@ -0,0 +1,33 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.internal.rj.servi.rcpdemo;
+
+import org.eclipse.ui.IPageLayout;
+import org.eclipse.ui.IPerspectiveFactory;
+
+
+public class Perspective implements IPerspectiveFactory {
+	
+	
+	public Perspective() {
+	}
+	
+	
+	@Override
+	public void createInitialLayout(final IPageLayout layout) {
+		layout.setEditorAreaVisible(false);
+	}
+	
+}
diff --git a/examples/org.eclipse.statet.rj.servi.rcpdemo2/src/org/eclipse/statet/internal/rj/servi/rcpdemo/views/GraphDemoView.java b/examples/org.eclipse.statet.rj.servi.rcpdemo2/src/org/eclipse/statet/internal/rj/servi/rcpdemo/views/GraphDemoView.java
new file mode 100644
index 0000000..e268ed6
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.rcpdemo2/src/org/eclipse/statet/internal/rj/servi/rcpdemo/views/GraphDemoView.java
@@ -0,0 +1,188 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.internal.rj.servi.rcpdemo.views;
+
+import static org.eclipse.statet.rj.eclient.graphics.RGraphicCompositeActionSet.CONTEXT_MENU_GROUP_ID;
+import static org.eclipse.statet.rj.eclient.graphics.RGraphicCompositeActionSet.SIZE_MENU_GROUP_ID;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.jface.action.IToolBarManager;
+import org.eclipse.jface.action.Separator;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.IActionBars;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.part.ViewPart;
+import org.eclipse.ui.services.IServiceLocator;
+
+import org.eclipse.statet.ecommons.ts.core.ToolRunnable;
+
+import org.eclipse.statet.internal.rj.servi.rcpdemo.Activator;
+import org.eclipse.statet.rj.eclient.core.AbstractRToolRunnable;
+import org.eclipse.statet.rj.eclient.core.RToolService;
+import org.eclipse.statet.rj.eclient.graphics.ERGraphic;
+import org.eclipse.statet.rj.eclient.graphics.RGraphicComposite;
+import org.eclipse.statet.rj.eclient.graphics.RGraphicCompositeActionSet;
+import org.eclipse.statet.rj.graphic.core.RGraphic;
+import org.eclipse.statet.rj.services.RGraphicCreator;
+
+
+/** 
+ * View for R plots using RJ graphic device (rj.gd) and SWT rendering.
+ * 
+ * Note: All field access occur in display thread.
+ */
+public class GraphDemoView extends ViewPart {
+	
+	
+	public static final String VIEW_ID= "org.eclipse.statet.rj.servi.rcpdemo.views.GraphDemo";
+	
+	
+	private Text commandControl;
+	
+	private RGraphicComposite imageControl;
+	
+	private ERGraphic currentPlot;
+	
+	private RGraphicCompositeActionSet actionSet;
+	
+	
+	public GraphDemoView() {
+	}
+	
+	
+	@Override
+	public void createPartControl(final Composite parent) {
+		final Composite composite= new Composite(parent, SWT.NONE);
+		composite.setLayout(new GridLayout(3, false));
+		
+		final Label label= new Label(composite, SWT.LEFT);
+		label.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false));
+		label.setText("Graphic &command:");
+		
+		this.commandControl= new Text(composite, SWT.BORDER);
+		this.commandControl.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+		
+		final Button button= new Button(composite, SWT.PUSH);
+		button.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false));
+		button.setText("Run");
+		button.addSelectionListener(new SelectionAdapter() {
+			@Override
+			public void widgetSelected(final SelectionEvent e) {
+				run();
+			}
+		});
+		
+		this.commandControl.setText("hist(rnorm(1e+07))");
+		
+		this.imageControl= new RGraphicComposite(composite, null);
+		this.imageControl.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 3, 1));
+		
+		initActions(getViewSite());
+		contributeToActionsBars(getViewSite(), getViewSite().getActionBars());
+	}
+	
+	protected void initActions(final IServiceLocator serviceLocator) {
+		this.actionSet= new RGraphicCompositeActionSet(this.imageControl) {
+			@Override
+			public void contributeToActionsBars(final IServiceLocator serviceLocator, final IActionBars actionBars) {
+				super.contributeToActionsBars(serviceLocator, actionBars);
+				
+				addSizeActions(serviceLocator, actionBars);
+				addTestLocator(serviceLocator, actionBars);
+			}
+		};
+		this.actionSet.initActions(serviceLocator);
+	}
+	
+	protected void contributeToActionsBars(final IServiceLocator serviceLocator,
+			final IActionBars actionBars) {
+		final IToolBarManager toolBar= actionBars.getToolBarManager();
+		toolBar.add(new Separator("additions"));
+		toolBar.insertBefore("additions", new Separator(CONTEXT_MENU_GROUP_ID));
+		toolBar.insertBefore("additions", new Separator(SIZE_MENU_GROUP_ID));
+		
+		this.actionSet.contributeToActionsBars(serviceLocator, actionBars);
+	}
+	
+	protected void setGraphic(final ERGraphic graphic) {
+		this.imageControl.setGraphic(graphic);
+		this.actionSet.setGraphic(graphic);
+		
+		if (this.currentPlot != null) {
+			this.currentPlot.close();
+			this.currentPlot= null;
+		}
+		this.currentPlot= graphic;
+	}
+	
+	@Override
+	public void dispose() {
+		super.dispose();
+		if (this.currentPlot != null) {
+			this.currentPlot.close();
+			this.currentPlot= null;
+		}
+	}
+	
+	@Override
+	public void setFocus() {
+		this.commandControl.setFocus();
+	}
+	
+	private void run() {
+		final Point size= this.imageControl.getSize();
+		final String command= this.commandControl.getText();
+		final ToolRunnable job= new AbstractRToolRunnable("r/demo/graphic", "Graphic Demo") {
+			@Override
+			protected void run(final RToolService r,
+					final IProgressMonitor monitor) throws CoreException {
+				monitor.beginTask("Creating graphic in R...", 100);
+				
+				final RGraphicCreator rGraphicCreator= r.createRGraphicCreator(0);
+				rGraphicCreator.setSize(size.x, size.y);
+				final RGraphic plot= rGraphicCreator.create(command, monitor);
+				
+				monitor.worked(90);
+				
+				if (plot instanceof ERGraphic) {
+					final ERGraphic erPlot= (ERGraphic) plot;
+					PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() {
+						@Override
+						public void run() {
+							if (GraphDemoView.this.imageControl.isDisposed()) {
+								erPlot.close();
+								return;
+							}
+							setGraphic(erPlot);
+						}
+					});
+				}
+				return;
+			}
+		};
+		Activator.getInstance().getRServiManager().scheduleDemo(job);
+	}
+	
+}
diff --git a/examples/org.eclipse.statet.rj.servi.rcpdemo2/src/org/eclipse/statet/internal/rj/servi/rcpdemo/views/RServiConfigView.java b/examples/org.eclipse.statet.rj.servi.rcpdemo2/src/org/eclipse/statet/internal/rj/servi/rcpdemo/views/RServiConfigView.java
new file mode 100644
index 0000000..4f61d7d
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.rcpdemo2/src/org/eclipse/statet/internal/rj/servi/rcpdemo/views/RServiConfigView.java
@@ -0,0 +1,154 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.internal.rj.servi.rcpdemo.views;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.DirectoryDialog;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.part.ViewPart;
+import org.eclipse.ui.statushandlers.StatusManager;
+
+import org.eclipse.statet.internal.rj.servi.rcpdemo.Activator;
+import org.eclipse.statet.rj.servi.rcpdemo.RServiManager;
+
+
+public class RServiConfigView extends ViewPart {
+	
+	
+	public static final String VIEW_ID= "org.eclipse.statet.rj.servi.rcpdemo.views.RServiConfig";
+	
+	
+	private Button remoteSelectControl;
+	private Text remoteAddressControl;
+	private Button localSelectControl;
+	private Text localRhomeControl;
+	private Button rsetupSelectControl;
+	private Text rsetupIdControl;
+	
+	
+	public RServiConfigView() {
+	}
+	
+	
+	@Override
+	public void createPartControl(final Composite parent) {
+		final Composite composite= new Composite(parent, SWT.NONE);
+		composite.setLayout(new GridLayout());
+		
+		this.remoteSelectControl= new Button(composite, SWT.RADIO);
+		this.remoteSelectControl.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+		this.remoteSelectControl.setText("Remote/Pool - RMI pool address:");
+		
+		{	this.remoteAddressControl= new Text(composite, SWT.BORDER);
+			final GridData gd= new GridData(SWT.FILL, SWT.CENTER, true, false);
+			gd.horizontalIndent= 10; 
+			this.remoteAddressControl.setLayoutData(gd);
+		}
+		
+		this.localSelectControl= new Button(composite, SWT.RADIO);
+		this.localSelectControl.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+		this.localSelectControl.setText("Local - R_HOME:");
+		
+		{	this.localRhomeControl= new Text(composite, SWT.BORDER);
+			final GridData gd= new GridData(SWT.FILL, SWT.CENTER, true, false);
+			gd.horizontalIndent= 10; 
+			this.localRhomeControl.setLayoutData(gd);
+		}
+		
+		{	final Button button= new Button(composite, SWT.PUSH);
+			button.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+			button.setText("Select...");
+			button.addSelectionListener(new SelectionAdapter() {
+				@Override
+				public void widgetSelected(final SelectionEvent e) {
+					final DirectoryDialog dialog= new DirectoryDialog(button.getShell());
+					dialog.setMessage("Select R_HOME directory:");
+					final String path= dialog.open();
+					if (path != null) {
+						RServiConfigView.this.localRhomeControl.setText(path);
+					}
+				}
+			});
+		}
+		
+		this.rsetupSelectControl= new Button(composite, SWT.RADIO);
+		this.rsetupSelectControl.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+		this.rsetupSelectControl.setText("Supplied R Setup - Id:");
+		
+		{	this.rsetupIdControl= new Text(composite, SWT.BORDER);
+			final GridData gd= new GridData(SWT.FILL, SWT.CENTER, true, false);
+			gd.horizontalIndent= 10; 
+			this.rsetupIdControl.setLayoutData(gd);
+		}
+		
+		final Label label= new Label(composite, SWT.NONE);
+		label.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
+		
+		final Button applyControl= new Button(composite, SWT.PUSH);
+		applyControl.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+		applyControl.setText("Apply");
+		applyControl.addSelectionListener(new SelectionAdapter() {
+			@Override
+			public void widgetSelected(final SelectionEvent e) {
+				applyConfig();
+			}
+		});
+		
+		this.remoteSelectControl.setSelection(true);
+		this.remoteAddressControl.setText("rmi://localhost/rservi-pool");
+		final String rhome= System.getenv("R_HOME");
+		this.localRhomeControl.setText((rhome != null) ? rhome : "");
+		this.rsetupIdControl.setText("org.rproject.r.DefaultSetup");
+	}
+	
+	@Override
+	public void setFocus() {
+	}
+	
+	private void applyConfig() {
+		try {
+			final RServiManager manager= Activator.getInstance().getRServiManager();
+			if (this.remoteSelectControl.getSelection()) {
+				manager.setPool(this.remoteAddressControl.getText());
+				return;
+			}
+			if (this.localSelectControl.getSelection()) {
+				manager.setLocalInst(this.localRhomeControl.getText());
+				return;
+			}
+			if (this.rsetupSelectControl.getSelection()) {
+				manager.setRSetup(this.rsetupIdControl.getText());
+				return;
+			}
+		}
+		catch (final CoreException e) {
+			StatusManager.getManager().handle(new Status(IStatus.ERROR, Activator.BUNDLE_ID,
+					"Could not apply RServi configuration.", e),
+					StatusManager.SHOW | StatusManager.LOG);
+		}
+		return;
+	}
+	
+}
diff --git a/examples/org.eclipse.statet.rj.servi.rcpdemo2/src/org/eclipse/statet/rj/servi/rcpdemo/RServiManager.java b/examples/org.eclipse.statet.rj.servi.rcpdemo2/src/org/eclipse/statet/rj/servi/rcpdemo/RServiManager.java
new file mode 100644
index 0000000..f8635ed
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.rcpdemo2/src/org/eclipse/statet/rj/servi/rcpdemo/RServiManager.java
@@ -0,0 +1,278 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.servi.rcpdemo;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.NoSuchElementException;
+
+import javax.security.auth.login.LoginException;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.ui.statushandlers.StatusManager;
+
+import org.eclipse.statet.jcommons.lang.Disposable;
+
+import org.eclipse.statet.ecommons.rmi.core.RMIRegistry;
+import org.eclipse.statet.ecommons.rmi.core.RMIRegistryManager;
+import org.eclipse.statet.ecommons.ts.core.Tool;
+import org.eclipse.statet.ecommons.ts.core.ToolRunnable;
+
+import org.eclipse.statet.internal.rj.servi.rcpdemo.Activator;
+import org.eclipse.statet.rj.RjException;
+import org.eclipse.statet.rj.eclient.graphics.comclient.ERClientGraphicActionsFactory;
+import org.eclipse.statet.rj.rsetups.RSetup;
+import org.eclipse.statet.rj.rsetups.RSetupUtil;
+import org.eclipse.statet.rj.server.RjsComConfig;
+import org.eclipse.statet.rj.server.client.RClientGraphicFactory;
+import org.eclipse.statet.rj.server.osgi.ERJContext;
+import org.eclipse.statet.rj.servi.RServi;
+import org.eclipse.statet.rj.servi.RServiUtil;
+import org.eclipse.statet.rj.servi.node.RServiImpl;
+import org.eclipse.statet.rj.servi.node.RServiNodeConfig;
+import org.eclipse.statet.rj.servi.node.RServiNodeFactory;
+import org.eclipse.statet.rj.servi.node.RServiNodeManager;
+
+
+public class RServiManager implements Disposable {
+	
+	
+	private static final int LOCAL_INST= 1;
+	private static final int LOCAL_RSETUP= 2;
+	private static final int POOL= 3;
+	
+	private static class Config {
+		
+		private int mode;
+		private String address;
+		
+	}
+	
+	
+	private final String name;
+	
+	private Config config= new Config();
+	
+	private RServiNodeManager localR;
+	
+	private RServiSession currentSession;
+	private final List<RServiSession> runningSessions= new ArrayList<>();
+	
+	
+	public RServiManager(final String appId, final RClientGraphicFactory graphicFactory) {
+		this.name= appId;
+		
+		RjsComConfig.setProperty("rj.servi.graphicFactory", graphicFactory);
+		RjsComConfig.setProperty("rj.servi.comClientGraphicActionsFactory",
+				new ERClientGraphicActionsFactory() );
+	}
+	
+	
+	public void setLocalInst(final String rHome) throws CoreException {
+		closeRServiSession();
+		
+		final Config config= new Config();
+		config.mode= LOCAL_INST;
+		config.address= rHome;
+		this.config= config;
+		
+		final RServiNodeConfig rConfig= new RServiNodeConfig();
+		rConfig.setRHome(rHome);
+		rConfig.setEnableVerbose(true);
+		
+		startLocal(rConfig);
+	}
+	
+	public void setRSetup(final String setupId) throws CoreException {
+		closeRServiSession();
+		
+		final Config config= new Config();
+		config.mode= LOCAL_RSETUP;
+		config.address= setupId;
+		this.config= config;
+		
+		final RSetup setup= RSetupUtil.loadSetup(setupId, null);
+		if (setup == null) {
+			throw new CoreException(new Status(IStatus.ERROR, Activator.BUNDLE_ID, "No R setup with specified id found."));
+		}
+		
+		final RServiNodeConfig rConfig= new RServiNodeConfig();
+		rConfig.setRHome(setup.getRHome());
+		setLibs(setup.getRLibsSite(), rConfig, "R_LIBS_SITE");
+		setLibs(setup.getRLibs(), rConfig, "R_LIBS");
+		setLibs(setup.getRLibsUser(), rConfig, "R_LIBS_USER");
+		rConfig.setEnableVerbose(true);
+		
+		startLocal(rConfig);
+	}
+	
+	public void setPool(final String poolAddress) {
+		closeRServiSession();
+		
+		final Config config= new Config();
+		config.mode= POOL;
+		config.address= poolAddress;
+		this.config= config;
+	}
+	
+	
+	private void setLibs(final List<String> locations, final RServiNodeConfig rConfig, final String varName) {
+		if (locations != null && locations.size() > 0) {
+			final StringBuilder sb= new StringBuilder(locations.get(0));
+			for (int i= 0; i < locations.size(); i++) {
+				sb.append(File.pathSeparatorChar);
+				sb.append(locations.get(i));
+			}
+			rConfig.getEnvironmentVariables().put(varName, sb.toString());
+		}
+	}
+	
+	private void startLocal(final RServiNodeConfig rConfig) throws CoreException {
+		startLocal(rConfig, new NullProgressMonitor()); // TODO real monitor, e.g. in a Job
+	}
+	
+	private void startLocal(final RServiNodeConfig rConfig,
+			final IProgressMonitor monitor) throws CoreException {
+		if (rConfig == null) {
+			throw new NullPointerException("rConfig");
+		}
+		if (monitor == null) {
+			throw new NullPointerException("monitor");
+		}
+		try {
+			final ERJContext context= new ERJContext();
+			if (System.getSecurityManager() == null) {
+				if (System.getProperty("java.security.policy") == null) {
+					final String policyFile= context.getServerPolicyFilePath();
+					System.setProperty("java.security.policy", policyFile);
+				}
+				System.setSecurityManager(new SecurityManager());
+			}
+			
+			final RMIRegistry registry= RMIRegistryManager.INSTANCE.getEmbeddedPrivateRegistry(monitor);
+			
+			final RServiNodeFactory nodeFactory= RServiImpl.createLocalNodeFactory(this.name, context);
+			nodeFactory.setRegistry(registry);
+			nodeFactory.setConfig(rConfig);
+			
+			final RServiNodeManager newLocalR= RServiImpl.createNodeManager(this.name, registry, nodeFactory);
+			newLocalR.start();
+			if (this.localR != null) {
+				this.localR.stop();
+				this.localR= null;
+			}
+			this.localR= newLocalR;
+		}
+		catch (final RjException e) {
+			throw new CoreException(new Status(IStatus.ERROR, Activator.BUNDLE_ID, "Local R instance could not created.", e));
+		}
+	}
+	
+	
+	public synchronized Tool getRServiSession() throws CoreException {
+		if (this.currentSession == null) {
+			final RServi servi= getRServi("session");
+			this.currentSession= new RServiSession(servi) {
+				@Override
+				protected void terminated() {
+					synchronized (RServiManager.this.runningSessions) {
+						RServiManager.this.runningSessions.remove(this);
+					}
+				}
+			};
+			synchronized (this.runningSessions) {
+				this.runningSessions.add(this.currentSession);
+			}
+		}
+		return this.currentSession;
+	}
+	
+	private void closeRServiSession() {
+		if (this.currentSession != null) {
+			this.currentSession.close(false);
+			this.currentSession= null;
+		}
+	}
+	
+	
+	public void schedule(final ToolRunnable runnable) throws CoreException {
+		final Tool session= getRServiSession();
+		final IStatus status;
+		if (session != null) {
+			status= session.getQueue().add(runnable);
+		}
+		else {
+			status= new Status(IStatus.ERROR, Activator.BUNDLE_ID,
+					"R engine not available.");
+		}
+		if (!status.isOK()) {
+			throw new CoreException(status);
+		}
+	}
+	
+	public void scheduleDemo(final ToolRunnable runnable) {
+		try {
+			schedule(runnable);
+		}
+		catch (final CoreException e) {
+			final Status status= new Status(e.getStatus().getSeverity(), Activator.BUNDLE_ID,
+					"Cannot schedule '" + runnable.getLabel() + "'", e);
+			StatusManager.getManager().handle(status, StatusManager.SHOW | StatusManager.LOG);
+		}
+	}
+	
+	@Override
+	public void dispose() {
+		this.config= new Config();
+		final RServiSession[] sessions;
+		synchronized (this.runningSessions) {
+			sessions= this.runningSessions.toArray(new RServiSession[this.runningSessions.size()]);
+		}
+		for (final RServiSession session : sessions) {
+			session.close(true);
+		}
+	}
+	
+	private RServi getRServi(final String task) throws CoreException {
+		final Config config= this.config;
+		final String key= this.name + "-" + task;
+		
+		try {
+			switch (config.mode) {
+			case LOCAL_INST:
+			case LOCAL_RSETUP:
+				return RServiUtil.getRServi(this.localR, key);
+			case POOL:
+				return RServiUtil.getRServi(config.address, key);
+			}
+		}
+		catch (final CoreException e) {
+			throw new CoreException(new Status(IStatus.ERROR, Activator.BUNDLE_ID, "R not available, please check the configuration.", e));
+		}
+		catch (final LoginException e) {
+			throw new CoreException(new Status(IStatus.ERROR, Activator.BUNDLE_ID, "R not available, please check the configuration.", e));
+		}
+		catch (final NoSuchElementException e) {
+			throw new CoreException(new Status(IStatus.INFO, Activator.BUNDLE_ID, "R currently not available, please try again later.", e));
+		}
+		throw new CoreException(new Status(IStatus.ERROR, Activator.BUNDLE_ID, "R is not configured, please check the configuration."));
+	}
+	
+}
diff --git a/examples/org.eclipse.statet.rj.servi.rcpdemo2/src/org/eclipse/statet/rj/servi/rcpdemo/RServiSession.java b/examples/org.eclipse.statet.rj.servi.rcpdemo2/src/org/eclipse/statet/rj/servi/rcpdemo/RServiSession.java
new file mode 100644
index 0000000..f964e2b
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.rcpdemo2/src/org/eclipse/statet/rj/servi/rcpdemo/RServiSession.java
@@ -0,0 +1,421 @@
+/*=============================================================================#
+ # Copyright (c) 2011, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.servi.rcpdemo;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.PlatformObject;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.jobs.IJobChangeEvent;
+import org.eclipse.core.runtime.jobs.IJobChangeListener;
+import org.eclipse.core.runtime.jobs.ISchedulingRule;
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.ui.statushandlers.StatusManager;
+
+import org.eclipse.statet.ecommons.ts.core.SystemRunnable;
+import org.eclipse.statet.ecommons.ts.core.Tool;
+import org.eclipse.statet.ecommons.ts.core.ToolQueue;
+import org.eclipse.statet.ecommons.ts.core.ToolRunnable;
+import org.eclipse.statet.ecommons.ts.core.ToolService;
+
+import org.eclipse.statet.internal.rj.servi.RServiImpl;
+import org.eclipse.statet.internal.rj.servi.rcpdemo.Activator;
+import org.eclipse.statet.rj.data.RObject;
+import org.eclipse.statet.rj.data.RReference;
+import org.eclipse.statet.rj.eclient.core.RToolService;
+import org.eclipse.statet.rj.servi.RServi;
+import org.eclipse.statet.rj.services.FunctionCall;
+import org.eclipse.statet.rj.services.RGraphicCreator;
+import org.eclipse.statet.rj.services.RPlatform;
+import org.eclipse.statet.rj.services.RService;
+
+
+/**
+ * Implementations of ECommons Tool Service and Scheduling interfaces (org.eclipse.statet.ecommons.ts.core) for 
+ * RServi using Eclipse jobs.
+ */
+public class RServiSession extends PlatformObject implements Tool {
+	
+	
+	private class Queue implements ToolQueue {
+		
+		@Override
+		public IStatus add(final ToolRunnable runnable) {
+			synchronized (RServiSession.this.jobs) {
+				if (isTerminated()) {
+					return new Status(IStatus.ERROR, Activator.BUNDLE_ID,
+							"The R session is terminated.");
+				}
+				if (!runnable.changed(ToolRunnable.ADDING_TO, RServiSession.this)) {
+					return Status.CANCEL_STATUS;
+				}
+				final RunnableJob job= new RunnableJob(runnable);
+				RServiSession.this.jobs.add(job);
+				job.addJobChangeListener(RServiSession.this.jobListener);
+				job.schedule();
+				return Status.OK_STATUS;
+			}
+		}
+		
+		@Override
+		public void remove(final ToolRunnable runnable) {
+			RunnableJob removed= null;
+			synchronized (RServiSession.this.jobs) {
+				for (int i= 0; i < RServiSession.this.jobs.size(); i++) {
+					final RunnableJob job= RServiSession.this.jobs.get(i);
+					if (job.runnable == runnable) {
+						if (job.runnable.changed(ToolRunnable.REMOVING_FROM, RServiSession.this)) {
+							removed= job;
+							RServiSession.this.jobs.remove(i);
+							break;
+						}
+						return;
+					}
+				}
+			}
+			if (removed != null) {
+				removed.cancel();
+			}
+		}
+		
+		@Override
+		public boolean isHotSupported() {
+			return false;
+		}
+		
+		@Override
+		public IStatus addHot(final ToolRunnable runnable) {
+			return add(runnable);
+		}
+		
+		@Override
+		public void removeHot(final ToolRunnable runnable) {
+			remove(runnable);
+		}
+		
+	}
+	
+	private class RServiService implements RToolService, RService, ToolService {
+		
+		@Override
+		public Tool getTool() {
+			return RServiSession.this;
+		}
+		
+		@Override
+		public RPlatform getPlatform() {
+			return RServiSession.this.servi.getPlatform();
+		}
+		
+		@Override
+		public void evalVoid(final String expression,
+				final IProgressMonitor monitor) throws CoreException {
+			RServiSession.this.servi.evalVoid(expression, monitor);
+		}
+		
+		@Override
+		public void evalVoid(final String expression, final RObject envir,
+				final IProgressMonitor monitor) throws CoreException {
+			RServiSession.this.servi.evalVoid(expression, envir, monitor);
+		}
+		
+		@Override
+		public RObject evalData(final String expression,
+				final IProgressMonitor monitor) throws CoreException {
+			return RServiSession.this.servi.evalData(expression, monitor);
+		}
+		
+		@Override
+		public RObject evalData(final String expression,
+				final String factoryId, final int options, final int depth,
+				final IProgressMonitor monitor) throws CoreException {
+			return RServiSession.this.servi.evalData(expression, factoryId, options, depth, monitor);
+		}
+		
+		@Override
+		public RObject evalData(final String expression, final RObject envir,
+				final String factoryId, final int options, final int depth,
+				final IProgressMonitor monitor) throws CoreException {
+			return RServiSession.this.servi.evalData(expression, envir, factoryId, options, depth, monitor);
+		}
+		
+		@Override
+		public RObject evalData(final RReference reference,
+				final IProgressMonitor monitor) throws CoreException {
+			return RServiSession.this.servi.evalData(reference, monitor);
+		}
+		
+		@Override
+		public RObject evalData(final RReference reference,
+				final String factoryId, final int options, final int depth,
+				final IProgressMonitor monitor) throws CoreException {
+			return RServiSession.this.servi.evalData(reference, factoryId, options, depth, monitor);
+		}
+		
+		@Override
+		public void assignData(final String expression, final RObject data,
+				final IProgressMonitor monitor) throws CoreException {
+			RServiSession.this.servi.assignData(expression, data, monitor);
+		}
+		
+		@Override
+		public void uploadFile(final InputStream in, final long length, final String fileName,
+				final int options, final IProgressMonitor monitor) throws CoreException {
+			RServiSession.this.servi.uploadFile(in, length, fileName, options, monitor);
+		}
+		
+		@Override
+		public void downloadFile(final OutputStream out, final String fileName, final int options,
+				final IProgressMonitor monitor) throws CoreException {
+			RServiSession.this.servi.downloadFile(fileName, options, monitor);
+		}
+		
+		@Override
+		public byte[] downloadFile(final String fileName, final int options,
+				final IProgressMonitor monitor) throws CoreException {
+			return RServiSession.this.servi.downloadFile(fileName, options, monitor);
+		}
+		
+		@Override
+		public FunctionCall createFunctionCall(final String name) throws CoreException {
+			return RServiSession.this.servi.createFunctionCall(name);
+		}
+		
+		@Override
+		public RGraphicCreator createRGraphicCreator(final int options) throws CoreException {
+			return RServiSession.this.servi.createRGraphicCreator(options);
+		}
+		
+	}
+	
+	private class RunnableJob extends Job {
+		
+		private final ToolRunnable runnable;
+		
+		public RunnableJob(final ToolRunnable runnable) {
+			super(runnable.getLabel());
+			this.runnable= runnable;
+			setRule(RServiSession.this.schedulingRule);
+			if (runnable instanceof SystemRunnable) {
+				setSystem(true);
+			}
+		}
+		
+		@Override
+		public boolean belongsTo(final Object family) {
+			return (family == RServiSession.this);
+		}
+		
+		@Override
+		public boolean shouldRun() {
+			synchronized (RServiSession.this.jobs) {
+				return RServiSession.this.jobs.remove(this);
+			}
+		}
+		
+		@Override
+		protected IStatus run(final IProgressMonitor monitor) {
+			try {
+				this.runnable.run(RServiSession.this.service, monitor);
+				this.runnable.changed(ToolRunnable.FINISHING_OK, RServiSession.this);
+				return Status.OK_STATUS;
+			}
+			catch (final CoreException e) {
+				if (e.getStatus() != null && e.getStatus().getSeverity() == IStatus.CANCEL) {
+					this.runnable.changed(ToolRunnable.FINISHING_CANCEL, RServiSession.this);
+					return e.getStatus();
+				}
+				final Status status= new Status(IStatus.ERROR, Activator.BUNDLE_ID,
+						"An error occurred when running " + getName() + ".", e);
+				StatusManager.getManager().handle(status, StatusManager.SHOW | StatusManager.LOG);
+				this.runnable.changed(ToolRunnable.FINISHING_ERROR, RServiSession.this);
+				return status;
+			}
+		}
+		
+	}
+	
+	private class JobListener implements IJobChangeListener {
+		
+		@Override
+		public void aboutToRun(final IJobChangeEvent event) {
+		}
+		
+		@Override
+		public void awake(final IJobChangeEvent event) {
+		}
+		
+		@Override
+		public void done(final IJobChangeEvent event) {
+			if (event.getResult() == Status.CANCEL_STATUS) {
+				synchronized (RServiSession.this.jobs) {
+					if (RServiSession.this.jobs.remove(event.getJob())) {
+						((RunnableJob) event.getJob()).runnable.changed(ToolRunnable.BEING_ABANDONED, RServiSession.this);
+					}
+				}
+			}
+		}
+		
+		@Override
+		public void running(final IJobChangeEvent event) {
+		}
+		
+		@Override
+		public void scheduled(final IJobChangeEvent event) {
+		}
+		
+		@Override
+		public void sleeping(final IJobChangeEvent event) {
+		}
+		
+	}
+	
+	
+	private final Queue queue= new Queue();
+	private final RServiService service= new RServiService();
+	private final String label;
+	
+	private final ISchedulingRule schedulingRule;
+	private int state;
+	private RServi servi;
+	
+	private final List<RunnableJob> jobs= new ArrayList<>();
+	private final IJobChangeListener jobListener= new JobListener();
+	
+	
+	public RServiSession(final RServi servi) {
+		this("R engine", servi, new ISchedulingRule() {
+			@Override
+			public boolean contains(final ISchedulingRule rule) {
+				return (rule == this);
+			}
+			@Override
+			public boolean isConflicting(final ISchedulingRule rule) {
+				return (rule == this);
+			}
+		});
+	}
+	
+	public RServiSession(final String label,
+			final RServi servi, final ISchedulingRule schedulingRule) {
+		this.label= label;
+		this.servi= servi;
+		this.schedulingRule= schedulingRule;
+		
+		doStart();
+	}
+	
+	
+	@Override
+	public String getMainType() {
+		return "R";
+	}
+	
+	@Override
+	public boolean isProvidingFeatureSet(final String featureSetId) {
+		return "org.eclipse.statet.rj.services.RService".equals(featureSetId); //$NON-NLS-1$
+	}
+	
+	@Override
+	public ToolQueue getQueue() {
+		return this.queue;
+	}
+	
+	@Override
+	public boolean isTerminated() {
+		return (this.state < 0);
+	}
+	
+	private void doStart() {
+		if (this.servi != null) {
+			((RServiImpl) this.servi).setRHandle(this);
+			this.state= 1;
+		}
+		else {
+			doTerminate();
+		}
+	}
+	
+	private void doTerminate() {
+		if (this.servi != null) {
+			try {
+				this.servi.close();
+			}
+			catch (final CoreException e) {
+				// TODO Auto-generated catch block
+				e.printStackTrace();
+			}
+			this.servi= null;
+		}
+		if (this.state != -2) {
+			this.state= -2;
+			terminated();
+		}
+	}
+	
+	protected void terminated() {
+	}
+	
+	@Override
+	public String getLabel(final int config) {
+		return this.label;
+	}
+	
+	public void close(final boolean immediately) {
+		synchronized (this.jobs) {
+			if (this.state < 0) {
+				return;
+			}
+			if (immediately) {
+				Job.getJobManager().cancel(this);
+				for (int i= 0; i < this.jobs.size(); i++) {
+					this.jobs.get(i).runnable.changed(ToolRunnable.BEING_ABANDONED, RServiSession.this);
+				}
+				this.jobs.clear();
+			}
+			this.queue.add(new SystemRunnable() {
+				@Override
+				public String getTypeId() {
+					return "r/session/close";
+				}
+				@Override
+				public String getLabel() {
+					return "Close R Session";
+				}
+				@Override
+				public boolean canRunIn(final Tool tool) {
+					return (tool == RServiSession.this);
+				}
+				@Override
+				public boolean changed(final int event, final Tool tool) {
+					return true;
+				}
+				@Override
+				public void run(final ToolService service,
+						final IProgressMonitor monitor) throws CoreException {
+					doTerminate();
+				}
+			});
+			this.state= -1;
+		}
+	}
+	
+}
diff --git a/servi/_build/org.eclipse.statet.rj.servi-devbundle/democlient/startup.bat b/servi/_build/org.eclipse.statet.rj.servi-devbundle/democlient/startup.bat
new file mode 100644
index 0000000..d4fcf7d
--- /dev/null
+++ b/servi/_build/org.eclipse.statet.rj.servi-devbundle/democlient/startup.bat
@@ -0,0 +1 @@
+java -cp "*" org.eclipse.statet.rj.servi.demo.DemoApp

diff --git a/servi/_build/org.eclipse.statet.rj.servi-devbundle/devbundle.xml b/servi/_build/org.eclipse.statet.rj.servi-devbundle/devbundle.xml
new file mode 100644
index 0000000..45ad5b0
--- /dev/null
+++ b/servi/_build/org.eclipse.statet.rj.servi-devbundle/devbundle.xml
@@ -0,0 +1,103 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2"
+		xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+		xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
+	<id>distr</id>
+	
+	<formats>
+		<format>zip</format>
+	</formats>
+	
+	<includeBaseDirectory>false</includeBaseDirectory>
+	<files>
+		<file>
+			<source>info.txt</source>
+		</file>
+	</files>
+	<fileSets>
+		<fileSet>
+			<directory>/</directory>
+			<includes>
+				<include>info.txt</include>
+				<include>democlient/**</include>
+				<include>sprojects/**</include>
+				<include>eprojects/**</include>
+			</includes>
+		</fileSet>
+	</fileSets>
+	
+	<dependencySets>
+		
+		<dependencySet>
+			<outputDirectory>rservi</outputDirectory>
+			<useTransitiveDependencies>false</useTransitiveDependencies>
+			<includes>
+				<include>org.eclipse.statet.rj:org.eclipse.statet.rj.servi.webapp</include>
+			</includes>
+			<unpack>true</unpack>
+		</dependencySet>
+		
+		<dependencySet>
+			<outputDirectory>democlient</outputDirectory>
+			<useTransitiveDependencies>false</useTransitiveDependencies>
+			<includes>
+				<include>org.eclipse.statet.rj:org.eclipse.statet.rj.data</include>
+				<include>org.eclipse.statet.rj:org.eclipse.statet.rj.server</include>
+				<include>org.eclipse.statet.rj:org.eclipse.statet.rj.client</include>
+				<include>org.eclipse.statet.rj:org.eclipse.statet.rj.services.eruntime</include>
+				<include>org.eclipse.statet.rj:org.eclipse.statet.rj.servi</include>
+				<include>org.eclipse.statet.rj:org.eclipse.statet.rj.servi.demo</include>
+				<!-- +SWT ? -->
+			</includes>
+			<outputFileNameMapping>${artifact.artifactId}_${artifact.version}.${artifact.extension}</outputFileNameMapping>
+		</dependencySet>
+		
+		<dependencySet>
+			<outputDirectory>sprojects</outputDirectory>
+			<useTransitiveDependencies>false</useTransitiveDependencies>
+			<includes>
+				<include>org.eclipse.statet.rj:rj-core</include>
+				<include>org.eclipse.statet.rj:rj-client</include>
+				<include>org.eclipse.statet.rj:rj-servi</include>
+				<!-- +SWT ? -->
+			</includes>
+			<unpack>true</unpack>
+			<unpackOptions>
+				<includes>
+					<include>org.eclipse.statet.rj.data/**</include>
+					<include>org.eclipse.statet.rj.server/**</include>
+					<include>org.eclipse.statet.rj.client/**</include>
+					<include>org.eclipse.statet.rj.services.eruntime/**</include>
+					<include>org.eclipse.statet.rj.servi/**</include>
+					<include>org.eclipse.statet.rj.servi.webapp/**</include>
+					<include>org.eclipse.statet.rj.servi.demo/**</include>
+				</includes>
+			</unpackOptions>
+		</dependencySet>
+		
+		<dependencySet>
+			<outputDirectory>eprojects</outputDirectory>
+			<useTransitiveDependencies>false</useTransitiveDependencies>
+			<includes>
+				<include>org.eclipse.statet.rj:rj-servi</include>
+			</includes>
+			<unpack>true</unpack>
+			<unpackOptions>
+				<includes>
+					<include>org.eclipse.statet.rj.servi.rcpdemo/**</include>
+					<include>org.eclipse.statet.rj.servi.rcpdemo2/**</include>
+				</includes>
+			</unpackOptions>
+		</dependencySet>
+		<dependencySet>
+			<outputDirectory>eprojects/org.eclipse.statet.rj.devbundle/libs</outputDirectory>
+			<useTransitiveDependencies>false</useTransitiveDependencies>
+			<includes>
+				<include>org.eclipse.statet.rj-packaging:org.eclipse.statet.rj.servi-repo</include>
+			</includes>
+			<unpack>true</unpack>
+		</dependencySet>
+		
+	</dependencySets>
+	
+</assembly>
diff --git a/servi/_build/org.eclipse.statet.rj.servi-devbundle/eprojects/org.eclipse.statet.rj.devbundle/.project b/servi/_build/org.eclipse.statet.rj.servi-devbundle/eprojects/org.eclipse.statet.rj.devbundle/.project
new file mode 100644
index 0000000..00cd555
--- /dev/null
+++ b/servi/_build/org.eclipse.statet.rj.servi-devbundle/eprojects/org.eclipse.statet.rj.devbundle/.project
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>org.eclipse.statet.rj.devbundle</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+	</buildSpec>
+	<natures>
+	</natures>
+</projectDescription>
diff --git a/servi/_build/org.eclipse.statet.rj.servi-devbundle/eprojects/org.eclipse.statet.rj.devbundle/rcp-rj.source.target b/servi/_build/org.eclipse.statet.rj.servi-devbundle/eprojects/org.eclipse.statet.rj.devbundle/rcp-rj.source.target
new file mode 100644
index 0000000..184170f
--- /dev/null
+++ b/servi/_build/org.eclipse.statet.rj.servi-devbundle/eprojects/org.eclipse.statet.rj.devbundle/rcp-rj.source.target
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<?pde version="3.6"?>
+
+<target name="Base RCP with RServices (with Sources)">
+	<locations>
+		<location id="org.eclipse.rcp" path="${eclipse_home}" type="Feature"/>
+		<location includeAllPlatforms="false" includeMode="planner" includeConfigurePhase="false"
+				type="InstallableUnit">
+			<repository location="platform:/resource/org.eclipse.statet.rj.devbundle/libs/"/>
+			<unit id="org.eclipse.statet.rj.servi.e.sdk.feature.group" version="0.0.0"/>
+		</location>
+	</locations>
+</target>
diff --git a/servi/_build/org.eclipse.statet.rj.servi-devbundle/eprojects/org.eclipse.statet.rj.devbundle/rcp-rj.target b/servi/_build/org.eclipse.statet.rj.servi-devbundle/eprojects/org.eclipse.statet.rj.devbundle/rcp-rj.target
new file mode 100644
index 0000000..28e6db5
--- /dev/null
+++ b/servi/_build/org.eclipse.statet.rj.servi-devbundle/eprojects/org.eclipse.statet.rj.devbundle/rcp-rj.target
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<?pde version="3.6"?>
+
+<target name="Base RCP with RServices (Binary only)">
+	<locations>
+		<location id="org.eclipse.rcp" path="${eclipse_home}" type="Feature"/>
+		<location includeAllPlatforms="false" includeMode="planner" includeConfigurePhase="false"
+				type="InstallableUnit">
+			<repository location="platform:/resource/org.eclipse.statet.rj.devbundle/libs/"/>
+			<unit id="org.eclipse.statet.rj.servi.e.feature.group" version="0.0.0"/>
+		</location>
+	</locations>
+</target>
diff --git a/servi/_build/org.eclipse.statet.rj.servi-devbundle/info.txt b/servi/_build/org.eclipse.statet.rj.servi-devbundle/info.txt
new file mode 100644
index 0000000..84b367f
--- /dev/null
+++ b/servi/_build/org.eclipse.statet.rj.servi-devbundle/info.txt
@@ -0,0 +1,55 @@
+(RJ) RServi Development Bundle
+
+== Requirement for all RJ setups ==
+
+The R packages 'rj' and 'rj.gd' (for graphics) must be installed in an R library.
+
+
+== Content ==
+
+rservi/
+  (rservi web application)
+  Web application providing an RServi pool configurable via web and or JMX.
+  The pool id is the web context name (so by default rservi).
+  
+  To start the pool using Tomcat:
+   1. Put it into the 'webapps' directory of Tomcat
+   2. Start Tomcat
+   3. Open the configuration interface in a browser:
+          http://localhost:8080/rservi
+  
+  The WEB-INF/lib folder can be used also for the standalone server
+  providing an RServi pool configurable via JMX:
+     java -cp "*" org.eclipse.statet.rj.servi.pool.StandalonePoolServer <id>
+  See also the JavaDoc of org.eclipse.statet.rj.servi.pool.StandalonePoolServer.
+
+democlient/
+  (demo client)
+  Binaries of a small demo client to connect to an RServi pool
+  
+   1. Copy the SWT bundles for your platform into the directory.
+   2. To start the client run:
+          java -cp "*" org.eclipse.statet.rj.servi.demo.DemoApp
+
+sprojects/
+  (source snapshot / webapp+democlient projects)
+  Eclipse projects with all sources of the web application and demo client
+  above
+  
+   1. Import the projects using the import wizard 'Existing projects into
+      Workspace'
+   2. The rj.server project depends on the JRI API. Add the JRI library to the
+      build path, if required.
+  
+  To absolutely exclude all Eclipse dependencies, remove the source folders
+  named 'srcEExtensions' from the build-/class-path.
+
+eprojects/
+  (eclipse rcp projects)
+  Eclipse plug-ins (Osgi bundles) relevant for Eclipse RCP client development
+  and the Eclipse project of the RCP demo application
+  
+   1. Import the projects using the import wizard 'Existing projects into
+      Workspace'
+   2. Load the plug-in target definition 'rcp-rj.source.target' located in the project
+      'org.eclipse.statet.rj' project
diff --git a/servi/_build/org.eclipse.statet.rj.servi-devbundle/pom.xml b/servi/_build/org.eclipse.statet.rj.servi-devbundle/pom.xml
new file mode 100644
index 0000000..7907c9f
--- /dev/null
+++ b/servi/_build/org.eclipse.statet.rj.servi-devbundle/pom.xml
@@ -0,0 +1,122 @@
+<?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>
+	
+	<parent>
+		<groupId>org.eclipse.statet.rj</groupId>
+		<artifactId>rj-servi</artifactId>
+		<version>2.1-SNAPSHOT</version>
+	</parent>
+	
+	<groupId>org.eclipse.statet.rj-packaging</groupId>
+	<artifactId>org.eclipse.statet.rj.servi-devbundle</artifactId>
+	<version>2.1.0-SNAPSHOT</version>
+	<packaging>pom</packaging>
+	
+	<dependencies>
+		<dependency>
+			<groupId>org.eclipse.statet.rj</groupId>
+			<artifactId>rj-core</artifactId>
+			<version>2.1-SNAPSHOT</version>
+			<classifier>module-snapshot</classifier>
+			<type>zip</type>
+		</dependency>
+		<dependency>
+			<groupId>org.eclipse.statet.rj</groupId>
+			<artifactId>rj-client</artifactId>
+			<version>2.1-SNAPSHOT</version>
+			<classifier>module-snapshot</classifier>
+			<type>zip</type>
+		</dependency>
+		<dependency>
+			<groupId>org.eclipse.statet.rj</groupId>
+			<artifactId>rj-servi</artifactId>
+			<version>2.1-SNAPSHOT</version>
+			<classifier>module-snapshot</classifier>
+			<type>zip</type>
+		</dependency>
+		
+		<dependency>
+			<groupId>org.eclipse.statet.rj</groupId>
+			<artifactId>org.eclipse.statet.rj.data</artifactId>
+			<version>2.1.0-SNAPSHOT</version>
+			<type>eclipse-plugin</type>
+		</dependency>
+		<dependency>
+			<groupId>org.eclipse.statet.rj</groupId>
+			<artifactId>org.eclipse.statet.rj.server</artifactId>
+			<version>2.1.0-SNAPSHOT</version>
+			<type>eclipse-plugin</type>
+		</dependency>
+		<dependency>
+			<groupId>org.eclipse.statet.rj</groupId>
+			<artifactId>org.eclipse.statet.rj.client</artifactId>
+			<version>2.1.0-SNAPSHOT</version>
+			<type>eclipse-plugin</type>
+		</dependency>
+		
+		<dependency>
+			<groupId>org.eclipse.statet.rj</groupId>
+			<artifactId>org.eclipse.statet.rj.services.eruntime</artifactId>
+			<version>1.4.0-SNAPSHOT</version>
+		</dependency>
+		<dependency>
+			<groupId>org.eclipse.statet.rj</groupId>
+			<artifactId>org.eclipse.statet.rj.servi</artifactId>
+			<version>2.1.0-SNAPSHOT</version>
+		</dependency>
+		<dependency>
+			<groupId>org.eclipse.statet.rj</groupId>
+			<artifactId>org.eclipse.statet.rj.servi.webapp</artifactId>
+			<version>2.1.0-SNAPSHOT</version>
+			<type>war</type>
+		</dependency>
+		<dependency>
+			<groupId>org.eclipse.statet.rj-packaging</groupId>
+			<artifactId>org.eclipse.statet.rj.servi-repo</artifactId>
+			<version>2.1.0-SNAPSHOT</version>
+			<type>eclipse-repository</type>
+		</dependency>
+		<dependency>
+			<groupId>org.eclipse.statet.rj</groupId>
+			<artifactId>org.eclipse.statet.rj.servi.demo</artifactId>
+			<version>2.1.0-SNAPSHOT</version>
+		</dependency>
+		<dependency>
+			<groupId>org.eclipse.statet.rj</groupId>
+			<artifactId>org.eclipse.statet.rj.servi.rcpdemo</artifactId>
+			<version>2.1.0-SNAPSHOT</version>
+		</dependency>
+		<dependency>
+			<groupId>org.eclipse.statet.rj</groupId>
+			<artifactId>org.eclipse.statet.rj.servi.rcpdemo2</artifactId>
+			<version>2.1.0-SNAPSHOT</version>
+		</dependency>
+	</dependencies>
+	
+	<build>
+		<plugins>
+			<plugin>
+				<artifactId>maven-assembly-plugin</artifactId>
+				<version>2.4</version>
+				<executions>
+					<execution>
+						<id>pack-bundle</id>
+						<phase>package</phase>
+						<goals>
+							<goal>single</goal>
+						</goals>
+						<configuration>
+							<descriptors>
+								<descriptor>devbundle.xml</descriptor>
+							</descriptors>
+						</configuration>
+					</execution>
+				</executions>
+			</plugin>
+		</plugins>
+	</build>
+	
+</project>
diff --git a/servi/_build/org.eclipse.statet.rj.servi.e-feature/.project b/servi/_build/org.eclipse.statet.rj.servi.e-feature/.project
new file mode 100644
index 0000000..a2dff0c
--- /dev/null
+++ b/servi/_build/org.eclipse.statet.rj.servi.e-feature/.project
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>org.eclipse.statet.rj.servi.e-feature</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.pde.FeatureBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.pde.FeatureNature</nature>
+	</natures>
+</projectDescription>
diff --git a/servi/_build/org.eclipse.statet.rj.servi.e-feature/build.properties b/servi/_build/org.eclipse.statet.rj.servi.e-feature/build.properties
new file mode 100644
index 0000000..7f1f3e9
--- /dev/null
+++ b/servi/_build/org.eclipse.statet.rj.servi.e-feature/build.properties
@@ -0,0 +1,2 @@
+bin.includes= feature.xml,\
+               feature.properties
diff --git a/servi/_build/org.eclipse.statet.rj.servi.e-feature/feature.properties b/servi/_build/org.eclipse.statet.rj.servi.e-feature/feature.properties
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/servi/_build/org.eclipse.statet.rj.servi.e-feature/feature.properties
diff --git a/servi/_build/org.eclipse.statet.rj.servi.e-feature/feature.xml b/servi/_build/org.eclipse.statet.rj.servi.e-feature/feature.xml
new file mode 100644
index 0000000..830e991
--- /dev/null
+++ b/servi/_build/org.eclipse.statet.rj.servi.e-feature/feature.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<feature
+      id="org.eclipse.statet.rj.servi.e"
+      version="2.1.0.qualifier"
+      label="StatET RJ - RServi E-Compilation"
+      provider-name="Eclipse.org"
+      license-feature="org.eclipse.license"
+      license-feature-version="1.0.1">
+
+   <description url="https://www.eclipse.org/statet">
+      Compilation for RServi for projects based on the Eclipse Workbench
+   </description>
+
+   <copyright>
+      Copyright (c) 2003, 2017 Stephan Wahlbrink and others. All rights reserved.
+   </copyright>
+
+   <license url="%license_url">
+      %license_text
+   </license>
+
+   <includes
+         id="org.eclipse.statet.rj.core"
+         version="0.0.0"/>
+
+   <includes
+         id="org.eclipse.statet.rj.eclient.core"
+         version="0.0.0"/>
+
+   <plugin
+         id="org.eclipse.statet.rj.servi"
+         download-size="0"
+         install-size="0"
+         version="0.0.0"
+         unpack="false"/>
+
+</feature>
diff --git a/servi/_build/repo/category.xml b/servi/_build/repo/category.xml
new file mode 100644
index 0000000..8f4ba9f
--- /dev/null
+++ b/servi/_build/repo/category.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<site>
+	<category-def name="org.eclipse.statet.libs" label="StatET - Libraries"/>
+	<category-def name="org.eclipse.statet.sources" label="StatET - Sources"/>
+	
+	<feature id="org.eclipse.statet.ecommons.e" version="0.0.0">
+		<category name="org.eclipse.statet.libs"/>
+	</feature>
+	<feature id="org.eclipse.statet.ecommons.e.source" version="0.0.0">
+		<category name="org.eclipse.statet.sources"/>
+	</feature>
+	
+	<feature id="org.eclipse.statet.rj.core" version="0.0.0">
+		<category name="org.eclipse.statet.libs"/>
+	</feature>
+	<feature id="org.eclipse.statet.rj.core.source" version="0.0.0">
+		<category name="org.eclipse.statet.sources"/>
+	</feature>
+	<feature id="org.eclipse.statet.rj.eclient.core" version="0.0.0">
+		<category name="org.eclipse.statet.libs"/>
+	</feature>
+	<feature id="org.eclipse.statet.rj.eclient.core.source" version="0.0.0">
+		<category name="org.eclipse.statet.sources"/>
+	</feature>
+	
+	<feature id="org.eclipse.statet.rj.servi.e" version="0.0.0">
+		<category name="org.eclipse.statet.libs"/>
+	</feature>
+	<feature id="org.eclipse.statet.rj.servi.e.source" version="0.0.0">
+		<category name="org.eclipse.statet.sources"/>
+	</feature>
+	
+</site>
diff --git a/servi/org.eclipse.statet.rj.servi.webapp/.classpath b/servi/org.eclipse.statet.rj.servi.webapp/.classpath
new file mode 100644
index 0000000..168a660
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi.webapp/.classpath
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8">
+		<attributes>
+			<attribute name="owner.project.facets" value="java"/>
+		</attributes>
+	</classpathentry>
+	<classpathentry kind="con" path="org.eclipse.jst.j2ee.internal.web.container"/>
+	<classpathentry kind="con" path="org.eclipse.jst.server.core.container/org.eclipse.jst.server.tomcat.runtimeTarget/tomcat-6">
+		<attributes>
+			<attribute name="owner.project.facets" value="jst.web"/>
+		</attributes>
+	</classpathentry>
+	<classpathentry kind="con" path="org.eclipse.jdt.USER_LIBRARY/jsf-1.2">
+		<attributes>
+			<attribute name="org.eclipse.jst.component.dependency" value="/WEB-INF/lib"/>
+			<attribute name="owner.project.facets" value="jst.jsf"/>
+		</attributes>
+	</classpathentry>
+	<classpathentry kind="con" path="org.eclipse.jdt.USER_LIBRARY/jstl-1.2">
+		<attributes>
+			<attribute name="org.eclipse.jst.component.dependency" value="/WEB-INF/lib"/>
+			<attribute name="owner.project.facets" value="jst.jsf"/>
+		</attributes>
+	</classpathentry>
+	<classpathentry kind="src" path="src"/>
+	<classpathentry combineaccessrules="false" kind="src" path="/org.eclipse.equinox.common"/>
+	<classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/servi/org.eclipse.statet.rj.servi.webapp/.gitignore b/servi/org.eclipse.statet.rj.servi.webapp/.gitignore
new file mode 100644
index 0000000..5e56e04
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi.webapp/.gitignore
@@ -0,0 +1 @@
+/bin
diff --git a/servi/org.eclipse.statet.rj.servi.webapp/.metadata/web/WEB-INF/faces-config.pageflow b/servi/org.eclipse.statet.rj.servi.webapp/.metadata/web/WEB-INF/faces-config.pageflow
new file mode 100644
index 0000000..bee5685
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi.webapp/.metadata/web/WEB-INF/faces-config.pageflow
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>

+<pageflow:Pageflow xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:pageflow="http://www.sybase.com/suade/pageflow" id="pf12465916868870" configfile="/org.eclipse.statet.rj.servi.webapp/web/WEB-INF/faces-config.xml">

+  <nodes xsi:type="pageflow:PFPage" name="conf-pool" x="122" y="178" id="pf12482896383170" referenceLink="//@navigationRule.1/@navigationCase.0/@toViewId|" path="/m/conf-pool.jsp"/>

+  <nodes xsi:type="pageflow:PFPage" name="conf-r" x="122" y="562" id="pf12482896383172" referenceLink="//@navigationRule.2/@navigationCase.0/@toViewId|" path="/m/conf-r.jsp"/>

+  <nodes xsi:type="pageflow:PFPage" name="m/*" x="122" y="946" id="pf12482896383174" referenceLink="//@navigationRule.3/@fromViewId|" path="/m/*"/>

+  <nodes xsi:type="pageflow:PFPage" name="m/status-poolnodes" x="122" y="1330" id="pf12482896383176" referenceLink="//@navigationRule.3/@navigationCase.0/@toViewId|" path="/m/status-poolnodes.jsp"/>

+  <nodes xsi:type="pageflow:PFPage" name="conf-pool" x="122" y="2098" id="pf13632771976130" referenceLink="//@navigationRule.1/@navigationCase.0/@toViewId|" outlinks="pf13632771976131" inlinks="pf13632771976131" path="/resources/conf-pool.jsp"/>

+  <nodes xsi:type="pageflow:PFPage" name="conf-r" x="122" y="2482" id="pf13632771976132" referenceLink="//@navigationRule.2/@navigationCase.0/@toViewId|" outlinks="pf13632771976133" inlinks="pf13632771976133" path="/resources/conf-r.jsp"/>

+  <nodes xsi:type="pageflow:PFPage" name="resources/*" x="122" y="1714" id="pf13632771976134" referenceLink="//@navigationRule.3/@fromViewId|" outlinks="pf13632771976135" path="/resources/*"/>

+  <nodes xsi:type="pageflow:PFPage" name="resources/status-poolnodes" x="338" y="1714" id="pf13632771976136" referenceLink="//@navigationRule.3/@navigationCase.0/@toViewId|" inlinks="pf13632771976135" path="/resources/status-poolnodes.jsp"/>

+  <links id="pf13632771976135" target="pf13632771976136" source="pf13632771976134" outcome="status-pool"/>

+  <links id="pf13632771976131" target="pf13632771976130" source="pf13632771976130" outcome="conf-pool">

+    <bendPoints d1Height="-36" d2Height="-36"/>

+    <bendPoints d1Width="-64" d1Height="-36" d2Width="-64" d2Height="-36"/>

+    <bendPoints d1Width="-64" d2Width="-64"/>

+  </links>

+  <links id="pf13632771976133" target="pf13632771976132" source="pf13632771976132" outcome="conf-r">

+    <bendPoints d1Height="-36" d2Height="-36"/>

+    <bendPoints d1Width="-64" d1Height="-36" d2Width="-64" d2Height="-36"/>

+    <bendPoints d1Width="-64" d2Width="-64"/>

+  </links>

+</pageflow:Pageflow>

diff --git a/servi/org.eclipse.statet.rj.servi.webapp/.project b/servi/org.eclipse.statet.rj.servi.webapp/.project
new file mode 100644
index 0000000..25d9c38
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi.webapp/.project
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>org.eclipse.statet.rj.servi.webapp</name>
+	<comment></comment>
+	<projects>
+		<project>org.eclipse.statet.jcommons.util</project>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.wst.common.project.facet.core.builder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.wst.jsdt.core.javascriptValidator</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.jdt.core.javabuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.wst.validation.validationbuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.jem.workbench.JavaEMFNature</nature>
+		<nature>org.eclipse.wst.common.modulecore.ModuleCoreNature</nature>
+		<nature>org.eclipse.wst.common.project.facet.core.nature</nature>
+		<nature>org.eclipse.jdt.core.javanature</nature>
+		<nature>org.eclipse.wst.jsdt.core.jsNature</nature>
+	</natures>
+</projectDescription>
diff --git a/servi/org.eclipse.statet.rj.servi.webapp/.settings/.jsdtscope b/servi/org.eclipse.statet.rj.servi.webapp/.settings/.jsdtscope
new file mode 100644
index 0000000..bbb8e68
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi.webapp/.settings/.jsdtscope
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+	<classpathentry kind="con" path="org.eclipse.wst.jsdt.launching.JRE_CONTAINER"/>
+	<classpathentry kind="con" path="org.eclipse.wst.jsdt.launching.WebProject">
+		<attributes>
+			<attribute name="hide" value="true"/>
+		</attributes>
+	</classpathentry>
+	<classpathentry kind="con" path="org.eclipse.wst.jsdt.launching.baseBrowserLibrary"/>
+	<classpathentry kind="output" path=""/>
+</classpath>
diff --git a/servi/org.eclipse.statet.rj.servi.webapp/.settings/oracle.eclipse.tools.webtier.ui.prefs b/servi/org.eclipse.statet.rj.servi.webapp/.settings/oracle.eclipse.tools.webtier.ui.prefs
new file mode 100644
index 0000000..9b1426c
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi.webapp/.settings/oracle.eclipse.tools.webtier.ui.prefs
@@ -0,0 +1,20 @@
+#Fri Jul 08 00:02:58 CEST 2011
+//_hiddenCategory_\:http\://java.sun.com/jsf/core=false
+//_hiddenCategory_\:http\://java.sun.com/jsf/html=false
+//_hiddenCategory_\:http\://java.sun.com/jsp/jstl/core=false
+//_hiddenCategory_\:http\://java.sun.com/jsp/jstl/fmt=false
+//_hiddenCategory_\:http\://java.sun.com/jsp/jstl/sql=false
+//_hiddenCategory_\:http\://java.sun.com/jsp/jstl/xml=false
+//_hiddenCategory_\:http\://java.sun.com/jstl/core=false
+//_hiddenCategory_\:http\://java.sun.com/jstl/core_rt=false
+//_hiddenCategory_\:http\://java.sun.com/jstl/fmt=false
+//_hiddenCategory_\:http\://java.sun.com/jstl/fmt_rt=false
+//_hiddenCategory_\:http\://java.sun.com/jstl/sql=false
+//_hiddenCategory_\:http\://java.sun.com/jstl/sql_rt=false
+//_hiddenCategory_\:http\://java.sun.com/jstl/xml=false
+//_hiddenCategory_\:http\://java.sun.com/jstl/xml_rt=false
+//_hiddenCategory_\:http\://mojarra.dev.java.net/mojarra_ext=true
+_hiddenCategory_\:DataPalette=false
+_hiddenCategory_\:HTML=false
+_hiddenCategory_\:JSP11=false
+eclipse.preferences.version=1
diff --git a/servi/org.eclipse.statet.rj.servi.webapp/.settings/org.eclipse.core.resources.prefs b/servi/org.eclipse.statet.rj.servi.webapp/.settings/org.eclipse.core.resources.prefs
new file mode 100644
index 0000000..99f26c0
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi.webapp/.settings/org.eclipse.core.resources.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+encoding/<project>=UTF-8
diff --git a/servi/org.eclipse.statet.rj.servi.webapp/.settings/org.eclipse.core.runtime.prefs b/servi/org.eclipse.statet.rj.servi.webapp/.settings/org.eclipse.core.runtime.prefs
new file mode 100644
index 0000000..5a0ad22
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi.webapp/.settings/org.eclipse.core.runtime.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+line.separator=\n
diff --git a/servi/org.eclipse.statet.rj.servi.webapp/.settings/org.eclipse.jdt.core.prefs b/servi/org.eclipse.statet.rj.servi.webapp/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000..ccb1eaa
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi.webapp/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,325 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.codeComplete.argumentPrefixes=
+org.eclipse.jdt.core.codeComplete.argumentSuffixes=
+org.eclipse.jdt.core.codeComplete.fieldPrefixes=
+org.eclipse.jdt.core.codeComplete.fieldSuffixes=
+org.eclipse.jdt.core.codeComplete.localPrefixes=
+org.eclipse.jdt.core.codeComplete.localSuffixes=
+org.eclipse.jdt.core.codeComplete.staticFieldPrefixes=
+org.eclipse.jdt.core.codeComplete.staticFieldSuffixes=
+org.eclipse.jdt.core.codeComplete.staticFinalFieldPrefixes=
+org.eclipse.jdt.core.codeComplete.staticFinalFieldSuffixes=
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=1.8
+org.eclipse.jdt.core.compiler.debug.lineNumber=generate
+org.eclipse.jdt.core.compiler.debug.localVariable=generate
+org.eclipse.jdt.core.compiler.debug.sourceFile=generate
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.source=1.8
+org.eclipse.jdt.core.formatter.align_fields_grouping_blank_lines=2147483647
+org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_assignment=0
+org.eclipse.jdt.core.formatter.alignment_for_binary_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_compact_if=16
+org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=80
+org.eclipse.jdt.core.formatter.alignment_for_enum_constants=0
+org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16
+org.eclipse.jdt.core.formatter.alignment_for_expressions_in_for_loop_header=0
+org.eclipse.jdt.core.formatter.alignment_for_method_declaration=0
+org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16
+org.eclipse.jdt.core.formatter.alignment_for_parameterized_type_references=0
+org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_resources_in_try=85
+org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=16
+org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_type_arguments=0
+org.eclipse.jdt.core.formatter.alignment_for_type_parameters=0
+org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch=16
+org.eclipse.jdt.core.formatter.blank_lines_after_imports=2
+org.eclipse.jdt.core.formatter.blank_lines_after_package=1
+org.eclipse.jdt.core.formatter.blank_lines_before_field=0
+org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=1
+org.eclipse.jdt.core.formatter.blank_lines_before_imports=1
+org.eclipse.jdt.core.formatter.blank_lines_before_member_type=1
+org.eclipse.jdt.core.formatter.blank_lines_before_method=1
+org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=2
+org.eclipse.jdt.core.formatter.blank_lines_before_package=1
+org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=1
+org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=1
+org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_block=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_lambda_body=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=false
+org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=false
+org.eclipse.jdt.core.formatter.comment.format_block_comments=true
+org.eclipse.jdt.core.formatter.comment.format_header=false
+org.eclipse.jdt.core.formatter.comment.format_html=true
+org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=true
+org.eclipse.jdt.core.formatter.comment.format_line_comments=true
+org.eclipse.jdt.core.formatter.comment.format_source_code=true
+org.eclipse.jdt.core.formatter.comment.indent_parameter_description=false
+org.eclipse.jdt.core.formatter.comment.indent_root_tags=true
+org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert
+org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=do not insert
+org.eclipse.jdt.core.formatter.comment.line_length=100
+org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries=false
+org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries=true
+org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments=false
+org.eclipse.jdt.core.formatter.compact_else_if=true
+org.eclipse.jdt.core.formatter.continuation_indentation=2
+org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=2
+org.eclipse.jdt.core.formatter.disabling_tag=@formatter\:off
+org.eclipse.jdt.core.formatter.enabling_tag=@formatter\:on
+org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false
+org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true
+org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true
+org.eclipse.jdt.core.formatter.indent_empty_lines=true
+org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true
+org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true
+org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true
+org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=false
+org.eclipse.jdt.core.formatter.indentation.size=4
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_enum_constant=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_label=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_type_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert
+org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert
+org.eclipse.jdt.core.formatter.insert_space_after_lambda_arrow=insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources=insert
+org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert
+org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=insert
+org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert
+org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw=insert
+org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.join_lines_in_comments=true
+org.eclipse.jdt.core.formatter.join_wrapped_lines=true
+org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=false
+org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false
+org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=false
+org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false
+org.eclipse.jdt.core.formatter.lineSplit=100
+org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false
+org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=false
+org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0
+org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=1
+org.eclipse.jdt.core.formatter.parentheses_positions_in_annotation=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_catch_clause=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_enum_constant_declaration=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_for_statment=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_if_while_statement=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_lambda_declaration=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_method_delcaration=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_method_invocation=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_switch_statement=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_try_clause=common_lines
+org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=true
+org.eclipse.jdt.core.formatter.tabulation.char=tab
+org.eclipse.jdt.core.formatter.tabulation.size=4
+org.eclipse.jdt.core.formatter.use_on_off_tags=false
+org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false
+org.eclipse.jdt.core.formatter.wrap_before_assignment_operator=false
+org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true
+org.eclipse.jdt.core.formatter.wrap_before_conditional_operator=false
+org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch=true
+org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true
+org.eclipse.jdt.core.javaFormatter=org.eclipse.jdt.core.defaultJavaFormatter
diff --git a/servi/org.eclipse.statet.rj.servi.webapp/.settings/org.eclipse.jdt.ui.prefs b/servi/org.eclipse.statet.rj.servi.webapp/.settings/org.eclipse.jdt.ui.prefs
new file mode 100644
index 0000000..e62a4f5
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi.webapp/.settings/org.eclipse.jdt.ui.prefs
@@ -0,0 +1,131 @@
+cleanup.add_default_serial_version_id=true
+cleanup.add_generated_serial_version_id=false
+cleanup.add_missing_annotations=true
+cleanup.add_missing_deprecated_annotations=true
+cleanup.add_missing_methods=false
+cleanup.add_missing_nls_tags=false
+cleanup.add_missing_override_annotations=true
+cleanup.add_missing_override_annotations_interface_methods=true
+cleanup.add_serial_version_id=false
+cleanup.always_use_blocks=true
+cleanup.always_use_parentheses_in_expressions=true
+cleanup.always_use_this_for_non_static_field_access=true
+cleanup.always_use_this_for_non_static_method_access=false
+cleanup.convert_functional_interfaces=false
+cleanup.convert_to_enhanced_for_loop=false
+cleanup.correct_indentation=false
+cleanup.format_source_code=false
+cleanup.format_source_code_changes_only=false
+cleanup.insert_inferred_type_arguments=false
+cleanup.make_local_variable_final=true
+cleanup.make_parameters_final=true
+cleanup.make_private_fields_final=true
+cleanup.make_type_abstract_if_missing_method=false
+cleanup.make_variable_declarations_final=true
+cleanup.never_use_blocks=false
+cleanup.never_use_parentheses_in_expressions=false
+cleanup.organize_imports=true
+cleanup.qualify_static_field_accesses_with_declaring_class=false
+cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true
+cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=false
+cleanup.qualify_static_member_accesses_with_declaring_class=true
+cleanup.qualify_static_method_accesses_with_declaring_class=false
+cleanup.remove_private_constructors=true
+cleanup.remove_redundant_type_arguments=true
+cleanup.remove_trailing_whitespaces=false
+cleanup.remove_trailing_whitespaces_all=true
+cleanup.remove_trailing_whitespaces_ignore_empty=false
+cleanup.remove_unnecessary_casts=true
+cleanup.remove_unnecessary_nls_tags=true
+cleanup.remove_unused_imports=true
+cleanup.remove_unused_local_variables=false
+cleanup.remove_unused_private_fields=true
+cleanup.remove_unused_private_members=false
+cleanup.remove_unused_private_methods=true
+cleanup.remove_unused_private_types=true
+cleanup.sort_members=false
+cleanup.sort_members_all=false
+cleanup.use_anonymous_class_creation=false
+cleanup.use_blocks=true
+cleanup.use_blocks_only_for_return_and_throw=false
+cleanup.use_lambda=true
+cleanup.use_parentheses_in_expressions=false
+cleanup.use_this_for_non_static_field_access=true
+cleanup.use_this_for_non_static_field_access_only_if_necessary=false
+cleanup.use_this_for_non_static_method_access=true
+cleanup.use_this_for_non_static_method_access_only_if_necessary=true
+cleanup.use_type_arguments=false
+cleanup_profile=_StatET
+cleanup_settings_version=2
+eclipse.preferences.version=1
+editor_save_participant_org.eclipse.jdt.ui.postsavelistener.cleanup=true
+formatter_profile=_StatET
+formatter_settings_version=12
+org.eclipse.jdt.ui.exception.name=e
+org.eclipse.jdt.ui.gettersetter.use.is=true
+org.eclipse.jdt.ui.ignorelowercasenames=true
+org.eclipse.jdt.ui.importorder=\#;java;javax;com.ibm.icu;org.osgi;org.eclipse;;org.eclipse.statet.jcommons;org.eclipse.statet.ecommons;org.eclipse.statet;
+org.eclipse.jdt.ui.javadoc=true
+org.eclipse.jdt.ui.keywordthis=true
+org.eclipse.jdt.ui.ondemandthreshold=99
+org.eclipse.jdt.ui.overrideannotation=true
+org.eclipse.jdt.ui.staticondemandthreshold=99
+org.eclipse.jdt.ui.text.custom_code_templates=<?xml version\="1.0" encoding\="UTF-8" standalone\="no"?><templates><template autoinsert\="true" context\="gettercomment_context" deleted\="false" description\="Comment for getter method" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.gettercomment" name\="gettercomment">/**\n * @return the ${bare_field_name}\n */</template><template autoinsert\="true" context\="settercomment_context" deleted\="false" description\="Comment for setter method" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.settercomment" name\="settercomment">/**\n * @param ${param} the ${bare_field_name} to set\n */</template><template autoinsert\="true" context\="constructorcomment_context" deleted\="false" description\="Comment for created constructors" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.constructorcomment" name\="constructorcomment">/**\n * ${tags}\n */</template><template autoinsert\="false" context\="filecomment_context" deleted\="false" description\="Comment for created Java files" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.filecomment" name\="filecomment">/*\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\#\n \# Copyright (c) ${year} ${user} and others.\n # \n # This program and the accompanying materials are made available under the\n # terms of the Eclipse Public License 2.0 which is available at\n # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n # which is available at https://www.apache.org/licenses/LICENSE-2.0.\n # \n # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n # \n \# Contributors\:\n \#     ${user} - initial API and implementation\n \#\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=*/</template><template autoinsert\="false" context\="typecomment_context" deleted\="false" description\="Comment for created types" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.typecomment" name\="typecomment">/**\n * \n * ${tags}\n */</template><template autoinsert\="true" context\="fieldcomment_context" deleted\="false" description\="Comment for fields" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.fieldcomment" name\="fieldcomment">/**\n * \n */</template><template autoinsert\="true" context\="methodcomment_context" deleted\="false" description\="Comment for non-overriding methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.methodcomment" name\="methodcomment">/**\n * ${tags}\n */</template><template autoinsert\="false" context\="overridecomment_context" deleted\="false" description\="Comment for overriding methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.overridecomment" name\="overridecomment"/><template autoinsert\="true" context\="delegatecomment_context" deleted\="false" description\="Comment for delegate methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.delegatecomment" name\="delegatecomment">/**\n * ${tags}\n * ${see_to_target}\n */</template><template autoinsert\="false" context\="newtype_context" deleted\="false" description\="Newly created files" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.newtype" name\="newtype">${filecomment}\n\n${package_declaration}\n\n${typecomment}\n${type_declaration}</template><template autoinsert\="true" context\="classbody_context" deleted\="false" description\="Code in new class type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.classbody" name\="classbody">\n</template><template autoinsert\="true" context\="interfacebody_context" deleted\="false" description\="Code in new interface type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.interfacebody" name\="interfacebody">\n</template><template autoinsert\="true" context\="enumbody_context" deleted\="false" description\="Code in new enum type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.enumbody" name\="enumbody">\n</template><template autoinsert\="true" context\="annotationbody_context" deleted\="false" description\="Code in new annotation type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.annotationbody" name\="annotationbody">\n</template><template autoinsert\="true" context\="catchblock_context" deleted\="false" description\="Code in new catch blocks" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.catchblock" name\="catchblock">// ${todo} Auto-generated catch block\n${exception_var}.printStackTrace();</template><template autoinsert\="true" context\="methodbody_context" deleted\="false" description\="Code in created method stubs" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.methodbody" name\="methodbody">// ${todo} Auto-generated method stub\n${body_statement}</template><template autoinsert\="true" context\="constructorbody_context" deleted\="false" description\="Code in created constructor stubs" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.constructorbody" name\="constructorbody">${body_statement}\n// ${todo} Auto-generated constructor stub</template><template autoinsert\="true" context\="getterbody_context" deleted\="false" description\="Code in created getters" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.getterbody" name\="getterbody">return ${field};</template><template autoinsert\="true" context\="setterbody_context" deleted\="false" description\="Code in created setters" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.setterbody" name\="setterbody">${field} \= ${param};</template></templates>
+sp_cleanup.add_default_serial_version_id=true
+sp_cleanup.add_generated_serial_version_id=false
+sp_cleanup.add_missing_annotations=true
+sp_cleanup.add_missing_deprecated_annotations=true
+sp_cleanup.add_missing_methods=false
+sp_cleanup.add_missing_nls_tags=false
+sp_cleanup.add_missing_override_annotations=true
+sp_cleanup.add_missing_override_annotations_interface_methods=true
+sp_cleanup.add_serial_version_id=false
+sp_cleanup.always_use_blocks=true
+sp_cleanup.always_use_parentheses_in_expressions=true
+sp_cleanup.always_use_this_for_non_static_field_access=true
+sp_cleanup.always_use_this_for_non_static_method_access=false
+sp_cleanup.convert_functional_interfaces=false
+sp_cleanup.convert_to_enhanced_for_loop=false
+sp_cleanup.correct_indentation=false
+sp_cleanup.format_source_code=false
+sp_cleanup.format_source_code_changes_only=false
+sp_cleanup.insert_inferred_type_arguments=false
+sp_cleanup.make_local_variable_final=true
+sp_cleanup.make_parameters_final=true
+sp_cleanup.make_private_fields_final=true
+sp_cleanup.make_type_abstract_if_missing_method=false
+sp_cleanup.make_variable_declarations_final=false
+sp_cleanup.never_use_blocks=false
+sp_cleanup.never_use_parentheses_in_expressions=false
+sp_cleanup.on_save_use_additional_actions=true
+sp_cleanup.organize_imports=true
+sp_cleanup.qualify_static_field_accesses_with_declaring_class=false
+sp_cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true
+sp_cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=false
+sp_cleanup.qualify_static_member_accesses_with_declaring_class=true
+sp_cleanup.qualify_static_method_accesses_with_declaring_class=false
+sp_cleanup.remove_private_constructors=true
+sp_cleanup.remove_redundant_type_arguments=true
+sp_cleanup.remove_trailing_whitespaces=false
+sp_cleanup.remove_trailing_whitespaces_all=false
+sp_cleanup.remove_trailing_whitespaces_ignore_empty=true
+sp_cleanup.remove_unnecessary_casts=true
+sp_cleanup.remove_unnecessary_nls_tags=false
+sp_cleanup.remove_unused_imports=false
+sp_cleanup.remove_unused_local_variables=false
+sp_cleanup.remove_unused_private_fields=false
+sp_cleanup.remove_unused_private_members=false
+sp_cleanup.remove_unused_private_methods=false
+sp_cleanup.remove_unused_private_types=true
+sp_cleanup.sort_members=false
+sp_cleanup.sort_members_all=false
+sp_cleanup.use_anonymous_class_creation=false
+sp_cleanup.use_blocks=true
+sp_cleanup.use_blocks_only_for_return_and_throw=false
+sp_cleanup.use_lambda=false
+sp_cleanup.use_parentheses_in_expressions=false
+sp_cleanup.use_this_for_non_static_field_access=true
+sp_cleanup.use_this_for_non_static_field_access_only_if_necessary=false
+sp_cleanup.use_this_for_non_static_method_access=true
+sp_cleanup.use_this_for_non_static_method_access_only_if_necessary=true
+sp_cleanup.use_type_arguments=false
diff --git a/servi/org.eclipse.statet.rj.servi.webapp/.settings/org.eclipse.jst.jsp.core.prefs b/servi/org.eclipse.statet.rj.servi.webapp/.settings/org.eclipse.jst.jsp.core.prefs
new file mode 100644
index 0000000..69b0fc5
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi.webapp/.settings/org.eclipse.jst.jsp.core.prefs
@@ -0,0 +1,27 @@
+#Sat Jun 13 18:01:19 CEST 2009
+eclipse.preferences.version=1
+validation.actions-missing-required-attribute=1
+validation.actions-non-empty-inline-tag=2
+validation.actions-unknown-attribute=2
+validation.directive-include-fragment-file-not-found=1
+validation.directive-include-fragment-file-not-specified=1
+validation.directive-taglib-duplicate-prefixes-different-uris=1
+validation.directive-taglib-duplicate-prefixes-same-uris=-1
+validation.directive-taglib-missing-prefix=1
+validation.directive-taglib-missing-uri-or-tagdir=1
+validation.directive-taglib-unresolvable-uri-or-tagdir=1
+validation.el-general-syntax=1
+validation.el-lexical-failure=-1
+validation.java-=-1
+validation.java-local-variable-is-never-used=-1
+validation.java-null-local-variable-reference=-1
+validation.java-potential-null-local-variable-reference=-1
+validation.java-unused-import=-1
+validation.translation-tag-class-not-found=2
+validation.translation-tei-class-not-found=2
+validation.translation-tei-class-not-instantiated=2
+validation.translation-tei-class-runtime-exception=2
+validation.translation-tei-message=1
+validation.translation-usebean-ambiguous-type-info=2
+validation.translation-usebean-invalid-id=1
+validation.translation-usebean-missing-type-info=1
diff --git a/servi/org.eclipse.statet.rj.servi.webapp/.settings/org.eclipse.ltk.core.refactoring.prefs b/servi/org.eclipse.statet.rj.servi.webapp/.settings/org.eclipse.ltk.core.refactoring.prefs
new file mode 100644
index 0000000..cc50da5
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi.webapp/.settings/org.eclipse.ltk.core.refactoring.prefs
@@ -0,0 +1,3 @@
+#Mon Jun 15 10:42:38 CEST 2009
+eclipse.preferences.version=1
+org.eclipse.ltk.core.refactoring.enable.project.refactoring.history=false
diff --git a/servi/org.eclipse.statet.rj.servi.webapp/.settings/org.eclipse.wst.common.component b/servi/org.eclipse.statet.rj.servi.webapp/.settings/org.eclipse.wst.common.component
new file mode 100644
index 0000000..ea03122
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi.webapp/.settings/org.eclipse.wst.common.component
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?><project-modules id="moduleCoreId" project-version="1.5.0">

+    <wb-module deploy-name="org.eclipse.statet.rj.servi.webapp">

+        <wb-resource deploy-path="/" source-path="/web"/>

+        <wb-resource deploy-path="/WEB-INF/classes" source-path="/src"/>

+        <dependent-module archiveName="org.eclipse.statet.ecommons.runtime.core.jar" deploy-path="/WEB-INF/lib" handle="module:/resource/org.eclipse.statet.ecommons.runtime.core/org.eclipse.statet.ecommons.runtime.core">

+            <dependency-type>uses</dependency-type>

+        </dependent-module>

+        <dependent-module archiveName="org.eclipse.statet.ecommons.rmi.core.jar" deploy-path="/WEB-INF/lib" handle="module:/resource/org.eclipse.statet.ecommons.rmi.core/org.eclipse.statet.ecommons.rmi.core">

+            <dependency-type>uses</dependency-type>

+        </dependent-module>

+        <dependent-module archiveName="org.eclipse.statet.rj.servi.jar" deploy-path="/WEB-INF/lib" handle="module:/resource/org.eclipse.statet.rj.servi/org.eclipse.statet.rj.servi">

+            <dependency-type>uses</dependency-type>

+        </dependent-module>

+        <dependent-module archiveName="org.eclipse.statet.rj.client.jar" deploy-path="/WEB-INF/lib" handle="module:/resource/org.eclipse.statet.rj.client/org.eclipse.statet.rj.client">

+            <dependency-type>uses</dependency-type>

+        </dependent-module>

+        <dependent-module archiveName="org.eclipse.statet.rj.services.core.jar" deploy-path="/WEB-INF/lib" handle="module:/resource/org.eclipse.statet.rj.services.core/org.eclipse.statet.rj.services.core">

+            <dependency-type>uses</dependency-type>

+        </dependent-module>

+        <dependent-module archiveName="org.eclipse.statet.rj.data.jar" deploy-path="/WEB-INF/lib" handle="module:/resource/org.eclipse.statet.rj.data/org.eclipse.statet.rj.data">

+            <dependency-type>uses</dependency-type>

+        </dependent-module>

+        <dependent-module archiveName="org.eclipse.statet.rj.server.jar" deploy-path="/WEB-INF/lib" handle="module:/resource/org.eclipse.statet.rj.server/org.eclipse.statet.rj.server">

+            <dependency-type>uses</dependency-type>

+        </dependent-module>

+        <dependent-module archiveName="org.eclipse.statet.jcommons.util.jar" deploy-path="/WEB-INF/lib" handle="module:/resource/org.eclipse.statet.jcommons.util/org.eclipse.statet.jcommons.util">

+            <dependency-type>uses</dependency-type>

+        </dependent-module>

+        <property name="java-output-path"/>

+        <property name="context-root" value="rservi"/>

+    </wb-module>

+</project-modules>

diff --git a/servi/org.eclipse.statet.rj.servi.webapp/.settings/org.eclipse.wst.common.project.facet.core.prefs.xml b/servi/org.eclipse.statet.rj.servi.webapp/.settings/org.eclipse.wst.common.project.facet.core.prefs.xml
new file mode 100644
index 0000000..9b4b9fc
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi.webapp/.settings/org.eclipse.wst.common.project.facet.core.prefs.xml
@@ -0,0 +1,7 @@
+<root>
+  <facet id="jst.jsf">
+    <node name="libprov">
+      <attribute name="provider-id" value="jsf-user-library-provider"/>
+    </node>
+  </facet>
+</root>
diff --git a/servi/org.eclipse.statet.rj.servi.webapp/.settings/org.eclipse.wst.common.project.facet.core.xml b/servi/org.eclipse.statet.rj.servi.webapp/.settings/org.eclipse.wst.common.project.facet.core.xml
new file mode 100644
index 0000000..f1a2542
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi.webapp/.settings/org.eclipse.wst.common.project.facet.core.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<faceted-project>
+  <runtime name="tomcat-6"/>
+  <fixed facet="java"/>
+  <fixed facet="jst.web"/>
+  <installed facet="java" version="1.8"/>
+  <installed facet="jst.web" version="2.5"/>
+  <installed facet="jst.jsf" version="1.2"/>
+</faceted-project>
diff --git a/servi/org.eclipse.statet.rj.servi.webapp/.settings/org.eclipse.wst.jsdt.ui.superType.container b/servi/org.eclipse.statet.rj.servi.webapp/.settings/org.eclipse.wst.jsdt.ui.superType.container
new file mode 100644
index 0000000..3bd5d0a
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi.webapp/.settings/org.eclipse.wst.jsdt.ui.superType.container
@@ -0,0 +1 @@
+org.eclipse.wst.jsdt.launching.baseBrowserLibrary
\ No newline at end of file
diff --git a/servi/org.eclipse.statet.rj.servi.webapp/.settings/org.eclipse.wst.jsdt.ui.superType.name b/servi/org.eclipse.statet.rj.servi.webapp/.settings/org.eclipse.wst.jsdt.ui.superType.name
new file mode 100644
index 0000000..05bd71b
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi.webapp/.settings/org.eclipse.wst.jsdt.ui.superType.name
@@ -0,0 +1 @@
+Window
\ No newline at end of file
diff --git a/servi/org.eclipse.statet.rj.servi.webapp/.settings/org.eclipse.wst.ws.service.policy.prefs b/servi/org.eclipse.statet.rj.servi.webapp/.settings/org.eclipse.wst.ws.service.policy.prefs
new file mode 100644
index 0000000..e812326
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi.webapp/.settings/org.eclipse.wst.ws.service.policy.prefs
@@ -0,0 +1,3 @@
+#Fri Jun 12 11:04:53 CEST 2009
+eclipse.preferences.version=1
+org.eclipse.wst.ws.service.policy.projectEnabled=false
diff --git a/servi/org.eclipse.statet.rj.servi.webapp/about.html b/servi/org.eclipse.statet.rj.servi.webapp/about.html
new file mode 100644
index 0000000..7206cec
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi.webapp/about.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+		"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+<title>About</title>
+</head>
+<body lang="EN-US">
+<h2>About This Content</h2>
+
+<p>December 1, 2017</p>
+<h3>License</h3>
+
+<p>
+	The Eclipse Foundation makes available all content in this plug-in
+	(&quot;Content&quot;). Unless otherwise indicated below, the Content
+	is provided to you under the terms and conditions of the Eclipse
+	Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is
+	available at <a href="https://www.eclipse.org/legal/epl-2.0">https://www.eclipse.org/legal/epl-2.0</a>.
+	For purposes of the EPL, &quot;Program&quot; will mean the Content.
+</p>
+
+<p>
+	If you did not receive this Content directly from the Eclipse
+	Foundation, the Content is being redistributed by another party
+	(&quot;Redistributor&quot;) and different terms and conditions may
+	apply to your use of any object code in the Content. Check the
+	Redistributor's license that was provided with the Content. If no such
+	license exists, contact the Redistributor. Unless otherwise indicated
+	below, the terms and conditions of the EPL still apply to any source
+	code in the Content and such source code may be obtained at <a
+	href="https://www.eclipse.org/">https://www.eclipse.org</a>.
+</p>
+
+</body>
+</html>
diff --git a/servi/org.eclipse.statet.rj.servi.webapp/pom.xml b/servi/org.eclipse.statet.rj.servi.webapp/pom.xml
new file mode 100644
index 0000000..e981f77
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi.webapp/pom.xml
@@ -0,0 +1,101 @@
+<?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>
+	
+	<parent>
+		<groupId>org.eclipse.statet.rj</groupId>
+		<artifactId>rj-servi</artifactId>
+		<version>2.1-SNAPSHOT</version>
+		<relativePath>../_build</relativePath>
+	</parent>
+	
+	<groupId>org.eclipse.statet.rj</groupId>
+	<artifactId>org.eclipse.statet.rj.servi.webapp</artifactId>
+	<version>2.1.0-SNAPSHOT</version>
+	<packaging>war</packaging>
+	
+	<dependencies>
+		<!-- RJ Servi -->
+		<dependency>
+			<groupId>org.eclipse.statet.rj</groupId>
+			<artifactId>org.eclipse.statet.rj.servi</artifactId>
+			<version>2.1.0-SNAPSHOT</version>
+		</dependency>
+		<dependency>
+			<groupId>org.eclipse.statet.rj</groupId>
+			<artifactId>org.eclipse.statet.rj.client</artifactId>
+			<version>2.1.0-SNAPSHOT</version>
+		</dependency>
+		<dependency>
+			<groupId>org.eclipse.statet.rj</groupId>
+			<artifactId>org.eclipse.statet.rj.services.eruntime</artifactId>
+			<version>1.4.0-SNAPSHOT</version>
+		</dependency>
+		<!-- RJ Core -->
+		<dependency>
+			<groupId>org.eclipse.statet.rj</groupId>
+			<artifactId>org.eclipse.statet.rj.data</artifactId>
+			<version>2.1.0-SNAPSHOT</version>
+		</dependency>
+		<dependency>
+			<groupId>org.eclipse.statet.rj</groupId>
+			<artifactId>org.eclipse.statet.rj.server</artifactId>
+			<version>2.1.0-SNAPSHOT</version>
+		</dependency>
+		<!-- JSF -->
+		<dependency>
+			<groupId>javax.faces</groupId>
+			<artifactId>jsf-api</artifactId>
+			<version>1.2_15</version>
+		</dependency>
+		<dependency>
+			<groupId>javax.faces</groupId>
+			<artifactId>jsf-impl</artifactId>
+			<version>1.2_15</version>
+			<scope>runtime</scope>
+		</dependency>
+		<dependency>
+			<groupId>javax.servlet</groupId>
+			<artifactId>jstl</artifactId>
+			<version>1.2</version>
+		</dependency>
+		<!-- Java Web (EE 5) -->
+		<dependency>
+			<groupId>javax.el</groupId>
+			<artifactId>el-api</artifactId>
+			<version>1.0</version>
+			<scope>provided</scope>
+		</dependency>
+		<dependency>
+			<groupId>javax.servlet</groupId>
+			<artifactId>servlet-api</artifactId>
+			<version>2.5</version>
+			<scope>provided</scope>
+		</dependency>
+		<dependency>
+			<groupId>javax.annotation</groupId>
+			<artifactId>jsr250-api</artifactId>
+			<version>1.0</version>
+			<scope>provided</scope>
+		</dependency>
+	</dependencies>
+	
+	<build>
+		<sourceDirectory>src</sourceDirectory>
+		<plugins>
+			<plugin>
+				<groupId>org.apache.maven.plugins</groupId>
+				<artifactId>maven-war-plugin</artifactId>
+				<version>2.1.1</version>
+				<configuration>
+					<warSourceDirectory>${basedir}/web</warSourceDirectory>
+					<outputFileNameMapping>@{artifactId}@_@{version}@.@{extension}@</outputFileNameMapping>
+					<warName>rservi</warName>
+				</configuration>
+			</plugin>
+		</plugins>
+	</build>
+	
+</project>
diff --git a/servi/org.eclipse.statet.rj.servi.webapp/src/org/eclipse/statet/rj/servi/webapp/CheckingFilter.java b/servi/org.eclipse.statet.rj.servi.webapp/src/org/eclipse/statet/rj/servi/webapp/CheckingFilter.java
new file mode 100644
index 0000000..550f81c
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi.webapp/src/org/eclipse/statet/rj/servi/webapp/CheckingFilter.java
@@ -0,0 +1,65 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.servi.webapp;
+
+import java.io.IOException;
+
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+
+
+/**
+ * Checks http request:
+ *  - session timeout (to avoid JSF message)
+ */
+public class CheckingFilter implements Filter {
+	
+	
+	public CheckingFilter() {
+	}
+	
+	
+	@Override
+	public void init(final FilterConfig fConfig) throws ServletException {
+	}
+	
+	@Override
+	public void destroy() {
+	}
+	
+	@Override
+	public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain chain) throws IOException, ServletException {
+		final HttpServletRequest httpRequest= (HttpServletRequest) request;
+		final HttpServletResponse httpResponse= (HttpServletResponse) response;
+		final HttpSession session= httpRequest.getSession(false);
+		if (!httpRequest.getParameterMap().isEmpty()
+				&& httpRequest.getRequestedSessionId() != null
+				&& ((session == null) || session.isNew() || !session.getId().equals(httpRequest.getRequestedSessionId()))
+				) {
+			httpResponse.sendRedirect(httpRequest.getContextPath()+"/faces/resources/sessionexpired.jsp");
+			return;
+		}
+		chain.doFilter(request, response);
+		return;
+	}
+	
+}
diff --git a/servi/org.eclipse.statet.rj.servi.webapp/src/org/eclipse/statet/rj/servi/webapp/DebugBean.java b/servi/org.eclipse.statet.rj.servi.webapp/src/org/eclipse/statet/rj/servi/webapp/DebugBean.java
new file mode 100644
index 0000000..a7f44a5
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi.webapp/src/org/eclipse/statet/rj/servi/webapp/DebugBean.java
@@ -0,0 +1,100 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.servi.webapp;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import javax.annotation.PreDestroy;
+import javax.el.ELContext;
+import javax.faces.context.FacesContext;
+
+import org.eclipse.statet.rj.servi.RServi;
+import org.eclipse.statet.rj.servi.node.RServiPool;
+import org.eclipse.statet.rj.servi.pool.PoolServer;
+import org.eclipse.statet.rj.servi.pool.RServiPoolManager;
+
+
+public class DebugBean {
+	
+	
+	private final List<RServi> nodes= new ArrayList<RServi>();
+	
+	
+	public DebugBean() {
+	}
+	
+	
+	@PreDestroy
+	public void destroy() {
+		actionCloseAllNodes();
+	}
+	
+	
+	public String actionNewNode() {
+		final PoolServer poolServer= FacesUtils.getPoolServer();
+		final RServiPoolManager poolManager= poolServer.getManager();
+		
+		if (poolManager == null) {
+			FacesUtils.addErrorMessage(null, "The pool is currently not available.");
+			return null;
+		}
+		try {
+			final RServi rservi= ((RServiPool) poolManager).getRServi("control-web-app", null);
+			synchronized(this) {
+				this.nodes.add(rservi);
+			}
+		}
+		catch (final Exception e) {
+			FacesUtils.addErrorMessage(null, "An error occurred getting a node: " + e.getMessage());
+		}
+		refreshPoolStatus();
+		return null;
+	}
+	
+	public String actionCloseAllNodes() {
+		synchronized (this) {
+			for (final Iterator<RServi> iter= this.nodes.iterator(); iter.hasNext(); ) {
+				final RServi rservi= iter.next();
+				iter.remove();
+				try {
+					rservi.close();
+				}
+				catch (final Exception e) {
+					FacesUtils.addErrorMessage(null, "An error occurred closing a node: " +e.getMessage());
+				}
+			}
+		}
+		
+		refreshPoolStatus();
+		return RJWeb.POOLSTATUS_NAV;
+	}
+	
+	private void refreshPoolStatus() {
+		final FacesContext context= FacesContext.getCurrentInstance();
+		if (context != null) {
+			try {
+				final ELContext elContext= context.getELContext();
+				final PoolStatusBean poolStatus= (PoolStatusBean) elContext.getELResolver().getValue(elContext, null, "poolStatus");
+				if (poolStatus != null) {
+					poolStatus.forceRefresh();
+				}
+			}
+			catch (final Exception exception) {}
+		}
+	}
+	
+}
diff --git a/servi/org.eclipse.statet.rj.servi.webapp/src/org/eclipse/statet/rj/servi/webapp/DurationConverter.java b/servi/org.eclipse.statet.rj.servi.webapp/src/org/eclipse/statet/rj/servi/webapp/DurationConverter.java
new file mode 100644
index 0000000..d2dabff
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi.webapp/src/org/eclipse/statet/rj/servi/webapp/DurationConverter.java
@@ -0,0 +1,72 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.servi.webapp;
+
+import javax.faces.component.UIComponent;
+import javax.faces.context.FacesContext;
+import javax.faces.convert.Converter;
+
+
+public class DurationConverter implements Converter {
+	
+	
+	public DurationConverter() {
+	}
+	
+	
+	@Override
+	public Object getAsObject(final FacesContext context, final UIComponent component, final String value) {
+		return null;
+	}
+	
+	@Override
+	public String getAsString(final FacesContext context, final UIComponent component, final Object value) {
+		if (value instanceof Long) {
+			long time1= ((Long)value).longValue();
+			if (time1 < 0L) {
+				time1= -time1;
+			}
+			time1 /= 1000L;
+			final long sec= time1 % 60L;
+			time1 /= 60L;
+			final long min= time1 % 60L;
+			time1 /= 60L;
+			final long hour= time1 % 24L;
+			time1 /= 24L;
+			final StringBuilder sb= new StringBuilder();
+			if (time1 > 0L) {
+				sb.append(time1);
+				sb.append(time1 != 1L ? " days " : " day ");
+			}
+			if (hour < 10L) {
+				sb.append('0');
+			}
+			sb.append(Long.toString(hour));
+			sb.append(':');
+			if (min < 10L) {
+				sb.append('0');
+			}
+			sb.append(Long.toString(min));
+			sb.append(':');
+			if (sec < 10L) {
+				sb.append('0');
+			}
+			sb.append(Long.toString(sec));
+			return sb.toString();
+		}
+		return null;
+	}
+	
+}
diff --git a/servi/org.eclipse.statet.rj.servi.webapp/src/org/eclipse/statet/rj/servi/webapp/EAppEnvDummy.java b/servi/org.eclipse.statet.rj.servi.webapp/src/org/eclipse/statet/rj/servi/webapp/EAppEnvDummy.java
new file mode 100644
index 0000000..6f04bf1
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi.webapp/src/org/eclipse/statet/rj/servi/webapp/EAppEnvDummy.java
@@ -0,0 +1,144 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.servi.webapp;
+
+import java.util.concurrent.CopyOnWriteArraySet;
+import java.util.logging.Level;
+import java.util.logging.LogRecord;
+import java.util.logging.Logger;
+
+import javax.servlet.ServletContext;
+import javax.servlet.ServletContextEvent;
+import javax.servlet.ServletContextListener;
+
+import org.eclipse.core.runtime.IStatus;
+
+import org.eclipse.statet.jcommons.lang.Disposable;
+
+import org.eclipse.statet.ecommons.runtime.core.ECommonsRuntime;
+
+
+public class EAppEnvDummy implements ServletContextListener, ECommonsRuntime.AppEnvironment {
+	
+	
+	private final CopyOnWriteArraySet<Disposable> stopListeners= new CopyOnWriteArraySet<>();
+	
+	private ServletContext context;
+	
+	private Logger logger;
+	
+	
+	public EAppEnvDummy() {
+	}
+	
+	
+	@Override
+	public void contextInitialized(final ServletContextEvent sce) {
+		this.context= sce.getServletContext();
+		ECommons.init("org.eclipse.statet.rj.services.eruntime", this);
+		
+		this.logger= Logger.getLogger("org.eclipse.statet.rj.servi.pool");
+	}
+	
+	@Override
+	public void contextDestroyed(final ServletContextEvent sce) {
+		try {
+			for (final Disposable listener : this.stopListeners) {
+				listener.dispose();
+			}
+		}
+		finally {
+			this.stopListeners.clear();
+			this.context= null;
+		}
+	}
+	
+	@Override
+	public void addStoppingListener(final Disposable listener) {
+		this.stopListeners.add(listener);
+	}
+	
+	@Override
+	public void removeStoppingListener(final Disposable listener) {
+		this.stopListeners.remove(listener);
+	}
+	
+//	public void log(final IStatus status) {
+//		final StringBuilder sb= new StringBuilder();
+//		switch (status.getSeverity()) {
+//		case IStatus.OK:
+//			sb.append("[OK] ");
+//			break;
+//		case IStatus.ERROR:
+//			sb.append("[ERROR] ");
+//			break;
+//		case IStatus.WARNING:
+//			sb.append("[WARNING] ");
+//			break;
+//		case IStatus.INFO:
+//			sb.append("[INFO] ");
+//			break;
+//		case IStatus.CANCEL:
+//			sb.append("[CANCEL] ");
+//			break;
+//		default:
+//			sb.append("[severity=");
+//			sb.append(status.getSeverity());
+//			sb.append(']');
+//			break;
+//		}
+//		sb.append(status.getMessage());
+//		
+//		this.context.log(sb.toString(), status.getException());
+//	}
+	
+	@Override
+	public void log(final IStatus status) {
+		final Level level;
+		switch (status.getSeverity()) {
+		case IStatus.INFO:
+			level= Level.INFO;
+			break;
+		case IStatus.WARNING:
+			level= Level.WARNING;
+			break;
+		case IStatus.ERROR:
+			level= Level.SEVERE;
+			break;
+		default:
+			level= Level.FINE;
+		}
+		final LogRecord record= new LogRecord(level, status.getMessage());
+		if (status.getException() != null) {
+			record.setThrown(status.getException());
+		}
+		
+		// set correct caller
+		try {
+			final StackTraceElement[] stackTrace= new Exception().getStackTrace();
+			for (int i= 1; i < stackTrace.length; i++) {
+				if (!stackTrace[i].getMethodName().startsWith("log")) {
+					record.setSourceClassName(stackTrace[i].getClassName());
+					record.setSourceMethodName(stackTrace[i].getMethodName());
+					break;
+				}
+			}
+		}
+		catch (final Exception ignore) {}
+		
+		this.logger.log(record);
+	}
+	
+}
diff --git a/servi/org.eclipse.statet.rj.servi.webapp/src/org/eclipse/statet/rj/servi/webapp/FacesUtils.java b/servi/org.eclipse.statet.rj.servi.webapp/src/org/eclipse/statet/rj/servi/webapp/FacesUtils.java
new file mode 100644
index 0000000..007d258
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi.webapp/src/org/eclipse/statet/rj/servi/webapp/FacesUtils.java
@@ -0,0 +1,200 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.servi.webapp;
+
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Properties;
+
+import javax.faces.application.FacesMessage;
+import javax.faces.component.UIComponent;
+import javax.faces.context.FacesContext;
+import javax.servlet.ServletContext;
+
+import org.eclipse.statet.rj.server.util.RJContext;
+import org.eclipse.statet.rj.servi.node.PropertiesBean;
+import org.eclipse.statet.rj.servi.node.RServiNodeConfig;
+import org.eclipse.statet.rj.servi.node.PropertiesBean.ValidationMessage;
+import org.eclipse.statet.rj.servi.pool.NetConfig;
+import org.eclipse.statet.rj.servi.pool.PoolConfig;
+import org.eclipse.statet.rj.servi.pool.PoolServer;
+
+
+public class FacesUtils {
+	
+	
+	public static String toUI(final String formId, final String propertyId) {
+		if (formId == null || propertyId == null) {
+			return null;
+		}
+		final StringBuilder sb= new StringBuilder(formId.length() + propertyId.length() + 1);
+		sb.append(formId);
+		sb.append(':');
+		for (int i= 0; i < propertyId.length(); i++) {
+			final char c= propertyId.charAt(i);
+			if (c == '.') {
+				sb.append('_');
+			}
+			else {
+				sb.append(c);
+			}
+		}
+		return sb.toString();
+	}
+	
+	public static String toFormId(final String beanId) {
+		if (beanId == NetConfig.BEAN_ID) {
+			return "net_config";
+		}
+		if (beanId == RServiNodeConfig.BEAN_ID) {
+			return "r_config";
+		}
+		if (beanId == PoolConfig.BEAN_ID) {
+			return "pool_config";
+		}
+		return null;
+	}
+	
+	public static boolean validate(final PropertiesBean bean) {
+		final List<ValidationMessage> messages= new ArrayList<ValidationMessage>();
+		if (bean.validate(messages)) {
+			return true;
+		}
+		final String formId= toFormId(bean.getBeanId()) + "_config";
+		for (final ValidationMessage message : messages) {
+			addErrorMessage(toUI(formId, message.getPropertyId()), message.getMessage());
+		}
+		return false;
+	}
+	
+	public static void addErrorMessage(final String ui, String message) {
+		{	int end= -1;
+			while (true) {
+				final int begin= message.indexOf('{', end + 1);
+				if (begin < 0) {
+					break;
+				}
+				end= message.indexOf('}', begin + 1);
+				if (end >= 0) {
+					final String label= getLabel(message.substring(begin + 1, end));
+					if (label != null && !label.isEmpty()) {
+						message= message.substring(0, begin) + label + message.substring(end + 1);
+					}
+				}
+				else {
+					end= begin;
+				}
+			}
+		}
+		
+		final String label= getLabel(ui);
+		if (label != null) {
+			message= label + ": " + message;
+		}
+		
+		FacesContext.getCurrentInstance().addMessage(ui, new FacesMessage(FacesMessage.SEVERITY_ERROR, message, message));
+	}
+	
+	public static String getLabel(final String componentId) {
+		if (componentId != null) {
+			final UIComponent component= FacesContext.getCurrentInstance().getViewRoot().findComponent(componentId);
+			if (component != null) {
+				return (String) component.getAttributes().get("label");
+			}
+		}
+		return null;
+	}
+	
+	public static PoolServer getPoolServer() {
+		final Object externalContext= FacesContext.getCurrentInstance().getExternalContext().getContext();
+		if (externalContext instanceof ServletContext) {
+			return (PoolServer) ((ServletContext) externalContext).getAttribute(RJWeb.RJ_POOLSERVER_KEY);
+		}
+		throw new IllegalStateException();
+	}
+	
+	private static RJContext getRJContext() {
+		final Object externalContext= FacesContext.getCurrentInstance().getExternalContext().getContext();
+		if (externalContext instanceof ServletContext) {
+			return (RJContext) ((ServletContext) externalContext).getAttribute(RJWeb.RJCONTEXT_KEY);
+		}
+		throw new IllegalStateException();
+	}
+	
+	public static String getPoolId() {
+		final Object externalContext= FacesContext.getCurrentInstance().getExternalContext().getContext();
+		if (externalContext instanceof ServletContext) {
+			return (String) ((ServletContext) externalContext).getAttribute(RJWeb.POOLID_KEY);
+		}
+		throw new IllegalStateException();
+	}
+	
+	
+	public static boolean saveToFile(final PropertiesBean bean) {
+		try {
+			final Properties properties= new Properties();
+			
+			synchronized (bean) {
+				if (!validate(bean)) {
+					return false;
+				}
+				bean.save(properties);
+			}
+			
+			getRJContext().saveProperties(bean.getBeanId(), properties);
+			
+			FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_INFO, "Configuration saved.", null));
+			return true;
+		}
+		catch (final Exception e) {
+			FacesContext.getCurrentInstance().getExternalContext().log(
+					MessageFormat.format("Failed to save to the configuration file ''{0}''.", new Object[] { bean.getBeanId() }), e);
+			FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, "Failed to save the configuration: " + e.getMessage(), null));
+			return false;
+		}
+	}
+	
+	public static boolean loadFromFile(final PropertiesBean bean, final boolean report) {
+		try {
+			final Properties properties= getRJContext().loadProperties(bean.getBeanId());
+			if (properties == null) {
+				if (report) {
+					FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_WARN,
+							MessageFormat.format("The configuration file ''{0}'' could not be found. Default values are used.", new Object[] { bean.getBeanId() }), null));
+				}
+				return false;
+			}
+			
+			synchronized(bean) {
+				bean.load(properties);
+				
+				validate(bean);
+			}
+			return true;
+		}
+		catch (final Exception e) {
+			if (report) {
+				FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR,
+						MessageFormat.format("Failed to load the configuration from file ''{0}''.", new Object[] { bean.getBeanId() }), null));
+			}
+			return false;
+		}
+	}
+	
+	
+	private FacesUtils() {}
+	
+}
diff --git a/servi/org.eclipse.statet.rj.servi.webapp/src/org/eclipse/statet/rj/servi/webapp/NetConfigBean.java b/servi/org.eclipse.statet.rj.servi.webapp/src/org/eclipse/statet/rj/servi/webapp/NetConfigBean.java
new file mode 100644
index 0000000..efdab4a
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi.webapp/src/org/eclipse/statet/rj/servi/webapp/NetConfigBean.java
@@ -0,0 +1,88 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.servi.webapp;
+
+import javax.annotation.PostConstruct;
+import javax.management.OperationsException;
+import javax.naming.directory.InvalidAttributeValueException;
+
+import org.eclipse.statet.rj.servi.pool.NetConfig;
+import org.eclipse.statet.rj.servi.pool.PoolServer;
+
+
+public class NetConfigBean extends NetConfig {
+	
+	
+	public NetConfigBean() {
+	}
+	
+	
+	@PostConstruct
+	public void init() {
+		FacesUtils.loadFromFile(this, false);
+	}
+	
+	
+	public String getEffectivePoolAddress() {
+		final String address= getPoolAddress(this, FacesUtils.getPoolId());
+		return (address != null) ? address : "";
+	}
+	
+	
+	public String actionLoadCurrent() {
+		final PoolServer poolServer= FacesUtils.getPoolServer();
+		
+		synchronized (this) {
+			poolServer.getNetConfig(this);
+			FacesUtils.validate(this);
+		}
+		
+		return RJWeb.NETCONFIG_NAV;
+	}
+	
+	public String actionLoadDefaults() throws InvalidAttributeValueException {
+		synchronized (this) {
+			load(new NetConfigBean());
+			FacesUtils.validate(this);
+		}
+		
+		return RJWeb.NETCONFIG_NAV;
+	}
+	
+	public String actionRestart() {
+		final NetConfig config= new NetConfig(this);
+		
+		if (!FacesUtils.validate(config)) {
+			return null;
+		}
+		
+		final PoolServer poolServer= FacesUtils.getPoolServer();
+		
+		poolServer.setNetConfig(config);
+		try {
+			poolServer.restart();
+		}
+		catch (final OperationsException e) {
+			FacesUtils.addErrorMessage(null, e.getMessage());
+		}
+		return null;
+	}
+	
+	public String actionSave() {
+		FacesUtils.saveToFile(this);
+		return null;
+	}
+	
+}
diff --git a/servi/org.eclipse.statet.rj.servi.webapp/src/org/eclipse/statet/rj/servi/webapp/NodeConfigBean.java b/servi/org.eclipse.statet.rj.servi.webapp/src/org/eclipse/statet/rj/servi/webapp/NodeConfigBean.java
new file mode 100644
index 0000000..235ff83
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi.webapp/src/org/eclipse/statet/rj/servi/webapp/NodeConfigBean.java
@@ -0,0 +1,111 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.servi.webapp;
+
+import javax.annotation.PostConstruct;
+import javax.faces.application.FacesMessage;
+import javax.faces.context.FacesContext;
+
+import org.eclipse.statet.rj.RjException;
+import org.eclipse.statet.rj.servi.node.RServiNodeConfig;
+import org.eclipse.statet.rj.servi.pool.PoolServer;
+
+
+public class NodeConfigBean extends RServiNodeConfig {
+	
+	
+	public NodeConfigBean() {
+	}
+	
+	
+	@PostConstruct
+	public void init() {
+		actionLoadCurrent();
+	}
+	
+	
+	public synchronized String getRLibsVariable() {
+		return getEnvironmentVariables().get("R_LIBS");
+	}
+	
+	public synchronized void setRLibsVariable(final String value) {
+		if (value != null && value.length() > 0) {
+			getEnvironmentVariables().put("R_LIBS", value);
+		}
+		else {
+			getEnvironmentVariables().remove("R_LIBS");
+		}
+	}
+	
+	
+	public String actionLoadCurrent() {
+		final PoolServer poolServer= FacesUtils.getPoolServer();
+		
+		synchronized (this) {
+			poolServer.getNodeConfig(this);
+			FacesUtils.validate(this);
+		}
+		
+		return RJWeb.RCONFIG_NAV;
+	}
+	
+	public String actionLoadDefaults() {
+		synchronized (this) {
+			load(new RServiNodeConfig());
+			FacesUtils.validate(this);
+		}
+		
+		return RJWeb.RCONFIG_NAV;
+	}
+	
+	public String actionApply() {
+		final RServiNodeConfig config= new RServiNodeConfig(this);
+		
+		if (!FacesUtils.validate(config)) {
+			return null;
+		}
+		final PoolServer poolServer= FacesUtils.getPoolServer();
+		
+		try {
+			poolServer.setNodeConfig(config);
+			FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_INFO, "Configuration applied.", null));
+		}
+		catch (final RjException e) {
+			FacesUtils.addErrorMessage(null, e.getMessage());
+		}
+		return null;
+	}
+	
+	public synchronized String actionSaveAndApply() {
+		final RServiNodeConfig config= new RServiNodeConfig(this);
+		
+		if (!FacesUtils.validate(config)) {
+			return null;
+		}
+		final PoolServer poolServer= FacesUtils.getPoolServer();
+		
+		try {
+			poolServer.setNodeConfig(config);
+			FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_INFO, "Configuration applied.", null));
+		}
+		catch (final RjException e) {
+			FacesUtils.addErrorMessage(null, e.getMessage());
+			return null;
+		}
+		FacesUtils.saveToFile(config);
+		return null;
+	}
+	
+}
diff --git a/servi/org.eclipse.statet.rj.servi.webapp/src/org/eclipse/statet/rj/servi/webapp/PoolConfigBean.java b/servi/org.eclipse.statet.rj.servi.webapp/src/org/eclipse/statet/rj/servi/webapp/PoolConfigBean.java
new file mode 100644
index 0000000..a72f8c5
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi.webapp/src/org/eclipse/statet/rj/servi/webapp/PoolConfigBean.java
@@ -0,0 +1,88 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.servi.webapp;
+
+import javax.annotation.PostConstruct;
+import javax.faces.application.FacesMessage;
+import javax.faces.context.FacesContext;
+
+import org.eclipse.statet.rj.servi.pool.PoolConfig;
+import org.eclipse.statet.rj.servi.pool.PoolServer;
+
+
+public class PoolConfigBean extends PoolConfig {
+	
+	
+	public PoolConfigBean() {
+	}
+	
+	
+	@PostConstruct
+	public void init() {
+		final PoolServer poolServer= FacesUtils.getPoolServer();
+		
+		poolServer.getPoolConfig(this);
+	}
+	
+	
+	public String actionLoadCurrent() {
+		final PoolServer poolServer= FacesUtils.getPoolServer();
+		
+		synchronized (this) {
+			poolServer.getPoolConfig(this);
+			FacesUtils.validate(this);
+		}
+		
+		return RJWeb.POOLCONFIG_NAV;
+	}
+	
+	public String actionLoadDefaults() {
+		synchronized (this) {
+			load(new PoolConfig());
+			FacesUtils.validate(this);
+		}
+		
+		return RJWeb.POOLCONFIG_NAV;
+	}
+	
+	public String actionApply() {
+		final PoolConfig config= new PoolConfig(this);
+		
+		if (!FacesUtils.validate(config)) {
+			return null;
+		}
+		final PoolServer poolServer= FacesUtils.getPoolServer();
+		
+		poolServer.setPoolConfig(config);
+		FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_INFO, "Configuration applied.", null));
+		return null;
+	}
+	
+	public String actionSaveAndApply() {
+		final PoolConfig config= new PoolConfig(this);
+		
+		if (!FacesUtils.validate(config)) {
+			return null;
+		}
+		final PoolServer poolServer= FacesUtils.getPoolServer();
+		
+		poolServer.setPoolConfig(config);
+		FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_INFO, "Configuration applied.", null));
+		
+		FacesUtils.saveToFile(config);
+		return null;
+	}
+	
+}
diff --git a/servi/org.eclipse.statet.rj.servi.webapp/src/org/eclipse/statet/rj/servi/webapp/PoolItemBean.java b/servi/org.eclipse.statet.rj.servi.webapp/src/org/eclipse/statet/rj/servi/webapp/PoolItemBean.java
new file mode 100644
index 0000000..96b430e
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi.webapp/src/org/eclipse/statet/rj/servi/webapp/PoolItemBean.java
@@ -0,0 +1,73 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.servi.webapp;
+
+import org.eclipse.statet.ecommons.rmi.core.RMIAddress;
+
+import org.eclipse.statet.rj.RjException;
+import org.eclipse.statet.rj.servi.pool.PoolConfig;
+import org.eclipse.statet.rj.servi.pool.PoolNodeItem;
+import org.eclipse.statet.rj.servi.pool.PoolNodeObject;
+import org.eclipse.statet.rj.servi.pool.PoolServer;
+
+
+public class PoolItemBean extends PoolNodeItem {
+	
+	
+	public PoolItemBean(final PoolNodeObject poolObj, final long stamp) {
+		super(poolObj, stamp);
+	}
+	
+	
+	public String getRMIAddress() {
+		final RMIAddress address= getAddress();
+		return (address != null) ? address.getAddress() : null;
+	}
+	
+	
+	public String actionEnableConsole() {
+		try {
+			super.enableConsole("none");
+		}
+		catch (final RjException e) {
+			FacesUtils.addErrorMessage(null, e.getMessage());
+		}
+		return null;
+	}
+	
+	public String actionDisableConsole() {
+		try {
+			super.disableConsole();
+		}
+		catch (final RjException e) {
+			FacesUtils.addErrorMessage(null, e.getMessage());
+		}
+		return null;
+	}
+	
+	public void actionStop() {
+		final PoolServer poolServer= FacesUtils.getPoolServer();
+		
+		final PoolConfig config= new PoolConfig();
+		poolServer.getPoolConfig(config);
+		
+		evict(config.getEvictionTimeout());
+	}
+	
+	public void actionKill() {
+		evict(0);
+	}
+	
+}
diff --git a/servi/org.eclipse.statet.rj.servi.webapp/src/org/eclipse/statet/rj/servi/webapp/PoolStatusBean.java b/servi/org.eclipse.statet.rj.servi.webapp/src/org/eclipse/statet/rj/servi/webapp/PoolStatusBean.java
new file mode 100644
index 0000000..92fdc0c
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi.webapp/src/org/eclipse/statet/rj/servi/webapp/PoolStatusBean.java
@@ -0,0 +1,100 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.servi.webapp;
+
+import javax.annotation.PostConstruct;
+
+import org.eclipse.statet.rj.servi.pool.PoolNodeItem;
+import org.eclipse.statet.rj.servi.pool.PoolStatus;
+import org.eclipse.statet.rj.servi.pool.RServiPoolManager;
+
+
+public class PoolStatusBean extends PoolStatus<PoolItemBean> {
+	
+	
+	private boolean forceRefresh;
+	private boolean autoRefresh;
+	
+	
+	public PoolStatusBean() {
+		super(FacesUtils.getPoolServer());
+	}
+	
+	
+	@PostConstruct
+	public void init() {
+		load();
+	}
+	
+	private void load() {
+		final long stamp= System.currentTimeMillis();
+		final RServiPoolManager poolManager= this.server.getManager();
+		if (poolManager == null) {
+			FacesUtils.addErrorMessage(null, "The pool is currently not available.");
+		}
+		refresh(poolManager, stamp);
+	}
+	
+	@Override
+	protected PoolNodeItem createPoolItem(final Object itemData, final long stamp) {
+		return new PoolItemBean(itemData, stamp);
+	}
+	
+	@Override
+	protected PoolItemBean createNodeState(final PoolNodeItem item) {
+		return (PoolItemBean) item;
+	}
+	
+	
+	public synchronized long getStamp() {
+		check();
+		return super.getStatusStamp();
+	}
+	
+	@Override
+	protected void check() {
+		if (this.forceRefresh) {
+			load();
+		}
+	}
+	
+	public synchronized void forceRefresh() {
+		this.forceRefresh= true;
+	}
+	
+	
+	public String actionRefresh() {
+		return null;
+	}
+	
+	public synchronized String actionEnableAutoRefresh() {
+		this.autoRefresh= true;
+		return null;
+	}
+	
+	public synchronized String actionDisableAutoRefresh() {
+		this.autoRefresh= false;
+		return null;
+	}
+	
+	public synchronized void setAutoRefreshEnabled(final boolean enabled) {
+		this.autoRefresh= enabled;
+	}
+	
+	public synchronized boolean isAutoRefreshEnabled() {
+		return this.autoRefresh;
+	}
+	
+}
diff --git a/servi/org.eclipse.statet.rj.servi.webapp/src/org/eclipse/statet/rj/servi/webapp/RJServlet.java b/servi/org.eclipse.statet.rj.servi.webapp/src/org/eclipse/statet/rj/servi/webapp/RJServlet.java
new file mode 100644
index 0000000..e12f221
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi.webapp/src/org/eclipse/statet/rj/servi/webapp/RJServlet.java
@@ -0,0 +1,84 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.servi.webapp;
+
+import java.io.IOException;
+
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.eclipse.statet.rj.servi.pool.JMPoolServer;
+
+
+public class RJServlet extends HttpServlet {
+	
+	
+	private JMPoolServer server;
+	
+	
+	public RJServlet(){
+	}
+	
+	
+	@Override
+	public void init(final ServletConfig config) throws ServletException {
+		super.init(config);
+		try {
+			String id= getServletContext().getContextPath();
+			if (id.startsWith("/")) {
+				id= id.substring(1);
+			}
+			getServletContext().setAttribute(RJWeb.POOLID_KEY, id);
+			
+			final ServletRJContext rjContext= new ServletRJContext(getServletContext());
+			getServletContext().setAttribute(RJWeb.RJCONTEXT_KEY, rjContext);
+			
+			this.server= new JMPoolServer(id, rjContext);
+			this.server.start();
+			
+			getServletContext().setAttribute(RJWeb.RJ_POOLSERVER_KEY, this.server);
+		}
+		catch (final Exception e) {
+			if (this.server != null) {
+				this.server.shutdown();
+				this.server= null;
+			}
+			throw new ServletException("Failed to initialized RServi Server.", e);
+		}
+	}
+	
+	@Override
+	public void destroy() {
+		if (this.server != null) {
+			getServletContext().removeAttribute(RJWeb.RJ_POOLSERVER_KEY);
+			
+			this.server.shutdown();
+		}
+	}
+	
+	@Override
+	protected void doGet(final HttpServletRequest request, final HttpServletResponse response) throws ServletException, IOException {
+		if (this.server != null) {
+			response.setStatus(HttpServletResponse.SC_OK);
+		}
+		else {
+			response.setStatus(HttpServletResponse.SC_SERVICE_UNAVAILABLE);
+		}
+	}
+	
+}
diff --git a/servi/org.eclipse.statet.rj.servi.webapp/src/org/eclipse/statet/rj/servi/webapp/RJWeb.java b/servi/org.eclipse.statet.rj.servi.webapp/src/org/eclipse/statet/rj/servi/webapp/RJWeb.java
new file mode 100644
index 0000000..aba7837
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi.webapp/src/org/eclipse/statet/rj/servi/webapp/RJWeb.java
@@ -0,0 +1,35 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.servi.webapp;
+
+
+public class RJWeb {
+	
+	
+	public static final String BUNDLE_ID= "org.eclipse.statet.rj.servi.webapp";
+	
+	public static final String RJ_POOLSERVER_KEY= "rj.pool.server";
+	public static final String POOLID_KEY= "pool.id";
+	public static final String RJCONTEXT_KEY= "rj.context";
+	
+	public static final String POOLCONFIG_NAV= "conf-pool";
+	public static final String POOLSTATUS_NAV= "status-pool";
+	public static final String RCONFIG_NAV= "conf-r";
+	public static final String NETCONFIG_NAV= "conf-net";
+	
+	
+	private RJWeb() {}
+	
+}
diff --git a/servi/org.eclipse.statet.rj.servi.webapp/src/org/eclipse/statet/rj/servi/webapp/ServletRJContext.java b/servi/org.eclipse.statet.rj.servi.webapp/src/org/eclipse/statet/rj/servi/webapp/ServletRJContext.java
new file mode 100644
index 0000000..8223543
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi.webapp/src/org/eclipse/statet/rj/servi/webapp/ServletRJContext.java
@@ -0,0 +1,80 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.servi.webapp;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import javax.servlet.ServletContext;
+
+import org.eclipse.statet.rj.RjInvalidConfigurationException;
+import org.eclipse.statet.rj.server.util.RJContext;
+
+
+public class ServletRJContext extends RJContext {
+	
+	
+	private final ServletContext servletContext;
+	
+	
+	public ServletRJContext(final ServletContext context) {
+		this.servletContext= context;
+	}
+	
+	
+	@Override
+	protected String[] getLibDirPaths() throws RjInvalidConfigurationException {
+		return new String[] { this.servletContext.getRealPath("WEB-INF/lib") };
+	}
+	
+	
+	@Override
+	public String getServerPolicyFilePath() throws RjInvalidConfigurationException {
+		String path= this.servletContext.getRealPath("WEB-INF/lib");
+		final int length= path.length();
+		if (length == 0 || (path.charAt(length-1) != '/' && path.charAt(length-1) != File.separatorChar)) {
+			path+= File.separatorChar;
+		}
+		return path + "security.policy";
+	}
+	
+	
+	@Override
+	protected String getPropertiesDirPath() {
+		return "/WEB-INF/";
+	}
+	
+	@Override
+	protected InputStream getInputStream(final String path) throws IOException {
+		return this.servletContext.getResourceAsStream(path);
+	}
+	
+	@Override
+	protected OutputStream getOutputStream(final String path) throws IOException {
+		final String realPath= this.servletContext.getRealPath(path);
+		if (realPath == null) {
+			throw new IOException("Writing to '" + path + "' not supported.");
+		}
+		final File file= new File(realPath);
+		if (!file.exists()) {
+			file.createNewFile();
+		}
+		return new FileOutputStream(file, false);
+	}
+	
+}
diff --git a/servi/org.eclipse.statet.rj.servi.webapp/web/META-INF/MANIFEST.MF b/servi/org.eclipse.statet.rj.servi.webapp/web/META-INF/MANIFEST.MF
new file mode 100644
index 0000000..254272e
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi.webapp/web/META-INF/MANIFEST.MF
@@ -0,0 +1,3 @@
+Manifest-Version: 1.0
+Class-Path: 
+
diff --git a/servi/org.eclipse.statet.rj.servi.webapp/web/WEB-INF/faces-config.xml b/servi/org.eclipse.statet.rj.servi.webapp/web/WEB-INF/faces-config.xml
new file mode 100644
index 0000000..82d14df
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi.webapp/web/WEB-INF/faces-config.xml
@@ -0,0 +1,68 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<faces-config xmlns="http://java.sun.com/xml/ns/javaee"
+		xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+		xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_1_2.xsd"
+		version="1.2">
+	
+	<converter>
+		<converter-id>convertDuration</converter-id>
+		<converter-class>org.eclipse.statet.rj.servi.webapp.DurationConverter</converter-class>
+	</converter>
+	
+	<managed-bean>
+		<managed-bean-name>netConfig</managed-bean-name>
+		<managed-bean-class>org.eclipse.statet.rj.servi.webapp.NetConfigBean</managed-bean-class>
+		<managed-bean-scope>request</managed-bean-scope>
+	</managed-bean>
+	<managed-bean>
+		<managed-bean-name>poolConfig</managed-bean-name>
+		<managed-bean-class>org.eclipse.statet.rj.servi.webapp.PoolConfigBean</managed-bean-class>
+		<managed-bean-scope>request</managed-bean-scope>
+	</managed-bean>
+	<managed-bean>
+		<managed-bean-name>rConfig</managed-bean-name>
+		<managed-bean-class>org.eclipse.statet.rj.servi.webapp.NodeConfigBean</managed-bean-class>
+		<managed-bean-scope>request</managed-bean-scope>
+	</managed-bean>
+	<managed-bean>
+		<managed-bean-name>poolStatus</managed-bean-name>
+		<managed-bean-class>org.eclipse.statet.rj.servi.webapp.PoolStatusBean</managed-bean-class>
+		<managed-bean-scope>request</managed-bean-scope>
+	</managed-bean>
+	
+	<managed-bean>
+		<managed-bean-name>debug</managed-bean-name>
+		<managed-bean-class>org.eclipse.statet.rj.servi.webapp.DebugBean</managed-bean-class>
+		<managed-bean-scope>session</managed-bean-scope>
+	</managed-bean>
+	
+	<navigation-rule>
+		<display-name>welcome</display-name>
+		<from-view-id>/resources/welcome.jsp</from-view-id>
+	</navigation-rule>
+	<navigation-rule>
+		<display-name>conf-pool</display-name>
+		<from-view-id>/resources/conf-pool.jsp</from-view-id>
+		<navigation-case>
+			<from-outcome>conf-pool</from-outcome>
+			<to-view-id>/resources/conf-pool.jsp</to-view-id>
+		</navigation-case>
+	</navigation-rule>
+	<navigation-rule>
+		<display-name>conf-r</display-name>
+		<from-view-id>/resources/conf-r.jsp</from-view-id>
+		<navigation-case>
+			<from-outcome>conf-r</from-outcome>
+			<to-view-id>/resources/conf-r.jsp</to-view-id>
+		</navigation-case>
+	</navigation-rule>
+	
+	<navigation-rule>
+		<from-view-id>/resources/*</from-view-id>
+		<navigation-case>
+			<from-outcome>status-pool</from-outcome>
+			<to-view-id>/resources/status-poolnodes.jsp</to-view-id>
+		</navigation-case>
+	</navigation-rule>
+	
+</faces-config>
diff --git a/servi/org.eclipse.statet.rj.servi.webapp/web/WEB-INF/keystore b/servi/org.eclipse.statet.rj.servi.webapp/web/WEB-INF/keystore
new file mode 100644
index 0000000..64d2dd3
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi.webapp/web/WEB-INF/keystore
Binary files differ
diff --git a/servi/org.eclipse.statet.rj.servi.webapp/web/WEB-INF/lib/security.policy b/servi/org.eclipse.statet.rj.servi.webapp/web/WEB-INF/lib/security.policy
new file mode 100644
index 0000000..6e902c1
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi.webapp/web/WEB-INF/lib/security.policy
@@ -0,0 +1,7 @@
+grant codeBase "file:${{java.ext.dirs}}/*" {

+	permission java.security.AllPermission;

+};

+

+grant {

+	permission java.security.AllPermission;

+};

diff --git a/servi/org.eclipse.statet.rj.servi.webapp/web/WEB-INF/netconfig.properties b/servi/org.eclipse.statet.rj.servi.webapp/web/WEB-INF/netconfig.properties
new file mode 100644
index 0000000..c454063
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi.webapp/web/WEB-INF/netconfig.properties
@@ -0,0 +1,3 @@
+#Mon May 06 14:22:42 CEST 2013
+ssl.enabled=false
+rmi_registry.embed.enabled=true
diff --git a/servi/org.eclipse.statet.rj.servi.webapp/web/WEB-INF/rconfig.properties b/servi/org.eclipse.statet.rj.servi.webapp/web/WEB-INF/rconfig.properties
new file mode 100644
index 0000000..6eb18af
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi.webapp/web/WEB-INF/rconfig.properties
@@ -0,0 +1,9 @@
+#Mon May 06 13:55:51 CEST 2013
+r_home.path=D\:\\R\\R-3.0-org
+java_cmd.args=
+r_startup.snippet=
+debug_verbose.enabled=false
+base_wd.path=D\:\\OrcaForge\\temp
+debug_console.enabled=false
+node_cmd.args=
+startstop_timeout.millis=30000
diff --git a/servi/org.eclipse.statet.rj.servi.webapp/web/WEB-INF/server.cer b/servi/org.eclipse.statet.rj.servi.webapp/web/WEB-INF/server.cer
new file mode 100644
index 0000000..e9cb25c
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi.webapp/web/WEB-INF/server.cer
Binary files differ
diff --git a/servi/org.eclipse.statet.rj.servi.webapp/web/WEB-INF/truststore b/servi/org.eclipse.statet.rj.servi.webapp/web/WEB-INF/truststore
new file mode 100644
index 0000000..0df9807
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi.webapp/web/WEB-INF/truststore
Binary files differ
diff --git a/servi/org.eclipse.statet.rj.servi.webapp/web/WEB-INF/web.xml b/servi/org.eclipse.statet.rj.servi.webapp/web/WEB-INF/web.xml
new file mode 100644
index 0000000..8cf7223
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi.webapp/web/WEB-INF/web.xml
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">
+	
+	<display-name>org.eclipse.statet.rj.servi.webapp</display-name>
+	
+	<welcome-file-list>
+		<welcome-file>index.jsp</welcome-file>
+	</welcome-file-list>
+	
+	<servlet>
+		<servlet-name>RJServlet</servlet-name>
+		<servlet-class>org.eclipse.statet.rj.servi.webapp.RJServlet</servlet-class>
+		<load-on-startup>1</load-on-startup>
+	</servlet>
+	<servlet-mapping>
+		<servlet-name>RJServlet</servlet-name>
+		<url-pattern>/status</url-pattern>
+	</servlet-mapping>
+	
+	<servlet>
+		<servlet-name>FacesServlet</servlet-name>
+		<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
+		<load-on-startup>2</load-on-startup>
+	</servlet>
+	<servlet-mapping>
+		<servlet-name>FacesServlet</servlet-name>
+		<url-pattern>/faces/*</url-pattern>
+	</servlet-mapping>
+	
+	<filter>
+		<display-name>CheckingFilter</display-name>
+		<filter-name>CheckingFilter</filter-name>
+		<filter-class>org.eclipse.statet.rj.servi.webapp.CheckingFilter</filter-class>
+	</filter>
+	<filter-mapping>
+		<filter-name>CheckingFilter</filter-name>
+		<url-pattern>/faces/resources/*</url-pattern>
+		<dispatcher>REQUEST</dispatcher>
+	</filter-mapping>
+	
+	<listener>
+		<display-name>AppEnv for ECommons</display-name>
+		<listener-class>org.eclipse.statet.rj.servi.webapp.EAppEnvDummy</listener-class>
+	</listener>
+	
+	<session-config>
+		<session-timeout>30</session-timeout>
+	</session-config>
+
+<!--
+	<security-constraint>
+		<web-resource-collection>
+		<web-resource-name>admin</web-resource-name>
+			<url-pattern>/resources/*</url-pattern>
+		</web-resource-collection>
+		<auth-constraint>
+			<role-name>admin</role-name>
+		</auth-constraint>
+	</security-constraint>
+-->
+
+</web-app>
diff --git a/servi/org.eclipse.statet.rj.servi.webapp/web/index.jsp b/servi/org.eclipse.statet.rj.servi.webapp/web/index.jsp
new file mode 100644
index 0000000..d80cf54
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi.webapp/web/index.jsp
@@ -0,0 +1 @@
+<% response.sendRedirect(request.getContextPath()+"/faces/resources/"); %>
\ No newline at end of file
diff --git a/servi/org.eclipse.statet.rj.servi.webapp/web/resources/body-footer.jspf b/servi/org.eclipse.statet.rj.servi.webapp/web/resources/body-footer.jspf
new file mode 100644
index 0000000..7f5eaa3
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi.webapp/web/resources/body-footer.jspf
@@ -0,0 +1 @@
+</div>
\ No newline at end of file
diff --git a/servi/org.eclipse.statet.rj.servi.webapp/web/resources/body-header.jspf b/servi/org.eclipse.statet.rj.servi.webapp/web/resources/body-header.jspf
new file mode 100644
index 0000000..6d50907
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi.webapp/web/resources/body-header.jspf
@@ -0,0 +1,17 @@
+<div class="menu">
+
+<h:outputLink value="."><h3>(RJ) <i>RServi</i><small> - Server</small></h3></h:outputLink>
+
+<h4>Configuration</h4>
+<ul>
+<li><h:outputLink value="conf-net.jsp"><h:outputText value="Net (RMI)"/></h:outputLink></li>
+<li><h:outputLink value="conf-pool.jsp"><h:outputText value="Pool"/></h:outputLink></li>
+<li><h:outputLink value="conf-r.jsp"><h:outputText value="R/RServi Nodes"/></h:outputLink></li>
+</ul>
+<h4>Status</h4>
+<ul>
+<li><h:outputLink value="status-poolnodes.jsp"><h:outputText value="Pool Nodes"/></h:outputLink></li>
+</ul>
+
+</div>
+<div class="content"><%-- content --%>
diff --git a/servi/org.eclipse.statet.rj.servi.webapp/web/resources/conf-net.jsp b/servi/org.eclipse.statet.rj.servi.webapp/web/resources/conf-net.jsp
new file mode 100644
index 0000000..669e1ac
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi.webapp/web/resources/conf-net.jsp
@@ -0,0 +1,82 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+<%@page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1" %>
+<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
+<%@taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
+<%@taglib uri="http://java.sun.com/jsf/core" prefix="f" %>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<%--
+ #=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================#
+--%>
+<f:view>
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
+<meta http-equiv="Content-Style-Type" content="text/css" />
+<link rel="stylesheet" type="text/css" href="css/style.css" />
+
+<title>(RJ) Configuration: General</title>
+</head>
+<body>
+<%@include file="body-header.jspf" %>
+
+<h2>Configuration: General</h2>
+
+<h:form id="net_config">
+	<h:messages errorClass="error" />
+	
+<h:panelGrid columns="3" styleClass="grid" columnClasses="label,input,info">
+	<f:facet name="header"><h:outputText value="RMI Parameters" /></f:facet>
+	
+	<h:outputLabel for="host_address" value="(1) Host address (IP/name):" accesskey="1" />
+	<h:inputText id="host_address" label="Host address (1)" value="#{netConfig.hostAddress}" required="false" size="40" />
+	<h:outputText>This setting is synchronized with the global Java property 'java.rmi.server.hostname'</h:outputText>
+	
+	<h:outputLabel for="eff_host_address" value="--> Resolved IP:" />
+	<h:inputText id="eff_host_address" label="Host address (1)" value="#{netConfig.effectiveHostaddress}" required="false" readonly="true" size="40" />
+	<h:outputText />
+	
+	<h:outputLabel for="rmi_registry_address_port" value="(2) RMI registry port:" accesskey="2" />
+	<h:inputText id="rmi_registry_address_port" label="RMI registry port (2)" value="#{netConfig.registryPort}" required="false" size="6" />
+	<h:outputText>(-1 &#x21d2; default)</h:outputText>
+	
+	<h:outputLabel for="rmi_registry_embed_enabled" value="(3) Start embedded registry:" accesskey="3" />
+	<h:selectBooleanCheckbox id="rmi_registry_embed_enabled" label="Start embedded registry (3)" value="#{netConfig.registryEmbed}" required="true" />
+	<h:outputText></h:outputText>
+	
+	<h:outputLabel for="ssl_enabled" value="(4) Enable SSL:" accesskey="4" />
+	<h:selectBooleanCheckbox id="ssl_enabled" label="Start embedded registry (4)" value="#{netConfig.SSLEnabled}" required="true" />
+	<h:outputText></h:outputText>
+	
+</h:panelGrid>
+	
+	<h:commandButton id="loadDefaults" value="Load Defaults" action="#{netConfig.actionLoadDefaults}" type="button" immediate="true" accesskey="L" />
+	<h:commandButton id="loadCurrent" value="Load Current" action="#{netConfig.actionLoadCurrent}" type="button" immediate="true" accesskey="C" />
+	<br/>
+	<h:commandButton id="restart" value="Apply and Restart" action="#{netConfig.actionRestart}" accesskey="R" />
+	<h:commandButton id="save" value="Save" action="#{netConfig.actionSave}" accesskey="S" />
+	<b>Changes require restart!</b>
+</h:form>
+
+<h:panelGrid columns="2" styleClass="grid" columnClasses=",,">
+	<f:facet name="header"><h:outputText value="Info" /></f:facet>
+	
+	<h:outputLabel for="eff_pool_address" value="RMI pool address:" />
+	<h:inputText id="eff_pool_address" value="#{netConfig.effectivePoolAddress}" required="false" size="40" />
+</h:panelGrid>
+
+<%@include file="body-footer.jspf" %>
+</body>
+</html>
+</f:view>
diff --git a/servi/org.eclipse.statet.rj.servi.webapp/web/resources/conf-pool.jsp b/servi/org.eclipse.statet.rj.servi.webapp/web/resources/conf-pool.jsp
new file mode 100644
index 0000000..70fa7f1
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi.webapp/web/resources/conf-pool.jsp
@@ -0,0 +1,101 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+<%@page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1" %>
+<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
+<%@taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
+<%@taglib uri="http://java.sun.com/jsf/core" prefix="f" %>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<%--
+ #=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================#
+--%>
+<f:view>
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
+<meta http-equiv="Content-Style-Type" content="text/css" />
+<link rel="stylesheet" type="text/css" href="css/style.css" />
+
+<title>(RJ) Configuration: Pool</title>
+</head>
+<body>
+<%@include file="body-header.jspf" %>
+
+<h2>Configuration: Pool</h2>
+
+<h:form id="pool_config">
+	<h:messages errorClass="error" />
+	
+<h:panelGrid columns="3" styleClass="grid" columnClasses="label,value,info special1">
+	<f:facet name="header"><h:outputText value="Parameters for dynamic pool" /></f:facet>
+	
+	<h:outputText/>
+	<h:outputText/>
+	<h:outputText>Startup new nodes if...</h:outputText>
+	
+	<h:outputLabel for="max_total_count" value="(1) Max total nodes (count):" accesskey="1" />
+	<h:inputText id="max_total_count" label="Max total nodes (1)" value="#{poolConfig.maxTotalCount}" required="true" />
+	<h:outputText>... total count smaller than (1) ...</h:outputText>
+	
+	<h:outputLabel for="min_idle_count" value="(2) Min idle nodes (count):" accesskey="2" />
+	<h:inputText id="min_idle_count" label="Min idle nodes (2)" value="#{poolConfig.minIdleCount}" required="true" />
+	<h:outputText>... and idle count smaller than (2).</h:outputText>
+	
+	<h:outputText/>
+	<h:outputText/>
+	<h:outputText>Evict idling nodes if...</h:outputText>
+	
+	<h:outputLabel for="max_idle_count" value="(3) Max idle nodes (count):" accesskey="3" />
+	<h:inputText id="max_idle_count" label="Max idle nodes (3)" value="#{poolConfig.maxIdleCount}" required="true" />
+	<h:outputText>... idle count greater than (3) ...</h:outputText>
+	
+	<h:outputLabel for="min_idle_millis" value="(4) Min node idle time (millisec):" accesskey="4" />
+	<h:inputText id="min_idle_millis" label="Min node idle time (4)" value="#{poolConfig.minIdleTime}" required="true" />
+	<h:outputText>... or idle count greater than (2) count and idle time greater than (4).</h:outputText>
+	
+	<h:outputText/>
+	<h:outputText/>
+	<h:outputText>When node is requested and max count nodes (1) is in use ...</h:outputText>
+	
+	<h:outputLabel for="max_wait_millis" value="(5) Max wait time (millisec):" accesskey="5" />
+	<h:inputText id="max_wait_millis" label="Max wait time (5)" value="#{poolConfig.maxWaitTime}" required="true"/>
+	<h:outputText>... wait for a free node until timeout (5).</h:outputText>
+	
+	<h:outputText/>
+	<h:outputText/>
+	<h:outputText>To keep healthy ...</h:outputText>
+	
+	<h:outputLabel for="max_usage_count" value="(6) Max node reuse (count):" accesskey="6" />
+	<h:inputText id="max_usage_count" label="Max node reuse (6)" value="#{poolConfig.maxUsageCount}" required="true" />
+	<h:outputText>... recycle a node maximal (6) times.</h:outputText>
+	
+	<h:outputText/>
+	<h:outputText/>
+	<h:outputText>When stopping the pool or single nodes:</h:outputText>
+	
+	<h:outputLabel for="eviction_timeout_millis" value="(7) Timeout when evicting node in use (millisec):" accesskey="7" />
+	<h:inputText id="eviction_timeout_millis" label="Timeout when evicting node (7)" value="#{poolConfig.evictionTimeout}" required="true" />
+	<h:outputText></h:outputText>
+</h:panelGrid>
+	
+	<h:commandButton id="loadDefaults" value="Load Defaults" action="#{poolConfig.actionLoadDefaults}" type="button" immediate="true" accesskey="L" />
+	<h:commandButton id="loadCurrent" value="Load Current" action="#{poolConfig.actionLoadCurrent}" type="button" immediate="true" accesskey="C" />
+	<br/>
+	<h:commandButton id="apply" value="Apply" action="#{poolConfig.actionApply}" accesskey="A" />
+	<h:commandButton id="saveAndApply" value="Save and Apply" action="#{poolConfig.actionSaveAndApply}" accesskey="S" />
+</h:form>
+
+<%@include file="body-footer.jspf" %>
+</body>
+</html>
+</f:view>
diff --git a/servi/org.eclipse.statet.rj.servi.webapp/web/resources/conf-r.jsp b/servi/org.eclipse.statet.rj.servi.webapp/web/resources/conf-r.jsp
new file mode 100644
index 0000000..5628941
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi.webapp/web/resources/conf-r.jsp
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+<%@page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1" %>
+<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
+<%@taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
+<%@taglib uri="http://java.sun.com/jsf/core" prefix="f" %>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<%--
+ #=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================#
+--%>
+<f:view>
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
+<meta http-equiv="Content-Style-Type" content="text/css" />
+<link rel="stylesheet" type="text/css" href="css/style.css" />
+
+<title>(RJ) Configuration: R/RJ Nodes</title>
+</head>
+<body>
+<%@include file="body-header.jspf" %>
+
+<h2>Configuration: R/RJ Nodes</h2>
+
+<h:form id="r_config">
+	<h:messages errorClass="error" />
+	
+<h:panelGrid columns="3" styleClass="grid" columnClasses="label,value,info">
+	<f:facet name="header"><h:outputText value="Parameters to start R" /></f:facet>
+	
+	<h:outputLabel for="java_home_path" value="(1) Java home (path):" accesskey="1" />
+	<h:inputText id="java_home_path" label="Java home (1)" value="#{rConfig.javaHome}" required="false" size="80" />
+	<h:outputText>(empty &#x21d2; same as the server)</h:outputText>
+	
+	<h:outputLabel for="java_cmd_args" value="(2) Java arguments:" accesskey="2" />
+	<h:inputTextarea id="java_cmd_args" label="Java arguments (2)" value="#{rConfig.javaArgs}" required="false" cols="76" rows="4" />
+	<h:outputText></h:outputText>
+	
+	<h:outputLabel for="r_home_path" value="(3) R home / R_HOME (path):" accesskey="3" />
+	<h:inputText id="r_home_path" label="R home / R_HOME (3)" value="#{rConfig.RHome}" required="true" size="80" />
+	<h:outputText></h:outputText>
+	
+	<h:outputLabel for="r_arch_code" value="(4) Architecture of binaries / R_ARCH:" accesskey="4" />
+	<h:inputText id="r_arch_code" label="Architecture / R_ARCH (4)" value="#{rConfig.RArch}" required="false" size="10" />
+	<h:outputText>(empty &#x21d2; autodetection)</h:outputText>
+	
+	<h:outputLabel for="r_libs_path" value="(5) R libraries / R_LIBS (path):" accesskey="5" />
+	<h:inputText id="r_libs_path" label="R libraries / R_LIBS (5)" value="#{rConfig.RLibsVariable}" required="false" size="80" />
+	<h:outputText>(optional)</h:outputText>
+	
+	<h:outputLabel for="base_wd_path" value="(6) Working directory (path):" accesskey="6" />
+	<h:inputText id="base_wd_path" label="Working directory (6)" value="#{rConfig.baseWorkingDirectory}" required="false" size="80" />
+	<h:outputText>(empty &#x21d2; default temp dir)</h:outputText>
+	
+	<h:outputLabel for="r_startup_snippet" value="(7) R startup snippet (complete R command per line):" accesskey="7" />
+	<h:inputTextarea id="r_startup_snippet" label="R startup snippet (7)" value="#{rConfig.RStartupSnippet}" required="false" cols="76" rows="4" />
+	<h:outputText />
+	
+	<h:outputLabel for="debug_console_enabled" value="(8) Enable debug console:" accesskey="8" />
+	<h:selectBooleanCheckbox id="debug_console_enabled" label="Enable debug console by default (8)" value="#{rConfig.enableConsole}" required="true" />
+	<h:outputText>Enables debug console automatically at startup (use only for development!)</h:outputText>
+	
+	<h:outputLabel for="verbose_console_enabled" value="(9) Enable verbose logging:" accesskey="9" />
+	<h:selectBooleanCheckbox id="verbose_console_enabled" label="Enable verbose logging (9)" value="#{rConfig.enableVerbose}" required="true" />
+	<h:outputText>Enables verbose logging and prevents deletion of the node directory</h:outputText>
+	
+</h:panelGrid>
+	
+	<h:commandButton id="loadDefaults" value="Load Defaults" action="#{rConfig.actionLoadDefaults}" type="button" immediate="true" accesskey="L" />
+	<h:commandButton id="loadCurrent" value="Load Current" action="#{rConfig.actionLoadCurrent}" type="button" immediate="true" accesskey="C" />
+	<br/>
+	<h:commandButton id="apply" value="Apply" action="#{rConfig.actionApply}" accesskey="A" />
+	<h:commandButton id="saveAndApply" value="Save and Apply" action="#{rConfig.actionSaveAndApply}" accesskey="S" />
+</h:form>
+
+<%@include file="body-footer.jspf" %>
+</body>
+</html>
+</f:view>
diff --git a/servi/org.eclipse.statet.rj.servi.webapp/web/resources/css/style.css b/servi/org.eclipse.statet.rj.servi.webapp/web/resources/css/style.css
new file mode 100644
index 0000000..bad8973
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi.webapp/web/resources/css/style.css
@@ -0,0 +1,79 @@
+@CHARSET "ISO-8859-1";
+
+div.menu {
+	border: 1px solid #000033;
+	background-color: #ddddee;
+	padding: 0.5em 0.5em 1em 0.5em; 
+	margin: 0 1.0em 0 0;
+	float: left;
+	width: 180px;
+}
+div.menu h3 {
+	margin: 0 0 0.5em 0;
+}
+	div.menu h4, div.menu ul {
+	margin: 0;
+}
+div.content {
+	margin-left: 240px;
+}
+
+.error {
+	color: #ff0000;
+}
+
+table.table1 {
+	border-spacing: 0;
+	border-collapse: collapse;
+}
+table.table1 th, table.grid th {
+	border-bottom: 2px solid black;
+	padding: 0.25em 0.5em;
+	text-align: left;
+	white-space: nowrap;
+}
+table.table1 td {
+	border-top: 1px solid black;
+	border-bottom: 1px solid black;
+	padding: 0.25em 0.5em;
+	vertical-align: top;
+	white-space: nowrap;
+}
+table.table1 th.spanleft, table.table1 td.spanleft {
+	padding-left: 0;
+	border-left: 0;
+}
+th.alignright, td.alignright {
+	text-align: right;
+}
+
+table.grid {
+	border-bottom: 1px solid black;
+	margin-top: 0.5em;
+	margin-bottom: 0.5em;
+}
+table.grid td {
+	vertical-align: top;
+	padding-left: 0.5em;
+	padding-right: 0.5em;
+}
+
+input[type="text"], textarea {
+	font-family: sans-serif;
+	font-size: 90%;
+}
+input[type="submit"] {
+	margin: 0.25em 0.5em;
+}
+.label {
+	white-space: nowrap;
+}
+td.label {
+	padding-right: 0;
+}
+td.info {
+	padding-left: 1em;
+}
+td.special1 {
+	font-style: italic;
+}
diff --git a/servi/org.eclipse.statet.rj.servi.webapp/web/resources/index.jsp b/servi/org.eclipse.statet.rj.servi.webapp/web/resources/index.jsp
new file mode 100644
index 0000000..8585eaf
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi.webapp/web/resources/index.jsp
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+<%@page language="java" contentType="text/html; charset=ISO-8859-1"
+    pageEncoding="ISO-8859-1"%>
+<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
+<%@taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
+<%@taglib uri="http://java.sun.com/jsf/core" prefix="f" %>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<%--
+ #=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================#
+--%>
+<f:view>
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
+<meta http-equiv="Content-Style-Type" content="text/css" />
+<link rel="stylesheet" type="text/css" href="css/style.css" />
+
+<title>(RJ) Welcome</title>
+</head>
+<body>
+<%@include file="body-header.jspf" %>
+
+<h2>Welcome</h2>
+
+<table class="grid">
+<tr><th colspan="2" scope="colgroup">Links</th></tr>
+<tr><td>StatET Project</td><td><a href="https://www.eclipse.org/statet">www.eclipse.org/statet</a></td></tr>
+<tr><td>R Project</td><td><a href="http://www.r-project.org">www.r-project.org</a></td></tr>
+</table>
+
+<table class="grid">
+<tr><th colspan="2" scope="colgroup">Sources</th></tr>
+<tr><td>RJ</td><td><a href="http://git.eclipse.org/c/statet/org.eclipse.statet-rj.git">git.eclipse.org/c/statet/org.eclipse.statet-rj.git</a></td></tr>
+</table>
+
+<hr/>
+
+<p>
+Copyright (c) 2007, 2017 Stephan Wahlbrink and others.</p>
+<p>
+This product includes software developed by The Apache Software Foundation
+(<a href="http://www.apache.org">www.apache.org</a>).</p>
+
+<%@include file="body-footer.jspf" %>
+</body>
+</html>
+</f:view>
diff --git a/servi/org.eclipse.statet.rj.servi.webapp/web/resources/sessionexpired.jsp b/servi/org.eclipse.statet.rj.servi.webapp/web/resources/sessionexpired.jsp
new file mode 100644
index 0000000..d74f2b9
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi.webapp/web/resources/sessionexpired.jsp
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+<%@page language="java" contentType="text/html; charset=ISO-8859-1"
+    pageEncoding="ISO-8859-1"%>
+<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
+<%@taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
+<%@taglib uri="http://java.sun.com/jsf/core" prefix="f" %>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<f:view>
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
+<meta http-equiv="Content-Style-Type" content="text/css" />
+<link rel="stylesheet" type="text/css" href="css/style.css" />
+
+<title>(RJ) Error</title>
+</head>
+<body>
+<%@include file="body-header.jspf" %>
+
+Sorry, your session expired.
+
+<%@include file="body-footer.jspf" %>
+</body>
+</html>
+</f:view>
diff --git a/servi/org.eclipse.statet.rj.servi.webapp/web/resources/status-poolnodes.jsp b/servi/org.eclipse.statet.rj.servi.webapp/web/resources/status-poolnodes.jsp
new file mode 100644
index 0000000..90e92f8
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi.webapp/web/resources/status-poolnodes.jsp
@@ -0,0 +1,156 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+<%@page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1" %>
+<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
+<%@taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
+<%@taglib uri="http://java.sun.com/jsf/core" prefix="f" %>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<%--
+ #=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================#
+--%>
+<f:view>
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
+<meta http-equiv="Content-Style-Type" content="text/css" />
+<link rel="stylesheet" type="text/css" href="css/style.css" />
+
+<title>(RJ) Status: Overview Pool Nodes</title>
+</head>
+
+<body onload="<c:if test="${poolStatus.autoRefreshEnabled}">window.setTimeout('javascript:document.getElementById(\'pool_nodes:refresh\').click()', 5000)</c:if>">
+
+<%@include file="body-header.jspf" %>
+
+<h2>Status: Current Pool Nodes</h2>
+
+<h:panelGrid columns="2" styleClass="grid" columnClasses=",," style="border-bottom: 2px solid black">
+	<h:outputLabel for="eff_pool_address" value="RMI pool address:" />
+	<h:inputText id="eff_pool_address" value="#{netConfig.effectivePoolAddress}" readonly="true" size="40" />
+</h:panelGrid>
+
+<h:form id="pool_nodes">
+	<h:messages errorClass="error" />
+	
+<h:inputHidden value="#{poolStatus.autoRefreshEnabled}" immediate="true" />
+<h:commandButton id="refresh" value="Refresh" action="#{poolStatus.actionRefresh}" />
+<c:if test="${!poolStatus.autoRefreshEnabled}">
+<h:commandButton id="enableAutoRefresh" value="Enable Auto Refresh" action="#{poolStatus.actionEnableAutoRefresh}" />
+</c:if>
+<c:if test="${poolStatus.autoRefreshEnabled}">
+<h:commandButton id="disableAutoRefresh" value="Disable Auto Refresh" action="#{poolStatus.actionDisableAutoRefresh}" immediate="true" />
+</c:if>
+
+<br/>
+
+<h:panelGrid columns="3" styleClass="table1" columnClasses=",alignright,alignright">
+	<f:facet name="header"><h:outputText value="Summary" /></f:facet>
+	
+	<h:outputText />
+	<h:outputText value="Current" />
+	<h:outputText value="Max" />
+	
+	<h:outputText value="Idling:" />
+	<h:outputText value="#{poolStatus.numIdling}" />
+	<h:outputText value="#{poolStatus.maxIdling}" />
+	
+	<h:outputText value="In use:" />
+	<h:outputText value="#{poolStatus.numInUse}" />
+	<h:outputText value="#{poolStatus.maxInUse}" />
+	
+	<h:outputText value="Total:" />
+	<h:outputText value="#{poolStatus.numTotal}" />
+	<h:outputText value="#{poolStatus.maxTotal}" />
+</h:panelGrid>
+	
+<br/>
+	
+<h:dataTable value="#{poolStatus.nodeStates}" var="dataItem" styleClass="table1" columnClasses=",,spanleft,,alignright">
+	<h:column>
+		<f:facet name="header">
+			<h:outputText value="Created" />
+		</f:facet>
+		<h:outputText value="#{dataItem.creationTime}" >
+			<f:convertDateTime pattern="yyyy-MM-dd HH:mm:ss"/> 
+		</h:outputText>
+	</h:column>
+	
+	<h:column>
+		<f:facet name="header">
+			<h:outputText value="State" />
+		</f:facet>
+		<h:outputText value="#{dataItem.state}" />
+	</h:column>
+	
+	<h:column headerClass="spanleft">
+		<f:facet name="header">
+			<h:outputText value="" />
+		</f:facet>
+		(<h:outputText value="#{dataItem.stateTime - poolStatus.stamp}" >
+			<f:converter converterId="convertDuration" /> 
+		</h:outputText>)
+	</h:column>
+	
+	<h:column>
+		<f:facet name="header">
+			<h:outputText value="Client" />
+		</f:facet>
+		<h:outputText value="#{dataItem.currentClientId}" />
+	</h:column>
+	
+	<h:column>
+		<f:facet name="header">
+			<h:outputText value="Usage" />
+		</f:facet>
+		<h:outputText value="#{dataItem.usageCount}" />
+	</h:column>
+	
+	<h:column>
+		<f:facet name="header">
+			<h:outputText value="Debug Console" />
+		</f:facet>
+		<h:selectBooleanCheckbox value="#{dataItem.consoleEnabled}" readonly="true" disabled="true" />
+		<h:inputText value="#{dataItem.RMIAddress}" readonly="true" size="40" />
+		<h:outputText value=" " />
+		<h:commandLink value="On" action="#{dataItem.actionEnableConsole}" rendered="#{!dataItem.consoleEnabled}" />
+		<h:commandLink value="Off" action="#{dataItem.actionDisableConsole}" rendered="#{dataItem.consoleEnabled}" />
+	</h:column>
+	
+	<h:column>
+		<f:facet name="header">
+			<h:outputText value="Evict" />
+		</f:facet>
+		<h:commandLink value="Stop" action="#{dataItem.actionStop}" />
+		<h:outputText value=" " />
+		<h:commandLink value="Kill" action="#{dataItem.actionKill}" />
+	</h:column>
+	
+</h:dataTable>
+
+<h:panelGrid columns="2" styleClass="grid" columnClasses=",info">
+	<f:facet name="header"><h:outputText value="Test Actions" /></f:facet>
+	
+	<h:commandLink action="#{debug.actionNewNode}" immediate="true">Get node (<code>RServiPool#getRServi</code>)</h:commandLink>
+	<h:outputText value="acquire node from pool" />
+	
+	<h:commandLink action="#{debug.actionCloseAllNodes}" immediate="true">Close all nodes (<code>RServi#close</code>)</h:commandLink>
+	<h:outputText value="return acquired nodes to pool" />
+</h:panelGrid>
+	
+</h:form>
+
+<%@include file="body-footer.jspf" %>
+</body>
+</html>
+</f:view>
diff --git a/servi/org.eclipse.statet.rj.servi/.classpath b/servi/org.eclipse.statet.rj.servi/.classpath
new file mode 100644
index 0000000..b323920
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi/.classpath
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8">
+		<attributes>
+			<attribute name="owner.project.facets" value="java"/>
+		</attributes>
+	</classpathentry>
+	<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+	<classpathentry kind="src" path="src"/>
+	<classpathentry kind="src" path="srcServer"/>
+	<classpathentry kind="src" path="srcServiPool"/>
+	<classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/servi/org.eclipse.statet.rj.servi/.gitignore b/servi/org.eclipse.statet.rj.servi/.gitignore
new file mode 100644
index 0000000..5e56e04
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi/.gitignore
@@ -0,0 +1 @@
+/bin
diff --git a/servi/org.eclipse.statet.rj.servi/.project b/servi/org.eclipse.statet.rj.servi/.project
new file mode 100644
index 0000000..3ce8a73
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi/.project
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>org.eclipse.statet.rj.servi</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.wst.common.project.facet.core.builder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.jdt.core.javabuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.pde.ManifestBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.pde.SchemaBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.pde.PluginNature</nature>
+		<nature>org.eclipse.jdt.core.javanature</nature>
+		<nature>org.eclipse.wst.common.modulecore.ModuleCoreNature</nature>
+		<nature>org.eclipse.wst.common.project.facet.core.nature</nature>
+	</natures>
+</projectDescription>
diff --git a/servi/org.eclipse.statet.rj.servi/.settings/org.eclipse.core.resources.prefs b/servi/org.eclipse.statet.rj.servi/.settings/org.eclipse.core.resources.prefs
new file mode 100644
index 0000000..99f26c0
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi/.settings/org.eclipse.core.resources.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+encoding/<project>=UTF-8
diff --git a/servi/org.eclipse.statet.rj.servi/.settings/org.eclipse.core.runtime.prefs b/servi/org.eclipse.statet.rj.servi/.settings/org.eclipse.core.runtime.prefs
new file mode 100644
index 0000000..5a0ad22
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi/.settings/org.eclipse.core.runtime.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+line.separator=\n
diff --git a/servi/org.eclipse.statet.rj.servi/.settings/org.eclipse.jdt.core.prefs b/servi/org.eclipse.statet.rj.servi/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000..ccb1eaa
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,325 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.codeComplete.argumentPrefixes=
+org.eclipse.jdt.core.codeComplete.argumentSuffixes=
+org.eclipse.jdt.core.codeComplete.fieldPrefixes=
+org.eclipse.jdt.core.codeComplete.fieldSuffixes=
+org.eclipse.jdt.core.codeComplete.localPrefixes=
+org.eclipse.jdt.core.codeComplete.localSuffixes=
+org.eclipse.jdt.core.codeComplete.staticFieldPrefixes=
+org.eclipse.jdt.core.codeComplete.staticFieldSuffixes=
+org.eclipse.jdt.core.codeComplete.staticFinalFieldPrefixes=
+org.eclipse.jdt.core.codeComplete.staticFinalFieldSuffixes=
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=1.8
+org.eclipse.jdt.core.compiler.debug.lineNumber=generate
+org.eclipse.jdt.core.compiler.debug.localVariable=generate
+org.eclipse.jdt.core.compiler.debug.sourceFile=generate
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.source=1.8
+org.eclipse.jdt.core.formatter.align_fields_grouping_blank_lines=2147483647
+org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_assignment=0
+org.eclipse.jdt.core.formatter.alignment_for_binary_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_compact_if=16
+org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=80
+org.eclipse.jdt.core.formatter.alignment_for_enum_constants=0
+org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16
+org.eclipse.jdt.core.formatter.alignment_for_expressions_in_for_loop_header=0
+org.eclipse.jdt.core.formatter.alignment_for_method_declaration=0
+org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16
+org.eclipse.jdt.core.formatter.alignment_for_parameterized_type_references=0
+org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_resources_in_try=85
+org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=16
+org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_type_arguments=0
+org.eclipse.jdt.core.formatter.alignment_for_type_parameters=0
+org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch=16
+org.eclipse.jdt.core.formatter.blank_lines_after_imports=2
+org.eclipse.jdt.core.formatter.blank_lines_after_package=1
+org.eclipse.jdt.core.formatter.blank_lines_before_field=0
+org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=1
+org.eclipse.jdt.core.formatter.blank_lines_before_imports=1
+org.eclipse.jdt.core.formatter.blank_lines_before_member_type=1
+org.eclipse.jdt.core.formatter.blank_lines_before_method=1
+org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=2
+org.eclipse.jdt.core.formatter.blank_lines_before_package=1
+org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=1
+org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=1
+org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_block=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_lambda_body=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=false
+org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=false
+org.eclipse.jdt.core.formatter.comment.format_block_comments=true
+org.eclipse.jdt.core.formatter.comment.format_header=false
+org.eclipse.jdt.core.formatter.comment.format_html=true
+org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=true
+org.eclipse.jdt.core.formatter.comment.format_line_comments=true
+org.eclipse.jdt.core.formatter.comment.format_source_code=true
+org.eclipse.jdt.core.formatter.comment.indent_parameter_description=false
+org.eclipse.jdt.core.formatter.comment.indent_root_tags=true
+org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert
+org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=do not insert
+org.eclipse.jdt.core.formatter.comment.line_length=100
+org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries=false
+org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries=true
+org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments=false
+org.eclipse.jdt.core.formatter.compact_else_if=true
+org.eclipse.jdt.core.formatter.continuation_indentation=2
+org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=2
+org.eclipse.jdt.core.formatter.disabling_tag=@formatter\:off
+org.eclipse.jdt.core.formatter.enabling_tag=@formatter\:on
+org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false
+org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true
+org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true
+org.eclipse.jdt.core.formatter.indent_empty_lines=true
+org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true
+org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true
+org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true
+org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=false
+org.eclipse.jdt.core.formatter.indentation.size=4
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_enum_constant=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_label=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_type_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert
+org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert
+org.eclipse.jdt.core.formatter.insert_space_after_lambda_arrow=insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources=insert
+org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert
+org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=insert
+org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert
+org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw=insert
+org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.join_lines_in_comments=true
+org.eclipse.jdt.core.formatter.join_wrapped_lines=true
+org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=false
+org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false
+org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=false
+org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false
+org.eclipse.jdt.core.formatter.lineSplit=100
+org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false
+org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=false
+org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0
+org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=1
+org.eclipse.jdt.core.formatter.parentheses_positions_in_annotation=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_catch_clause=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_enum_constant_declaration=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_for_statment=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_if_while_statement=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_lambda_declaration=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_method_delcaration=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_method_invocation=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_switch_statement=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_try_clause=common_lines
+org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=true
+org.eclipse.jdt.core.formatter.tabulation.char=tab
+org.eclipse.jdt.core.formatter.tabulation.size=4
+org.eclipse.jdt.core.formatter.use_on_off_tags=false
+org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false
+org.eclipse.jdt.core.formatter.wrap_before_assignment_operator=false
+org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true
+org.eclipse.jdt.core.formatter.wrap_before_conditional_operator=false
+org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch=true
+org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true
+org.eclipse.jdt.core.javaFormatter=org.eclipse.jdt.core.defaultJavaFormatter
diff --git a/servi/org.eclipse.statet.rj.servi/.settings/org.eclipse.jdt.ui.prefs b/servi/org.eclipse.statet.rj.servi/.settings/org.eclipse.jdt.ui.prefs
new file mode 100644
index 0000000..e62a4f5
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi/.settings/org.eclipse.jdt.ui.prefs
@@ -0,0 +1,131 @@
+cleanup.add_default_serial_version_id=true
+cleanup.add_generated_serial_version_id=false
+cleanup.add_missing_annotations=true
+cleanup.add_missing_deprecated_annotations=true
+cleanup.add_missing_methods=false
+cleanup.add_missing_nls_tags=false
+cleanup.add_missing_override_annotations=true
+cleanup.add_missing_override_annotations_interface_methods=true
+cleanup.add_serial_version_id=false
+cleanup.always_use_blocks=true
+cleanup.always_use_parentheses_in_expressions=true
+cleanup.always_use_this_for_non_static_field_access=true
+cleanup.always_use_this_for_non_static_method_access=false
+cleanup.convert_functional_interfaces=false
+cleanup.convert_to_enhanced_for_loop=false
+cleanup.correct_indentation=false
+cleanup.format_source_code=false
+cleanup.format_source_code_changes_only=false
+cleanup.insert_inferred_type_arguments=false
+cleanup.make_local_variable_final=true
+cleanup.make_parameters_final=true
+cleanup.make_private_fields_final=true
+cleanup.make_type_abstract_if_missing_method=false
+cleanup.make_variable_declarations_final=true
+cleanup.never_use_blocks=false
+cleanup.never_use_parentheses_in_expressions=false
+cleanup.organize_imports=true
+cleanup.qualify_static_field_accesses_with_declaring_class=false
+cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true
+cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=false
+cleanup.qualify_static_member_accesses_with_declaring_class=true
+cleanup.qualify_static_method_accesses_with_declaring_class=false
+cleanup.remove_private_constructors=true
+cleanup.remove_redundant_type_arguments=true
+cleanup.remove_trailing_whitespaces=false
+cleanup.remove_trailing_whitespaces_all=true
+cleanup.remove_trailing_whitespaces_ignore_empty=false
+cleanup.remove_unnecessary_casts=true
+cleanup.remove_unnecessary_nls_tags=true
+cleanup.remove_unused_imports=true
+cleanup.remove_unused_local_variables=false
+cleanup.remove_unused_private_fields=true
+cleanup.remove_unused_private_members=false
+cleanup.remove_unused_private_methods=true
+cleanup.remove_unused_private_types=true
+cleanup.sort_members=false
+cleanup.sort_members_all=false
+cleanup.use_anonymous_class_creation=false
+cleanup.use_blocks=true
+cleanup.use_blocks_only_for_return_and_throw=false
+cleanup.use_lambda=true
+cleanup.use_parentheses_in_expressions=false
+cleanup.use_this_for_non_static_field_access=true
+cleanup.use_this_for_non_static_field_access_only_if_necessary=false
+cleanup.use_this_for_non_static_method_access=true
+cleanup.use_this_for_non_static_method_access_only_if_necessary=true
+cleanup.use_type_arguments=false
+cleanup_profile=_StatET
+cleanup_settings_version=2
+eclipse.preferences.version=1
+editor_save_participant_org.eclipse.jdt.ui.postsavelistener.cleanup=true
+formatter_profile=_StatET
+formatter_settings_version=12
+org.eclipse.jdt.ui.exception.name=e
+org.eclipse.jdt.ui.gettersetter.use.is=true
+org.eclipse.jdt.ui.ignorelowercasenames=true
+org.eclipse.jdt.ui.importorder=\#;java;javax;com.ibm.icu;org.osgi;org.eclipse;;org.eclipse.statet.jcommons;org.eclipse.statet.ecommons;org.eclipse.statet;
+org.eclipse.jdt.ui.javadoc=true
+org.eclipse.jdt.ui.keywordthis=true
+org.eclipse.jdt.ui.ondemandthreshold=99
+org.eclipse.jdt.ui.overrideannotation=true
+org.eclipse.jdt.ui.staticondemandthreshold=99
+org.eclipse.jdt.ui.text.custom_code_templates=<?xml version\="1.0" encoding\="UTF-8" standalone\="no"?><templates><template autoinsert\="true" context\="gettercomment_context" deleted\="false" description\="Comment for getter method" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.gettercomment" name\="gettercomment">/**\n * @return the ${bare_field_name}\n */</template><template autoinsert\="true" context\="settercomment_context" deleted\="false" description\="Comment for setter method" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.settercomment" name\="settercomment">/**\n * @param ${param} the ${bare_field_name} to set\n */</template><template autoinsert\="true" context\="constructorcomment_context" deleted\="false" description\="Comment for created constructors" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.constructorcomment" name\="constructorcomment">/**\n * ${tags}\n */</template><template autoinsert\="false" context\="filecomment_context" deleted\="false" description\="Comment for created Java files" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.filecomment" name\="filecomment">/*\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\#\n \# Copyright (c) ${year} ${user} and others.\n # \n # This program and the accompanying materials are made available under the\n # terms of the Eclipse Public License 2.0 which is available at\n # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n # which is available at https://www.apache.org/licenses/LICENSE-2.0.\n # \n # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n # \n \# Contributors\:\n \#     ${user} - initial API and implementation\n \#\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=*/</template><template autoinsert\="false" context\="typecomment_context" deleted\="false" description\="Comment for created types" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.typecomment" name\="typecomment">/**\n * \n * ${tags}\n */</template><template autoinsert\="true" context\="fieldcomment_context" deleted\="false" description\="Comment for fields" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.fieldcomment" name\="fieldcomment">/**\n * \n */</template><template autoinsert\="true" context\="methodcomment_context" deleted\="false" description\="Comment for non-overriding methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.methodcomment" name\="methodcomment">/**\n * ${tags}\n */</template><template autoinsert\="false" context\="overridecomment_context" deleted\="false" description\="Comment for overriding methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.overridecomment" name\="overridecomment"/><template autoinsert\="true" context\="delegatecomment_context" deleted\="false" description\="Comment for delegate methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.delegatecomment" name\="delegatecomment">/**\n * ${tags}\n * ${see_to_target}\n */</template><template autoinsert\="false" context\="newtype_context" deleted\="false" description\="Newly created files" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.newtype" name\="newtype">${filecomment}\n\n${package_declaration}\n\n${typecomment}\n${type_declaration}</template><template autoinsert\="true" context\="classbody_context" deleted\="false" description\="Code in new class type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.classbody" name\="classbody">\n</template><template autoinsert\="true" context\="interfacebody_context" deleted\="false" description\="Code in new interface type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.interfacebody" name\="interfacebody">\n</template><template autoinsert\="true" context\="enumbody_context" deleted\="false" description\="Code in new enum type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.enumbody" name\="enumbody">\n</template><template autoinsert\="true" context\="annotationbody_context" deleted\="false" description\="Code in new annotation type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.annotationbody" name\="annotationbody">\n</template><template autoinsert\="true" context\="catchblock_context" deleted\="false" description\="Code in new catch blocks" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.catchblock" name\="catchblock">// ${todo} Auto-generated catch block\n${exception_var}.printStackTrace();</template><template autoinsert\="true" context\="methodbody_context" deleted\="false" description\="Code in created method stubs" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.methodbody" name\="methodbody">// ${todo} Auto-generated method stub\n${body_statement}</template><template autoinsert\="true" context\="constructorbody_context" deleted\="false" description\="Code in created constructor stubs" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.constructorbody" name\="constructorbody">${body_statement}\n// ${todo} Auto-generated constructor stub</template><template autoinsert\="true" context\="getterbody_context" deleted\="false" description\="Code in created getters" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.getterbody" name\="getterbody">return ${field};</template><template autoinsert\="true" context\="setterbody_context" deleted\="false" description\="Code in created setters" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.setterbody" name\="setterbody">${field} \= ${param};</template></templates>
+sp_cleanup.add_default_serial_version_id=true
+sp_cleanup.add_generated_serial_version_id=false
+sp_cleanup.add_missing_annotations=true
+sp_cleanup.add_missing_deprecated_annotations=true
+sp_cleanup.add_missing_methods=false
+sp_cleanup.add_missing_nls_tags=false
+sp_cleanup.add_missing_override_annotations=true
+sp_cleanup.add_missing_override_annotations_interface_methods=true
+sp_cleanup.add_serial_version_id=false
+sp_cleanup.always_use_blocks=true
+sp_cleanup.always_use_parentheses_in_expressions=true
+sp_cleanup.always_use_this_for_non_static_field_access=true
+sp_cleanup.always_use_this_for_non_static_method_access=false
+sp_cleanup.convert_functional_interfaces=false
+sp_cleanup.convert_to_enhanced_for_loop=false
+sp_cleanup.correct_indentation=false
+sp_cleanup.format_source_code=false
+sp_cleanup.format_source_code_changes_only=false
+sp_cleanup.insert_inferred_type_arguments=false
+sp_cleanup.make_local_variable_final=true
+sp_cleanup.make_parameters_final=true
+sp_cleanup.make_private_fields_final=true
+sp_cleanup.make_type_abstract_if_missing_method=false
+sp_cleanup.make_variable_declarations_final=false
+sp_cleanup.never_use_blocks=false
+sp_cleanup.never_use_parentheses_in_expressions=false
+sp_cleanup.on_save_use_additional_actions=true
+sp_cleanup.organize_imports=true
+sp_cleanup.qualify_static_field_accesses_with_declaring_class=false
+sp_cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true
+sp_cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=false
+sp_cleanup.qualify_static_member_accesses_with_declaring_class=true
+sp_cleanup.qualify_static_method_accesses_with_declaring_class=false
+sp_cleanup.remove_private_constructors=true
+sp_cleanup.remove_redundant_type_arguments=true
+sp_cleanup.remove_trailing_whitespaces=false
+sp_cleanup.remove_trailing_whitespaces_all=false
+sp_cleanup.remove_trailing_whitespaces_ignore_empty=true
+sp_cleanup.remove_unnecessary_casts=true
+sp_cleanup.remove_unnecessary_nls_tags=false
+sp_cleanup.remove_unused_imports=false
+sp_cleanup.remove_unused_local_variables=false
+sp_cleanup.remove_unused_private_fields=false
+sp_cleanup.remove_unused_private_members=false
+sp_cleanup.remove_unused_private_methods=false
+sp_cleanup.remove_unused_private_types=true
+sp_cleanup.sort_members=false
+sp_cleanup.sort_members_all=false
+sp_cleanup.use_anonymous_class_creation=false
+sp_cleanup.use_blocks=true
+sp_cleanup.use_blocks_only_for_return_and_throw=false
+sp_cleanup.use_lambda=false
+sp_cleanup.use_parentheses_in_expressions=false
+sp_cleanup.use_this_for_non_static_field_access=true
+sp_cleanup.use_this_for_non_static_field_access_only_if_necessary=false
+sp_cleanup.use_this_for_non_static_method_access=true
+sp_cleanup.use_this_for_non_static_method_access_only_if_necessary=true
+sp_cleanup.use_type_arguments=false
diff --git a/servi/org.eclipse.statet.rj.servi/.settings/org.eclipse.wst.common.component b/servi/org.eclipse.statet.rj.servi/.settings/org.eclipse.wst.common.component
new file mode 100644
index 0000000..1cb3c70
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi/.settings/org.eclipse.wst.common.component
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project-modules id="moduleCoreId" project-version="1.5.0">
+    <wb-module deploy-name="org.eclipse.statet.rj.servi">
+        <wb-resource deploy-path="/" source-path="/src"/>
+        <wb-resource deploy-path="/" source-path="/srcServer"/>
+        <wb-resource deploy-path="/" source-path="/srcServiPool"/>
+    </wb-module>
+</project-modules>
diff --git a/servi/org.eclipse.statet.rj.servi/.settings/org.eclipse.wst.common.project.facet.core.xml b/servi/org.eclipse.statet.rj.servi/.settings/org.eclipse.wst.common.project.facet.core.xml
new file mode 100644
index 0000000..f4ef8aa
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi/.settings/org.eclipse.wst.common.project.facet.core.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<faceted-project>
+  <installed facet="java" version="1.8"/>
+</faceted-project>
diff --git a/servi/org.eclipse.statet.rj.servi/META-INF/MANIFEST.MF b/servi/org.eclipse.statet.rj.servi/META-INF/MANIFEST.MF
new file mode 100644
index 0000000..1cb545f
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi/META-INF/MANIFEST.MF
@@ -0,0 +1,21 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-SymbolicName: org.eclipse.statet.rj.servi;singleton:=true
+Bundle-Version: 2.1.0.qualifier
+Bundle-Vendor: Eclipse.org
+Bundle-Name: StatET RJ - RServi
+Bundle-ActivationPolicy: lazy
+Bundle-RequiredExecutionEnvironment: JavaSE-1.8
+Require-Bundle: org.eclipse.statet.ecommons.runtime.core;bundle-version="1.1.0",
+ org.eclipse.statet.ecommons.rmi.core;bundle-version="1.4.0",
+ org.eclipse.statet.rj.data;bundle-version="[2.1.0,2.2.0)",
+ org.eclipse.statet.rj.server;bundle-version="[2.1.0,2.2.0)",
+ org.eclipse.statet.rj.services.core;bundle-version="[2.1.0,2.2.0)";visibility:=reexport,
+ org.eclipse.statet.rj.client;bundle-version="[2.1.0,2.2.0)",
+ org.apache.commons.pool
+Import-Package: org.eclipse.statet.jcommons.collections;version="1.0.0",
+ org.eclipse.statet.jcommons.lang;version="1.0.0"
+Export-Package: org.eclipse.statet.internal.rj.servi;x-friends:="org.eclipse.statet.rj.tests",
+ org.eclipse.statet.rj.servi;version="1.2.0",
+ org.eclipse.statet.rj.servi.node,
+ org.eclipse.statet.rj.servi.pool
diff --git a/servi/org.eclipse.statet.rj.servi/about.html b/servi/org.eclipse.statet.rj.servi/about.html
new file mode 100644
index 0000000..e71ae66
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi/about.html
@@ -0,0 +1,37 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+		"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+<title>About</title>
+</head>
+<body lang="EN-US">
+<h2>About This Content</h2>
+
+<p>December 1, 2017</p>
+<h3>License</h3>
+
+<p>
+	The Eclipse Foundation makes available all content in this plug-in
+	(&quot;Content&quot;). Unless otherwise indicated below, the Content
+	is provided to you under the terms and conditions of the Eclipse
+	Public License Version 2.0 (&quot;EPL&quot;), or the Apache License,
+	Version 2.0 (AL). A copy of the EPL is available at <a href="https://www.eclipse.org/legal/epl-2.0">https://www.eclipse.org/legal/epl-2.0</a>.
+	For purposes of the EPL, &quot;Program&quot; will mean the Content.
+	A copy of the AL is available at <a href="https://www.apache.org/licenses/LICENSE-2.0">https://www.apache.org/licenses/LICENSE-2.0</a>.
+</p>
+
+<p>
+	If you did not receive this Content directly from the Eclipse
+	Foundation, the Content is being redistributed by another party
+	(&quot;Redistributor&quot;) and different terms and conditions may
+	apply to your use of any object code in the Content. Check the
+	Redistributor's license that was provided with the Content. If no such
+	license exists, contact the Redistributor. Unless otherwise indicated
+	below, the terms and conditions of the EPL or AL still apply to any
+	source code in the Content and such source code may be obtained at <a
+	href="https://www.eclipse.org/">https://www.eclipse.org</a>.
+</p>
+
+</body>
+</html>
diff --git a/servi/org.eclipse.statet.rj.servi/build.properties b/servi/org.eclipse.statet.rj.servi/build.properties
new file mode 100644
index 0000000..625de79
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi/build.properties
@@ -0,0 +1,16 @@
+source..= src/,\
+          srcServer/,\
+          srcServiPool/
+output..= bin/
+extra..= platform:/plugin/org.eclipse.osgi,\
+         platform:/plugin/org.eclipse.equinox.common,\
+         platform:/plugin/org.eclipse.core.runtime
+javacDefaultEncoding..= UTF-8
+
+bin.includes= META-INF/,\
+              .,\
+              plugin.xml,\
+              about.html,\
+              asl-v20.txt,\
+              NOTICE.txt
+src.includes= .settings/org.eclipse.core.resources.prefs
diff --git a/servi/org.eclipse.statet.rj.servi/plugin.xml b/servi/org.eclipse.statet.rj.servi/plugin.xml
new file mode 100644
index 0000000..4ec0dab
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi/plugin.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<?eclipse version="3.4"?>
+<!--
+ #=============================================================================#
+ # Copyright (c) 2011, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================#
+-->
+
+<plugin>
+   
+   <extension
+         point="org.eclipse.statet.ecommons.rmi.ERegistry">
+      <codebaseEntry
+            pluginId="org.eclipse.statet.rj.server"/>
+   </extension>
+   
+</plugin>
diff --git a/servi/org.eclipse.statet.rj.servi/src/org/eclipse/statet/internal/rj/servi/LocalNodeFactory.java b/servi/org.eclipse.statet.rj.servi/src/org/eclipse/statet/internal/rj/servi/LocalNodeFactory.java
new file mode 100644
index 0000000..b1aa907
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi/src/org/eclipse/statet/internal/rj/servi/LocalNodeFactory.java
@@ -0,0 +1,639 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.internal.rj.servi;
+
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.rmi.NotBoundException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+
+import org.eclipse.statet.jcommons.collections.CollectionUtils;
+import org.eclipse.statet.jcommons.collections.ImCollections;
+import org.eclipse.statet.jcommons.collections.ImList;
+
+import org.eclipse.statet.ecommons.rmi.core.RMIAddress;
+import org.eclipse.statet.ecommons.rmi.core.RMIRegistry;
+
+import org.eclipse.statet.rj.RjException;
+import org.eclipse.statet.rj.RjInvalidConfigurationException;
+import org.eclipse.statet.rj.server.Server;
+import org.eclipse.statet.rj.server.ServerLogin;
+import org.eclipse.statet.rj.server.util.LocalREnv;
+import org.eclipse.statet.rj.server.util.RJContext;
+import org.eclipse.statet.rj.server.util.ServerUtils;
+import org.eclipse.statet.rj.servi.node.RServiNode;
+import org.eclipse.statet.rj.servi.node.RServiNodeConfig;
+
+
+public class LocalNodeFactory implements NodeFactory {
+	
+	
+	public static final ImList<String> CODEBASE_LIBS= ImCollections.newList(
+			ServerUtils.RJ_SERVER_ID );
+	
+	private static final Set<String> EXCLUDE_ENV_VAR_NAMES= ImCollections.newSet(
+			"CLASSPATH", "R_HOME");
+	
+	private static void copySystemProperty(final String key, final List<String> command) {
+		final String property= System.getProperty(key);
+		if (property != null) {
+			command.add("-D" + key + "=" + property);
+		}
+	}
+	
+	private static void copySystemPropertyPath(final String key, final List<String> command) {
+		String property= System.getProperty(key);
+		if (property != null) {
+			if (!new File(property).isAbsolute()) {
+				property= new File(System.getProperty("user.dir"), property).getPath();
+			}
+			command.add("-D" + key + "=" + property);
+		}
+	}
+	
+	private static List<String> createSSLPropertyArgs() {
+		final List<String> args= new ArrayList<>();
+		copySystemPropertyPath("javax.net.ssl.keyStore", args);
+		copySystemProperty("javax.net.ssl.keyStorePassword", args);
+		copySystemPropertyPath("javax.net.ssl.trustStore", args);
+		copySystemProperty("javax.net.ssl.trustStorePassword", args);
+		return args;
+	}
+	
+	private static class ProcessConfig {
+		final Map<String, String> addEnv= new HashMap<>();
+		final List<String> command= new ArrayList<>();
+		int nameCommandIdx= -1;
+		String baseWd;
+		String authConfig;
+		String rStartupSnippet;
+	}
+	
+	
+	private final String poolId;
+	private RServiNodeConfig baseConfig;
+	private final RJContext context;
+	private final ImList<String> libIds;
+	
+	private ProcessConfig processConfig;
+	
+	private String errorMessage= null;
+	
+	private RMIRegistry nodeRegistry;
+	
+	private boolean verbose;
+	
+	private long timeoutNanos= TimeUnit.SECONDS.toNanos(30);
+	
+	private final List<String> sslPropertyArgs;
+	
+	
+	public LocalNodeFactory(final String poolId,
+			final RJContext context, final List<String> libIds) {
+		if (poolId == null) {
+			throw new NullPointerException("poolId");
+		}
+		if (context == null) {
+			throw new NullPointerException("context");
+		}
+		this.poolId= poolId;
+		this.context= context;
+		this.libIds= ImCollections.toList(libIds);
+		
+		this.sslPropertyArgs= createSSLPropertyArgs();
+	}
+	
+	
+	@Override
+	public void setRegistry(final RMIRegistry registry) {
+		this.nodeRegistry= registry;
+	}
+	
+	@Override
+	public void setConfig(final RServiNodeConfig config) throws RjInvalidConfigurationException {
+		final ProcessConfig p= new ProcessConfig();
+		final StringBuilder sb= new StringBuilder();
+		
+		// R home
+		final String rHome;
+		{	String value= config.getRHome();
+			if (value == null || value.length() == 0) {
+				value= config.getEnvironmentVariables().get("R_HOME");
+				if (value == null || value.length() == 0) {
+					this.errorMessage= "Missing value for R_HOME.";
+					throw new RjInvalidConfigurationException(this.errorMessage);
+				}
+			}
+			rHome= value;
+		}
+		final File rHomeFile= new File(rHome);
+		if (!rHomeFile.exists() || !rHomeFile.isDirectory()) {
+			this.errorMessage= "Invalid value for R_HOME (directory does not exists).";
+			throw new RjInvalidConfigurationException(this.errorMessage);
+		}
+		p.addEnv.put("R_HOME", rHome);
+		
+		// R lib path
+		final LocalREnv serverREnv= new LocalREnv((final String name) -> {
+			if (name.equals("R_HOME")) {
+				return rHome;
+			}
+			return config.getEnvironmentVariables().get(name);
+		});
+		final Path rjPkgPath= serverREnv.searchRPkg("rj");
+		if (rjPkgPath == null) {
+			this.errorMessage= "Could not find the R package 'rj' in the R library path:" + 
+					CollectionUtils.toString(serverREnv.getRLibPaths(), "\n\t");
+			throw new RjInvalidConfigurationException(this.errorMessage);
+		}
+		
+		// Java
+		String javaHome= config.getJavaHome();
+		if (javaHome == null || javaHome.length() == 0) {
+			javaHome= System.getProperty("java.home");
+		}
+		p.addEnv.put("JAVA_HOME", javaHome);
+		
+		p.command.add(javaHome + File.separatorChar + "bin" + File.separatorChar + "java");
+		
+		{	p.command.add("-classpath");
+			final LinkedHashSet<String> classpath= new LinkedHashSet<>();
+			try {
+				classpath.add(rjPkgPath.resolve(Paths.get("server/rj-boot.jar")).toString());
+				classpath.addAll(this.context.searchRJLibs(this.libIds));
+			}
+			catch (final RjInvalidConfigurationException e) {
+				this.errorMessage= e.getMessage();
+				throw e;
+			}
+			String s= ServerUtils.concatPathVar(classpath);
+			final String env= config.getEnvironmentVariables().get("CLASSPATH");
+			if (env != null) {
+				s+= File.pathSeparatorChar + env;
+			}
+			p.command.add(s);
+		}
+		
+		String javaArgs= config.getJavaArgs();
+		if (javaArgs != null && (javaArgs= javaArgs.trim()).length() > 0) {
+			p.command.addAll(Utils.parseArguments(javaArgs));
+		}
+		else {
+			javaArgs= "";
+		}
+		
+		// RMI
+		final String hostname= System.getProperty("java.rmi.server.hostname");
+		if (hostname != null && hostname.length() > 0) {
+			p.command.add("-Djava.rmi.server.hostname=" +  hostname);
+		}
+		if (javaArgs.indexOf("-Djava.security.policy=") < 0) {
+			sb.setLength(0);
+			sb.append("-Djava.security.policy=");
+			sb.append(this.context.getServerPolicyFilePath());
+			p.command.add(sb.toString());
+		}
+		if (javaArgs.indexOf("-Djava.rmi.server.codebase=") < 0) {
+			final List<String> libs;
+			try {
+				libs= this.context.searchRJLibs(CODEBASE_LIBS);
+			}
+			catch (final RjInvalidConfigurationException e) {
+				this.errorMessage= e.getMessage();
+				throw e;
+			}
+			sb.setLength(0);
+			sb.append("-Djava.rmi.server.codebase=");
+			sb.append(ServerUtils.concatCodebase(libs));
+			p.command.add(sb.toString());
+		}
+		
+		// Main
+		p.command.add("RJSrv");
+		p.command.add("start");
+		
+		p.nameCommandIdx= p.command.size();
+		p.command.add("");
+		
+		p.command.add("-server=org.eclipse.statet.internal.rj.servi.server.NodeServer");
+		p.command.add("-log");
+		
+		// ...
+		String nodeArgs= config.getNodeArgs();
+		if (nodeArgs != null && (nodeArgs= nodeArgs.trim()).length() > 0) {
+			p.command.addAll(Utils.parseArguments(nodeArgs));
+		}
+		
+		String rArch= config.getRArch();
+		if (rArch != null && rArch.length() == 0) {
+			rArch= null;
+		}
+		boolean rArchAuto= false;
+		if (rArch == null && javaHome.equals(System.getProperty("java.home"))) {
+			rArch= System.getProperty("os.arch");
+			if (rArch.equals("amd64")) {
+				rArch= "x86_64";
+			}
+			else if (rArch.equals("x86")) {
+				rArch= "i386";
+			}
+			rArchAuto= true;
+		}
+		if (rArch != null) {
+			// validate R_ARCH
+			if (Utils.IS_WINDOWS) {
+				if (rArch.equals("x86_64")) {
+					rArch= "x64";
+				}
+				if (!new File(new File(rHomeFile, "bin"), rArch).exists()) {
+					rArch= null;
+				}
+			}
+			else {
+				final File execDir= new File(new File(rHomeFile, "bin"), "exec");
+				if (!new File(execDir, rArch).exists()) {
+					if (execDir.exists() &&
+							(rArch.equals("i386") || rArch.equals("i586") || rArch.equals("i686")) ) {
+						if (new File(execDir, "i686").exists()) {
+							rArch= "i686";
+						}
+						else if (new File(execDir, "i586").exists()) {
+							rArch= "i586";
+						}
+						else if (new File(execDir, "i386").exists()) {
+							rArch= "i386";
+						}
+						else {
+							rArch= null;
+						}
+					}
+					else {
+						rArch= null;
+					}
+				}
+			}
+			if (rArch != null) {
+				p.addEnv.put("R_ARCH", '/'+rArch);
+			}
+			else if (!rArchAuto) {
+				Utils.logInfo("Failed to validate specified architecture, value is not used.");
+			}
+		}
+		
+		if (Utils.IS_WINDOWS) {
+			final String rBinDir;
+			if (rArch != null) {
+				rBinDir= rHome + File.separatorChar + "bin" + File.separatorChar + rArch;
+			}
+			else {
+				rBinDir= rHome + File.separatorChar + "bin";
+			}
+			final String pathEnv= System.getenv("PATH");
+			p.addEnv.put("PATH", (pathEnv != null) ? (rBinDir + File.pathSeparatorChar + pathEnv) : rBinDir);
+		}
+		else if (Utils.IS_MAC) {
+			final String rBinDir= rHome + File.separatorChar + "bin";
+			final String pathEnv= System.getenv("PATH");
+			p.addEnv.put("PATH", (pathEnv != null) ? (rBinDir + File.pathSeparatorChar + pathEnv) : rBinDir);
+			
+			final String rLibDir= rHome + File.separatorChar + "lib";
+			final String libPathEnv= System.getenv("DYLD_LIBRARY_PATH");
+			p.addEnv.put("DYLD_LIBRARY_PATH", (libPathEnv != null) ? (rLibDir + File.pathSeparatorChar + libPathEnv) : rLibDir);
+		}
+		else {
+			final String rBinDir= rHome + File.separatorChar + "bin";
+			final String pathEnv= System.getenv("PATH");
+			p.addEnv.put("PATH", (pathEnv != null) ? (rBinDir + File.pathSeparatorChar + pathEnv) : rBinDir);
+			
+			final String rLibDir;
+			if (rArch != null) {
+				rLibDir= rHome + File.separatorChar + "lib" + File.separatorChar + rArch;
+			}
+			else {
+				rLibDir= rHome + File.separatorChar + "lib";
+			}
+			final String libPathEnv= System.getenv("LD_LIBRARY_PATH");
+			p.addEnv.put("LD_LIBRARY_PATH", (libPathEnv != null) ? (rLibDir + File.pathSeparatorChar + libPathEnv) : rLibDir);
+		}
+		
+		p.baseWd= config.getBaseWorkingDirectory();
+		if (p.baseWd == null || p.baseWd.length() == 0) {
+			p.baseWd= System.getProperty("java.io.tmpdir");
+		}
+		if (!testBaseDir(p.baseWd)) {
+			this.errorMessage= "Invalid working directory base path.";
+			throw new RjInvalidConfigurationException(this.errorMessage);
+		}
+		
+		for (final Entry<String, String> var : config.getEnvironmentVariables().entrySet()) {
+			if (!EXCLUDE_ENV_VAR_NAMES.contains(var.getKey())) {
+				p.addEnv.put(var.getKey(), var.getValue());
+			}
+		}
+		
+		p.authConfig= config.getEnableConsole() ? "none" : null;
+		
+		p.rStartupSnippet= config.getRStartupSnippet();
+		
+		long timeout= config.getStartStopTimeout();
+		if (timeout > 0) {
+			timeout= TimeUnit.MILLISECONDS.toNanos(timeout);
+		}
+		synchronized (this) {
+			this.verbose= config.getEnableVerbose();
+			this.baseConfig= config;
+			this.processConfig= p;
+			this.timeoutNanos= timeout;
+		}
+	}
+	
+	private boolean testBaseDir(final String path) {
+		final File file= new File(path + File.separatorChar + this.poolId + "-test");
+		if (file.isDirectory()) {
+			return true;
+		}
+		if (file.mkdirs()) {
+			file.delete();
+			return true;
+		}
+		return false;
+	}
+	
+	@Override
+	public RServiNodeConfig getConfig() {
+		return this.baseConfig;
+	}
+	
+	
+	@Override
+	public void createNode(final NodeHandler poolObj) throws RjException {
+		final long t= System.nanoTime();
+		final long timeout;
+		
+		final ProcessConfig p;
+		final RMIRegistry registry;
+		synchronized (this) {
+			p= this.processConfig;
+			if (p == null) {
+				final String message= this.errorMessage;
+				throw new RjInvalidConfigurationException((message != null) ? message :
+						"Missing R node configuration.");
+			}
+			registry= this.nodeRegistry;
+			if (registry == null) {
+				throw new RjInvalidConfigurationException("Missing registry configuration.");
+			}
+			timeout= this.timeoutNanos;
+		}
+		ProcessBuilder pBuilder;
+		String id;
+		List<String> command= null;
+		try {
+			synchronized (this) {
+				for (int i= 0; ; i++) {
+					id= this.poolId + '-' + System.currentTimeMillis();
+					poolObj.dir= new File(p.baseWd + File.separatorChar + id);
+					if (!poolObj.dir.exists() && poolObj.dir.mkdirs()) {
+						break;
+					}
+					if (i >= 20) {
+						throw new RjException("Failed to create working directory (parent="+p.baseWd+").");
+					}
+				}
+			}
+			command= new ArrayList<>(p.command.size() + 2);
+			command.addAll(p.command);
+			poolObj.address= new RMIAddress(registry.getAddress(), id);
+			command.set(p.nameCommandIdx, poolObj.address.toString());
+			if (this.verbose) {
+				command.add("-verbose");
+			}
+			if (registry.getAddress().isSSL()) {
+				command.addAll(p.nameCommandIdx - 1, this.sslPropertyArgs);
+			}
+			pBuilder= new ProcessBuilder(command);
+			pBuilder.environment().remove("Path");
+			pBuilder.environment().putAll(p.addEnv);
+			pBuilder.directory(poolObj.dir);
+			pBuilder.redirectErrorStream(true);
+		}
+		catch (final Exception e) {
+			throw new RjException("Error preparing R node.", e);
+		}
+		Process process= null;
+		try {
+			process= pBuilder.start();
+			
+			for (int i= 1; i < Integer.MAX_VALUE; i++) {
+				try {
+					final Server server= (Server) registry.getRegistry().lookup(id);
+					final ServerLogin login= server.createLogin(Server.C_RSERVI_NODECONTROL);
+					final RServiNode node= (RServiNode) server.execute(Server.C_RSERVI_NODECONTROL, null, login);
+					
+					Utils.logInfo("New R node started (t="+((System.nanoTime()-t)/1000000)+"ms).");
+					
+					String line= null;
+					try {
+						if (p.rStartupSnippet != null && p.rStartupSnippet.length() > 0) {
+							final String[] lines= p.rStartupSnippet.split("\\p{Blank}*\\r[\\n]?|\\n\\p{Blank}*"); //$NON-NLS-1$
+							for (int j= 0; j < lines.length; j++) {
+								line= lines[j];
+								if (line.length() > 0) {
+									node.runSnippet(line);
+								}
+							}
+						}
+					}
+					catch (final RjException e) {
+						try {
+							node.shutdown();
+						}
+						catch (final Exception ignore) {}
+						throw new RjException("Running the R startup snippet failed in line '" + line + "'.", e);
+					}
+					try {
+						poolObj.isConsoleEnabled= node.setConsole(p.authConfig);
+					}
+					catch (final RjException e) {
+						try {
+							node.shutdown();
+						}
+						catch (final Exception ignore) {}
+						throw e;
+					}
+					
+					poolObj.init(node, process);
+					return;
+				}
+				catch (final NotBoundException e) {
+					final long diff= System.nanoTime() - t;
+					if (i >= 10 && timeout >= 0 && diff > timeout) {
+						throw new RjException("Start of R node aborted because of timeout (t="+(diff/1000000L)+"ms).", e);
+					}
+				};
+				
+				try {
+					final int exitValue= process.exitValue();
+					throw new RjException("R node process stopped (exit code= "+exitValue+").");
+				}
+				catch (final IllegalThreadStateException ok) {}
+				
+				Thread.sleep(250);
+			}
+		}
+		catch (final Exception e) {
+			final StringBuilder sb= new StringBuilder("Error starting R node:");
+			if (pBuilder != null) {
+				sb.append("\n<COMMAND>");
+				ServerUtils.prettyPrint(pBuilder.command(), sb);
+				sb.append("\n</COMMAND>");
+			}
+			if (process != null) {
+				final char[] buffer= new char[4096];
+				final InputStream stdout= process.getInputStream();
+				{
+					sb.append("\n<STDOUT>\n");
+					final InputStreamReader reader= new InputStreamReader(stdout);
+					try { // read non-blocking
+						int n;
+						while (reader.ready() && (n= reader.read(buffer, 0, buffer.length)) >= 0) {
+							sb.append(buffer, 0, n);
+						}
+					}
+					catch (final IOException ignore) {
+					}
+					process.destroy();
+					try {
+						int n;
+						while ((n= reader.read(buffer, 0, buffer.length)) >= 0) {
+							sb.append(buffer, 0, n);
+						}
+					}
+					catch (final IOException ignore) {
+					}
+					finally {
+						if (reader != null) {
+							try {
+								reader.close();
+							}
+							catch (final IOException ignore) {}
+						}
+					}
+					sb.append("</STDOUT>");
+				}
+				final File logfile= new File(poolObj.dir, "out.log");
+				if (logfile.exists()) {
+					sb.append("\n<LOG file=\"out.log\">\n");
+					FileReader reader= null;
+					try {
+						reader= new FileReader(logfile);
+						int n;
+						while ((n= reader.read(buffer, 0, buffer.length)) >= 0) {
+							sb.append(buffer, 0, n);
+							if (sb.length() > 100000) {
+								break;
+							}
+						}
+					}
+					catch (final IOException ignore) {
+					}
+					finally {
+						if (reader != null) {
+							try {
+								reader.close();
+							}
+							catch (final IOException ignore) {}
+						}
+					}
+					sb.append("</LOG>");
+				}
+				sb.append("\n--------");
+			}
+			
+			Thread.interrupted();
+			if (poolObj.dir.exists() && poolObj.dir.isDirectory()) {
+				ServerUtils.delDir(poolObj.dir);
+			}
+			throw new RjException(sb.toString(), e);
+		}
+	}
+	
+	@Override
+	public void stopNode(final NodeHandler poolObj) {
+		final long t= System.nanoTime();
+		final long timeout= this.timeoutNanos;
+		
+		try {
+			poolObj.shutdown();
+		}
+		catch (final Throwable e) {
+			Utils.logWarning(Messages.ShutdownNode_error_message, e);
+		}
+		
+		final Process process= poolObj.process;
+		poolObj.process= null;
+		if (process != null) {
+			for (int i= 0; i < Integer.MAX_VALUE; i++) {
+				try {
+					Thread.sleep(250);
+				}
+				catch (final InterruptedException e) {
+				}
+				try {
+					process.exitValue();
+					break;
+				}
+				catch (final IllegalThreadStateException e) {
+					final long diff= System.nanoTime() - t;
+					if (i >= 10 && timeout >= 0 && diff > timeout) {
+						process.destroy();
+						Utils.logWarning("Killed RServi node '" + poolObj.getAddress().getName() + "'.");
+						break;
+					}
+					continue;
+				}
+			}
+		}
+		
+		if (!this.verbose && poolObj.dir != null
+				&& poolObj.dir.exists() && poolObj.dir.isDirectory() ) {
+			for (int i= 0; i < 20; i++) {
+				try {
+					Thread.sleep(250);
+				}
+				catch (final InterruptedException e) {
+				}
+				
+				if (!poolObj.dir.exists() || ServerUtils.delDir(poolObj.dir)) {
+					return;
+				}
+			}
+			Utils.logWarning("Failed to delete the RServi node working directory '" + poolObj.dir.toString() + "'.");
+		}
+	}
+	
+}
diff --git a/servi/org.eclipse.statet.rj.servi/src/org/eclipse/statet/internal/rj/servi/LocalNodeManager.java b/servi/org.eclipse.statet.rj.servi/src/org/eclipse/statet/internal/rj/servi/LocalNodeManager.java
new file mode 100644
index 0000000..5b77126
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi/src/org/eclipse/statet/internal/rj/servi/LocalNodeManager.java
@@ -0,0 +1,159 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.internal.rj.servi;
+
+import java.rmi.RemoteException;
+import java.util.NoSuchElementException;
+
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+
+import org.eclipse.statet.jcommons.lang.Disposable;
+
+import org.eclipse.statet.ecommons.rmi.core.RMIRegistry;
+import org.eclipse.statet.ecommons.runtime.core.ECommonsRuntime;
+
+import org.eclipse.statet.rj.RjException;
+import org.eclipse.statet.rj.RjInitFailedException;
+import org.eclipse.statet.rj.servi.RServi;
+import org.eclipse.statet.rj.servi.RServiUtil;
+import org.eclipse.statet.rj.servi.node.RServiNodeFactory;
+import org.eclipse.statet.rj.servi.node.RServiNodeManager;
+
+
+public class LocalNodeManager implements RServiNodeManager, Disposable {
+	
+	
+	private class ThisNodeHandler extends NodeHandler implements RServiImpl.PoolRef {
+		
+		@Override
+		public void returnObject(final long accessId) throws RjException, RemoteException {
+			returnRServi(accessId);
+		}
+		
+	}
+	
+	
+	private final String id;
+	
+	private final RMIRegistry registry;
+	
+	private final LocalNodeFactory factory;
+	
+	private ThisNodeHandler handler;
+	
+	private boolean inUse;
+	private long accessId;
+	
+	
+	public LocalNodeManager(final String id, final RMIRegistry registry, final LocalNodeFactory factory) {
+		if (id == null || registry == null) {
+			throw new NullPointerException();
+		}
+		this.id= id;
+		this.registry= registry;
+		this.factory= factory;
+		
+		Utils.preLoad();
+	}
+	
+	
+	@Override
+	public String getId() {
+		return this.id;
+	}
+	
+	@Override
+	public RServiNodeFactory getFactory() {
+		return this.factory;
+	}
+	
+	@Override
+	public void dispose() {
+		stop();
+	}
+	
+	@Override
+	public synchronized void start() throws RjException {
+		final ThisNodeHandler poolObj= new ThisNodeHandler();
+		try {
+			this.factory.createNode(poolObj);
+			this.handler= poolObj;
+			ECommonsRuntime.getEnv().addStoppingListener(this);
+		}
+		catch (final Throwable e) {
+			ECommonsRuntime.getEnv().log(new Status(IStatus.ERROR, RServiUtil.RJ_SERVI_ID,
+					Messages.StartNode_error_message, e ));
+			throw new RjInitFailedException(Messages.StartLocal_pub_error_message,
+					(e instanceof RjException) ? e : null);
+		}
+	}
+	
+	@Override
+	public synchronized void stop() {
+		if (this.handler == null) {
+			return;
+		}
+		ECommonsRuntime.getEnv().removeStoppingListener(this);
+		if (this.inUse) {
+			returnRServi(this.accessId);
+			if (this.handler == null) {
+				return;
+			}
+		}
+		this.factory.stopNode(this.handler);
+		this.handler= null;
+	}
+	
+	@Override
+	public synchronized RServi getRServi(final String name) throws NoSuchElementException, RjException {
+		if (this.handler == null) {
+			start();
+		}
+		if (this.inUse) {
+			throw new NoSuchElementException(Messages.GetRServi_NoInstance_pub_Single_message);
+		}
+		try {
+			this.handler.bindClient(name, "local");
+		}
+		catch (final Throwable e) {
+			ECommonsRuntime.getEnv().log(new Status(IStatus.ERROR, RServiUtil.RJ_SERVI_ID,
+					Messages.BindClient_error_message, e ));
+			throw new RjException(Messages.GetRServi_pub_error_message);
+		}
+		this.inUse= true;
+		return new RServiImpl(this.accessId, this.handler, this.handler.getClientHandler());
+	}
+	
+	private synchronized void returnRServi(final long accessId) {
+		if (this.handler == null) {
+			return;
+		}
+		if (this.accessId != accessId) {
+			throw new IllegalStateException("Access id no longer valid.");
+		}
+		this.inUse= false;
+		this.accessId++;
+		try {
+			this.handler.unbindClient();
+		}
+		catch (final Throwable e) {
+			ECommonsRuntime.getEnv().log(new Status(IStatus.ERROR, RServiUtil.RJ_SERVI_ID,
+					Messages.UnbindClient_error_message, e ));
+			stop();
+		}
+	}
+	
+}
diff --git a/servi/org.eclipse.statet.rj.servi/src/org/eclipse/statet/internal/rj/servi/Messages.java b/servi/org.eclipse.statet.rj.servi/src/org/eclipse/statet/internal/rj/servi/Messages.java
new file mode 100644
index 0000000..9e700f6
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi/src/org/eclipse/statet/internal/rj/servi/Messages.java
@@ -0,0 +1,31 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.internal.rj.servi;
+
+
+public class Messages {
+	
+	
+	public static String BindClient_error_message= "An exception was thrown when trying to bind the client (activate a node).";
+	public static String GetRServi_pub_error_message= "Cannot provide RServi instance: Internal error occurred.";
+	public static String GetRServi_NoInstance_pub_Single_message= "Cannot provide RServi instance: Single instance is already in use.";
+	public static String GetRServi_NoInstance_pub_Pool_message= "Cannot provide RServi instance: No free node available.";
+	public static String UnbindClient_error_message= "An exception was thrown when trying to unbind the client (passivate a node).";
+	public static String StartNode_error_message= "An exception was thrown when trying to start the node (make a node).";
+	public static String StartLocal_pub_error_message= "Cannot start the RServi instance.";
+	public static String ShutdownNode_error_message= "An exception was thrown when trying to shutdown the node (destroy a node).";
+	public static String RmiUnexportNode_error_message= "An exception was thrown when trying to unexport the node (destroy a node).";
+	
+}
diff --git a/servi/org.eclipse.statet.rj.servi/src/org/eclipse/statet/internal/rj/servi/NodeFactory.java b/servi/org.eclipse.statet.rj.servi/src/org/eclipse/statet/internal/rj/servi/NodeFactory.java
new file mode 100644
index 0000000..f1cbfe5
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi/src/org/eclipse/statet/internal/rj/servi/NodeFactory.java
@@ -0,0 +1,27 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.internal.rj.servi;
+
+import org.eclipse.statet.rj.RjException;
+import org.eclipse.statet.rj.servi.node.RServiNodeFactory;
+
+
+public interface NodeFactory extends RServiNodeFactory {
+	
+	
+	void createNode(NodeHandler poolObj) throws RjException;
+	void stopNode(NodeHandler poolObj);
+	
+}
diff --git a/servi/org.eclipse.statet.rj.servi/src/org/eclipse/statet/internal/rj/servi/NodeHandler.java b/servi/org.eclipse.statet.rj.servi/src/org/eclipse/statet/internal/rj/servi/NodeHandler.java
new file mode 100644
index 0000000..4778ca1
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi/src/org/eclipse/statet/internal/rj/servi/NodeHandler.java
@@ -0,0 +1,128 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.internal.rj.servi;
+
+import java.io.File;
+import java.rmi.RemoteException;
+
+import org.eclipse.statet.ecommons.rmi.core.RMIAddress;
+
+import org.eclipse.statet.internal.rj.servi.server.RServiBackend;
+import org.eclipse.statet.rj.RjException;
+import org.eclipse.statet.rj.servi.node.RServiNode;
+
+
+public abstract class NodeHandler {
+	
+	
+	protected RServiNode node;
+	
+	RMIAddress address;
+	File dir;
+	Process process;
+	
+	private String clientLabel;
+	private RServiBackend clientHandler;
+	
+	boolean isConsoleEnabled;
+	
+	private final long startTime;
+	private long shutdownTime;
+	
+	
+	public NodeHandler() {
+		this.startTime= System.currentTimeMillis();
+		this.shutdownTime= -1;
+	}
+	
+	
+	public boolean isConsoleEnabled() {
+		return this.isConsoleEnabled;
+	}
+	
+	public void enableConsole(final String authConfig) throws RjException {
+		try {
+			this.isConsoleEnabled= this.node.setConsole(authConfig);
+		}
+		catch (final Exception e) {
+			Utils.logError("An error occurred when configuring the debug console.", e);
+			throw new RjException("An error occurred when configuring the debug console. See server log for detail.");
+		}
+	}
+	
+	public void disableConsole() throws RjException {
+		enableConsole(null);
+	}
+	
+	public RMIAddress getAddress() {
+		return this.address;
+	}
+	
+	
+	void init(final RServiNode node, final Process process) {
+		this.node= node;
+		this.process= process;
+	}
+	
+	void bindClient(final String name, final String host) throws RemoteException {
+		final StringBuilder sb= new StringBuilder(80);
+		if (name != null) {
+			sb.append(name);
+		}
+		sb.append('@');
+		sb.append(host);
+		final String client= sb.toString();
+		this.clientHandler= this.node.bindClient(client);
+		setClientLabel(client);
+	}
+	
+	void unbindClient() throws RemoteException {
+		this.clientHandler= null;
+		setClientLabel(null);
+		this.node.unbindClient();
+	}
+	
+	void shutdown() throws RemoteException {
+		this.shutdownTime= System.currentTimeMillis();
+		this.clientHandler= null;
+		setClientLabel(null);
+		final RServiNode node= this.node;
+		this.node= null;
+		if (node != null) {
+			node.shutdown();
+		}
+	}
+	
+	RServiBackend getClientHandler() {
+		return this.clientHandler;
+	}
+	
+	void setClientLabel(final String clientLabel) {
+		this.clientLabel= clientLabel;
+	}
+	
+	public String getClientLabel() {
+		return this.clientLabel;
+	}
+	
+	public long getStartTime() {
+		return this.startTime;
+	}
+	
+	public long getShutdownTime() {
+		return this.shutdownTime;
+	}
+	
+}
diff --git a/servi/org.eclipse.statet.rj.servi/src/org/eclipse/statet/internal/rj/servi/RServiImpl.java b/servi/org.eclipse.statet.rj.servi/src/org/eclipse/statet/internal/rj/servi/RServiImpl.java
new file mode 100644
index 0000000..3a341c8
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi/src/org/eclipse/statet/internal/rj/servi/RServiImpl.java
@@ -0,0 +1,324 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.internal.rj.servi;
+
+import java.io.Externalizable;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import java.io.OutputStream;
+import java.rmi.Remote;
+import java.rmi.RemoteException;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+
+import org.eclipse.statet.ecommons.runtime.core.ECommonsRuntime;
+
+import org.eclipse.statet.internal.rj.servi.server.RServiBackend;
+import org.eclipse.statet.rj.RjException;
+import org.eclipse.statet.rj.data.RObject;
+import org.eclipse.statet.rj.data.RReference;
+import org.eclipse.statet.rj.data.impl.DefaultRObjectFactory;
+import org.eclipse.statet.rj.server.RjsComConfig;
+import org.eclipse.statet.rj.server.RjsStatus;
+import org.eclipse.statet.rj.server.Server;
+import org.eclipse.statet.rj.server.client.AbstractRJComClient;
+import org.eclipse.statet.rj.server.client.AbstractRJComClientGraphicActions;
+import org.eclipse.statet.rj.server.client.FunctionCallImpl;
+import org.eclipse.statet.rj.server.client.RClientGraphicFactory;
+import org.eclipse.statet.rj.server.client.RGraphicCreatorImpl;
+import org.eclipse.statet.rj.servi.RServi;
+import org.eclipse.statet.rj.servi.RServiUtil;
+import org.eclipse.statet.rj.services.FunctionCall;
+import org.eclipse.statet.rj.services.RGraphicCreator;
+import org.eclipse.statet.rj.services.RPlatform;
+import org.eclipse.statet.rj.services.RService;
+
+
+/**
+ * Client side {@link RServi} handler
+ */
+public class RServiImpl implements RServi, Externalizable {
+	
+	
+	private class RServiComClient extends AbstractRJComClient {
+		
+		
+		public RServiComClient() {
+		}
+		
+		
+		@Override
+		protected void initGraphicFactory() {
+			final Object graphicFactory= RjsComConfig.getProperty("rj.servi.graphicFactory");
+			final Object actionsFactory= RjsComConfig.getProperty("rj.servi.comClientGraphicActionsFactory");
+			if (graphicFactory instanceof RClientGraphicFactory) {
+				setGraphicFactory((RClientGraphicFactory) graphicFactory,
+						(actionsFactory instanceof AbstractRJComClientGraphicActions.Factory) ?
+								((AbstractRJComClientGraphicActions.Factory) actionsFactory).create(
+										this, getRHandle() ) : null );
+			}
+		}
+		
+		@Override
+		protected void handleServerStatus(final RjsStatus serverStatus, final IProgressMonitor monitor) throws CoreException {
+			switch (serverStatus.getCode()) {
+			case 0:
+				return;
+			case Server.S_DISCONNECTED:
+			case Server.S_LOST:
+			case Server.S_STOPPED:
+				break;
+			case RjsStatus.ERROR:
+				throw new CoreException(new Status(IStatus.ERROR, RServiUtil.RJ_SERVI_ID, "Server or IO error."));
+			default:
+				throw new IllegalStateException();
+			}
+			
+			if (!isClosed()) {
+				setClosed(true);
+				handleStatus(new Status(IStatus.INFO, RServiUtil.RJ_SERVI_ID, "RServi is disconnected."), monitor);
+			}
+			throw new CoreException(new Status(IStatus.ERROR, RServiUtil.RJ_SERVI_ID, "RServi is closed."));
+		}
+		
+		@Override
+		protected void handleStatus(final Status status, final IProgressMonitor monitor) {
+			if (!status.isOK()) {
+				log(status);
+			}
+		}
+		
+		@Override
+		protected void log(final IStatus status) {
+			ECommonsRuntime.getEnv().log(status);
+		}
+		
+	}
+	
+	
+	public static interface PoolRef extends Remote {
+		void returnObject(long accessId) throws RjException, RemoteException;
+	}
+	
+	
+	private long accessId;
+	private PoolRef poolRef;
+	private RServiBackend backend;
+	
+	private final AbstractRJComClient rjs= new RServiComClient();
+	private int rjsId;
+	
+	private Object rHandle;
+	
+	
+	public RServiImpl(final long accessId, final PoolRef ref, final RServiBackend backend) {
+		this.accessId= accessId;
+		this.poolRef= ref;
+		this.backend= backend;
+		this.rjs.setServer(this.backend, 1);
+	}
+	
+	public RServiImpl() {
+	}
+	
+	
+	public void setRHandle(final Object rHandle) {
+		this.rHandle= rHandle;
+	}
+	
+	public Object getRHandle() {
+		return this.rHandle;
+	}
+	
+	@Override
+	public void readExternal(final ObjectInput in) throws IOException, ClassNotFoundException {
+		this.accessId= in.readLong();
+		this.poolRef= (PoolRef) in.readObject();
+		this.backend= (RServiBackend) in.readObject();
+		this.rjs.setServer(this.backend, 1);
+	}
+	
+	@Override
+	public void writeExternal(final ObjectOutput out) throws IOException {
+		out.writeLong(this.accessId);
+		out.writeObject(this.poolRef);
+		out.writeObject(this.backend);
+	}
+	
+	
+	private void init() throws CoreException {
+		this.rjsId= RjsComConfig.registerClientComHandler(this.rjs);
+		final Map<String, Object> properties= new HashMap<>();
+		this.rjs.initClient(this.rHandle, this, properties, this.rjsId);
+		this.rjs.setRjsProperties(properties);
+	}
+	
+	@Override
+	public boolean isClosed() {
+		return this.rjs.isClosed();
+	}
+	
+	@Override
+	public synchronized void close() throws CoreException {
+		if (this.rjs.isClosed()) {
+			throw new CoreException(new Status(IStatus.ERROR, RServiUtil.RJ_SERVI_ID, 0,
+					"RServi is already closed.", null));
+		}
+		try {
+			this.rjs.setClosed(true);
+			this.poolRef.returnObject(this.accessId);
+		}
+		catch (final Exception e) {
+			throw new CoreException(new Status(IStatus.ERROR, RServiUtil.RJ_SERVI_ID, 0,
+					"An error occurred when closing RServi instance.", e));
+		}
+		finally {
+			this.poolRef= null;
+			this.backend= null;
+			RjsComConfig.unregisterClientComHandler(this.rjsId);
+			this.rjs.disposeAllGraphics();
+		}
+	}
+	
+	
+	@Override
+	public RPlatform getPlatform() {
+		return this.rjs.getRPlatform();
+	}
+	
+	@Override
+	public void evalVoid(final String expression,
+			final IProgressMonitor monitor) throws CoreException {
+		if (this.rjsId == 0) {
+			init();
+		}
+		this.rjs.evalVoid(expression, null, monitor);
+	}
+	
+	@Override
+	public void evalVoid(final String expression, final RObject envir,
+			final IProgressMonitor monitor) throws CoreException {
+		if (this.rjsId == 0) {
+			init();
+		}
+		this.rjs.evalVoid(expression, envir, monitor);
+	}
+	
+	@Override
+	public RObject evalData(final String expression,
+			final IProgressMonitor monitor) throws CoreException {
+		if (this.rjsId == 0) {
+			init();
+		}
+		return this.rjs.evalData(expression, null, null, 0, RService.DEPTH_INFINITE, monitor);
+	}
+	
+	@Override
+	public RObject evalData(final String expression, final String factoryId, final int options, final int depth,
+			final IProgressMonitor monitor) throws CoreException {
+		if (this.rjsId == 0) {
+			init();
+		}
+		return this.rjs.evalData(expression, null, factoryId, options, depth, monitor);
+	}
+	
+	@Override
+	public RObject evalData(final String expression, final RObject envir,
+			final String factoryId, final int options, final int depth,
+			final IProgressMonitor monitor) throws CoreException {
+		if (this.rjsId == 0) {
+			init();
+		}
+		return this.rjs.evalData(expression, envir, factoryId, options, depth, monitor);
+	}
+	
+	@Override
+	public RObject evalData(final RReference reference,
+			final IProgressMonitor monitor) throws CoreException {
+		if (this.rjsId == 0) {
+			init();
+		}
+		return this.rjs.evalData(reference, null, 0, -1, monitor);
+	}
+	
+	@Override
+	public RObject evalData(final RReference reference, final String factoryId, final int options, final int depth,
+			final IProgressMonitor monitor) throws CoreException {
+		if (this.rjsId == 0) {
+			init();
+		}
+		return this.rjs.evalData(reference, factoryId, options, depth, monitor);
+	}
+	
+	@Override
+	public void assignData(final String expression, final RObject data,
+			final IProgressMonitor monitor) throws CoreException {
+		if (this.rjsId == 0) {
+			init();
+		}
+		this.rjs.assignData(expression, data, null, monitor);
+	}
+	
+	@Override
+	public void downloadFile(final OutputStream out, final String fileName, final int options,
+			final IProgressMonitor monitor) throws CoreException {
+		if (this.rjsId == 0) {
+			init();
+		}
+		this.rjs.downloadFile(out, fileName, options, monitor);
+	}
+	
+	@Override
+	public byte[] downloadFile(final String fileName, final int options,
+			final IProgressMonitor monitor) throws CoreException {
+		if (this.rjsId == 0) {
+			init();
+		}
+		return this.rjs.downloadFile(fileName, options, monitor);
+	}
+	
+	@Override
+	public void uploadFile(final InputStream in, final long length, final String fileName, final int options,
+			final IProgressMonitor monitor) throws CoreException {
+		if (this.rjsId == 0) {
+			init();
+		}
+		this.rjs.uploadFile(in, length, fileName, options, monitor);
+	}
+	
+	@Override
+	public FunctionCall createFunctionCall(final String name) throws CoreException {
+		if (this.rjsId == 0) {
+			init();
+		}
+		return new FunctionCallImpl(this.rjs, name, DefaultRObjectFactory.INSTANCE);
+	}
+	
+	@Override
+	public RGraphicCreator createRGraphicCreator(final int options) throws CoreException {
+		if (this.rjsId == 0) {
+			init();
+		}
+		return new RGraphicCreatorImpl(this, this.rjs, options);
+	}
+	
+}
diff --git a/servi/org.eclipse.statet.rj.servi/src/org/eclipse/statet/internal/rj/servi/Utils.java b/servi/org.eclipse.statet.rj.servi/src/org/eclipse/statet/internal/rj/servi/Utils.java
new file mode 100644
index 0000000..940ead5
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi/src/org/eclipse/statet/internal/rj/servi/Utils.java
@@ -0,0 +1,229 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.internal.rj.servi;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Properties;
+
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+
+import org.eclipse.statet.ecommons.runtime.core.ECommonsRuntime;
+import org.eclipse.statet.ecommons.runtime.core.ECommonsRuntime.AppEnvironment;
+
+import org.eclipse.statet.rj.servi.RServiUtil;
+
+
+public class Utils {
+	
+	
+	public static final boolean IS_WINDOWS= System.getProperty("os.name").toLowerCase().startsWith("win");
+	public static final boolean IS_MAC= System.getProperty("os.name").toLowerCase().startsWith("mac");
+	
+	
+	public static void preLoad() {
+		// Load class for errors
+		new Status(IStatus.INFO, RServiUtil.RJ_SERVI_ID, Messages.StartNode_error_message);
+	}
+	
+	/**
+	 * Utility class to parse command line arguments.
+	 */
+	private static class ArgumentParser {
+		
+		private final String args;
+		private int index= 0;
+		private int ch= -1;
+		
+		public ArgumentParser(final String args) {
+			this.args= args;
+		}
+		
+		public List<String> parseArguments() {
+			final List<String> v= new ArrayList<>();
+			
+			this.ch= getNext();
+			while (this.ch > 0) {
+				if (Character.isWhitespace((char) this.ch)) {
+					this.ch= getNext();	
+				}
+				else {
+					if (this.ch == '"') {
+						final StringBuffer buf= new StringBuffer();
+						buf.append(parseString());
+						if (buf.length() == 0 && IS_WINDOWS) {
+							// empty string on windows platform
+							buf.append("\"\""); //$NON-NLS-1$
+						}
+						v.add(buf.toString());
+					}
+					else {
+						v.add(parseToken());
+					}
+				}
+			}
+			
+			return v;
+		}
+		
+		private int getNext() {
+			if (this.index < this.args.length()) {
+				return this.args.charAt(this.index++);
+			}
+			return -1;
+		}
+		
+		private String parseString() {
+			this.ch= getNext();
+			if (this.ch == '"') {
+				this.ch= getNext();
+				return ""; //$NON-NLS-1$
+			}
+			final StringBuffer buf= new StringBuffer();
+			while (this.ch > 0 && this.ch != '"') {
+				if (this.ch == '\\') {
+					this.ch= getNext();
+					if (this.ch != '"') { // Only escape double quotes
+						buf.append('\\');
+					}
+					else {
+						if (IS_WINDOWS) {
+							buf.append('\\');
+						}
+					}
+				}
+				if (this.ch > 0) {
+					buf.append((char) this.ch);
+					this.ch= getNext();
+				}
+			}
+			this.ch= getNext();
+			return buf.toString();
+		}
+		
+		private String parseToken() {
+			final StringBuffer buf= new StringBuffer();
+			
+			while (this.ch > 0 && !Character.isWhitespace((char) this.ch)) {
+				if (this.ch == '\\') {
+					this.ch= getNext();
+					if (Character.isWhitespace((char) this.ch)) {
+						// end of token, don't lose trailing backslash
+						buf.append('\\');
+						return buf.toString();
+					}
+					if (this.ch > 0) {
+						if (this.ch != '"') {           // Only escape double quotes
+							buf.append('\\');
+						}
+						else {
+							if (IS_WINDOWS) {
+								buf.append('\\');
+							}
+						}
+						buf.append((char) this.ch);
+						this.ch= getNext();
+					}
+					else if (this.ch == -1) {     // Don't lose a trailing backslash
+						buf.append('\\');
+					}
+				}
+				else if (this.ch == '"') {
+					buf.append(parseString());
+				}
+				else {
+					buf.append((char) this.ch);
+					this.ch= getNext();
+				}
+			}
+			return buf.toString();
+		}
+	}
+	
+	public static List<String> parseArguments(final String args) {
+		if (args == null) {
+			return new ArrayList<>(0);
+		}
+		else {
+			final ArgumentParser parser= new ArgumentParser(args);
+			return parser.parseArguments();
+		}
+	}
+	
+	public static void logInfo(final String message) {
+		final AppEnvironment env= ECommonsRuntime.getEnv();
+		if (env != null) {
+			env.log(new Status(IStatus.INFO, RServiUtil.RJ_SERVI_ID, message));
+		}
+	}
+	
+	public static void logInfo(final String message, final Throwable e) {
+		final AppEnvironment env= ECommonsRuntime.getEnv();
+		if (env != null) {
+			env.log(new Status(IStatus.INFO, RServiUtil.RJ_SERVI_ID, message, e));
+		}
+	}
+	
+	public static void logWarning(final String message) {
+		final AppEnvironment env= ECommonsRuntime.getEnv();
+		if (env != null) {
+			env.log(new Status(IStatus.WARNING, RServiUtil.RJ_SERVI_ID, message));
+		}
+	}
+	
+	public static void logWarning(final String message, final Throwable e) {
+		final AppEnvironment env= ECommonsRuntime.getEnv();
+		if (env != null) {
+			env.log(new Status(IStatus.WARNING, RServiUtil.RJ_SERVI_ID, message, e));
+		}
+	}
+	
+	public static void logError(final String message) {
+		final AppEnvironment env= ECommonsRuntime.getEnv();
+		if (env != null) {
+			env.log(new Status(IStatus.ERROR, RServiUtil.RJ_SERVI_ID, message));
+		}
+	}
+	
+	public static void logError(final String message, final Throwable e) {
+		final AppEnvironment env= ECommonsRuntime.getEnv();
+		if (env != null) {
+			env.log(new Status(IStatus.ERROR, RServiUtil.RJ_SERVI_ID, message, e));
+		}
+	}
+	
+	public static String getProperty(final Properties properties, final String key, final String altKey) {
+		String s= properties.getProperty(key);
+		if (s == null && altKey != null) {
+			s= properties.getProperty(altKey);
+		}
+		return s;
+	}
+	
+	public static void setProperty(final Properties properties, final String key, final String value) {
+		if (value != null) {
+			properties.setProperty(key, value);
+		}
+		else {
+			properties.remove(key);
+		}
+	}
+	
+	
+	private Utils() {
+	}
+	
+}
diff --git a/servi/org.eclipse.statet.rj.servi/src/org/eclipse/statet/rj/servi/RServi.java b/servi/org.eclipse.statet.rj.servi/src/org/eclipse/statet/rj/servi/RServi.java
new file mode 100644
index 0000000..bea9d66
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi/src/org/eclipse/statet/rj/servi/RServi.java
@@ -0,0 +1,83 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.servi;
+
+import org.eclipse.core.runtime.CoreException;
+
+import org.eclipse.statet.rj.services.RService;
+
+
+/**
+ * A RServi provides {@link RService R services} as background computing engine without an 
+ * interactive R console. An RServi can be for example connected to a server side R engine or 
+ * an R engine embedded in the local application.
+ * <p>
+ * How to receive an RServi instance depends on the application.
+ * The RServi framework includes a server side RServi 
+ * {@link org.eclipse.statet.rj.servi.node.RServiPool pool}
+ * which can be used to provide RServi instances. To get a RServi instance
+ * from such a pool which made available via RMI {@link org.eclipse.statet.rj.servi.pool.RServiUtil RServiUtil}
+ * provides helper methods to request a RServi instance.</p>
+ * <p>
+ * In many applications it is sufficient to use an RServi for a direct 
+ * sequence of executions, so that request, evaluations and closing can be
+ * performed one after another in a single thread. If it is required to use
+ * the RServi multiple times (e.g. a large data set should be reused),
+ * the application must prevent concurrent access.</p>
+ * <p>
+ * A RServi instance must be closed if it is no longer used,
+ * so that the R service consumer doesn't block the resources.
+ * When using a RServi pool closing means that the RServi is returned
+ * to the pool and can can be used by other consumers.</p>
+ * <p>
+ * After closing the RServi all resources created by it, R data objects and
+ * files on the R host system are cleaned up. Client side R data objects and
+ * files are not affected by the clean up. After calling this method,
+ * the RServi instance can no longer be used; further function call will 
+ * throw an exception.</p>
+ * <p>
+ * All common guidelines of {@link RService} should be taken into account.</p>
+ * 
+ * @since 0.1
+ */
+public interface RServi extends RService {
+	
+	
+	/**
+	 * Returns the current state of the RServi instance.
+	 * <p>
+	 * The RServi instance is usually closed by {@link #close()} or if a disconnection to the
+	 * R engine was detected. The method does not actively test the connection.
+	 * 
+	 * @return <code>true</code> if the RServi instance is closed, otherwise <code>false</code>.
+	 * @since 1.2
+	 */
+	boolean isClosed();
+	
+	/**
+	 * Closes this RServi instance. An cleanup of resources created by this RServi
+	 * is automatically performed.
+	 * <p>
+	 * See {@link RServi class comment} for detail.</p>
+	 * <p>
+	 * After calling the method the RServi instance is closed even if the method
+	 * thrown an exception.</p>
+	 * 
+	 * @throws CoreException if the operation failed; the status
+	 *     of the exception contains detail about the cause
+	 */
+	void close() throws CoreException;
+	
+}
diff --git a/servi/org.eclipse.statet.rj.servi/src/org/eclipse/statet/rj/servi/RServiUtil.java b/servi/org.eclipse.statet.rj.servi/src/org/eclipse/statet/rj/servi/RServiUtil.java
new file mode 100644
index 0000000..e50411f
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi/src/org/eclipse/statet/rj/servi/RServiUtil.java
@@ -0,0 +1,155 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.servi;
+
+import java.net.MalformedURLException;
+import java.net.UnknownHostException;
+import java.rmi.NotBoundException;
+import java.rmi.RemoteException;
+import java.rmi.registry.LocateRegistry;
+import java.rmi.registry.Registry;
+import java.util.NoSuchElementException;
+
+import javax.rmi.ssl.SslRMIClientSocketFactory;
+import javax.security.auth.login.LoginException;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+
+import org.eclipse.statet.ecommons.rmi.core.RMIAddress;
+
+import org.eclipse.statet.rj.RjException;
+import org.eclipse.statet.rj.server.RjsComConfig;
+import org.eclipse.statet.rj.servi.node.RServiNodeManager;
+import org.eclipse.statet.rj.servi.node.RServiPool;
+
+
+/**
+ * The class provides utility methods for the work with {@link RServi}.
+ * <p>
+ * It is not intend to instance the class.</p>
+ */
+public class RServiUtil {
+	
+	
+	public static final String RJ_SERVI_ID= "org.eclipse.statet.rj.servi";
+	public static final String RJ_CLIENT_ID= "org.eclipse.statet.rj.client";
+	
+	
+	/**
+	 * Requests a {@link RServi} instance from a pool. The pool must be accessible
+	 * via RMI under the given address.
+	 * <p>
+	 * The R services returned by this method are available for exclusive usage
+	 * by the caller (consumer). The consumer is responsible to return it to the pool
+	 * by {@link RServi#close() closing} the RServi.
+	 * 
+	 * For SSL connections, use the prefix <code>ssl:</code>. Note that SSL requires
+	 * the configuration of keystore and truststore at server and client side.
+	 * 
+	 * @param address the RMI address of the pool
+	 * @param name a name which can be used to identify the client
+	 * @return a reference to the RServi instance
+	 * @throws CoreException if the operation was failed; the status
+	 *     of the exception contains detail about the cause
+	 * @throws NoSuchElementException if there is currently no free RServi
+	 *     instance available. A later call with the same configuration 
+	 *     can be successfully.
+	 * @throws LoginException if the RServi request requires authentication
+	 */
+	public static RServi getRServi(final String address, final String name) throws CoreException, NoSuchElementException, LoginException {
+		try {
+			RjsComConfig.setRMIClientSocketFactory(null);
+			RServiPool pool;
+			try {
+				final RMIAddress rmiAddress= new RMIAddress(address);
+				final Registry registry= LocateRegistry.getRegistry(rmiAddress.getHost(), rmiAddress.getPortNum(),
+						(rmiAddress.isSSL()) ? new SslRMIClientSocketFactory() : null );
+				pool= (RServiPool) registry.lookup(rmiAddress.getName());
+			}
+			catch (final MalformedURLException e) {
+				throw new CoreException(new Status(IStatus.ERROR, RJ_SERVI_ID, 0,
+						"Invalid address for the RServi pool.", e));
+			}
+			catch (final UnknownHostException e) {
+				throw new CoreException(new Status(IStatus.ERROR, RJ_SERVI_ID, 0,
+						"Invalid address for the RServi pool.", e));
+			}
+			catch (final NotBoundException e) {
+				throw new CoreException(new Status(IStatus.ERROR, RJ_SERVI_ID, 0,
+						"The address does not point to a valid RServi pool.", e));
+			}
+			catch (final ClassCastException e) {
+				throw new CoreException(new Status(IStatus.ERROR, RJ_SERVI_ID, 0,
+						"The address does not point to a valid/compatible RServi pool.", e));
+			}
+			catch (final RemoteException e) {
+				throw new CoreException(new Status(IStatus.ERROR, RJ_SERVI_ID, 0,
+						"Failed looking for RServi pool in the RMI registry.", e));
+			}
+			try {
+				return pool.getRServi(name, null);
+			}
+			catch (final RjException e) {
+				throw new CoreException(new Status(IStatus.ERROR, RJ_SERVI_ID, 0,
+						"Failed getting an RServi instance from the RServi pool.", e));
+			}
+			catch (final RemoteException e) {
+				throw new CoreException(new Status(IStatus.ERROR, RJ_SERVI_ID, 0,
+						"Failed looking for RServi pool in the RMI registry.", e));
+			}
+		}
+		finally {
+			RjsComConfig.clearRMIClientSocketFactory();
+		}
+	}
+	
+	/**
+	 * Requests a {@link RServi} instance from the given manager. The manager must be
+	 * configured and started.
+	 * <p>
+	 * The R services returned by this method are available for exclusive usage
+	 * by the caller (consumer). The consumer is responsible to return it to the manager
+	 * by {@link RServi#close() closing} the RServi.
+	 * 
+	 * @param manager manager for RServi node(s)
+	 * @param name a name which can be used to identify the client
+	 * @return a reference to the RServi instance
+	 * @throws CoreException if the operation was failed; the status
+	 *     of the exception contains detail about the cause
+	 * @throws NoSuchElementException if there is currently no free RServi
+	 *     instance available. A later call with the same configuration 
+	 *     can be successfully.
+	 */
+	public static RServi getRServi(final RServiNodeManager manager, final String name) throws CoreException, NoSuchElementException {
+		if (manager == null) {
+			throw new CoreException(new Status(IStatus.ERROR, RJ_SERVI_ID, 0,
+					"RServi is not available.", null));
+		}
+		try {
+			return manager.getRServi(name);
+		}
+		catch (final RjException e) {
+			throw new CoreException(new Status(IStatus.ERROR, RJ_SERVI_ID, 0,
+					"Failed getting an RServi instance.", e));
+		}
+	}
+	
+	
+	private RServiUtil() {
+	}
+	
+}
diff --git a/servi/org.eclipse.statet.rj.servi/src/org/eclipse/statet/rj/servi/node/PropertiesBean.java b/servi/org.eclipse.statet.rj.servi/src/org/eclipse/statet/rj/servi/node/PropertiesBean.java
new file mode 100644
index 0000000..61863df
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi/src/org/eclipse/statet/rj/servi/node/PropertiesBean.java
@@ -0,0 +1,58 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.servi.node;
+
+import java.util.Collection;
+import java.util.Properties;
+
+
+public interface PropertiesBean {
+	
+	
+	class ValidationMessage {
+		
+		
+		private final String propertyId;
+		private final String message;
+		
+		
+		public ValidationMessage(final String message) {
+			this(null, message);
+		}
+		
+		public ValidationMessage(final String propertyId, final String message) {
+			this.propertyId= propertyId;
+			this.message= message;
+		}
+		
+		
+		public String getPropertyId() {
+			return this.propertyId;
+		}
+		
+		public String getMessage() {
+			return this.message;
+		}
+		
+	}
+	
+	
+	String getBeanId();
+	void load(Properties map);
+	void save(Properties map);
+	
+	boolean validate(Collection<ValidationMessage> messages);
+	
+}
diff --git a/servi/org.eclipse.statet.rj.servi/src/org/eclipse/statet/rj/servi/node/RServiImpl.java b/servi/org.eclipse.statet.rj.servi/src/org/eclipse/statet/rj/servi/node/RServiImpl.java
new file mode 100644
index 0000000..a31bf89
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi/src/org/eclipse/statet/rj/servi/node/RServiImpl.java
@@ -0,0 +1,89 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.servi.node;
+
+import static org.eclipse.statet.rj.server.util.ServerUtils.RJ_DATA_ID;
+import static org.eclipse.statet.rj.server.util.ServerUtils.RJ_SERVER_ID;
+import static org.eclipse.statet.rj.servi.RServiUtil.RJ_SERVI_ID;
+
+import org.eclipse.statet.jcommons.collections.ImCollections;
+import org.eclipse.statet.jcommons.collections.ImList;
+
+import org.eclipse.statet.ecommons.rmi.core.RMIRegistry;
+
+import org.eclipse.statet.internal.rj.servi.LocalNodeFactory;
+import org.eclipse.statet.internal.rj.servi.LocalNodeManager;
+import org.eclipse.statet.internal.rj.servi.PoolManager;
+import org.eclipse.statet.rj.RjInvalidConfigurationException;
+import org.eclipse.statet.rj.server.util.RJContext;
+import org.eclipse.statet.rj.servi.pool.RServiPoolManager;
+
+
+/**
+ * Factory for RServi objects
+ */
+public class RServiImpl {
+	
+	
+	private static final ImList<String> LIB_IDS= ImCollections.newList(
+			RJ_DATA_ID, RJ_SERVER_ID, RJ_SERVI_ID );
+	
+	
+	/**
+	 * Creates a node factory establishing RServi nodes on the local system.
+	 * 
+	 * This method is intended for RServi pools when utilizing the default bundles.
+	 * 
+	 * @param poolId the id of the pool or application
+	 * @param context context to resolve the RJ libraries
+	 * @return a node factory
+	 * @throws RjInvalidConfigurationException
+	 */
+	public static RServiNodeFactory createLocalNodeFactory(final String poolId, final RJContext context)
+			throws RjInvalidConfigurationException {
+		final ImList<String> libIds= LIB_IDS;
+		context.searchRJLibs(libIds); // check
+		
+		return new LocalNodeFactory(poolId, context, libIds);
+	}
+	
+	/**
+	 * Creates an {@link RServiPoolManager RServi pool}.
+	 * 
+	 * @param poolId the id of the pool
+	 * @param registry a handler for the RMI registry to use
+	 * @return the pool manager
+	 */
+	public static RServiPoolManager createPool(final String poolId, final RMIRegistry registry) {
+		return new PoolManager(poolId, registry);
+	}
+	
+	/**
+	 * Creates an {@link RServiNodeManager RServi node manager}.
+	 * 
+	 * @param id the id (like the poolId)
+	 * @param registry a handler for the RMI registry to use
+	 * @param factory the node factory to use to establish the node
+	 * @return the manager for the RServi instance
+	 */
+	public static RServiNodeManager createNodeManager(final String id, final RMIRegistry registry,
+			final RServiNodeFactory factory) {
+		if (factory instanceof LocalNodeFactory) {
+			return new LocalNodeManager(id, registry, (LocalNodeFactory) factory);
+		}
+		throw new UnsupportedOperationException(factory.getClass().getName());
+	}
+	
+}
diff --git a/servi/org.eclipse.statet.rj.servi/src/org/eclipse/statet/rj/servi/node/RServiNode.java b/servi/org.eclipse.statet.rj.servi/src/org/eclipse/statet/rj/servi/node/RServiNode.java
new file mode 100644
index 0000000..a5c9db0
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi/src/org/eclipse/statet/rj/servi/node/RServiNode.java
@@ -0,0 +1,48 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.servi.node;
+
+import java.rmi.Remote;
+import java.rmi.RemoteException;
+
+import org.eclipse.statet.internal.rj.servi.server.RServiBackend;
+import org.eclipse.statet.rj.RjException;
+
+
+public interface RServiNode extends Remote {
+	
+	
+	void ping() throws RemoteException;
+	
+	String getPoolHost() throws RemoteException;
+	RServiBackend bindClient(String client) throws RemoteException;
+	void unbindClient() throws RemoteException;
+	
+	void shutdown() throws RemoteException;
+	
+	int getEvalTime() throws RemoteException;
+	
+	boolean setConsole(String authConfig) throws RjException, RemoteException;
+	
+	/**
+	 * Runs the given code in R
+	 * 
+	 * @param code the R code
+	 * @throws RjException if an R error occurred when running the snippet
+	 * @throws RemoteException if an RMI/communication error occurred
+	 */
+	void runSnippet(String code) throws RjException, RemoteException;
+	
+}
diff --git a/servi/org.eclipse.statet.rj.servi/src/org/eclipse/statet/rj/servi/node/RServiNodeConfig.java b/servi/org.eclipse.statet.rj.servi/src/org/eclipse/statet/rj/servi/node/RServiNodeConfig.java
new file mode 100644
index 0000000..960e0d6
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi/src/org/eclipse/statet/rj/servi/node/RServiNodeConfig.java
@@ -0,0 +1,340 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.servi.node;
+
+import java.io.File;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Properties;
+
+import org.eclipse.statet.internal.rj.servi.Utils;
+
+
+/**
+ * Configuration for an R node.
+ */
+public class RServiNodeConfig implements PropertiesBean {
+	
+	
+	public static final String BEAN_ID= "rconfig";
+	
+	public static final String R_HOME_ID= "r_home.path";
+	
+	public static final String R_ARCH_ID= "r_arch.code";
+	
+	public static final String JAVA_HOME_ID= "java_home.path";
+	
+	public static final String JAVA_ARGS_ID= "java_cmd.args";
+	private static final String JAVA_ARGS_OLD_ID= "java_args.path";
+	
+	public static final String NODE_ENVIRONMENT_VARIABLES_PREFIX= "node_environment.variables.";
+	public static final String NODE_ARGS_ID= "node_cmd.args";
+	
+	public static final String BASE_WD_ID= "base_wd.path";
+	
+	/**
+	 * Property id for R startup snippet
+	 * 
+	 * @see #setRStartupSnippet(String)
+	 * @since 0.5
+	 */
+	public static final String R_STARTUP_SNIPPET_ID= "r_startup.snippet";
+	
+	public static final String CONSOLE_ENABLED_ID= "debug_console.enabled";
+	
+	public static final String VERBOSE_ENABLED_ID= "debug_verbose.enabled";
+	
+	/**
+	 * Property id for timeout of start/stop of nodes
+	 * 
+	 * @see #setStartStopTimeout(long)
+	 * @since 2.0
+	 */
+	public static final String STARTSTOP_TIMEOUT__ID= "startstop_timeout.millis";
+	
+	private static final long STARTSTOP_TIMEOUT_DEFAULT= 30 * 1000;
+	
+	
+	private String rHome;
+	private String rArch;
+	
+	private String javaHome;
+	private String javaArgs;
+	
+	private final Map<String, String> environmentVariables= new HashMap<>();
+	private String nodeArgs;
+	
+	private String baseWd;
+	
+	private String rStartupSnippet;
+	
+	private boolean enableConsole;
+	private boolean enableVerbose;
+	
+	private long startStopTimeout;
+	
+	
+	public RServiNodeConfig() {
+		this.rHome= System.getenv("R_HOME");
+		this.rArch= System.getenv("R_ARCH");
+		this.javaArgs= "-server";
+		this.nodeArgs= "";
+		this.rStartupSnippet= "";
+		this.startStopTimeout= STARTSTOP_TIMEOUT_DEFAULT;
+	}
+	
+	public RServiNodeConfig(final RServiNodeConfig config) {
+		this();
+		synchronized (config) {
+			load(config);
+		}
+	}
+	
+	
+	@Override
+	public String getBeanId() {
+		return BEAN_ID;
+	}
+	
+	public synchronized void load(final RServiNodeConfig templ) {
+		this.rHome= templ.rHome;
+		this.rArch= templ.rArch;
+		this.javaHome= templ.javaHome;
+		this.javaArgs= templ.javaArgs;
+		this.environmentVariables.clear();
+		this.environmentVariables.putAll(templ.environmentVariables);
+		this.nodeArgs= templ.nodeArgs;
+		this.baseWd= templ.baseWd;
+		this.rStartupSnippet= templ.rStartupSnippet;
+		this.enableConsole= templ.enableConsole;
+		this.enableVerbose= templ.enableVerbose;
+		this.startStopTimeout= templ.startStopTimeout;
+	}
+	
+	@Override
+	public synchronized void load(final Properties map) {
+		setRHome(map.getProperty(R_HOME_ID));
+		setRArch(map.getProperty(R_ARCH_ID));
+		setJavaHome(map.getProperty(JAVA_HOME_ID));
+		setJavaArgs(map.getProperty(JAVA_ARGS_ID));
+		if (this.javaArgs.length() == 0) {
+			setJavaArgs(map.getProperty(JAVA_ARGS_OLD_ID));
+		}
+		this.environmentVariables.clear();
+		final int prefixLength= NODE_ENVIRONMENT_VARIABLES_PREFIX.length();
+		for (final Entry<Object, Object> p : map.entrySet()) {
+			final String name= (String) p.getKey();
+			if (name != null && name.length() > prefixLength
+					&& name.startsWith(NODE_ENVIRONMENT_VARIABLES_PREFIX)
+					&& p.getValue() instanceof String) {
+				this.environmentVariables.put(name.substring(prefixLength), (String) p.getValue());
+			}
+		}
+		setNodeArgs(map.getProperty(NODE_ARGS_ID));
+		setBaseWorkingDirectory(map.getProperty(BASE_WD_ID));
+		setRStartupSnippet(map.getProperty(R_STARTUP_SNIPPET_ID));
+		setEnableConsole(Boolean.parseBoolean(map.getProperty(CONSOLE_ENABLED_ID)));
+		setEnableVerbose(Boolean.parseBoolean(map.getProperty(VERBOSE_ENABLED_ID)));
+		{	final String s= map.getProperty(STARTSTOP_TIMEOUT__ID);
+			this.startStopTimeout= ((s != null) ? Long.parseLong(s) : STARTSTOP_TIMEOUT_DEFAULT);
+		}
+	}
+	
+	@Override
+	public synchronized void save(final Properties map) {
+		Utils.setProperty(map, R_HOME_ID, this.rHome);
+		Utils.setProperty(map, R_ARCH_ID, this.rArch);
+		Utils.setProperty(map, JAVA_HOME_ID, this.javaHome);
+		Utils.setProperty(map, JAVA_ARGS_ID, this.javaArgs);
+		for (final Entry<String, String> variable : this.environmentVariables.entrySet()) {
+			map.setProperty(NODE_ENVIRONMENT_VARIABLES_PREFIX + variable.getKey(), variable.getValue());
+		}
+		Utils.setProperty(map, NODE_ARGS_ID, this.nodeArgs);
+		Utils.setProperty(map, BASE_WD_ID, this.baseWd);
+		Utils.setProperty(map, R_STARTUP_SNIPPET_ID, this.rStartupSnippet);
+		Utils.setProperty(map, CONSOLE_ENABLED_ID, Boolean.toString(this.enableConsole));
+		Utils.setProperty(map, VERBOSE_ENABLED_ID, Boolean.toString(this.enableVerbose));
+		Utils.setProperty(map, STARTSTOP_TIMEOUT__ID, Long.toString(this.startStopTimeout));
+	}
+	
+	public synchronized void setRHome(final String path) {
+		this.rHome= path;
+	}
+	
+	public synchronized String getRHome() {
+		return this.rHome;
+	}
+	
+	public synchronized void setRArch(final String code) {
+		this.rArch= code;
+	}
+	
+	public synchronized String getRArch() {
+		return this.rArch;
+	}
+	
+	public synchronized String getJavaHome() {
+		return this.javaHome;
+	}
+	
+	public synchronized void setJavaHome(final String javaHome) {
+		this.javaHome= (javaHome != null && javaHome.trim().length() > 0) ? javaHome : null;
+	}
+	
+	public synchronized String getJavaArgs() {
+		return this.javaArgs;
+	}
+	
+	public synchronized void setJavaArgs(final String args) {
+		this.javaArgs= (args != null) ? args : "";
+	}
+	
+	/**
+	 * Additional environment variables for the R process.
+	 * 
+	 * @return a name - value map of the environment variables
+	 */
+	public synchronized Map<String, String> getEnvironmentVariables() {
+		return this.environmentVariables;
+	}
+	
+	public synchronized void addToClasspath(final String entry) {
+		String cp= this.environmentVariables.get("CLASSPATH");
+		if (cp != null) {
+			cp+= File.pathSeparatorChar + entry;
+		}
+		else {
+			cp= entry;
+		}
+		this.environmentVariables.put("CLASSPATH", cp);
+	}
+	
+	public synchronized String getNodeArgs() {
+		return this.nodeArgs;
+	}
+	
+	public synchronized void setNodeArgs(final String args) {
+		this.nodeArgs= (args != null) ? args : "";
+	}
+	
+	public synchronized void setBaseWorkingDirectory(final String path) {
+		this.baseWd= (path != null && path.trim().length() > 0) ? path : null;
+	}
+	
+	public synchronized String getBaseWorkingDirectory() {
+		return this.baseWd;
+	}
+	
+	/**
+	 * Returns the R code snippet to run at startup of a node.
+	 * 
+	 * @return the code
+	 * 
+	 * @see #setRStartupSnippet(String)
+	 * @since 0.5
+	 */
+	public synchronized String getRStartupSnippet() {
+		return this.rStartupSnippet;
+	}
+	
+	/**
+	 * Sets the R code snippet to run at startup of a node.
+	 * <p>
+	 * Typical use case is to load required R packages. The default is an empty snippet.
+	 * If the execution of the code throws an error, the startup of the node is canceled.</p>
+	 * 
+	 * @param code the R code to run
+	 * 
+	 * @since 0.5
+	 */
+	public synchronized void setRStartupSnippet(final String code) {
+		this.rStartupSnippet= (code != null) ? code : "";
+	}
+	
+	public synchronized boolean getEnableConsole() {
+		return this.enableConsole;
+	}
+	
+	public synchronized void setEnableConsole(final boolean enable) {
+		this.enableConsole= enable;
+	}
+	
+	public synchronized boolean getEnableVerbose() {
+		return this.enableVerbose;
+	}
+	
+	public synchronized void setEnableVerbose(final boolean enable) {
+		this.enableVerbose= enable;
+	}
+	
+	/**
+	 * Returns the timeout of start/stop of nodes
+	 * 
+	 * @return the timeout in milliseconds
+	 * 
+	 * @since 2.0
+	 */
+	public long getStartStopTimeout() {
+		return this.startStopTimeout;
+	}
+	
+	/**
+	 * Sets the timeout of start/stop of nodes
+	 * 
+	 * @param milliseconds the timeout in milliseconds
+	 * 
+	 * @since 2.0
+	 */
+	public void setStartStopTimeout(final long milliseconds) {
+		this.startStopTimeout= milliseconds;
+	}
+	
+	
+	@Override
+	public synchronized boolean validate(final Collection<ValidationMessage> messages) {
+		boolean valid= true;
+		
+		if (this.rHome != null && !new File(this.rHome).exists()) {
+			if (messages != null) {
+				messages.add(new ValidationMessage(R_HOME_ID, "The directory does not exist."));
+			}
+			valid= false;
+		}
+		if (this.javaHome != null && !new File(this.javaHome).exists()) {
+			if (messages != null) {
+				messages.add(new ValidationMessage(JAVA_HOME_ID, "The directory does not exist."));
+			}
+			valid= false;
+		}
+		if (this.baseWd != null && !new File(this.baseWd).exists()) {
+			if (messages != null) {
+				messages.add(new ValidationMessage(BASE_WD_ID, "The directory does not exist."));
+			}
+			valid= false;
+		}
+		
+		if (this.startStopTimeout != -1 && this.startStopTimeout < 0) {
+			if (messages != null) {
+				messages.add(new ValidationMessage(STARTSTOP_TIMEOUT__ID, "Value must be > 0 or -1 (infinite)."));
+			}
+			valid= false;
+		}
+		
+		return valid;
+	}
+	
+}
diff --git a/servi/org.eclipse.statet.rj.servi/src/org/eclipse/statet/rj/servi/node/RServiNodeFactory.java b/servi/org.eclipse.statet.rj.servi/src/org/eclipse/statet/rj/servi/node/RServiNodeFactory.java
new file mode 100644
index 0000000..4a893cb
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi/src/org/eclipse/statet/rj/servi/node/RServiNodeFactory.java
@@ -0,0 +1,30 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.servi.node;
+
+import org.eclipse.statet.ecommons.rmi.core.RMIRegistry;
+
+import org.eclipse.statet.rj.RjInvalidConfigurationException;
+
+
+public interface RServiNodeFactory {
+	
+	
+	void setRegistry(RMIRegistry rmiRegistry);
+	
+	RServiNodeConfig getConfig();
+	void setConfig(RServiNodeConfig config) throws RjInvalidConfigurationException;
+	
+}
diff --git a/servi/org.eclipse.statet.rj.servi/src/org/eclipse/statet/rj/servi/node/RServiNodeManager.java b/servi/org.eclipse.statet.rj.servi/src/org/eclipse/statet/rj/servi/node/RServiNodeManager.java
new file mode 100644
index 0000000..a99472e
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi/src/org/eclipse/statet/rj/servi/node/RServiNodeManager.java
@@ -0,0 +1,64 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.servi.node;
+
+import java.util.NoSuchElementException;
+
+import org.eclipse.statet.rj.RjException;
+import org.eclipse.statet.rj.servi.RServi;
+
+
+/**
+ * Manager for a directly controlled RServi instance.
+ * 
+ * @see RServiImpl
+ */
+public interface RServiNodeManager {
+	
+	
+	String getId();
+	
+	/**
+	 * Returns the R factory passed during creation.
+	 * 
+	 * @return the factory
+	 */
+	RServiNodeFactory getFactory();
+	
+	/**
+	 * Starts the RServi respectively R instance.
+	 * Does nothing if already started.
+	 * 
+	 * @throws RjException if the node could not be started
+	 */
+	void start() throws RjException;
+	
+	/**
+	 * Stops the RServi respectively R instance.
+	 * Does nothing if not started.
+	 */
+	void stop();
+	
+	/**
+	 * Returns the RServi instance.
+	 * 
+	 * @param name
+	 * @return the RServi instance
+	 * @throws NoSuchElementException if the RServi instance is already in use
+	 * @throws RjException if an error occurred
+	 */
+	RServi getRServi(final String name) throws NoSuchElementException, RjException;
+	
+}
diff --git a/servi/org.eclipse.statet.rj.servi/src/org/eclipse/statet/rj/servi/node/RServiPool.java b/servi/org.eclipse.statet.rj.servi/src/org/eclipse/statet/rj/servi/node/RServiPool.java
new file mode 100644
index 0000000..464f195
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi/src/org/eclipse/statet/rj/servi/node/RServiPool.java
@@ -0,0 +1,54 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.servi.node;
+
+import java.rmi.Remote;
+import java.rmi.RemoteException;
+import java.util.NoSuchElementException;
+
+import javax.security.auth.login.LoginException;
+
+import org.eclipse.statet.rj.RjException;
+import org.eclipse.statet.rj.server.ServerLogin;
+import org.eclipse.statet.rj.servi.RServi;
+
+
+/**
+ * Generic interface to a pool providing RServi instances.
+ */
+public interface RServiPool extends Remote {
+	
+	
+	/**
+	 * Requests a {@link RServi} instance from this pool.
+	 * 
+	 * <p>The R services returned by this method are available for exclusive usage
+	 * by the caller (consumer). The consumer is responsible to return it to the pool
+	 * by {@link RServi#close() closing} the RServi.
+	 * 
+	 * @param name a name which can be used to identify the client
+	 * @param login not yet used
+	 * @return an R services node
+	 * 
+	 * @throws NoSuchElementException if there is currently no free RServi
+	 *     instance available. A later call with the same configuration 
+	 *     can be successfully.
+	 * @throws RjException when an server error occurs (retry not promising)
+	 * @throws LoginException when the login failed
+	 * @throws RemoteException when communication or runtime error occurs
+	 */
+	RServi getRServi(String name, ServerLogin login) throws NoSuchElementException, RjException, LoginException, RemoteException;
+	
+}
diff --git a/servi/org.eclipse.statet.rj.servi/srcServer/org/eclipse/statet/internal/rj/servi/server/NodeServer.java b/servi/org.eclipse.statet.rj.servi/srcServer/org/eclipse/statet/internal/rj/servi/server/NodeServer.java
new file mode 100644
index 0000000..1c51343
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi/srcServer/org/eclipse/statet/internal/rj/servi/server/NodeServer.java
@@ -0,0 +1,460 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.internal.rj.servi.server;
+
+import java.io.File;
+import java.io.PrintStream;
+import java.rmi.ConnectException;
+import java.rmi.RemoteException;
+import java.rmi.server.RMIClientSocketFactory;
+import java.rmi.server.RMIServerSocketFactory;
+import java.rmi.server.RemoteServer;
+import java.rmi.server.ServerNotActiveException;
+import java.rmi.server.UnicastRemoteObject;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Timer;
+import java.util.TimerTask;
+import java.util.logging.Level;
+
+import javax.rmi.ssl.SslRMIClientSocketFactory;
+import javax.rmi.ssl.SslRMIServerSocketFactory;
+import javax.security.auth.login.LoginException;
+
+import org.eclipse.statet.rj.RjException;
+import org.eclipse.statet.rj.server.DataCmdItem;
+import org.eclipse.statet.rj.server.MainCmdC2SList;
+import org.eclipse.statet.rj.server.MainCmdItem;
+import org.eclipse.statet.rj.server.MainCmdS2CList;
+import org.eclipse.statet.rj.server.RjsComConfig;
+import org.eclipse.statet.rj.server.RjsComObject;
+import org.eclipse.statet.rj.server.RjsStatus;
+import org.eclipse.statet.rj.server.Server;
+import org.eclipse.statet.rj.server.ServerLogin;
+import org.eclipse.statet.rj.server.srv.RMIServerControl;
+import org.eclipse.statet.rj.server.srv.engine.SrvEngineServer;
+import org.eclipse.statet.rj.server.srvext.Client;
+import org.eclipse.statet.rj.server.srvext.ServerAuthMethod;
+import org.eclipse.statet.rj.server.srvext.ServerRuntimePlugin;
+import org.eclipse.statet.rj.server.srvext.auth.NoAuthMethod;
+import org.eclipse.statet.rj.server.util.ServerUtils;
+import org.eclipse.statet.rj.servi.node.RServiNode;
+
+
+public class NodeServer extends SrvEngineServer {
+	
+	
+	class ConsoleDummy extends Thread {
+		
+		private final Client client;
+		private final PrintStream out;
+		
+		private final MainCmdC2SList c2sList= new MainCmdC2SList();
+		
+		ConsoleDummy(final Client client) {
+			setName("R Console");
+			setDaemon(true);
+			setPriority(NORM_PRIORITY-1);
+			this.client= client;
+			this.out= System.out;
+		}
+		
+		@Override
+		public void run() {
+			try {
+				synchronized (NodeServer.this.srvEngine) {
+					if (NodeServer.this.isConsoleEnabled || NodeServer.this.isConsoleDummyRunning) {
+						return;
+					}
+					NodeServer.this.srvEngine.connect(this.client, new HashMap<String, Object>());
+					NodeServer.this.isConsoleDummyRunning= true;
+				}
+				
+				RjsComObject sendCom= null;
+				boolean error= false;
+				while (true) {
+					try {
+						if (sendCom == null) {
+							this.c2sList.setObjects(null);
+							sendCom= this.c2sList;
+						}
+						final RjsComObject receivedCom= NodeServer.this.srvEngine.runMainLoop(this.client, sendCom);
+						sendCom= null;
+						error= false;
+						if (receivedCom != null) {
+							switch (receivedCom.getComType()) {
+							case RjsComObject.T_PING:
+								sendCom= RjsStatus.OK_STATUS;
+								break;
+							case RjsComObject.T_MAIN_LIST:
+								MainCmdItem item= ((MainCmdS2CList) receivedCom).getItems();
+								MainCmdItem tmp;
+								ITER_ITEMS : for (; (item != null); tmp= item, item= item.next, tmp.next= null) {
+									switch (item.getCmdType()) {
+									case MainCmdItem.T_CONSOLE_WRITE_ITEM:
+										this.out.println("R-OUT (" + item.getOp() + "): " + item.getDataText());
+										break;
+									case MainCmdItem.T_CONSOLE_READ_ITEM:
+										this.out.println("R-PROMPT: " + item.getDataText());
+										break;
+									}
+								}
+								break;
+							case RjsComObject.T_STATUS:
+								switch (((RjsStatus) receivedCom).getCode()) {
+								case Server.S_DISCONNECTED:
+									throw new ConnectException("");
+								case Server.S_LOST:
+								case Server.S_NOT_STARTED:
+								case Server.S_STOPPED:
+									return;
+								}
+							}
+						}
+					}
+					catch (final ConnectException e) {
+						synchronized (NodeServer.this.srvEngine) {
+							if (NodeServer.this.isConsoleEnabled) {
+								NodeServer.this.isConsoleDummyRunning= false;
+								return;
+							}
+							NodeServer.this.srvEngine.connect(this.client, new HashMap<String, Object>());
+						}
+					}
+					catch (final Exception e) {
+						if (error) {
+							throw e;
+						}
+						LOGGER.log(Level.SEVERE, "An error occurred when running dummy R REPL. Trying to continue REPL.", e);
+						error= true;
+					}
+					if (sendCom == null) {
+						try {
+							sleep(5000);
+						}
+						catch (final InterruptedException e) {
+						}
+					}
+				}
+			}
+			catch (final Exception e) {
+				LOGGER.log(Level.SEVERE, "An error occurred when running dummy R REPL. Stopping REPL.", e);
+			}
+		}
+		
+	}
+	
+	class Node implements RServiNode {
+		
+		@Override
+		public boolean setConsole(final String authConfig) throws RemoteException, RjException {
+			final boolean enabled;
+			synchronized (NodeServer.this.srvEngine) {
+//				LOGGER.fine("enter lock");
+				final Client currentClient= NodeServer.this.srvEngine.getCurrentClient();
+				if (currentClient != null) {
+					NodeServer.this.srvEngine.disconnect(currentClient);
+				}
+//				LOGGER.fine("disconnect");
+				if (authConfig != null) {
+					NodeServer.this.authMethod= NodeServer.this.control.createServerAuth(authConfig);
+					enabled= NodeServer.this.isConsoleEnabled= true;
+				}
+				else {
+					NodeServer.this.authMethod= new NoAuthMethod("<internal>");
+					enabled= NodeServer.this.isConsoleEnabled= false;
+//					LOGGER.fine("before start");
+					if (!NodeServer.this.isConsoleDummyRunning) {
+						new ConsoleDummy(NodeServer.this.consoleDummyClient).start();
+					}
+//					LOGGER.fine("after start");
+				}
+			}
+			return enabled;
+		}
+		
+		@Override
+		public int getEvalTime() throws RemoteException {
+			return 0;
+		}
+		
+		@Override
+		public void ping() throws RemoteException {
+		}
+		
+		@Override
+		public String getPoolHost() throws RemoteException {
+			try {
+				return RemoteServer.getClientHost();
+			}
+			catch (final ServerNotActiveException e) {
+				return "<internal>";
+			}
+		}
+		
+		@Override
+		public void runSnippet(final String code) throws RemoteException, RjException {
+			runServerLoopCommand(null, new DataCmdItem(DataCmdItem.EVAL_EXPR_VOID, 0,
+					code, null, null, null ));
+		}
+		
+		@Override
+		public RServiBackend bindClient(final String client) throws RemoteException {
+			return NodeServer.this.bindClient(client);
+		}
+		
+		@Override
+		public void unbindClient() throws RemoteException {
+			NodeServer.this.unbindClient();
+		}
+		
+		@Override
+		public void shutdown() throws RemoteException {
+			NodeServer.this.shutdown();
+		}
+		
+	}
+	
+	class Backend implements RServiBackend {
+		
+		@Override
+		public Server getPublic() throws RemoteException {
+			return null;
+		}
+		
+		@Override
+		public Map<String, Object> getPlatformData() {
+			return NodeServer.this.srvEngine.getPlatformData();
+		}
+		
+		@Override
+		public void setProperties(final Map<String, ? extends Object> properties) throws RemoteException {
+			NodeServer.this.setProperties(properties, this);
+		}
+		
+		public boolean interrupt() throws RemoteException {
+			throw new UnsupportedOperationException();
+		}
+		
+		@Override
+		public void disconnect() throws RemoteException {
+			throw new UnsupportedOperationException();
+		}
+		
+		@Override
+		public RjsComObject runMainLoop(final RjsComObject com) throws RemoteException {
+			return NodeServer.this.runMainLoop(com, this);
+		}
+		
+		@Override
+		public RjsComObject runAsync(final RjsComObject com) throws RemoteException {
+			return NodeServer.this.runAsync(com, this);
+		}
+		
+		@Override
+		public boolean isClosed() throws RemoteException {
+			return (NodeServer.this.currentClientBackend != this);
+		}
+		
+	}
+	
+	
+	private boolean isConsoleEnabled;
+	private boolean isConsoleDummyRunning;
+	
+	private final ServerAuthMethod rserviAuthMethod;
+	
+	private final Client consoleDummyClient;
+	
+	private String currentClientId;
+	private Backend currentClientBackend;
+	private RServiBackend currentClientExp;
+	
+	private final Object serviRunLock= new Object();
+	
+	private String resetCommand;
+	
+	private RMIClientSocketFactory clientSocketFactory;
+	private RMIServerSocketFactory serverSocketFactory;
+	
+	
+	public NodeServer(final RMIServerControl control) {
+		super(control, new NoAuthMethod("<internal>")); //$NON-NLS-1$
+		this.rserviAuthMethod= new NoAuthMethod("<internal>"); //$NON-NLS-1$
+		this.consoleDummyClient= new Client("-", "dummy", (byte) 0); //$NON-NLS-1$
+		
+		if (control.getOptions().containsKey("ssl")) { //$NON-NLS-1$
+			this.clientSocketFactory= new SslRMIClientSocketFactory();
+			this.serverSocketFactory= new SslRMIServerSocketFactory(null, null, true);
+		}
+	}
+	
+	
+	@Override
+	public boolean getConfigUnbindOnStartup() {
+		return false;
+	}
+	
+	
+	@Override
+	public void start(final ServerRuntimePlugin runtimePlugin) throws Exception {
+		super.start(runtimePlugin);
+		
+		this.resetCommand= "{" +
+				"rm(list=ls());" +
+				"gc();" +
+				".rj.getTmp<-function(o){x<-get(o,pos=.GlobalEnv);rm(list=o,pos=.GlobalEnv);x};" +
+				".rj.wd<-\""+this.workingDirectory.replace("\\", "\\\\")+"\";" +
+				"setwd(.rj.wd);" +
+				"graphics.off();" +
+		"}";
+		RjsComConfig.setServerPathResolver(this);
+		
+		final Map<String, Object> properties= new HashMap<>();
+		properties.put("args", new String[0]);
+		this.srvEngine.start(this.consoleDummyClient, properties);
+		
+		try {
+			synchronized (this.serviRunLock) {
+				LOGGER.log(Level.FINE, "Initializing R node: Loading R package 'rj'...");
+				runServerLoopCommand(null, new DataCmdItem(DataCmdItem.EVAL_EXPR_VOID, 0,
+						"library(rj)", null, null, null ));
+				LOGGER.log(Level.FINE, "Initializing R node: Preparing R workspace for first client...");
+				runServerLoopCommand(null, new DataCmdItem(DataCmdItem.EVAL_EXPR_VOID, 0,
+						this.resetCommand, null, null, null ));
+			}
+		}
+		catch (final Exception e) {
+			throw new RjException("An error occurred while preparing initially the workspace.", e);
+		}
+		
+		LOGGER.log(Level.FINE, "Initializing R node: R engine started and initialized.");
+	}
+	
+	@Override
+	protected ServerAuthMethod getAuthMethod(final String command) {
+		if (command.startsWith("rservi")) {
+			return this.rserviAuthMethod;
+		}
+		return super.getAuthMethod(command);
+	}
+	
+	@Override
+	public Object execute(final String command, final Map<String, ? extends Object> properties, final ServerLogin login) throws RemoteException, LoginException {
+		if (command.equals(C_CONSOLE_START)) {
+			throw new UnsupportedOperationException();
+		}
+		if (command.equals(C_CONSOLE_CONNECT)) {
+			synchronized (this.srvEngine) {
+				if (!this.isConsoleEnabled) {
+					throw new RemoteException("Console is not enabled.");
+				}
+				final Client client= connectClient(command, login);
+				return this.srvEngine.connect(client, properties);
+			}
+		}
+		if (command.equals(C_RSERVI_NODECONTROL)) {
+			final Client client= connectClient(command, login);
+			final Node node= new Node();
+			final RServiNode exported= (RServiNode) UnicastRemoteObject.exportObject(node, 0,
+					this.clientSocketFactory, this.serverSocketFactory );
+			return exported;
+		}
+		throw new UnsupportedOperationException();
+	}
+	
+	
+	RServiBackend bindClient(final String client) throws RemoteException {
+		synchronized (this.serverClient) {
+			if (NodeServer.this.currentClientBackend != null) {
+				throw new IllegalStateException();
+			}
+			final Backend backend= new Backend();
+			final RServiBackend export= (RServiBackend) UnicastRemoteObject.exportObject(backend, 0,
+					this.clientSocketFactory, this.serverSocketFactory );
+			this.currentClientId= client;
+			this.currentClientBackend= backend;
+			this.currentClientExp= export;
+			SrvEngineServer.addClient(export);
+			return export;
+		}
+	}
+	
+	void unbindClient() throws RemoteException {
+		synchronized (this.serverClient) {
+			final Backend previous= this.currentClientBackend;
+			if (previous != null) {
+				SrvEngineServer.removeClient(this.currentClientExp);
+				this.currentClientId= null;
+				this.currentClientBackend= null;
+				this.currentClientExp= null;
+				UnicastRemoteObject.unexportObject(previous, true);
+				try {
+					synchronized (this.serviRunLock) {
+						runServerLoopCommand(null, new DataCmdItem(DataCmdItem.EVAL_EXPR_VOID, 0,
+								this.resetCommand, null, null, null ));
+						ServerUtils.cleanDir(new File(this.workingDirectory), "out.log");
+					}
+				}
+				catch (final Exception e) {
+					throw new RemoteException("An error occurred while resetting the workspace.", e);
+				}
+			}
+		}
+	}
+	
+	void shutdown() {
+		this.control.checkCleanup();
+		new Timer(true).schedule(new TimerTask() {
+			@Override
+			public void run() {
+				try {
+					unbindClient();
+				}
+				catch (final Exception e) {
+					e.printStackTrace();
+				}
+				System.exit(0);
+			}
+		}, 500L);
+	}
+	
+	public void setProperties(final Map<String, ? extends Object> properties, final Object caller) throws RemoteException {
+		synchronized (this.serviRunLock) {
+			if (caller != null && this.currentClientBackend != caller) {
+				throw new IllegalAccessError();
+			}
+			this.srvEngine.setProperties(this.serverClient, properties);
+		}
+	}
+	
+	@Override
+	protected RjsComObject runMainLoop(final RjsComObject com, final Object caller) throws RemoteException {
+		synchronized (this.serviRunLock) {
+			if (caller != null && this.currentClientBackend != caller) {
+				throw new IllegalAccessError();
+			}
+		}
+		return super.runMainLoop(com, caller);
+	}
+	
+	private  RjsComObject runAsync(final RjsComObject com, final Backend backend) throws RemoteException {
+		if (backend != null && this.currentClientBackend != backend) {
+			throw new IllegalAccessError();
+		}
+		return this.srvEngine.runAsync(this.serverClient, com);
+	}
+	
+}
diff --git a/servi/org.eclipse.statet.rj.servi/srcServer/org/eclipse/statet/internal/rj/servi/server/RServiBackend.java b/servi/org.eclipse.statet.rj.servi/srcServer/org/eclipse/statet/internal/rj/servi/server/RServiBackend.java
new file mode 100644
index 0000000..a959962
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi/srcServer/org/eclipse/statet/internal/rj/servi/server/RServiBackend.java
@@ -0,0 +1,23 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.internal.rj.servi.server;
+
+import java.rmi.Remote;
+
+import org.eclipse.statet.rj.server.REngine;
+
+
+public interface RServiBackend extends REngine, Remote {
+}
diff --git a/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/internal/rj/servi/APool2.java b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/internal/rj/servi/APool2.java
new file mode 100644
index 0000000..1006117
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/internal/rj/servi/APool2.java
@@ -0,0 +1,153 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.internal.rj.servi;
+
+import org.apache.commons.pool2.PooledObject;
+import org.apache.commons.pool2.impl.DefaultEvictionPolicy;
+import org.apache.commons.pool2.impl.EvictionConfig;
+import org.apache.commons.pool2.impl.EvictionPolicy;
+import org.apache.commons.pool2.impl.GenericObjectPool;
+import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
+
+import org.eclipse.statet.jcommons.collections.ImList;
+
+import org.eclipse.statet.rj.servi.pool.PoolConfig;
+
+
+public class APool2 extends GenericObjectPool<APool2NodeHandler> {
+	
+	
+	private static final EvictionPolicy<APool2NodeHandler> EVICTION_POLICY= new DefaultEvictionPolicy<APool2NodeHandler>() {
+		
+		@Override
+		public boolean evict(final EvictionConfig config,
+				final PooledObject<APool2NodeHandler> underTest, final int idleCount) {
+			return (super.evict(config, underTest, idleCount)
+					|| underTest.getObject().isEvictRequested(0) );
+		}
+		
+	};
+	
+	
+	private static GenericObjectPoolConfig createAConfig(final PoolConfig config) {
+		final GenericObjectPoolConfig aConfig= new GenericObjectPoolConfig();
+		
+		aConfig.setLifo(true);
+		aConfig.setTestOnReturn(true);
+		aConfig.setTestWhileIdle(false);
+		aConfig.setTestOnBorrow(false);
+		aConfig.setBlockWhenExhausted(true);
+		aConfig.setMaxTotal(config.getMaxTotalCount());
+		aConfig.setMaxWaitMillis(config.getMaxWaitTime());
+		aConfig.setMinIdle(config.getMinIdleCount());
+		aConfig.setMaxIdle(config.getMaxIdleCount());
+		aConfig.setMinEvictableIdleTimeMillis(0L);
+		aConfig.setSoftMinEvictableIdleTimeMillis(config.getMinIdleTime());
+		aConfig.setTimeBetweenEvictionRunsMillis(7500L);
+		aConfig.setNumTestsPerEvictionRun(-3);
+		
+		return aConfig;
+	}
+	
+	
+	private final APool2NodeFactory factory;
+	
+	private volatile boolean closing;
+	
+	
+	public APool2(final APool2NodeFactory factory, final PoolConfig config) {
+		super(factory, createAConfig(config));
+		
+		factory.setPool(this);
+		this.factory= factory;
+	}
+	
+	
+	public void setConfig(final PoolConfig config) {
+		setConfig(createAConfig(config));
+	}
+	
+	
+	public APool2NodeHandler borrowObject(final String client) throws Exception {
+		if (this.closing) {
+			throw new IllegalStateException("Pool not open");
+		}
+		
+		this.factory.registerArgs(client);
+		try {
+			return super.borrowObject();
+		}
+		finally {
+			this.factory.clearArgs();
+		}
+	}
+	
+	@Override
+	public int getMinIdle() {
+		if (this.closing) {
+			return 0;
+		}
+		return super.getMinIdle();
+	}
+	
+	public void close(final long evictionTimeout) {
+		this.closing= true;
+		
+		clear();
+		
+		final long evictNanos= APool2NodeHandler.evictNanos(evictionTimeout);
+		final boolean evictDirect= (evictionTimeout == 0);
+		
+		final ImList<APool2NodeHandler> objects= this.factory.getAllObjects();
+		for (final APool2NodeHandler poolObj : objects) {
+			poolObj.doEvict(evictNanos, evictDirect);
+		}
+	}
+	
+	@Override
+	public void evict() throws Exception {
+		int evicted;
+		do {
+			evicted= 0;
+			final long nanos= APool2NodeHandler.safeNanos(System.nanoTime());
+			
+			final ImList<APool2NodeHandler> objects= this.factory.getAllObjects();
+			for (final APool2NodeHandler poolObj : objects) {
+				if (poolObj.isEvictRequested(nanos)) {
+					try {
+						evicted++;
+						invalidateObject(poolObj);
+					}
+					catch (final Exception e) {}
+				}
+			}
+		}
+		while (evicted > 0);
+		
+		super.evict();
+		
+		if (this.closing && this.factory.getNumAll() == 0) {
+			super.close();
+			
+			this.factory.dispose();
+		}
+	}
+	
+	@Override
+	protected EvictionPolicy<APool2NodeHandler> getEvictionPolicy() {
+		return EVICTION_POLICY;
+	}
+	
+}
diff --git a/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/internal/rj/servi/APool2NodeFactory.java b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/internal/rj/servi/APool2NodeFactory.java
new file mode 100644
index 0000000..af6d8ae
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/internal/rj/servi/APool2NodeFactory.java
@@ -0,0 +1,250 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.internal.rj.servi;
+
+import java.rmi.server.RMIClientSocketFactory;
+import java.rmi.server.RMIServerSocketFactory;
+import java.rmi.server.RemoteServer;
+import java.rmi.server.ServerNotActiveException;
+import java.rmi.server.UnicastRemoteObject;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+import javax.rmi.ssl.SslRMIClientSocketFactory;
+import javax.rmi.ssl.SslRMIServerSocketFactory;
+
+import org.apache.commons.pool2.PooledObject;
+import org.apache.commons.pool2.PooledObjectFactory;
+import org.apache.commons.pool2.impl.DefaultPooledObject;
+
+import org.eclipse.statet.jcommons.collections.CopyOnWriteIdentityListSet;
+import org.eclipse.statet.jcommons.collections.CopyOnWriteList;
+import org.eclipse.statet.jcommons.collections.ImList;
+
+
+public class APool2NodeFactory implements PooledObjectFactory<APool2NodeHandler> {
+	
+	
+	private APool2 pool;
+	
+	private final NodeFactory nodeFactory;
+	
+	private final CopyOnWriteList<APool2NodeHandler> nodes= new CopyOnWriteList<>();
+	
+	private final CopyOnWriteIdentityListSet<PoolListener> poolListeners;
+	
+	private int statMaxTotal;
+	private int statMaxAllocated;
+	
+	private int maxUsageCount;
+	
+	private RMIClientSocketFactory sslClientSocketFactory;
+	private RMIServerSocketFactory sslServerSocketFactory;
+	
+	private final ThreadLocal<String> activateArguments= new ThreadLocal<>();
+	
+	private final ExecutorService executor= Executors.newSingleThreadExecutor();
+	
+	
+	public APool2NodeFactory(final NodeFactory factory,
+			final CopyOnWriteIdentityListSet<PoolListener> poolListeners) {
+		this.nodeFactory= factory;
+		this.poolListeners= poolListeners;
+	}
+	
+	void setPool(final APool2 pool) {
+		this.pool= pool;
+	}
+	
+	void dispose() {
+		this.executor.shutdown();
+	}
+	
+	
+	public void setMaxUsageCount(final int count) {
+		this.maxUsageCount= count;
+	}
+	
+	public int getNumAll() {
+		return this.nodes.size();
+	}
+	
+	public ImList<APool2NodeHandler> getAllObjects() {
+		return this.nodes.toList();
+	}
+	
+	
+	@Override
+	public PooledObject<APool2NodeHandler> makeObject() throws Exception {
+		// start
+		final APool2NodeHandler poolObj= new APool2NodeHandler(this.pool);
+		synchronized (this.nodes) {
+			this.nodes.add(poolObj);
+			
+			final int total= this.nodes.size();
+			if (total > this.statMaxTotal) {
+				this.statMaxTotal= total;
+			}
+		}
+		
+		boolean ok= false;
+		try {
+			for (final PoolListener listener : this.poolListeners.toList()) {
+				try {
+					listener.initializing(poolObj);
+				}
+				catch (final Exception e) {
+					e.printStackTrace(); // TODO
+				}
+			}
+			
+			this.nodeFactory.createNode(poolObj);
+			
+			{	RMIClientSocketFactory clientSocketFactory= null;
+				RMIServerSocketFactory serverSocketFactory= null;
+				if (poolObj.address.isSSL()) {
+					synchronized (this) {
+						if (this.sslClientSocketFactory == null) {
+							this.sslClientSocketFactory= new SslRMIClientSocketFactory();
+							this.sslServerSocketFactory= new SslRMIServerSocketFactory(null, null, true);
+						}
+						clientSocketFactory= this.sslClientSocketFactory;
+						serverSocketFactory= this.sslServerSocketFactory;
+					}
+				}
+				poolObj.thisRemote= UnicastRemoteObject.exportObject(poolObj, 0,
+						clientSocketFactory, serverSocketFactory );
+			}
+			
+			for (final PoolListener listener : this.poolListeners.toList()) {
+				try {
+					listener.initialized(poolObj);
+				}
+				catch (final Exception e) {
+					e.printStackTrace(); // TODO
+				}
+			}
+			
+			ok= true;
+			return poolObj.getPooledObject();
+		}
+		finally {
+			if (!ok) {
+				this.nodes.remove(poolObj);
+			}
+		}
+	}
+	
+	
+	public void registerArgs(final String client) {
+		this.activateArguments.set(client);
+	}
+	
+	public void clearArgs() {
+		this.activateArguments.remove();
+	}
+	
+	@Override
+	public void activateObject(final PooledObject<APool2NodeHandler> p) throws Exception {
+		synchronized (this) {
+			final int numAllocated= this.pool.getNumActive();
+			if (numAllocated > this.statMaxAllocated) {
+				this.statMaxAllocated= numAllocated;
+			}
+		}
+		
+		final String name= this.activateArguments.get();
+		
+		final APool2NodeHandler poolObj= p.getObject();
+		String clientHost;
+		try {
+			clientHost= RemoteServer.getClientHost();
+		}
+		catch (final ServerNotActiveException e) {
+			clientHost= poolObj.node.getPoolHost();
+		}
+		poolObj.bindClient(name, clientHost);
+	}
+	
+	@Override
+	public void passivateObject(final PooledObject<APool2NodeHandler> p) throws Exception {
+		final APool2NodeHandler poolObj= p.getObject();
+		poolObj.unbindClient();
+	}
+	
+	@Override
+	public boolean validateObject(final PooledObject<APool2NodeHandler> p) {
+		final APool2NodeHandler poolObj= p.getObject();
+		
+		if (poolObj.isEvictRequested(0)) {
+			return false;
+		}
+		
+		final int max= this.maxUsageCount;
+		if (max > 0 && ((DefaultPooledObject<?>) p).getBorrowedCount() > max) {
+			poolObj.stats.shutdownReason= Stats.MAX_USAGE;
+			return false;
+		}
+		return true;
+	}
+	
+	@Override
+	public void destroyObject(final PooledObject<APool2NodeHandler> p) throws Exception {
+		final APool2NodeHandler poolObj= p.getObject();
+		try {
+			if (poolObj.thisRemote != null) {
+				try {
+					poolObj.thisRemote= null;
+					UnicastRemoteObject.unexportObject(poolObj, true);
+				}
+				catch (final Throwable e) {
+					Utils.logWarning(Messages.RmiUnexportNode_error_message, e);
+				}
+			}
+		}
+		finally {
+			this.executor.submit(new Runnable() {
+				@Override
+				public void run() {
+					try {
+						APool2NodeFactory.this.nodeFactory.stopNode(poolObj);
+						
+						for (final PoolListener listener : APool2NodeFactory.this.poolListeners.toList()) {
+							try {
+								listener.disposed(poolObj);
+							}
+							catch (final Exception e) {
+								e.printStackTrace(); // TODO
+							}
+						}
+					}
+					finally {
+						APool2NodeFactory.this.nodes.remove(poolObj);
+					}
+				}
+			});
+		}
+	}
+	
+	
+	public int getStatMaxTotal() {
+		return this.statMaxTotal;
+	}
+	
+	public int getStatMaxAllocated() {
+		return this.statMaxAllocated;
+	}
+	
+}
diff --git a/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/internal/rj/servi/APool2NodeHandler.java b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/internal/rj/servi/APool2NodeHandler.java
new file mode 100644
index 0000000..12cb215
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/internal/rj/servi/APool2NodeHandler.java
@@ -0,0 +1,223 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.internal.rj.servi;
+
+import java.rmi.Remote;
+import java.rmi.RemoteException;
+import java.rmi.server.Unreferenced;
+
+import org.apache.commons.pool2.PooledObject;
+import org.apache.commons.pool2.impl.DefaultPooledObject;
+
+import org.eclipse.statet.rj.RjException;
+import org.eclipse.statet.rj.servi.pool.PoolNodeObject;
+import org.eclipse.statet.rj.servi.pool.PoolNodeState;
+
+
+public class APool2NodeHandler extends NodeHandler implements PoolNodeObject,
+		RServiImpl.PoolRef, Unreferenced {
+	
+	
+	static final long safeNanos(final long nanos) {
+		return (nanos != 0) ? nanos : 1;
+	}
+	
+	static final long evictNanos(final long timeoutMillis) {
+		long nanos= System.nanoTime();
+		if (timeoutMillis > 0) {
+			nanos+= timeoutMillis * 1_000_000L;
+		}
+		return safeNanos(nanos);
+	}
+	
+	
+	private final APool2 pool;
+	private final DefaultPooledObject<APool2NodeHandler> p;
+	private volatile long evict;
+	
+	final Stats.NodeEntry stats= new Stats.NodeEntry();
+	
+	Remote thisRemote;
+	
+	private volatile long clientId;
+	
+	
+	public APool2NodeHandler(final APool2 pool) {
+		this.pool= pool;
+		this.p= new DefaultPooledObject<>(this);
+	}
+	
+	
+	@Override
+	public NodeHandler getNodeHandler() {
+		return this;
+	}
+	
+	PooledObject<APool2NodeHandler> getPooledObject() {
+		return this.p;
+	}
+	
+	@Override
+	public long getCreationTime() {
+		return this.p.getCreateTime();
+	}
+	
+	@Override
+	public long getAllocatedCount() {
+		return this.p.getBorrowedCount();
+	}
+	
+	@Override
+	public long getAllocatedDuration() {
+		return this.p.getActiveTimeMillis();
+	}
+	
+	@Override
+	public PoolNodeState getState() {
+		if (this.node == null) {
+			switch (this.p.getState()) {
+			case IDLE:
+				return PoolNodeState.INITIALIZING;
+			case INVALID:
+				return PoolNodeState.DISPOSED;
+			default:
+				break;
+			}
+		}
+		
+		switch(this.p.getState()) {
+		case IDLE:
+			return PoolNodeState.IDLING;
+		case ALLOCATED:
+			return PoolNodeState.ALLOCATED;
+		case EVICTION:
+			return PoolNodeState.EVICTING;
+		default:
+			return PoolNodeState.CHECKING;
+		}
+	}
+	
+	@Override
+	public long getStateTime() {
+		switch (getState()) {
+		case INITIALIZING:
+			return getStartTime();
+		case ALLOCATED:
+			return this.p.getLastBorrowTime();
+		case CHECKING:
+		case IDLING:
+		case EVICTING:
+			return this.p.getLastReturnTime();
+		case DISPOSED:
+			return getShutdownTime();
+		default:
+			return -1;
+		}
+	}
+	
+	
+	@Override
+	void bindClient(final String name, final String host) throws RemoteException {
+		super.bindClient(name, host);
+		synchronized (this) {
+			this.clientId= this.p.getBorrowedCount();
+		}
+	}
+	
+	void invalidateClient() {
+		this.clientId= -1L;
+		setClientLabel(null);
+	}
+	
+	@Override
+	void unbindClient() throws RemoteException {
+		synchronized (this) {
+			invalidateClient();
+		}
+		super.unbindClient();
+	}
+	
+	@Override
+	public void evict(final long timeout) {
+		doEvict(evictNanos(timeout), timeout == 0);
+	}
+	
+	void doEvict(final long nanos, boolean direct) {
+		synchronized (this.p) {
+			if (this.evict == 0 || this.evict > nanos) {
+				this.evict= safeNanos(nanos);
+			}
+			
+			direct|= this.p.startEvictionTest();
+		}
+		
+		if (direct) {
+			try {
+				this.pool.invalidateObject(this);
+			}
+			catch (final Exception e) {}
+		}
+	}
+	
+	boolean isEvictRequested(final long nanos) {
+		final long evict= this.evict;
+		return (evict != 0
+				&& (nanos == 0 || nanos >= evict) );
+	}
+	
+	public long getAccessId() {
+		final long clientId= this.clientId;
+		if (clientId == -1L) {
+			throw new IllegalAccessError();
+		}
+		return clientId;
+	}
+	
+	@Override
+	public void returnObject(final long accessId) throws RjException {
+		try {
+			synchronized (this) {
+				if (this.clientId != accessId) {
+					throw new IllegalStateException("Access id no longer valid.");
+				}
+				invalidateClient();
+			}
+			this.pool.returnObject(this);
+		}
+		catch (final Exception e) {
+			Utils.logError("An unexpected error occurred when returning RServi instance.", e);
+			throw new RjException("An unexpected error occurred when closing RServi instance. See server log for detail.");
+		}
+	}
+	
+	@Override
+	public void unreferenced() {
+		final PoolNodeState state= getState();
+		synchronized (this) {
+			if (state != PoolNodeState.ALLOCATED || this.clientId == -1L) {
+				return;
+			}
+			invalidateClient();
+		}
+		Utils.logInfo("The RServi instance is lent and unreferenced. It will be returned now.");
+		try {
+			this.pool.returnObject(this);
+		}
+		catch (final Exception e) {
+			Utils.logError("An unexpected error occurred when returning RServi instance.", e);
+		}
+	}
+	
+}
diff --git a/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/internal/rj/servi/MXNetConfig.java b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/internal/rj/servi/MXNetConfig.java
new file mode 100644
index 0000000..47cbc74
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/internal/rj/servi/MXNetConfig.java
@@ -0,0 +1,72 @@
+/*=============================================================================#
+ # Copyright (c) 2013, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.internal.rj.servi;
+
+import java.lang.management.ManagementFactory;
+
+import javax.management.JMException;
+import javax.management.ObjectName;
+import javax.management.OperationsException;
+
+import org.eclipse.statet.rj.servi.jmx.NetConfigMXBean;
+import org.eclipse.statet.rj.servi.pool.NetConfig;
+import org.eclipse.statet.rj.servi.pool.PoolServer;
+
+
+public class MXNetConfig extends NetConfig implements NetConfigMXBean {
+	
+	
+	private final PoolServer server;
+	
+	private ObjectName jmName;
+	
+	
+	public MXNetConfig(final PoolServer server) {
+		if (server == null) {
+			throw new NullPointerException("server");
+		}
+		this.server= server;
+	}
+	
+	
+	public void initJM() throws JMException {
+		this.jmName= new ObjectName(this.server.getJMBaseName() + "type=Server.NetConfig");
+		ManagementFactory.getPlatformMBeanServer().registerMBean(this, this.jmName);
+	}
+	
+	public void disposeJM() throws JMException {
+		if (this.jmName != null) {
+			ManagementFactory.getPlatformMBeanServer().unregisterMBean(this.jmName);
+			this.jmName= null;
+		}
+	}
+	
+	
+	@Override
+	public void loadDefault() throws OperationsException {
+		load(new NetConfig());
+	}
+	
+	@Override
+	public void loadSaved() throws OperationsException {
+		MXUtil.load(this, this.server.getRJContext());
+	}
+	
+	@Override
+	public void save() throws OperationsException {
+		MXUtil.save(this, this.server.getRJContext());
+	}
+	
+}
diff --git a/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/internal/rj/servi/MXNode.java b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/internal/rj/servi/MXNode.java
new file mode 100644
index 0000000..314169c
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/internal/rj/servi/MXNode.java
@@ -0,0 +1,126 @@
+/*=============================================================================#
+ # Copyright (c) 2013, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.internal.rj.servi;
+
+import java.lang.management.ManagementFactory;
+import java.util.Date;
+
+import javax.management.JMException;
+import javax.management.ObjectName;
+import javax.management.OperationsException;
+
+import org.eclipse.statet.ecommons.rmi.core.RMIAddress;
+
+import org.eclipse.statet.rj.RjException;
+import org.eclipse.statet.rj.servi.jmx.NodeMXBean;
+import org.eclipse.statet.rj.servi.jmx.NodeStateMX;
+import org.eclipse.statet.rj.servi.pool.PoolConfig;
+import org.eclipse.statet.rj.servi.pool.PoolNodeItem;
+import org.eclipse.statet.rj.servi.pool.PoolNodeObject;
+import org.eclipse.statet.rj.servi.pool.PoolServer;
+
+
+public class MXNode implements NodeMXBean {
+	
+	
+	private final PoolServer server;
+	private final PoolNodeObject nodeObj;
+	private final RMIAddress address;
+	private final Date creationTime;
+	
+	private ObjectName jmName;
+	
+	
+	public MXNode(final PoolServer server, final PoolNodeObject nodeObj) {
+		this.server= server;
+		this.nodeObj= nodeObj;
+		this.address= this.nodeObj.getNodeHandler().getAddress();
+		if (this.address == null) {
+			throw new NullPointerException("address");
+		}
+		this.creationTime= new Date(this.nodeObj.getCreationTime());
+	}
+	
+	
+	public void initJM() throws JMException {
+		this.jmName= new ObjectName(this.server.getJMBaseName() + "type=Server.Node,rservi.nodeId=" + this.address.getName());
+		ManagementFactory.getPlatformMBeanServer().registerMBean(this, this.jmName);
+	}
+	
+	public void disposeJM() throws JMException {
+		if (this.jmName != null) {
+			ManagementFactory.getPlatformMBeanServer().unregisterMBean(this.jmName);
+			this.jmName= null;
+		}
+	}
+	
+	
+	@Override
+	public String getId() {
+		return this.address.getName();
+	}
+	
+	@Override
+	public Date getCreationTime() {
+		return this.creationTime;
+	}
+	
+	@Override
+	public NodeStateMX getState() {
+		final PoolNodeItem item= new PoolNodeItem(this.nodeObj, System.currentTimeMillis());
+		return new MXNodeState(item);
+	}
+	
+	@Override
+	public boolean isConsoleEnabled() {
+		return this.nodeObj.getNodeHandler().isConsoleEnabled();
+	}
+	
+	@Override
+	public synchronized void setConsoleEnabled(final boolean enable) throws OperationsException {
+		try {
+			if (enable) {
+				this.nodeObj.getNodeHandler().enableConsole("none");
+			}
+			else {
+				this.nodeObj.getNodeHandler().disableConsole();
+			}
+		}
+		catch (final RjException e) {
+			throw new OperationsException(e.getMessage());
+		}
+	}
+	
+	@Override
+	public void stop() throws OperationsException {
+		final PoolConfig config= new PoolConfig();
+		this.server.getPoolConfig(config);
+		this.nodeObj.evict(config.getEvictionTimeout());
+	}
+	
+	@Override
+	public void stop(final long timeoutMillis) throws OperationsException {
+		if (timeoutMillis < 0) {
+			throw new OperationsException("Invalid parameter 'timeoutMillis' >= 0.");
+		}
+		this.nodeObj.evict(timeoutMillis);
+	}
+	
+	@Override
+	public void kill() throws OperationsException {
+		this.nodeObj.evict(0);
+	}
+	
+}
diff --git a/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/internal/rj/servi/MXNodeConfig.java b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/internal/rj/servi/MXNodeConfig.java
new file mode 100644
index 0000000..2e5e72c
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/internal/rj/servi/MXNodeConfig.java
@@ -0,0 +1,105 @@
+/*=============================================================================#
+ # Copyright (c) 2013, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.internal.rj.servi;
+
+import java.lang.management.ManagementFactory;
+import java.util.Map;
+
+import javax.management.JMException;
+import javax.management.ObjectName;
+import javax.management.OperationsException;
+
+import org.eclipse.statet.rj.RjInvalidConfigurationException;
+import org.eclipse.statet.rj.servi.jmx.NodeConfigMXBean;
+import org.eclipse.statet.rj.servi.node.RServiNodeConfig;
+import org.eclipse.statet.rj.servi.pool.PoolServer;
+
+
+public class MXNodeConfig extends RServiNodeConfig implements NodeConfigMXBean {
+	
+	
+	private final PoolServer server;
+	
+	private ObjectName jmName;
+	
+	
+	public MXNodeConfig(final PoolServer server) throws JMException {
+		if (server == null) {
+			throw new NullPointerException("server");
+		}
+		this.server= server;
+	}
+	
+	
+	public void initJM() throws JMException {
+		this.jmName= new ObjectName(this.server.getJMBaseName() + "type=Server.NodeConfig");
+		ManagementFactory.getPlatformMBeanServer().registerMBean(this, this.jmName);
+	}
+	
+	public void disposeJM() throws JMException {
+		if (this.jmName != null) {
+			ManagementFactory.getPlatformMBeanServer().unregisterMBean(this.jmName);
+			this.jmName= null;
+		}
+	}
+	
+	
+	@Override
+	public synchronized void setEnvironmentVariable(final String name, final String value) {
+		final Map<String, String> variables= getEnvironmentVariables();
+		if (value == null) {
+			variables.remove(name);
+		}
+		else {
+			variables.put(name, value);
+		}
+	}
+	
+	
+	@Override
+	public void apply() throws OperationsException {
+		synchronized (this) {
+			MXUtil.validate(this);
+			
+			try {
+				this.server.setNodeConfig(this);
+			}
+			catch (final RjInvalidConfigurationException e) {
+				throw new OperationsException(e.getMessage());
+			}
+		}
+	}
+	
+	@Override
+	public void loadActual() throws OperationsException {
+		this.server.getNodeConfig(this);
+	}
+	
+	@Override
+	public void loadDefault() throws OperationsException {
+		load(new RServiNodeConfig());
+	}
+	
+	@Override
+	public void loadSaved() throws OperationsException {
+		MXUtil.load(this, this.server.getRJContext());
+	}
+	
+	@Override
+	public void save() throws OperationsException {
+		MXUtil.save(this, this.server.getRJContext());
+	}
+	
+}
diff --git a/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/internal/rj/servi/MXNodeManager.java b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/internal/rj/servi/MXNodeManager.java
new file mode 100644
index 0000000..9ebb8c7
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/internal/rj/servi/MXNodeManager.java
@@ -0,0 +1,119 @@
+/*=============================================================================#
+ # Copyright (c) 2013, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.internal.rj.servi;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import javax.management.JMException;
+
+import org.eclipse.statet.rj.servi.pool.PoolNodeObject;
+import org.eclipse.statet.rj.servi.pool.PoolServer;
+
+
+public class MXNodeManager implements PoolListener {
+	
+	
+	private final PoolServer server;
+	
+	private final Map<PoolNodeObject, MXNode> nodes= new HashMap<>();
+	
+	private final PoolManager poolManager;
+	
+	
+	public MXNodeManager(final PoolServer server, final PoolManager poolManager) {
+		this.server= server;
+		this.poolManager= poolManager;
+	}
+	
+	
+	@Override
+	public void initializing(final PoolNodeObject nodeObj) {
+	}
+	
+	@Override
+	public void initialized(final PoolNodeObject nodeObj) {
+		final MXNode node;
+		synchronized (this) {
+			if (this.nodes.containsKey(nodeObj)) {
+				return;
+			}
+			node= new MXNode(this.server, nodeObj);
+			this.nodes.put(nodeObj, node);
+		}
+		try {
+			node.initJM();
+		}
+		catch (final JMException e) {
+			Utils.logError("An error occurred when initializing JMX for node '" + node.getId() + "'.", e);
+		}
+	}
+	
+	@Override
+	public void disposed(final PoolNodeObject nodeObj) {
+		final MXNode node= this.nodes.remove(nodeObj);
+		if (node != null) {
+			dispose(node);
+		}
+	}
+	
+	private void dispose(final MXNode node) {
+		try {
+			node.disposeJM();
+		}
+		catch (final JMException e) {
+			Utils.logError("An error occurred when disposing JMX for node '" + node.getId() + "'.", e);
+		}
+	}
+	
+	public void activate() {
+		this.poolManager.addPoolListener(this);
+		
+		final Collection<? extends PoolNodeObject> objects= this.poolManager.getPoolNodeObjects();
+		synchronized (this) {
+			for (final PoolNodeObject nodeObj : objects) {
+				switch (nodeObj.getState()) {
+				case EVICTING:
+				case DISPOSED:
+					break;
+				default:
+					initialized(nodeObj);
+					break;
+				}
+			}
+		}
+	}
+	
+	public void deactivate() {
+		this.poolManager.removePoolListener(this);
+		
+		synchronized (this) {
+			try {
+				for (final Entry<PoolNodeObject, MXNode> entry : this.nodes.entrySet()) {
+					dispose(entry.getValue());
+				}
+			}
+			catch (final Exception e) {
+				e.printStackTrace();
+			}
+			finally {
+				this.nodes.clear();
+			}
+		}
+	}
+	
+}
diff --git a/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/internal/rj/servi/MXNodeState.java b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/internal/rj/servi/MXNodeState.java
new file mode 100644
index 0000000..757c6c1
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/internal/rj/servi/MXNodeState.java
@@ -0,0 +1,80 @@
+/*=============================================================================#
+ # Copyright (c) 2013, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.internal.rj.servi;
+
+import java.util.Date;
+
+import org.eclipse.statet.ecommons.rmi.core.RMIAddress;
+
+import org.eclipse.statet.rj.servi.jmx.NodeStateMX;
+import org.eclipse.statet.rj.servi.pool.PoolNodeItem;
+import org.eclipse.statet.rj.servi.pool.PoolNodeState;
+
+
+public class MXNodeState implements NodeStateMX {
+	
+	
+	private final PoolNodeItem item;
+	
+	private final Date creationTime;
+	private final Date stateTime;
+	
+	
+	public MXNodeState(final PoolNodeItem item) {
+		this.item= item;
+		
+		this.creationTime= new Date(this.item.getCreationTime());
+		this.stateTime= new Date(this.item.getStateTime());
+	}
+	
+	
+	@Override
+	public PoolNodeState getState() {
+		return this.item.getState();
+	}
+	
+	@Override
+	public Date getStateBeginTime() {
+		return this.stateTime;
+	}
+	
+	@Override
+	public String getCurrentClientId() {
+		return this.item.getCurrentClientId();
+	}
+	
+	
+	@Override
+	public Date getCreationTime() {
+		return this.creationTime;
+	}
+	
+	@Override
+	public long getUsageCount() {
+		return this.item.getUsageCount();
+	}
+	
+	@Override
+	public long getUsageDuration() {
+		return this.item.getUsageDuration();
+	}
+	
+	@Override
+	public String getRMIAddress() {
+		final RMIAddress address= this.item.getAddress();
+		return (address != null) ? address.getAddress() : "";
+	}
+	
+}
diff --git a/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/internal/rj/servi/MXPoolConfig.java b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/internal/rj/servi/MXPoolConfig.java
new file mode 100644
index 0000000..1c6593a
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/internal/rj/servi/MXPoolConfig.java
@@ -0,0 +1,86 @@
+/*=============================================================================#
+ # Copyright (c) 2013, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.internal.rj.servi;
+
+import java.lang.management.ManagementFactory;
+
+import javax.management.JMException;
+import javax.management.ObjectName;
+import javax.management.OperationsException;
+
+import org.eclipse.statet.rj.servi.jmx.PoolConfigMXBean;
+import org.eclipse.statet.rj.servi.pool.PoolConfig;
+import org.eclipse.statet.rj.servi.pool.PoolServer;
+
+
+public class MXPoolConfig extends PoolConfig implements PoolConfigMXBean {
+	
+	
+	private final PoolServer server;
+	
+	private ObjectName jmName;
+	
+	
+	public MXPoolConfig(final PoolServer server) throws JMException {
+		if (server == null) {
+			throw new NullPointerException("server");
+		}
+		this.server= server;
+	}
+	
+	
+	public void initJM() throws JMException {
+		this.jmName= new ObjectName(this.server.getJMBaseName() + "type=Server.PoolConfig");
+		ManagementFactory.getPlatformMBeanServer().registerMBean(this, this.jmName);
+	}
+	
+	public void disposeJM() throws JMException {
+		if (this.jmName != null) {
+			ManagementFactory.getPlatformMBeanServer().unregisterMBean(this.jmName);
+			this.jmName= null;
+		}
+	}
+	
+	
+	@Override
+	public void apply() throws OperationsException {
+		synchronized (this) {
+			MXUtil.validate(this);
+			
+			this.server.setPoolConfig(this);
+		}
+	}
+	
+	@Override
+	public void loadActual() throws OperationsException {
+		this.server.getPoolConfig(this);
+	}
+	
+	@Override
+	public void loadDefault() throws OperationsException {
+		load(new PoolConfig());
+	}
+	
+	@Override
+	public void loadSaved() throws OperationsException {
+		MXUtil.load(this, this.server.getRJContext());
+	}
+	
+	@Override
+	public void save() throws OperationsException {
+		MXUtil.save(this, this.server.getRJContext());
+	}
+	
+}
diff --git a/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/internal/rj/servi/MXPoolStatus.java b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/internal/rj/servi/MXPoolStatus.java
new file mode 100644
index 0000000..a78fe32
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/internal/rj/servi/MXPoolStatus.java
@@ -0,0 +1,76 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.internal.rj.servi;
+
+import java.lang.management.ManagementFactory;
+import java.util.Date;
+
+import javax.management.JMException;
+import javax.management.ObjectName;
+
+import org.eclipse.statet.rj.servi.jmx.NodeStateMX;
+import org.eclipse.statet.rj.servi.jmx.PoolStatusMX;
+import org.eclipse.statet.rj.servi.pool.PoolNodeItem;
+import org.eclipse.statet.rj.servi.pool.PoolServer;
+import org.eclipse.statet.rj.servi.pool.PoolStatus;
+
+
+public class MXPoolStatus extends PoolStatus<NodeStateMX> implements PoolStatusMX {
+	
+	
+	private ObjectName jmName;
+	
+	private Date time;
+	
+	
+	public MXPoolStatus(final PoolServer server) {
+		super(server);
+		
+		refresh();
+	}
+	
+	
+	public void initJM() throws JMException {
+		this.jmName= new ObjectName(this.server.getJMBaseName() + "type=Server.PoolStatus");
+		ManagementFactory.getPlatformMBeanServer().registerMBean(this, this.jmName);
+	}
+	
+	public void disposeJM() throws JMException {
+		if (this.jmName != null) {
+			ManagementFactory.getPlatformMBeanServer().unregisterMBean(this.jmName);
+			this.jmName= null;
+		}
+	}
+	
+	protected synchronized void refresh() {
+		final long stamp= System.currentTimeMillis();
+		refresh(this.server.getManager(), stamp);
+		this.time= new Date(stamp);
+	}
+	
+	
+	@Override
+	protected NodeStateMX createNodeState(final PoolNodeItem item) {
+		return new MXNodeState(item);
+	}
+	
+	
+	@Override
+	public synchronized Date getStatusTime() {
+		return this.time;
+	}
+	
+	
+}
diff --git a/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/internal/rj/servi/MXUtil.java b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/internal/rj/servi/MXUtil.java
new file mode 100644
index 0000000..5fb08ac
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/internal/rj/servi/MXUtil.java
@@ -0,0 +1,108 @@
+/*=============================================================================#
+ # Copyright (c) 2013, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.internal.rj.servi;
+
+import java.io.IOException;
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Properties;
+
+import javax.management.OperationsException;
+
+import org.eclipse.statet.rj.RjInitFailedException;
+import org.eclipse.statet.rj.server.util.RJContext;
+import org.eclipse.statet.rj.servi.node.PropertiesBean;
+import org.eclipse.statet.rj.servi.node.PropertiesBean.ValidationMessage;
+
+
+public class MXUtil {
+	
+	public static boolean validate(final PropertiesBean bean) throws OperationsException {
+		final List<ValidationMessage> messages= new ArrayList<>();
+		if (bean.validate(messages)) {
+			return true;
+		}
+		final StringBuilder sb= new StringBuilder();
+		sb.append(MessageFormat.format("The configuration ''{0}'' has invalid values:\n", bean.getBeanId()));
+		for (final ValidationMessage message : messages) {
+			if (message.getPropertyId() != null) {
+				sb.append("{");
+				sb.append(message.getPropertyId());
+				sb.append("}: ");
+			}
+			sb.append(message);
+			sb.append('\n');
+		}
+		sb.deleteCharAt(sb.length() - 1);
+		throw new OperationsException(sb.toString());
+	}
+	
+	public static PropertiesBean loadInit(final PropertiesBean bean, final RJContext context) throws RjInitFailedException {
+		try {
+			final Properties map= context.loadProperties(bean.getBeanId());
+			if (map == null) {
+				Utils.logInfo(MessageFormat.format("The configuration ''{0}'' could not be found. Default values are used.", bean.getBeanId()));
+			}
+			else {
+				bean.load(map);
+				bean.validate(null);
+			}
+			
+			return bean;
+		}
+		catch (final IOException e) {
+			throw new RjInitFailedException(MessageFormat.format("Failed to load configuration ''{0}''.", bean.getBeanId()), e);
+		}
+	}
+	
+	
+	public static PropertiesBean load(final PropertiesBean bean, final RJContext context) throws OperationsException {
+		try {
+			final Properties map= context.loadProperties(bean.getBeanId());
+			
+			synchronized (bean) {
+				bean.load(map);
+				validate(bean);
+			}
+			
+			return bean;
+		}
+		catch (final IOException e) {
+			throw new OperationsException(MessageFormat.format("Failed to load configuration ''{0}'': {1}", bean.getBeanId(), e.getMessage()));
+		}
+	}
+	
+	public static void save(final PropertiesBean bean, final RJContext context) throws OperationsException {
+		try {
+			final Properties map= new Properties();
+			
+			synchronized (bean) {
+				if (!validate(bean)) {
+					return;
+				}
+				bean.save(map);
+			}
+			
+			context.saveProperties(bean.getBeanId(), map);
+			
+			return;
+		}
+		catch (final IOException e) {
+			throw new OperationsException(MessageFormat.format("Failed to save configuration ''{0}'': {1}", bean.getBeanId(), e.getMessage()));
+		}
+	}
+	
+}
diff --git a/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/internal/rj/servi/PoolListener.java b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/internal/rj/servi/PoolListener.java
new file mode 100644
index 0000000..270027d
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/internal/rj/servi/PoolListener.java
@@ -0,0 +1,28 @@
+/*=============================================================================#
+ # Copyright (c) 2013, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.internal.rj.servi;
+
+import org.eclipse.statet.rj.servi.pool.PoolNodeObject;
+
+
+public interface PoolListener {
+	
+	
+	void initializing(PoolNodeObject nodeObj);
+	void initialized(PoolNodeObject nodeObj);
+	
+	void disposed(PoolNodeObject nodeObj);
+	
+}
diff --git a/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/internal/rj/servi/PoolManager.java b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/internal/rj/servi/PoolManager.java
new file mode 100644
index 0000000..5c59c13
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/internal/rj/servi/PoolManager.java
@@ -0,0 +1,230 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.internal.rj.servi;
+
+import java.rmi.Remote;
+import java.rmi.server.RMIClientSocketFactory;
+import java.rmi.server.RMIServerSocketFactory;
+import java.rmi.server.UnicastRemoteObject;
+import java.util.Collection;
+import java.util.NoSuchElementException;
+
+import javax.rmi.ssl.SslRMIClientSocketFactory;
+import javax.rmi.ssl.SslRMIServerSocketFactory;
+
+import org.eclipse.statet.jcommons.collections.CopyOnWriteIdentityListSet;
+
+import org.eclipse.statet.ecommons.rmi.core.RMIRegistry;
+
+import org.eclipse.statet.rj.RjException;
+import org.eclipse.statet.rj.RjInitFailedException;
+import org.eclipse.statet.rj.server.ServerLogin;
+import org.eclipse.statet.rj.servi.RServi;
+import org.eclipse.statet.rj.servi.node.RServiNodeFactory;
+import org.eclipse.statet.rj.servi.node.RServiPool;
+import org.eclipse.statet.rj.servi.pool.PoolConfig;
+import org.eclipse.statet.rj.servi.pool.PoolNodeObject;
+import org.eclipse.statet.rj.servi.pool.RServiPoolManager;
+
+
+public class PoolManager implements RServiPool, RServiPoolManager {
+	
+	
+	private final String id;
+	
+	private final RMIRegistry registry;
+	
+	private Remote thisRemote;
+	
+	private APool2 pool;
+	private APool2NodeFactory poolFactory;
+	private PoolConfig poolConfig;
+	
+	private NodeFactory nodeFactory;
+	
+	private final CopyOnWriteIdentityListSet<PoolListener> poolListeners= new CopyOnWriteIdentityListSet<>();
+	private final Stats stats;
+	
+	
+	public PoolManager(final String id, final RMIRegistry registry) {
+		if (id == null || registry == null) {
+			throw new NullPointerException();
+		}
+		this.id= id;
+		this.registry= registry;
+		this.stats= new Stats();
+		this.poolListeners.add(this.stats);
+		this.poolConfig= new PoolConfig();
+		
+		Utils.preLoad();
+	}
+	
+	
+	@Override
+	public String getId() {
+		return this.id;
+	}
+	
+	@Override
+	public NodeFactory getFactories() {
+		return this.nodeFactory;
+	}
+	
+	@Override
+	public synchronized void addNodeFactory(final RServiNodeFactory factory) {
+		this.nodeFactory= (NodeFactory) factory;
+	}
+	
+	@Override
+	public synchronized void setConfig(final PoolConfig config) {
+		if (this.pool != null) {
+			this.pool.setConfig(config);
+			this.poolFactory.setMaxUsageCount(config.getMaxUsageCount());
+		}
+		this.poolConfig= config;
+	}
+	
+	@Override
+	public PoolConfig getConfig() {
+		return this.poolConfig;
+	}
+	
+	public void addPoolListener(final PoolListener listener) {
+		this.poolListeners.add(listener);
+	}
+	
+	public void removePoolListener(final PoolListener listener) {
+		this.poolListeners.remove(listener);
+	}
+	
+	@Override
+	public synchronized void init() throws RjException {
+		this.poolFactory= new APool2NodeFactory(this.nodeFactory, this.poolListeners);
+		this.poolFactory.setMaxUsageCount(this.poolConfig.getMaxUsageCount());
+		this.pool= new APool2(this.poolFactory, this.poolConfig);
+		
+		Utils.logInfo("Publishing pool in registry...");
+		if (this.registry != null) {
+			RMIClientSocketFactory clientSocketFactory= null;
+			RMIServerSocketFactory serverSocketFactory= null;
+			if (this.registry.getAddress().isSSL()) {
+				clientSocketFactory= new SslRMIClientSocketFactory();
+				serverSocketFactory= new SslRMIServerSocketFactory(null, null, true);
+			}
+			try {
+				this.thisRemote= UnicastRemoteObject.exportObject(this, 0,
+						clientSocketFactory, serverSocketFactory );
+				this.registry.getRegistry().rebind(PoolConfig.getPoolName(this.id), this.thisRemote);
+			}
+			catch (final Exception e) {
+				try {
+					stop(8);
+				}
+				catch (final Exception ignore) {}
+				Utils.logError("An error occurred when binding the pool in the registry.", e);
+				throw new RjInitFailedException("An error occurred when publishing the pool in the registry.");
+			}
+		}
+	}
+	
+	@Override
+	public Collection<? extends PoolNodeObject> getPoolNodeObjects() {
+		return this.poolFactory.getAllObjects();
+	}
+	
+	public boolean isInitialized() {
+		return (this.thisRemote != null);
+	}
+	
+	@Override
+	public synchronized void stop(final int mode) throws RjException {
+		Utils.logInfo("Unpublishing pool...");
+		if (this.registry != null) {
+			try {
+				this.registry.getRegistry().unbind(PoolConfig.getPoolName(this.id));
+			}
+			catch (final Exception e) {
+				if (mode != 8) {
+					Utils.logError("An error occurred when unbinding the pool from the registry.", e);
+				}
+			}
+		}
+		if (this.thisRemote != null) {
+			try {
+				this.thisRemote= null;
+				UnicastRemoteObject.unexportObject(this, true);
+			}
+			catch (final Exception e) {
+				if (mode != 8) {
+					Utils.logError("An error occurred when unexport the pool.", e);
+				}
+			}
+		}
+		
+		try {
+			Thread.sleep(1000);
+		}
+		catch (final InterruptedException e) {
+		}
+		if (PoolManager.this.pool != null) {
+			Utils.logInfo("Closing R nodes...");
+			try {
+				PoolManager.this.pool.close(this.poolConfig.getEvictionTimeout());
+			}
+			catch (final Exception e) {
+				Utils.logError("An error occurred when closing the pool.", e);
+			}
+			finally {
+				Runtime.getRuntime().gc();
+			}
+		}
+	}
+	
+	@Override
+	public RServi getRServi(final String name, final ServerLogin login) throws NoSuchElementException, RjException {
+		final APool2NodeHandler handler= getPoolObject(name);
+		return new RServiImpl(handler.getAccessId(), handler, handler.getClientHandler());
+	}
+	
+	public APool2NodeHandler getPoolObject(final String client) throws NoSuchElementException, RjException {
+		try {
+			return this.pool.borrowObject(client);
+		}
+		catch (final NoSuchElementException e) {
+			this.stats.logServRequestFailed(3);
+			throw new NoSuchElementException(Messages.GetRServi_NoInstance_pub_Pool_message);
+		}
+		catch (final Exception e) {
+			this.stats.logServRequestFailed(4);
+			Utils.logError(Messages.BindClient_error_message, e);
+			throw new RjException(Messages.GetRServi_pub_error_message);
+		}
+	}
+	
+	@Override
+	public RServiPoolManager.Counter getCounter() {
+		final RServiPoolManager.Counter counter= new RServiPoolManager.Counter();
+		synchronized (this.pool) {
+			counter.numIdling= this.pool.getNumIdle();
+			counter.numInUse= this.pool.getNumActive();
+			counter.numTotal= counter.numIdling + counter.numTotal;
+			counter.maxIdling= -1;
+			counter.maxInUse= this.poolFactory.getStatMaxAllocated();
+			counter.maxTotal= this.poolFactory.getStatMaxTotal();
+		}
+		return counter;
+	}
+	
+}
diff --git a/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/internal/rj/servi/Stats.java b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/internal/rj/servi/Stats.java
new file mode 100644
index 0000000..785fd21
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/internal/rj/servi/Stats.java
@@ -0,0 +1,57 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.internal.rj.servi;
+
+import org.eclipse.statet.rj.servi.pool.PoolNodeObject;
+
+
+public class Stats implements PoolListener {
+	
+	
+	public final static int MAX_USAGE= 1;
+	public final static int VALIDATION_FAILED= 2;
+	
+	public final static int EXHAUSTED_FAILED= 3;
+	public final static int UNEXPECTED_FAILED= 4;
+	
+	
+	static class NodeEntry {
+		int shutdownReason;
+	}
+	
+	
+//	private final ArrayList<NodeEntry> tempList= new ArrayList<NodeEntry>();
+	
+	
+	@Override
+	public void initializing(final PoolNodeObject nodeObj) {
+	}
+	
+	@Override
+	public void initialized(final PoolNodeObject nodeObj) {
+//		this.tempList.add(p.stats);
+	}
+	
+	@Override
+	public void disposed(final PoolNodeObject nodeObj) {
+	}
+	
+	public void logServUsage(final int borrowTime, final int evalTime) {
+	}
+	
+	public void logServRequestFailed(final int reason) {
+	}
+	
+}
diff --git a/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/rj/servi/jmx/DisplayName.java b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/rj/servi/jmx/DisplayName.java
new file mode 100644
index 0000000..c687e97
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/rj/servi/jmx/DisplayName.java
@@ -0,0 +1,35 @@
+/*=============================================================================#
+ # Copyright (c) 2013, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.servi.jmx;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import javax.management.DescriptorKey;
+
+
+@Documented
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface DisplayName {
+	
+	
+	@DescriptorKey("displayName")
+	String value();
+	
+}
diff --git a/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/rj/servi/jmx/NetConfigMXBean.java b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/rj/servi/jmx/NetConfigMXBean.java
new file mode 100644
index 0000000..4862543
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/rj/servi/jmx/NetConfigMXBean.java
@@ -0,0 +1,47 @@
+/*=============================================================================#
+ # Copyright (c) 2013, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.servi.jmx;
+
+import javax.management.OperationsException;
+
+
+public interface NetConfigMXBean {
+	
+	
+	@DisplayName("Host address (IP/name)")
+	String getHostAddress();
+	void setHostAddress(String address);
+	
+	@DisplayName("RMI registry port (-1 \u21d2 default)")
+	int getRegistryPort();
+	void setRegistryPort(int port);
+	
+	@DisplayName("Start embedded registry")
+	boolean getRegistryEmbed();
+	void setRegistryEmbed(boolean embed);
+	
+	@DisplayName("Enable SSL")
+	boolean isSSLEnabled();
+	void setSSLEnabled(boolean enable);
+	
+	
+	@DisplayName("Load the default configuration")
+	void loadDefault() throws OperationsException;
+	@DisplayName("Load the saved configuration")
+	void loadSaved() throws OperationsException;
+	@DisplayName("Save the current configuration")
+	void save() throws OperationsException;
+	
+}
diff --git a/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/rj/servi/jmx/NodeConfigMXBean.java b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/rj/servi/jmx/NodeConfigMXBean.java
new file mode 100644
index 0000000..a83c43a
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/rj/servi/jmx/NodeConfigMXBean.java
@@ -0,0 +1,79 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.servi.jmx;
+
+import java.util.Map;
+
+import javax.management.OperationsException;
+
+
+public interface NodeConfigMXBean {
+	
+	
+	@DisplayName("Java home (path; empty \u21d2 same as the server)")
+	String getJavaHome();
+	void setJavaHome(String javaHome);
+	
+	@DisplayName("Java arguments")
+	String getJavaArgs();
+	void setJavaArgs(String args);
+	
+	@DisplayName("R home / R_HOME (path)")
+	String getRHome();
+	void setRHome(String path);
+	
+	@DisplayName("Architecture of binaries / R_ARCH (empty \u21d2 autodetection)")
+	String getRArch();
+	void setRArch(String code);
+	
+	@DisplayName("Environment variables (like R_LIBS)")
+	Map<String, String> getEnvironmentVariables();
+	@DisplayName("Add/Set/Remove an environment variable (like R_LIBS)")
+	void setEnvironmentVariable(String name, String value);
+	
+	@DisplayName("Working directory (path; empty \u21d2 default temp dir)")
+	String getBaseWorkingDirectory();
+	void setBaseWorkingDirectory(String path);
+	
+	@DisplayName("R startup snippet (complete R command per line)")
+	String getRStartupSnippet();
+	void setRStartupSnippet(String code);
+	
+	@DisplayName("Timeout when starting/stopping node (millis)")
+	long getStartStopTimeout();
+	void setStartStopTimeout(long milliseconds);
+	
+	@DisplayName("Enable debug console")
+	boolean getEnableConsole();
+	void setEnableConsole(boolean enable);
+	
+	@DisplayName("Enable verbose logging")
+	boolean getEnableVerbose();
+	void setEnableVerbose(boolean enable);
+	
+	
+	@DisplayName("Apply the current configuration")
+	void apply() throws OperationsException;
+	
+	@DisplayName("Reset current changes / load actual configuration")
+	void loadActual() throws OperationsException;
+	@DisplayName("Load the default configuration")
+	void loadDefault() throws OperationsException;
+	@DisplayName("Load the saved configuration")
+	void loadSaved() throws OperationsException;
+	@DisplayName("Save the current configuration")
+	void save() throws OperationsException;
+	
+}
diff --git a/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/rj/servi/jmx/NodeMXBean.java b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/rj/servi/jmx/NodeMXBean.java
new file mode 100644
index 0000000..7654572
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/rj/servi/jmx/NodeMXBean.java
@@ -0,0 +1,41 @@
+/*=============================================================================#
+ # Copyright (c) 2013, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.servi.jmx;
+
+import java.util.Date;
+
+import javax.management.OperationsException;
+
+
+public interface NodeMXBean {
+	
+	
+	String getId();
+	Date getCreationTime();
+	
+	NodeStateMX getState();
+	
+	boolean isConsoleEnabled();
+	void setConsoleEnabled(boolean enable) throws OperationsException;
+	
+	
+	@DisplayName("Stop using the default timeout")
+	void stop() throws OperationsException;
+	@DisplayName("Stop using given timeout")
+	void stop(long timeoutMillis) throws OperationsException;
+	@DisplayName("Stop using timeout 0")
+	void kill() throws OperationsException;
+	
+}
diff --git a/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/rj/servi/jmx/NodeStateMX.java b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/rj/servi/jmx/NodeStateMX.java
new file mode 100644
index 0000000..d3f68a8
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/rj/servi/jmx/NodeStateMX.java
@@ -0,0 +1,39 @@
+/*=============================================================================#
+ # Copyright (c) 2013, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.servi.jmx;
+
+import java.util.Date;
+
+import org.eclipse.statet.rj.servi.pool.PoolNodeState;
+
+
+public interface NodeStateMX {
+	
+	
+	Date getCreationTime();
+	
+	PoolNodeState getState();
+	
+	Date getStateBeginTime();
+	
+	String getCurrentClientId();
+	
+	long getUsageCount();
+	
+	long getUsageDuration();
+	
+	String getRMIAddress();
+	
+}
diff --git a/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/rj/servi/jmx/PoolConfigMXBean.java b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/rj/servi/jmx/PoolConfigMXBean.java
new file mode 100644
index 0000000..ea173ee
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/rj/servi/jmx/PoolConfigMXBean.java
@@ -0,0 +1,64 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.servi.jmx;
+
+import javax.management.OperationsException;
+
+
+public interface PoolConfigMXBean {
+	
+	
+	@DisplayName("Max total nodes (count)")
+	int getMaxUsageCount();
+	void setMaxUsageCount(int count);
+	
+	@DisplayName("Min idle nodes (count)")
+	long getMaxWaitTime();
+	void setMaxWaitTime(long milliseconds);
+	
+	@DisplayName("Max idle nodes (count)")
+	long getMinIdleTime();
+	void setMinIdleTime(long milliseconds);
+	
+	@DisplayName("Min node idle time (millisec)")
+	int getMaxIdleCount();
+	void setMaxIdleCount(int count);
+	
+	@DisplayName("Max wait time (millisec)")
+	int getMinIdleCount();
+	void setMinIdleCount(int count);
+	
+	@DisplayName("Max node reuse (count)")
+	int getMaxTotalCount();
+	void setMaxTotalCount(int count);
+	
+	@DisplayName("Timeout when evicting node in use (millisec)")
+	long getEvictionTimeout();
+	void setEvictionTimeout(long milliseconds);
+	
+	
+	@DisplayName("Apply the current configuration")
+	void apply() throws OperationsException;
+	
+	@DisplayName("Reset current changes / load actual configuration")
+	void loadActual() throws OperationsException;
+	@DisplayName("Load the default configuration")
+	void loadDefault() throws OperationsException;
+	@DisplayName("Load the saved configuration")
+	void loadSaved() throws OperationsException;
+	@DisplayName("Save the current configuration")
+	void save() throws OperationsException;
+	
+}
diff --git a/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/rj/servi/jmx/PoolServerMXBean.java b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/rj/servi/jmx/PoolServerMXBean.java
new file mode 100644
index 0000000..c9c9a7f
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/rj/servi/jmx/PoolServerMXBean.java
@@ -0,0 +1,37 @@
+/*=============================================================================#
+ # Copyright (c) 2013, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.servi.jmx;
+
+import javax.management.OperationsException;
+
+
+public interface PoolServerMXBean {
+	
+	
+	String getId();
+	
+	String getPoolAddress();
+	
+	PoolStatusMX getPoolStatus();
+	
+	boolean isPoolNodeManagementEnabled();
+	void setPoolNodeManagementEnabled(boolean enable);
+	
+	
+	void start() throws OperationsException;
+	void stop() throws OperationsException;
+	void restart() throws OperationsException;
+	
+}
diff --git a/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/rj/servi/jmx/PoolStatusMX.java b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/rj/servi/jmx/PoolStatusMX.java
new file mode 100644
index 0000000..b603789
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/rj/servi/jmx/PoolStatusMX.java
@@ -0,0 +1,36 @@
+/*=============================================================================#
+ # Copyright (c) 2013, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.servi.jmx;
+
+import java.util.Date;
+import java.util.List;
+
+
+public interface PoolStatusMX {
+	
+	
+	Date getStatusTime();
+	
+	int getNumInUse();
+	int getNumIdling();
+	int getNumTotal();
+	
+	int getMaxInUse();
+	int getMaxIdling();
+	int getMaxTotal();
+	
+	List<NodeStateMX> getNodeStates();
+	
+}
diff --git a/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/rj/servi/jmx/StandalonePoolServerMXBean.java b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/rj/servi/jmx/StandalonePoolServerMXBean.java
new file mode 100644
index 0000000..1fb62d3
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/rj/servi/jmx/StandalonePoolServerMXBean.java
@@ -0,0 +1,25 @@
+/*=============================================================================#
+ # Copyright (c) 2013, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.servi.jmx;
+
+import javax.management.OperationsException;
+
+
+public interface StandalonePoolServerMXBean extends PoolServerMXBean {
+	
+	
+	void shutdown() throws OperationsException;
+	
+}
diff --git a/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/rj/servi/pool/JMPoolServer.java b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/rj/servi/pool/JMPoolServer.java
new file mode 100644
index 0000000..51f5809
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/rj/servi/pool/JMPoolServer.java
@@ -0,0 +1,445 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.servi.pool;
+
+import java.lang.management.ManagementFactory;
+import java.net.MalformedURLException;
+import java.net.UnknownHostException;
+import java.rmi.RemoteException;
+import java.rmi.registry.LocateRegistry;
+import java.rmi.registry.Registry;
+import java.rmi.server.RMIClientSocketFactory;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import javax.management.ObjectName;
+import javax.management.OperationsException;
+import javax.rmi.ssl.SslRMIClientSocketFactory;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.NullProgressMonitor;
+
+import org.eclipse.statet.jcommons.collections.ImCollections;
+
+import org.eclipse.statet.ecommons.rmi.core.RMIAddress;
+import org.eclipse.statet.ecommons.rmi.core.RMIRegistry;
+import org.eclipse.statet.ecommons.rmi.core.RMIRegistryManager;
+
+import org.eclipse.statet.internal.rj.servi.MXNetConfig;
+import org.eclipse.statet.internal.rj.servi.MXNodeConfig;
+import org.eclipse.statet.internal.rj.servi.MXNodeManager;
+import org.eclipse.statet.internal.rj.servi.MXPoolConfig;
+import org.eclipse.statet.internal.rj.servi.MXPoolStatus;
+import org.eclipse.statet.internal.rj.servi.MXUtil;
+import org.eclipse.statet.internal.rj.servi.PoolManager;
+import org.eclipse.statet.internal.rj.servi.Utils;
+import org.eclipse.statet.rj.RjException;
+import org.eclipse.statet.rj.RjInitFailedException;
+import org.eclipse.statet.rj.RjInvalidConfigurationException;
+import org.eclipse.statet.rj.server.util.RJContext;
+import org.eclipse.statet.rj.server.util.ServerUtils;
+import org.eclipse.statet.rj.servi.RServiUtil;
+import org.eclipse.statet.rj.servi.jmx.PoolServerMXBean;
+import org.eclipse.statet.rj.servi.jmx.PoolStatusMX;
+import org.eclipse.statet.rj.servi.node.RServiImpl;
+import org.eclipse.statet.rj.servi.node.RServiNodeConfig;
+import org.eclipse.statet.rj.servi.node.RServiNodeFactory;
+
+
+public class JMPoolServer implements PoolServer, PoolServerMXBean {
+	
+	
+	private final String id;
+	private final RJContext context;
+	
+	private final String jmBaseName;
+	private ObjectName jmxName;
+	
+	private RMIRegistry rmiRegistry;
+	private Set<Integer> rmiEmbeddedPorts;
+	private boolean rmiHostnameSet;
+	
+	private String poolAddress;
+	
+	private final MXNetConfig currentNetConfig;
+	private volatile PoolConfig currentPoolConfig;
+	private volatile RServiNodeConfig currentNodeConfig;
+	
+	private final MXNetConfig jmNetConfig;
+	private final MXPoolConfig jmPoolConfig;
+	private final MXNodeConfig jmNodeConfig;
+	
+	private volatile boolean jmIsNodeManagementEnabled;
+	private MXNodeManager jmNodeManager;
+	
+	private final RServiNodeFactory nodeFactory;
+	
+	private PoolManager poolManager;
+	
+	
+	public JMPoolServer(final String id, final RJContext context) throws RjInitFailedException {
+		this(id, context, true);
+	}
+	
+	public JMPoolServer(final String id, final RJContext context, final boolean enableJM) throws RjInitFailedException {
+		this.id= id;
+		this.context= context;
+		this.jmBaseName= "RServi:rservi.id=" + getId() + ",";
+		
+		this.currentNetConfig= (MXNetConfig) MXUtil.loadInit(new MXNetConfig(this), this.context);
+		this.currentPoolConfig= (PoolConfig) MXUtil.loadInit(new PoolConfig(), this.context);
+		this.currentNodeConfig= (RServiNodeConfig) MXUtil.loadInit(new RServiNodeConfig(), this.context);
+		
+		try {
+			this.nodeFactory= RServiImpl.createLocalNodeFactory(this.id, this.context);
+		}
+		catch (final RjInvalidConfigurationException e) {
+			throw new RjInitFailedException("Creating local R node factory failed.", e);
+		}
+		try {
+			if (enableJM) {
+				this.jmxName= new ObjectName(this.jmBaseName + "type=Server");
+				ManagementFactory.getPlatformMBeanServer().registerMBean(this, this.jmxName);
+			}
+			
+			this.jmNetConfig= this.currentNetConfig;
+			if (enableJM) {
+				this.jmNetConfig.initJM();
+			}
+			
+			this.jmPoolConfig= new MXPoolConfig(this);
+			this.jmPoolConfig.load(this.currentPoolConfig);
+			if (enableJM) {
+				this.jmPoolConfig.initJM();
+			}
+			
+			this.jmNodeConfig= new MXNodeConfig(this);
+			this.jmNodeConfig.load(this.currentNodeConfig);
+			if (enableJM) {
+				this.jmNodeConfig.initJM();
+			}
+		}
+		catch (final Exception e) {
+			try {
+				shutdown();
+			}
+			catch (final Exception e2) {}
+			throw new RjInitFailedException("Initializing JMX for pool server failed.", e);
+		}
+		try {
+			this.nodeFactory.setConfig(this.currentNodeConfig);
+		}
+		catch (final RjInvalidConfigurationException e) {
+			Utils.logWarning(e.getMessage());
+		}
+	}
+	
+	
+	@Override
+	public String getId() {
+		return this.id;
+	}
+	
+	@Override
+	public RJContext getRJContext() {
+		return this.context;
+	}
+	
+	@Override
+	public String getJMBaseName() {
+		return this.jmBaseName;
+	}
+	
+	@Override
+	public void getNetConfig(final NetConfig config) {
+		config.load(this.currentNetConfig);
+	}
+	
+	@Override
+	public void setNetConfig(NetConfig config) {
+		config= new NetConfig(config);
+		
+		if (!config.validate(null)) {
+			throw new IllegalArgumentException();
+		}
+		this.currentNetConfig.load(config);
+	}
+	
+	@Override
+	public void getPoolConfig(final PoolConfig config) {
+		config.load(this.currentPoolConfig);
+	}
+	
+	@Override
+	public void setPoolConfig(PoolConfig config) {
+		config= new PoolConfig(config); // intern
+		
+		if (!config.validate(null)) {
+			throw new IllegalArgumentException();
+		}
+		synchronized (this.jmPoolConfig) {
+			final PoolManager manager= this.poolManager;
+			if (manager != null) {
+				manager.setConfig(config);
+			}
+			
+			this.currentPoolConfig= config;
+			this.jmPoolConfig.load(config);
+		}
+	}
+	
+	@Override
+	public void getNodeConfig(final RServiNodeConfig config) {
+		config.load(this.currentNodeConfig);
+	}
+	
+	@Override
+	public void setNodeConfig(RServiNodeConfig config) throws RjInvalidConfigurationException {
+		config= new RServiNodeConfig(config); // intern
+		
+		if (!config.validate(null)) {
+			throw new IllegalArgumentException();
+		}
+		synchronized (this.jmPoolConfig) {
+			this.nodeFactory.setConfig(config);
+			
+			this.currentNodeConfig= config;
+			this.jmNodeConfig.load(config);
+		}
+	}
+	
+	
+	private void initRMI() throws RjException, OperationsException {
+		final String hostAddress;
+		final int registryPort;
+		final boolean embed;
+		final boolean ssl;
+		synchronized (this.currentNetConfig) {
+			if (!MXUtil.validate(this.currentNetConfig)) {
+				return;
+			}
+			hostAddress= this.currentNetConfig.getEffectiveHostaddress();
+			registryPort= this.currentNetConfig.getEffectiveRegistryPort();
+			embed= this.currentNetConfig.getRegistryEmbed();
+			ssl= this.currentNetConfig.isSSLEnabled();
+		}
+		
+		this.rmiRegistry= null;
+		this.nodeFactory.setRegistry(null);
+		this.poolAddress= null;
+		
+		// RMI registry setup
+		final String property= System.getProperty("java.rmi.server.codebase");
+		if (property == null) {
+			final List<String> libs= this.context.searchRJLibs(
+					ImCollections.newList(ServerUtils.RJ_SERVER_ID, RServiUtil.RJ_SERVI_ID) );
+			System.setProperty("java.rmi.server.codebase", ServerUtils.concatCodebase(libs));
+		}
+		
+		if (this.rmiHostnameSet || System.getProperty("java.rmi.server.hostname") == null) {
+			System.setProperty("java.rmi.server.hostname", hostAddress);
+			this.rmiHostnameSet= true;
+		}
+		
+		RMIAddress rmiRegistryAddress;
+		Registry registry;
+		try {
+			rmiRegistryAddress= new RMIAddress(hostAddress, registryPort, null);
+			final RMIClientSocketFactory csf= (ssl) ? new SslRMIClientSocketFactory() : null;
+			registry= LocateRegistry.getRegistry(null, registryPort, csf);
+		}
+		catch (final UnknownHostException e) {
+			throw new RjInvalidConfigurationException("Invalid RMI address.", e);
+		}
+		catch (final MalformedURLException e) {
+			throw new RjInvalidConfigurationException("Invalid RMI address.", e);
+		}
+		catch (final RemoteException e) {
+			throw new RjInitFailedException("Failed to reference local registry.", e);
+		}
+		RMIRegistry rmiRegistry= null;
+		if (embed) {
+			if (this.rmiEmbeddedPorts == null) {
+				this.rmiEmbeddedPorts= new HashSet<>();
+			}
+			try {
+				rmiRegistry= new RMIRegistry(rmiRegistryAddress, registry, true);
+				if (this.rmiEmbeddedPorts.add(registryPort)) {
+					Utils.logWarning("Found running RMI registry at port "+registryPort+", embedded RMI registry will not be started.");
+				}
+			}
+			catch (final RemoteException e) {
+				RMIRegistryManager.INSTANCE.setEmbeddedPrivateMode(false, ssl);
+				RMIRegistryManager.INSTANCE.setEmbeddedPrivatePort(registryPort);
+				try {
+					rmiRegistry= RMIRegistryManager.INSTANCE.getEmbeddedPrivateRegistry(new NullProgressMonitor());
+					if (rmiRegistry != null) {
+						Utils.logInfo("Embedded RMI registry at port "+registryPort+" started.");
+					}
+					else {
+						Utils.logInfo("Failed to connect to running RMI registry at port "+registryPort+".", e);
+						Utils.logError("Failed to start embedded RMI registry at port "+registryPort+".");
+						throw new RjInitFailedException("Initalization of RMI registry setup failed.");
+					}
+				}
+				catch (final CoreException ee) {
+					Utils.logError("Failed to start embedded RMI registry at port "+registryPort+".", ee);
+				}
+			}
+		}
+		else {
+			try {
+				rmiRegistry= new RMIRegistry(rmiRegistryAddress, registry, true);
+				Utils.logInfo("Found running RMI registry at port "+registryPort+".");
+			}
+			catch (final RemoteException e) {
+				Utils.logError("Failed to connect to running RMI registry at port "+registryPort+".", e);
+				throw new RjInitFailedException("Initalization of RMI registry setup failed.");
+			}
+		}
+		
+		this.rmiRegistry= rmiRegistry;
+		this.nodeFactory.setRegistry(rmiRegistry);
+		this.poolAddress= NetConfig.getPoolAddress(hostAddress, registryPort, this.id);
+	}
+	
+	private void startManager() throws RjException {
+		final PoolManager manager= new PoolManager(this.id, this.rmiRegistry);
+		synchronized (this.jmPoolConfig) {
+			
+			manager.setConfig(this.currentPoolConfig);
+			
+			manager.addNodeFactory(this.nodeFactory);
+			
+			manager.init();
+			
+			this.poolManager= manager;
+		}
+		
+		if (this.jmIsNodeManagementEnabled) {
+			this.jmNodeManager= new MXNodeManager(this, manager);
+			this.jmNodeManager.activate();
+		}
+	}
+	
+	
+	private void stopManager() {
+		final PoolManager manager= this.poolManager;
+		this.poolManager= null;
+		if (manager != null && manager.isInitialized()) {
+			try {
+				manager.stop(0);
+			}
+			catch (final RjException e) {
+				e.printStackTrace();
+			}
+		}
+	}
+	
+	
+	@Override
+	public PoolManager getManager() {
+		return this.poolManager;
+	}
+	
+	@Override
+	public String getPoolAddress() {
+		return this.poolAddress;
+	}
+	
+	@Override
+	public PoolStatusMX getPoolStatus() {
+		return new MXPoolStatus(this);
+	}
+	
+	@Override
+	public boolean isPoolNodeManagementEnabled() {
+		return this.jmIsNodeManagementEnabled;
+	}
+	
+	@Override
+	public synchronized void setPoolNodeManagementEnabled(final boolean enable) {
+		if (this.jmIsNodeManagementEnabled == enable) {
+			return;
+		}
+		this.jmIsNodeManagementEnabled= enable;
+		if (enable) {
+			if (this.jmNodeManager == null) {
+				this.jmNodeManager= new MXNodeManager(this, this.poolManager);
+			}
+			this.jmNodeManager.activate();
+		}
+		else {
+			if (this.jmNodeManager != null) {
+				this.jmNodeManager.deactivate();
+			}
+		}
+	}
+	
+	
+	@Override
+	public synchronized void start() throws OperationsException {
+		try {
+			final PoolManager manager= this.poolManager;
+			if (manager != null) {
+				return;
+			}
+			
+			initRMI();
+			
+			startManager();
+		}
+		catch (final RjException e) {
+			Utils.logError("Failed to start RServi pool server.", e);
+			throw new OperationsException("Failed to start RServi pool server: " + e.getMessage());
+		}
+	}
+	
+	@Override
+	public synchronized void stop() throws OperationsException {
+		stopManager();
+	}
+	
+	@Override
+	public synchronized void restart() throws OperationsException {
+		stop();
+		start();
+	}
+	
+	public synchronized void shutdown() {
+		stopManager();
+		try {
+			if (this.jmPoolConfig != null) {
+				this.jmPoolConfig.disposeJM();
+			}
+			if (this.jmNetConfig != null) {
+				this.jmNetConfig.disposeJM();
+			}
+			if (this.jmNodeConfig != null) {
+				this.jmNodeConfig.disposeJM();
+			}
+			
+			if (this.jmxName != null) {
+				ManagementFactory.getPlatformMBeanServer().unregisterMBean(this.jmxName);
+				this.jmxName= null;
+			}
+		}
+		catch (final Exception e) {
+			Utils.logError("An error occured when disposing JMX for pool server.", e);
+		}
+	}
+	
+}
diff --git a/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/rj/servi/pool/NetConfig.java b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/rj/servi/pool/NetConfig.java
new file mode 100644
index 0000000..eaca202
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/rj/servi/pool/NetConfig.java
@@ -0,0 +1,247 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.servi.pool;
+
+import java.net.InetAddress;
+import java.net.MalformedURLException;
+import java.net.UnknownHostException;
+import java.util.Collection;
+import java.util.Properties;
+
+import org.eclipse.statet.ecommons.rmi.core.RMIAddress;
+
+import org.eclipse.statet.internal.rj.servi.Utils;
+import org.eclipse.statet.rj.servi.node.PropertiesBean;
+
+
+public class NetConfig implements PropertiesBean {
+	
+	
+	public static final String BEAN_ID= "netconfig";
+	
+	
+	public static String getPoolAddress(final NetConfig config, final String poolId) {
+		final String hostAddress;
+		final int registryPort;
+		synchronized (config) {
+			if (!config.validate(null)) {
+				return null;
+			}
+			hostAddress= config.effectiveHostaddress;
+			registryPort= config.effectiveRegistryPort;
+		}
+		return getPoolAddress(hostAddress, registryPort, poolId);
+	}
+	
+	public static String getPoolAddress(final String hostAddress, final int registryPort,
+			final String poolId) {
+		try {
+			return new RMIAddress(hostAddress, registryPort, PoolConfig.getPoolName(poolId))
+					.toString();
+		}
+		catch (final UnknownHostException e) {}
+		catch (final MalformedURLException e) {
+		}
+		return null; 
+	}
+	
+	
+	public static final String HOSTADDRESS_ID= "host.address";
+	public static final String REGISTRY_PORT_ID= "rmi_registry.address.port";
+	public static final String REGISTRY_EMBED_ID= "rmi_registry.embed.enabled";
+	
+	/**
+	 * Property id if SSL is enabled
+	 * 
+	 * @see #setSSLEnabled(boolean)
+	 * @since 2.0
+	 */
+	public static final String SSL_ENABLED_ID= "ssl.enabled";
+	
+	private static final String REGISTRY_HOST_DEFAULT= null;
+	private static final int REGISTRY_PORT_DEFAULT= -1;
+	private static final boolean REGISTRY_EMBED_DEFAULT= true;
+	private static final boolean SSL_ENABLED_DEFAULT= false;
+	
+	
+	private String hostAddress;
+	private String effectiveHostaddress;
+	private int registryPort;
+	private int effectiveRegistryPort;
+	
+	private boolean registryEmbed;
+	
+	private boolean isSSLEnabled;
+	
+	
+	public NetConfig() {
+		loadDefaults();
+	}
+	
+	public NetConfig(final NetConfig config) {
+		load(config);
+	}
+	
+	
+	@Override
+	public String getBeanId() {
+		return BEAN_ID;
+	}
+	
+	
+	public synchronized void loadDefaults() {
+		setHostAddress(REGISTRY_HOST_DEFAULT);
+		setRegistryPort(REGISTRY_PORT_DEFAULT);
+		setRegistryEmbed(REGISTRY_EMBED_DEFAULT);
+		setSSLEnabled(SSL_ENABLED_DEFAULT);
+	}
+	
+	public synchronized void load(final NetConfig templ) {
+		setHostAddress(templ.hostAddress);
+		setRegistryPort(templ.registryPort);
+		setRegistryEmbed(templ.registryEmbed);
+		setSSLEnabled(templ.isSSLEnabled);
+	}
+	
+	@Override
+	public synchronized void load(final Properties map) {
+		loadDefaults();
+		
+		if (map != null) {
+			{	final String s= map.getProperty(HOSTADDRESS_ID);
+				if (s != null && !s.isEmpty()) {
+					setHostAddress(s);
+				}
+			}
+			{	final String s= map.getProperty(REGISTRY_PORT_ID);
+				setRegistryPort((s != null && !s.isEmpty()) ?
+						Integer.parseInt(s) : REGISTRY_PORT_DEFAULT );
+			}
+			{	final String s= map.getProperty(REGISTRY_EMBED_ID);
+				setRegistryEmbed((s != null && !s.isEmpty()) ?
+						Boolean.parseBoolean(s) : REGISTRY_EMBED_DEFAULT);
+			}
+			{	final String s= map.getProperty(SSL_ENABLED_ID);
+				setSSLEnabled((s != null && !s.isEmpty()) ?
+						Boolean.parseBoolean(s) : SSL_ENABLED_DEFAULT);
+			}
+		}
+	}
+	
+	@Override
+	public synchronized void save(final Properties map) {
+		Utils.setProperty(map, HOSTADDRESS_ID, this.hostAddress);
+		Utils.setProperty(map, REGISTRY_PORT_ID, (this.registryPort > 0) ? Integer.toString(this.registryPort) : null);
+		map.put(REGISTRY_EMBED_ID, Boolean.toString(this.registryEmbed));
+		map.put(SSL_ENABLED_ID, Boolean.toString(this.isSSLEnabled));
+	}
+	
+	
+	public synchronized String getHostAddress() {
+		return this.hostAddress;
+	}
+	
+	public synchronized void setHostAddress(final String address) {
+		this.hostAddress= address;
+		this.effectiveHostaddress= null;
+	}
+	
+	public synchronized String getEffectiveHostaddress() {
+		return this.effectiveHostaddress;
+	}
+	
+	public synchronized int getRegistryPort() {
+		return this.registryPort;
+	}
+	
+	public synchronized void setRegistryPort(final int port) {
+		this.registryPort= port;
+		this.effectiveRegistryPort= (port <= 0) ? 1099 : port;
+	}
+	
+	public synchronized int getEffectiveRegistryPort() {
+		return this.effectiveRegistryPort;
+	}
+	
+	public synchronized boolean getRegistryEmbed() {
+		return this.registryEmbed;
+	}
+	
+	public synchronized void setRegistryEmbed(final boolean embed) {
+		this.registryEmbed= embed;
+	}
+	
+	/**
+	 * Returns if SSL is enabled
+	 * 
+	 * @return <code>true</code> if SSL is enabled, otherwise <code>false</code>
+	 */
+	public synchronized boolean isSSLEnabled() {
+		return this.isSSLEnabled;
+	}
+	
+	/**
+	 * Sets if SSL is enabled.
+	 * 
+	 * @param enable
+	 * 
+	 * @since 2.0
+	 */
+	public synchronized void setSSLEnabled(final boolean enable) {
+		this.isSSLEnabled= enable;
+	}
+	
+	
+	@Override
+	public synchronized boolean validate(final Collection<ValidationMessage> messages) {
+		boolean valid= true;
+		
+		String effective= this.hostAddress;
+		if (effective == null || effective.length() == 0) {
+			effective= System.getProperty("java.rmi.server.hostname");
+		}
+		try {
+			InetAddress inet= null;
+			if (effective != null && !effective.isEmpty()) {
+				inet= InetAddress.getByName(effective);
+			}
+			else {
+				try {
+					inet= InetAddress.getLocalHost();
+				}
+				catch (final UnknownHostException e) {}
+				catch (final ArrayIndexOutOfBoundsException e) { /* JVM bug */ }
+				if (inet == null) {
+					inet= RMIAddress.LOOPBACK;
+				}
+			}
+			this.effectiveHostaddress= inet.getHostAddress();
+		}
+		catch (final Exception e) {
+			this.effectiveHostaddress= null;
+			String msg= e.getMessage();
+			if (e instanceof UnknownHostException) {
+				msg= "Unknown Host";
+			}
+			if (messages != null) {
+				messages.add(new ValidationMessage(HOSTADDRESS_ID, msg));
+			}
+			valid= false;
+		}
+		
+		return valid;
+	}
+	
+}
diff --git a/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/rj/servi/pool/PoolConfig.java b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/rj/servi/pool/PoolConfig.java
new file mode 100644
index 0000000..efc0e4e
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/rj/servi/pool/PoolConfig.java
@@ -0,0 +1,256 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.servi.pool;
+
+import java.util.Collection;
+import java.util.Properties;
+
+import org.eclipse.statet.internal.rj.servi.Utils;
+import org.eclipse.statet.rj.servi.node.PropertiesBean;
+
+
+public class PoolConfig implements PropertiesBean {
+	
+	
+	public static final String BEAN_ID= "poolconfig";
+	
+	
+	public static String getPoolName(final String id) {
+		return (new StringBuilder(String.valueOf(id))).append("-pool").toString();
+	}
+	
+	
+	public static final long MINUTES= 60000L;
+	public static final long SECONDS= 1000L;
+	
+	public static final String MAX_TOTAL_COUNT_ID= "max_total.count";
+	public static final String MIN_IDLE_COUNT_ID= "min_idle.count";
+	public static final String MAX_IDLE_COUNT_ID= "max_idle.count";
+	public static final String MIN_IDLE_MILLIS_ID= "min_idle.millis";
+	@Deprecated
+	public static final String MIN_IDLE_TIME_ID= "min_idle.time";
+	public static final String MAX_WAIT_MILLIS_ID= "max_wait.millis";
+	@Deprecated
+	public static final String MAX_WAIT_TIME_ID= "max_wait.time";
+	public static final String MAX_USAGE_COUNT_ID= "max_usage.count";
+	
+	/**
+	 * Id of timeout when evicing lent pool items
+	 * 
+	 * @since 2.0
+	 */
+	public static final String EVICT_TIMEOUT_ID= "eviction_timeout.millis";
+	
+	private static final long EVICT_TIMEOUT_DEFAULT= 30*MINUTES;
+	
+	
+	private int maxTotalCount;
+	private int minIdleCount;
+	private int maxIdleCount;
+	private long minIdleTime;
+	private long maxWaitTime;
+	private int maxUsageCount;
+	
+	private long evictTimeout;
+	
+	
+	public PoolConfig() {
+		this.maxTotalCount= 20;
+		this.minIdleCount= 1;
+		this.maxIdleCount= 10;
+		this.minIdleTime= 10*MINUTES;
+		this.maxWaitTime= 3*SECONDS;
+		this.maxUsageCount= 1000;
+		
+		this.evictTimeout= EVICT_TIMEOUT_DEFAULT;
+	}
+	
+	public PoolConfig(final PoolConfig config) {
+		this();
+		synchronized (config) {
+			load(config);
+		}
+	}
+	
+	
+	@Override
+	public String getBeanId() {
+		return BEAN_ID;
+	}
+	
+	public synchronized void load(final PoolConfig templ) {
+		this.maxTotalCount= templ.maxTotalCount;
+		this.minIdleCount= templ.minIdleCount;
+		this.maxIdleCount= templ.maxIdleCount;
+		this.minIdleTime= templ.minIdleTime;
+		this.maxWaitTime= templ.maxWaitTime;
+		this.maxUsageCount= templ.maxUsageCount;
+		this.evictTimeout= templ.evictTimeout;
+	}
+	
+	@Override
+	public synchronized void load(final Properties map) {
+		this.maxTotalCount= Integer.parseInt(map.getProperty(MAX_TOTAL_COUNT_ID));
+		this.minIdleCount= Integer.parseInt(map.getProperty(MIN_IDLE_COUNT_ID));
+		this.maxIdleCount= Integer.parseInt(map.getProperty(MAX_IDLE_COUNT_ID));
+		this.minIdleTime= Long.parseLong(Utils.getProperty(map, MIN_IDLE_MILLIS_ID, MIN_IDLE_TIME_ID));
+		this.maxWaitTime= Long.parseLong(Utils.getProperty(map, MAX_WAIT_MILLIS_ID, MAX_WAIT_TIME_ID));
+		this.maxUsageCount= Integer.parseInt(map.getProperty(MAX_USAGE_COUNT_ID));
+		{	final String s= map.getProperty(EVICT_TIMEOUT_ID);
+			this.evictTimeout= (s != null) ? Long.parseLong(s) : EVICT_TIMEOUT_DEFAULT;
+		}
+	}
+	
+	@Override
+	public synchronized void save(final Properties map) {
+		map.setProperty(MAX_TOTAL_COUNT_ID, Integer.toString(this.maxTotalCount));
+		map.setProperty(MIN_IDLE_COUNT_ID, Integer.toString(this.minIdleCount));
+		map.setProperty(MAX_IDLE_COUNT_ID, Integer.toString(this.maxIdleCount));
+		map.setProperty(MIN_IDLE_MILLIS_ID, Long.toString(this.minIdleTime));
+		map.setProperty(MAX_WAIT_MILLIS_ID, Long.toString(this.maxWaitTime));
+		map.setProperty(MAX_USAGE_COUNT_ID, Integer.toString(this.maxUsageCount));
+		map.setProperty(EVICT_TIMEOUT_ID, Long.toString(this.evictTimeout));
+	}
+	
+	public synchronized int getMaxTotalCount() {
+		return this.maxTotalCount;
+	}
+	
+	public synchronized void setMaxTotalCount(final int count) {
+		this.maxTotalCount= count;
+	}
+	
+	public synchronized int getMinIdleCount() {
+		return this.minIdleCount;
+	}
+	
+	public synchronized void setMinIdleCount(final int count) {
+		this.minIdleCount= count;
+	}
+	
+	public synchronized int getMaxIdleCount() {
+		return this.maxIdleCount;
+	}
+	
+	public synchronized void setMaxIdleCount(final int count) {
+		this.maxIdleCount= count;
+	}
+	
+	public synchronized long getMinIdleTime() {
+		return this.minIdleTime;
+	}
+	
+	public synchronized void setMinIdleTime(final long milliseconds) {
+		this.minIdleTime= milliseconds;
+	}
+	
+	public synchronized void setMaxWaitTime(final long milliseconds) {
+		this.maxWaitTime= milliseconds;
+	}
+	
+	public synchronized long getMaxWaitTime() {
+		return this.maxWaitTime;
+	}
+	
+	public synchronized void setMaxUsageCount(final int count) {
+		this.maxUsageCount= count;
+	}
+	
+	public synchronized int getMaxUsageCount() {
+		return this.maxUsageCount;
+	}
+	
+	
+	/**
+	 * Returns the timeout when evicing lent pool items
+	 * 
+	 * @return the timeout in milliseconds
+	 * 
+	 * @since 2.0
+	 */
+	public synchronized long getEvictionTimeout() {
+		return this.evictTimeout;
+	}
+	
+	/**
+	 * Sets the timeout when evicing lent pool items
+	 * 
+	 * @param milliseconds the timeout in milliseconds
+	 * 
+	 * @since 2.0
+	 */
+	
+	public synchronized void setEvictionTimeout(final long milliseconds) {
+		this.evictTimeout= milliseconds;
+	}
+	
+	
+	@Override
+	public synchronized boolean validate(final Collection<ValidationMessage> messages) {
+		boolean valid= true;
+		
+		if (this.minIdleCount < 0) {
+			if (messages != null) {
+				messages.add(new ValidationMessage(MIN_IDLE_COUNT_ID, "Value must be >= 0"));
+			}
+			valid= false;
+		}
+		if (this.maxTotalCount < 1) {
+			if (messages != null) {
+				messages.add(new ValidationMessage(MAX_TOTAL_COUNT_ID, "Value must be > 0."));
+			}
+			valid= false;
+		}
+		if (this.maxIdleCount < 0) {
+			if (messages != null) {
+				messages.add(new ValidationMessage(MAX_IDLE_COUNT_ID, "Value must be >= 0."));
+			}
+			valid= false;
+		}
+		if (this.minIdleCount >= 0 && this.maxIdleCount >= 0 && this.maxIdleCount < this.minIdleCount) {
+			if (messages != null) {
+				messages.add(new ValidationMessage(MAX_IDLE_COUNT_ID, "Value must be >= {" + MIN_IDLE_COUNT_ID + "}."));
+			}
+			valid= false;
+		}
+		if (this.minIdleTime < 0L) {
+			if (messages != null) {
+				messages.add(new ValidationMessage(MIN_IDLE_MILLIS_ID, "Value must be >= 0"));
+			}
+			valid= false;
+		}
+		if (this.maxWaitTime < 0L && this.maxUsageCount != -1) {
+			if (messages != null) {
+				messages.add(new ValidationMessage(MAX_WAIT_MILLIS_ID, "Value must be >= 0 or == -1 (infinite)"));
+			}
+			valid= false;
+		}
+		if (this.maxUsageCount < 1 && this.maxUsageCount != -1) {
+			if (messages != null) {
+				messages.add(new ValidationMessage(MAX_USAGE_COUNT_ID, "Value must be > 0 or == -1 (disable)"));
+			}
+			valid= false;
+		}
+		
+		if (this.evictTimeout < 0) {
+			if (messages != null) {
+				messages.add(new ValidationMessage(EVICT_TIMEOUT_ID, "Value must be >= 0"));
+			}
+			valid= false;
+		}
+		return valid;
+	}
+	
+}
diff --git a/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/rj/servi/pool/PoolNodeItem.java b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/rj/servi/pool/PoolNodeItem.java
new file mode 100644
index 0000000..4ab6fc7
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/rj/servi/pool/PoolNodeItem.java
@@ -0,0 +1,128 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.servi.pool;
+
+import org.eclipse.statet.ecommons.rmi.core.RMIAddress;
+
+import org.eclipse.statet.internal.rj.servi.NodeHandler;
+import org.eclipse.statet.rj.RjException;
+
+
+public class PoolNodeItem {
+	
+	
+	private long creationTime;
+	
+	private PoolNodeState state;
+	private long stateTime;
+	
+	private long usageCount;
+	private long usageDuration;
+	
+	private final PoolNodeObject object;
+	private final NodeHandler nodeHandler;
+	
+	private String client;
+	
+	
+	public PoolNodeItem(final PoolNodeObject nodeObj, final long stamp) {
+		synchronized(nodeObj) {
+			this.object= nodeObj;
+			this.nodeHandler= nodeObj.getNodeHandler();
+			
+			this.creationTime= nodeObj.getCreationTime();
+			this.state= nodeObj.getState();
+			
+			this.stateTime= nodeObj.getStateTime();
+			this.usageCount= nodeObj.getAllocatedCount();
+			this.usageDuration= nodeObj.getAllocatedDuration();
+//			if (this.state == PoolNodeState.ALLOCATED) {
+//				this.usageDuration+= Math.min(stamp - this.stateTime, 0L);
+//			}
+			this.client= nodeObj.getClientLabel();
+		}
+	}
+	
+	
+	public long getCreationTime() {
+		return this.creationTime;
+	}
+	
+	public PoolNodeState getState() {
+		return this.state;
+	}
+	
+	public long getStateTime() {
+		return this.stateTime;
+	}
+	
+	public String getCurrentClientId() {
+		return this.client;
+	}
+	
+	public long getUsageCount() {
+		return this.usageCount;
+	}
+	
+	public long getUsageDuration() {
+		return this.usageDuration;
+	}
+	
+	public boolean isConsoleEnabled() {
+		return (this.nodeHandler != null && this.nodeHandler.isConsoleEnabled());
+	}
+	
+	public void enableConsole(final String authConfig) throws RjException {
+		if (this.nodeHandler != null) {
+			this.nodeHandler.enableConsole(authConfig);
+		}
+	}
+	
+	public void disableConsole() throws RjException {
+		if (this.nodeHandler != null) {
+			this.nodeHandler.disableConsole();
+		}
+	}
+	
+	/**
+	 * Returns the RMI address of the node.
+	 * 
+	 * @return the address of the node if available, otherwise <code>null</code>
+	 * 
+	 * @since 2.0
+	 */
+	public RMIAddress getAddress() {
+		if (this.nodeHandler != null) {
+			return this.nodeHandler.getAddress();
+		}
+		return null;
+	}
+	
+	/**
+	 * Evicts the pool item.
+	 * 
+	 * The specified timeout is used when the node is in use.
+	 * 
+	 * @param timeoutMillis the timeout in milliseconds
+	 * 
+	 * @since 2.0
+	 */
+	public void evict(final long timeoutMillis) {
+		if (this.object != null) {
+			this.object.evict(timeoutMillis);
+		}
+	}
+	
+}
diff --git a/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/rj/servi/pool/PoolNodeObject.java b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/rj/servi/pool/PoolNodeObject.java
new file mode 100644
index 0000000..f5e5106
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/rj/servi/pool/PoolNodeObject.java
@@ -0,0 +1,37 @@
+/*=============================================================================#
+ # Copyright (c) 2016, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.servi.pool;
+
+import org.eclipse.statet.internal.rj.servi.NodeHandler;
+
+
+public interface PoolNodeObject {
+	
+	
+	NodeHandler getNodeHandler();
+	
+	long getCreationTime();
+	long getAllocatedCount();
+	long getAllocatedDuration();
+	
+	PoolNodeState getState();
+	long getStateTime();
+	
+	String getClientLabel();
+	
+	void evict(long timeoutMillis);
+	
+	
+}
diff --git a/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/rj/servi/pool/PoolNodeState.java b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/rj/servi/pool/PoolNodeState.java
new file mode 100644
index 0000000..7b76917
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/rj/servi/pool/PoolNodeState.java
@@ -0,0 +1,28 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.servi.pool;
+
+
+public enum PoolNodeState {
+	
+	
+	INITIALIZING,
+	CHECKING,
+	IDLING,
+	ALLOCATED,
+	EVICTING,
+	DISPOSED
+	
+}
diff --git a/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/rj/servi/pool/PoolServer.java b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/rj/servi/pool/PoolServer.java
new file mode 100644
index 0000000..98fb519
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/rj/servi/pool/PoolServer.java
@@ -0,0 +1,44 @@
+/*=============================================================================#
+ # Copyright (c) 2013, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.servi.pool;
+
+import org.eclipse.statet.rj.RjInvalidConfigurationException;
+import org.eclipse.statet.rj.server.util.RJContext;
+import org.eclipse.statet.rj.servi.jmx.PoolServerMXBean;
+import org.eclipse.statet.rj.servi.node.RServiNodeConfig;
+
+
+/**
+ * @since 2.0
+ */
+public interface PoolServer extends PoolServerMXBean {
+	
+	
+	RJContext getRJContext();
+	String getJMBaseName();
+	
+	void getNetConfig(NetConfig config);
+	void setNetConfig(NetConfig config);
+	
+	void getPoolConfig(PoolConfig config);
+	void setPoolConfig(PoolConfig config);
+	
+	void getNodeConfig(RServiNodeConfig config);
+	void setNodeConfig(RServiNodeConfig config) throws RjInvalidConfigurationException;
+	
+	RServiPoolManager getManager();
+	
+	
+}
diff --git a/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/rj/servi/pool/PoolServerDaemon.java b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/rj/servi/pool/PoolServerDaemon.java
new file mode 100644
index 0000000..7410527
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/rj/servi/pool/PoolServerDaemon.java
@@ -0,0 +1,56 @@
+/*=============================================================================#
+ # Copyright (c) 2013, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.servi.pool;
+
+
+/**
+ * This class allows to run the {@link StandalonePoolServer} as daemon using JSVC of Apache
+ * Commons-Daemon (http://commons.apache.org/proper/commons-daemon/).
+ * 
+ * Not tested, feedback welcome.
+ */
+public class PoolServerDaemon {
+	
+	
+	private StandalonePoolServer poolServer;
+	
+	
+	public PoolServerDaemon() {
+	}
+	
+	
+	public void init(final String[] args) throws Exception {
+		if (this.poolServer != null) {
+			throw new IllegalStateException();
+		}
+		this.poolServer= StandalonePoolServer.initServer(args);
+	}
+	
+	public void start() throws Exception {
+		this.poolServer.start();
+	}
+	
+	public void stop() throws Exception {
+		this.poolServer.stop();
+	}
+	
+	public void destroy() {
+		if (this.poolServer != null) {
+			this.poolServer.shutdown();
+			this.poolServer= null;
+		}
+	}
+	
+}
diff --git a/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/rj/servi/pool/PoolStatus.java b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/rj/servi/pool/PoolStatus.java
new file mode 100644
index 0000000..55e30ba
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/rj/servi/pool/PoolStatus.java
@@ -0,0 +1,141 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.servi.pool;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+
+/**
+ * A fixed pool status including note states.
+ * 
+ * @param <N> type of node state items, see {@link #createNodeState(PoolNodeItem)}
+ * 
+ * @since 2.0
+ */
+public abstract class PoolStatus<N> {
+	
+	
+	private final RServiPoolManager.Counter NO_MANAGER= new RServiPoolManager.Counter();
+	
+	
+	protected final PoolServer server;
+	
+	private long stamp;
+	private RServiPoolManager.Counter counter;
+	
+	private List<N> nodeStates;
+	
+	
+	public PoolStatus(final PoolServer server) {
+		if (server == null) {
+			throw new NullPointerException("server");
+		}
+		this.server= server;
+	}
+	
+	
+	protected long getStatusStamp() {
+		return this.stamp;
+	}
+	
+	public synchronized int getNumInUse() {
+		check();
+		return this.counter.numInUse;
+	}
+	
+	public synchronized int getNumIdling() {
+		check();
+		return this.counter.numIdling;
+	}
+	
+	public synchronized int getNumTotal() {
+		check();
+		return this.counter.numTotal;
+	}
+	
+	public synchronized int getMaxInUse() {
+		check();
+		return this.counter.maxInUse;
+	}
+	
+	public synchronized int getMaxIdling() {
+		check();
+		return this.counter.maxIdling;
+	}
+	
+	public synchronized int getMaxTotal() {
+		check();
+		return this.counter.maxTotal;
+	}
+	
+	
+	public synchronized List<N> getNodeStates() {
+		check();
+		return this.nodeStates;
+	}
+	
+	
+	protected void check() {
+	}
+	
+	
+	protected void refresh(final RServiPoolManager manager, final long stamp) {
+		final List<N> list;
+		RServiPoolManager.Counter counter;
+		
+		if (manager == null) {
+			counter= this.NO_MANAGER;
+			list= Collections.emptyList();
+		}
+		else {
+			final Collection<? extends PoolNodeObject> objects= manager.getPoolNodeObjects();
+			counter= manager.getCounter();
+			list= new ArrayList<>();
+			counter.numIdling= 0;
+			counter.numInUse= 0;
+			counter.numTotal= 0;
+			for (final PoolNodeObject nodeObj : objects) {
+				final PoolNodeItem item= createPoolItem(nodeObj, stamp);
+				final N nodeState= createNodeState(item);
+				switch (item.getState()) {
+				case ALLOCATED:
+					counter.numInUse++;
+					break;
+				case IDLING:
+					counter.numIdling++;
+					break;
+				default:
+					break;
+				}
+				counter.numTotal++;
+				list.add(nodeState);
+			}
+		}
+		
+		this.stamp= stamp;
+		this.counter= counter;
+		this.nodeStates= list;
+	}
+	
+	protected PoolNodeItem createPoolItem(final PoolNodeObject node, final long stamp) {
+		return new PoolNodeItem(node, stamp);
+	}
+	
+	protected abstract N createNodeState(PoolNodeItem item);
+	
+}
diff --git a/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/rj/servi/pool/RServiPoolManager.java b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/rj/servi/pool/RServiPoolManager.java
new file mode 100644
index 0000000..a756f5c
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/rj/servi/pool/RServiPoolManager.java
@@ -0,0 +1,51 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.servi.pool;
+
+import java.util.Collection;
+
+import org.eclipse.statet.rj.RjException;
+import org.eclipse.statet.rj.servi.node.RServiNodeFactory;
+
+
+public interface RServiPoolManager {
+	
+	
+	class Counter {
+		public int numIdling;
+		public int numInUse;
+		public int numTotal;
+		public int maxIdling;
+		public int maxInUse;
+		public int maxTotal;
+		
+		public Counter() {}
+	}
+	
+	
+	String getId();
+	
+	PoolConfig getConfig();
+	void setConfig(PoolConfig config);
+	void addNodeFactory(RServiNodeFactory nodeFactory);
+	RServiNodeFactory getFactories();
+	
+	void init() throws RjException;
+	void stop(int mode) throws RjException;
+	
+	RServiPoolManager.Counter getCounter();
+	Collection<? extends PoolNodeObject> getPoolNodeObjects();
+	
+}
diff --git a/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/rj/servi/pool/StandalonePoolServer.java b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/rj/servi/pool/StandalonePoolServer.java
new file mode 100644
index 0000000..30caefc
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/rj/servi/pool/StandalonePoolServer.java
@@ -0,0 +1,172 @@
+/*=============================================================================#
+ # Copyright (c) 2013, 2017 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.servi.pool;
+
+import java.io.File;
+import java.util.concurrent.CopyOnWriteArraySet;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import javax.management.OperationsException;
+
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+
+import org.eclipse.statet.jcommons.lang.Disposable;
+
+import org.eclipse.statet.ecommons.runtime.core.ECommonsRuntime;
+
+import org.eclipse.statet.rj.RjInitFailedException;
+import org.eclipse.statet.rj.RjInvalidConfigurationException;
+import org.eclipse.statet.rj.server.util.RJContext;
+import org.eclipse.statet.rj.servi.RServiUtil;
+import org.eclipse.statet.rj.servi.jmx.StandalonePoolServerMXBean;
+
+
+/**
+ * Standalone version of pool server managed by JMX
+ * 
+ * <p>Required bundles (libraries): <code>org.eclipse.statet.rj.data</code>,
+ * <code>org.eclipse.statet.rj.server</code>, <code>org.eclipse.statet.rj.client</code>,
+ * <code>org.eclipse.statet.rj.servi</code>, <code>org.eclipse.statet.rj.services.eruntime</code>
+ * </p>
+ * <p>The configuration is loaded from / saved to the current directory.
+ * </p>
+ * <p>To start the server use e.g.:
+ * <pre>
+ * java -cp "*" org.eclipse.statet.rj.servi.pool.StandalonePoolServer &lt;id&gt;
+ * </pre></p>
+ * <p>By default the libraries are expected in the current directory. If they are located
+ * in another directory, it must be specified in the java property <code>org.eclipse.statet.rj.path</code>:
+ * <pre>
+ * java -cp "/path/to/rjlibs/*" -Dorg.eclipse.statet.rj.path=/path/to/rjlibs/ org.eclipse.statet.rj.servi.pool.StandalonePoolServer &lt;id&gt;
+ * </pre></p>
+ * </p>
+ */
+public class StandalonePoolServer extends JMPoolServer implements StandalonePoolServerMXBean {
+	
+	
+	private static class EAppEnv implements ECommonsRuntime.AppEnvironment {
+		
+		
+		private final CopyOnWriteArraySet<Disposable> stopListeners= new CopyOnWriteArraySet<>();
+		
+		
+		public EAppEnv() {
+			Runtime.getRuntime().addShutdownHook(new Thread() {
+				@Override
+				public void run() {
+					for (final Disposable listener : EAppEnv.this.stopListeners) {
+						listener.dispose();
+					}
+				}
+			});
+		}
+		
+		
+		@Override
+		public void log(final IStatus status) {
+			System.out.println(status.toString());
+		}
+		
+		@Override
+		public void addStoppingListener(final Disposable listener) {
+			this.stopListeners.add(listener);
+		}
+		
+		@Override
+		public void removeStoppingListener(final Disposable listener) {
+			this.stopListeners.add(listener);
+		}
+		
+	}
+	
+	
+	private final AtomicBoolean running= new AtomicBoolean(true);
+	
+	
+	protected StandalonePoolServer(final String id, final RJContext context) throws RjInitFailedException {
+		super(id, context);
+		
+		new Thread("KeepAlive") {
+			{
+				setDaemon(false);
+			}
+			@Override
+			public void run() {
+				while (StandalonePoolServer.this.running.get()) {
+					synchronized (StandalonePoolServer.this.running) {
+						try {
+							StandalonePoolServer.this.running.wait();
+						}
+						catch (final InterruptedException e) {
+							Thread.interrupted();
+						}
+					}
+				}
+			}
+		}.start();
+	}
+	
+	
+	@Override
+	public synchronized void shutdown() {
+		try {
+			super.shutdown();
+		}
+		finally {
+			this.running.set(false);
+			synchronized (this.running) {
+				this.running.notifyAll();
+			}
+		}
+	}
+	
+	
+	public static void main(final String[] args) throws RjInitFailedException {
+		final StandalonePoolServer server= initServer(args);
+		
+		try {
+			server.start();
+		}
+		catch (final OperationsException e) {
+			ECommonsRuntime.getEnv().log(new Status(IStatus.WARNING, RServiUtil.RJ_SERVI_ID,
+					"The server is started, but the pool could not be started.", e));
+		}
+	}
+	
+	static StandalonePoolServer initServer(final String[] args) throws RjInitFailedException {
+		final String id= (args.length > 0) ? args[0] : null;
+		if (id == null || id.isEmpty()) {
+			throw new IllegalArgumentException("No pool id specified.");
+		}
+		
+		ECommonsRuntime.init(RServiUtil.RJ_SERVI_ID, new EAppEnv());
+		
+		final RJContext context= new RJContext(System.getProperty("user.dir")) {
+			@Override
+			public String getServerPolicyFilePath() throws RjInvalidConfigurationException {
+				final String path= getPropertiesDirPath() + "security.policy";
+				if (new File(path).exists()) {
+					return path;
+				}
+				return super.getServerPolicyFilePath();
+			}
+		};
+		
+		return new StandalonePoolServer(id, context);
+	}
+	
+	
+}