diff --git a/ma-impl.sublime-workspace b/ma-impl.sublime-workspace
index 12a293e29ec5b63837bfab546db8548fe2b2fa01..01b7a763d8d9090c7061359839b6ef57e3d12f48 100644
--- a/ma-impl.sublime-workspace
+++ b/ma-impl.sublime-workspace
@@ -279,18 +279,18 @@
 	"build_varint": "",
 	"command_palette":
 	{
-		"height": 375.0,
-		"last_filter": "close",
+		"height": 231.0,
+		"last_filter": "insta",
 		"selected_items":
 		[
-			[
-				"close",
-				"Project: Close"
-			],
 			[
 				"insta",
 				"Package Control: Install Package"
 			],
+			[
+				"close",
+				"Project: Close"
+			],
 			[
 				"synr",
 				"Set Syntax: R"
@@ -450,23 +450,54 @@
 	"expanded_folders":
 	[
 		"/home/eike/Repositories/fu/ss15/ma/impl",
-		"/home/eike/Repositories/fu/ss15/ma/impl/vipra-ui"
+		"/home/eike/Repositories/fu/ss15/ma/impl/vipra-ui/app",
+		"/home/eike/Repositories/fu/ss15/ma/impl/vipra-ui/app/templates/articles",
+		"/home/eike/Repositories/fu/ss15/ma/impl/vipra-ui/app/templates/components",
+		"/home/eike/Repositories/fu/ss15/ma/impl/vm"
 	],
 	"file_history":
 	[
-		"/home/eike/Repositories/fu/ss15/ma/impl/vipra-ui/bower.json",
-		"/home/eike/Repositories/fu/ss15/ma/impl/vipra-ui/bower_components/ember/ember.js",
-		"/home/eike/Repositories/fu/ss15/ma/impl/vipra-ui/app/routes/articles.js",
-		"/home/eike/Repositories/fu/ss15/ma/impl/vipra-ui/package.json",
+		"/home/eike/Repositories/fu/ss15/ma/impl/vipra-ui/app/components/article-list.js",
+		"/home/eike/Repositories/fu/ss15/ma/impl/vipra-ui/app/components/text-marker.js",
+		"/home/eike/Repositories/fu/ss15/ma/impl/vipra-ui/app/components/debounced-input.js",
+		"/home/eike/Repositories/fu/ss15/ma/impl/vipra-ui/app/components/dynamic-high-charts.js",
+		"/home/eike/Repositories/fu/ss15/ma/impl/vipra-ui/app/templates/components/text-marker.hbs",
+		"/home/eike/Repositories/fu/ss15/ma/impl/vipra-ui/app/templates/components/article-list.hbs",
+		"/home/eike/Repositories/fu/ss15/ma/impl/vipra-ui/app/templates/articles/list.hbs",
+		"/home/eike/Repositories/fu/ss15/ma/impl/vm/bootstrap.sh",
+		"/home/eike/Repositories/fu/ss15/ma/impl/vipra-ui/app/adapters/application.js",
+		"/home/eike/Repositories/fu/ss15/ma/impl/vipra-ui/app/routes/articles/list.js",
+		"/home/eike/Repositories/fu/ss15/ma/impl/vipra-ui/app/templates/articles/show.hbs",
+		"/home/eike/Repositories/fu/ss15/ma/impl/vipra-ui/app/components/filter-text.js",
+		"/home/eike/Repositories/fu/ss15/ma/impl/vm/webapps/test/index.html",
+		"/home/eike/Repositories/fu/ss15/ma/impl/vipra-ui/app/controllers/articles/list.js",
+		"/home/eike/Repositories/fu/ss15/ma/impl/vipra-ui/app/router.js",
+		"/home/eike/Repositories/fu/ss15/ma/impl/vipra-ui/app/index.html",
+		"/home/eike/Repositories/fu/ss15/ma/impl/vipra-ui/app/components/search-box.js",
+		"/home/eike/Repositories/fu/ss15/ma/impl/vipra-ui/app/templates/loading.hbs",
+		"/home/eike/Repositories/fu/ss15/ma/impl/vipra-ui/app/templates/not-found.hbs",
 		"/home/eike/Repositories/fu/ss15/ma/impl/vipra-ui/app/templates/articles.hbs",
 		"/home/eike/Repositories/fu/ss15/ma/impl/vipra-ui/app/models/article.js",
-		"/home/eike/Repositories/fu/ss15/ma/impl/vipra-ui/app/router.js",
-		"/home/eike/Repositories/fu/ss15/ma/impl/vipra-ui/app/adapters/application.js",
+		"/home/eike/Repositories/fu/ss15/ma/impl/vipra-ui/app/templates/index.hbs",
+		"/home/eike/Repositories/fu/ss15/ma/impl/vipra-ui/app/routes/articles/index.js",
+		"/home/eike/Repositories/fu/ss15/ma/impl/vipra-ui/app/routes/article.js",
+		"/home/eike/Repositories/fu/ss15/ma/impl/vipra-ui/app/templates/articles/index.hbs",
+		"/home/eike/Repositories/fu/ss15/ma/impl/vipra-ui/app/templates/articles/new.hbs",
+		"/home/eike/Repositories/fu/ss15/ma/impl/vipra-ui/app/routes/article/show.js",
+		"/home/eike/Repositories/fu/ss15/ma/impl/vipra-ui/app/templates/article.hbs",
+		"/home/eike/Repositories/fu/ss15/ma/impl/vipra-ui/app/routes/articles.js",
+		"/home/eike/Repositories/fu/ss15/ma/impl/vipra-ui/app/templates/articles.show.hbs",
+		"/home/eike/Repositories/fu/ss15/ma/impl/vipra-ui/app/routes/articles.show.js",
+		"/home/eike/Repositories/fu/ss15/ma/impl/vipra-ui/app/templates/articles/test.hbs",
+		"/home/eike/Repositories/fu/ss15/ma/impl/vipra-ui/.ember-cli",
+		"/home/eike/Repositories/fu/ss15/ma/impl/vipra-ui/bower_components/ember-data/ember-data.js",
+		"/home/eike/Repositories/fu/ss15/ma/impl/vipra-ui/bower_components/ember/ember.js",
+		"/home/eike/Repositories/fu/ss15/ma/impl/vipra-ui/app/templates/application.hbs",
 		"/home/eike/Repositories/fu/ss15/ma/impl/vipra-ui/app/serializers/application.js",
+		"/home/eike/Repositories/fu/ss15/ma/impl/vipra-ui/bower.json",
+		"/home/eike/Repositories/fu/ss15/ma/impl/vipra-ui/bower_components/ember/.bower.json",
+		"/home/eike/Repositories/fu/ss15/ma/impl/vipra-ui/package.json",
 		"/home/eike/Repositories/fu/ss15/ma/impl/vipra-ui/app/app.js",
-		"/home/eike/Repositories/fu/ss15/ma/impl/vipra-ui/app/templates/application.hbs",
-		"/home/eike/Repositories/fu/ss15/ma/impl/vipra-ui/app/templates/index.hbs",
-		"/home/eike/Repositories/fu/ss15/ma/impl/vm/bootstrap.sh",
 		"/home/eike/Repositories/fu/ss15/ma/doc/thesis/thesis.tex",
 		"/home/eike/Repositories/fu/ss15/ma/impl/Vagrantfile",
 		"/home/eike/Repositories/fu/ss15/ma/impl/tmbs-processor-backend/src/main/scala/de/cochu/tmbs/processor/MongoDBTest.scala",
@@ -583,6 +614,7 @@
 		"case_sensitive": false,
 		"find_history":
 		[
+			"json-api",
 			"\"id\":.*?\\n    ",
 			"\"id\":.*?\\n",
 			"\"_id\":",
@@ -709,8 +741,7 @@
 			"!important",
 			"images",
 			"url(\"../images/",
-			"fa-var",
-			"account.name"
+			"fa-var"
 		],
 		"highlight": true,
 		"in_selection": false,
diff --git a/vipra-cmd/.classpath b/vipra-cmd/.classpath
index 91251671bf896bb25780ea2ddbe38b6248295e34..1d99666bcace8e15a36c9dd09f3d921742acf5c3 100644
--- a/vipra-cmd/.classpath
+++ b/vipra-cmd/.classpath
@@ -15,5 +15,6 @@
 			<attribute name="owner.project.facets" value="java"/>
 		</attributes>
 	</classpathentry>
+	<classpathentry combineaccessrules="false" kind="src" path="/vipra-util"/>
 	<classpathentry kind="output" path="target/classes"/>
 </classpath>
diff --git a/vipra-cmd/.project b/vipra-cmd/.project
index 7457abc9569d7378c1550159176d5982a81e3fe9..42d5a8abc4acc1079b7e84ac965c26a5fce2d48c 100644
--- a/vipra-cmd/.project
+++ b/vipra-cmd/.project
@@ -33,11 +33,4 @@
 		<nature>org.eclipse.m2e.core.maven2Nature</nature>
 		<nature>org.eclipse.wst.common.project.facet.core.nature</nature>
 	</natures>
-	<linkedResources>
-		<link>
-			<name>src/main/resources/config.properties</name>
-			<type>1</type>
-			<locationURI>PARENT-1-PROJECT_LOC/vipra-config/config.properties</locationURI>
-		</link>
-	</linkedResources>
 </projectDescription>
diff --git a/vipra-cmd/src/main/java/de/vipra/cmd/Configuration.java b/vipra-cmd/src/main/java/de/vipra/cmd/Configuration.java
deleted file mode 100644
index c30776997c935ebb74d0a18dc0674b6399664249..0000000000000000000000000000000000000000
--- a/vipra-cmd/src/main/java/de/vipra/cmd/Configuration.java
+++ /dev/null
@@ -1,41 +0,0 @@
-package de.vipra.cmd;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.Properties;
-
-public class Configuration extends Properties {
-
-	private static final long serialVersionUID = 1L;
-
-	public static final String DEFAULT_HOST = "localhost";
-	public static final int DEFAULT_PORT = 27017;
-	public static final String DEFAULT_DB = "test";
-
-	public Configuration() {
-		this(Thread.currentThread().getContextClassLoader().getResourceAsStream("config.properties"));
-	}
-
-	public Configuration(InputStream in) {
-		try {
-			load(in);
-		} catch (IOException e) {}
-	}
-
-	public String getString(String key, String defaultValue) {
-		return getProperty(key, defaultValue);
-	}
-
-	public int getInt(String key, int defaultValue) {
-		try {
-			return Integer.parseInt(getProperty(key, Integer.toString(defaultValue)));
-		} catch (NumberFormatException e) {
-			return defaultValue;
-		}
-	}
-
-	public boolean getBool(String key, boolean defaultValue) {
-		return Boolean.parseBoolean(getProperty(key, Boolean.toString(defaultValue)));
-	}
-
-}
diff --git a/vipra-cmd/src/main/java/de/vipra/cmd/Main.java b/vipra-cmd/src/main/java/de/vipra/cmd/Main.java
index 34ea6ee604935ad706b0a70ea79aee773f4a4bd7..287f10cc6d587c4faeb692770f5cb764982415fe 100644
--- a/vipra-cmd/src/main/java/de/vipra/cmd/Main.java
+++ b/vipra-cmd/src/main/java/de/vipra/cmd/Main.java
@@ -1,15 +1,22 @@
 package de.vipra.cmd;
 
+import java.io.IOException;
+
 import org.apache.commons.cli.CommandLine;
 import org.apache.commons.cli.CommandLineParser;
 import org.apache.commons.cli.DefaultParser;
 import org.apache.commons.cli.ParseException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 import de.vipra.cmd.option.ImportOption;
+import de.vipra.util.ConfigException;
 
 public class Main {
 
-	public static void main(String[] args) {
+	public static final Logger log = LoggerFactory.getLogger(Main.class);
+
+	public static void main(String[] args) throws IOException, ConfigException {
 		CommandLineParser parser = new DefaultParser();
 		CmdOptions options = new CmdOptions();
 		try {
@@ -25,7 +32,9 @@ public class Main {
 			}
 		} catch (ParseException e) {
 			options.printHelp();
-		} catch (ExecutionException e) {}
+		} catch (ExecutionException e) {
+			log.error(e.getMessage());
+		}
 	}
 
 }
diff --git a/vipra-cmd/src/main/java/de/vipra/cmd/MongoDB.java b/vipra-cmd/src/main/java/de/vipra/cmd/MongoDB.java
deleted file mode 100644
index 9025c1bdad81f7486996bd5275dd1ad908b2c7a6..0000000000000000000000000000000000000000
--- a/vipra-cmd/src/main/java/de/vipra/cmd/MongoDB.java
+++ /dev/null
@@ -1,45 +0,0 @@
-package de.vipra.cmd;
-
-import com.mongodb.MongoClient;
-import com.mongodb.client.MongoDatabase;
-
-public class MongoDB {
-
-	private static MongoDB mongo;
-
-	private final MongoClient client;
-	private final MongoDatabase db;
-
-	private MongoDB(Configuration config) {
-		String host = config.getString("db.host", Configuration.DEFAULT_HOST);
-		Integer port = config.getInt("db.port", Configuration.DEFAULT_PORT);
-		String databaseName = config.getString("db.name", Configuration.DEFAULT_DB);
-
-		client = new MongoClient(host, port);
-		db = client.getDatabase(databaseName);
-	}
-
-	public MongoClient getClient() {
-		return client;
-	}
-
-	public MongoDatabase getDatabase() {
-		return db;
-	}
-
-	public static MongoDB getInstance() {
-		if (mongo == null) {
-			Configuration config = new Configuration();
-			mongo = new MongoDB(config);
-		}
-		return mongo;
-	}
-
-	public static MongoDB getInstance(Configuration config) {
-		if (mongo == null) {
-			mongo = new MongoDB(config);
-		}
-		return mongo;
-	}
-
-}
diff --git a/vipra-cmd/src/main/java/de/vipra/cmd/option/ImportOption.java b/vipra-cmd/src/main/java/de/vipra/cmd/option/ImportOption.java
index 25b02a08acb073f9cb1d6b81eabcbc5213a6c5b3..e8a61d32e0215922c526c79193c243b6237b6b0f 100644
--- a/vipra-cmd/src/main/java/de/vipra/cmd/option/ImportOption.java
+++ b/vipra-cmd/src/main/java/de/vipra/cmd/option/ImportOption.java
@@ -12,15 +12,24 @@ import org.json.simple.parser.JSONParser;
 import org.json.simple.parser.ParseException;
 
 import de.vipra.cmd.ExecutionException;
-import de.vipra.cmd.MongoDB;
+import de.vipra.util.Config;
+import de.vipra.util.ConfigException;
+import de.vipra.util.Mongo;
 
 public class ImportOption {
 
 	private ArrayList<File> files = new ArrayList<>();
 	private JSONParser parser = new JSONParser();
-	private MongoDB mongo = MongoDB.getInstance();
+	private Config config;
+	private Mongo mongo;
 
 	public ImportOption(String[] paths) throws ExecutionException {
+		try {
+			config = new Config();
+			mongo = Mongo.getInstance(config);
+		} catch (IOException | ConfigException e) {
+			throw new ExecutionException(e.getMessage());
+		}
 		addPaths(paths);
 	}
 
@@ -70,14 +79,18 @@ public class ImportOption {
 	}
 
 	private void importArticle(JSONObject obj) {
-
+		// 1. add article to mongodb
+		// 2. add article to file database
+		// 4. topic modeling
+		// 3. index article via elasticsearch, include topics
 	}
 
 	public void doImport() {
 		for (File file : files) {
 			try {
 				importFile(file);
-			} catch (Exception e) {}
+			} catch (Exception e) {
+			}
 		}
 	}
 
diff --git a/vipra-config/config.properties b/vipra-cmd/src/main/resources/config.properties
similarity index 100%
rename from vipra-config/config.properties
rename to vipra-cmd/src/main/resources/config.properties
diff --git a/vipra-rest/.classpath b/vipra-rest/.classpath
index 6acf3eeecaebe2d096ef46a44bf6988db916e316..d8728319c5ba6bfc3e74f4b13ce346e356fab451 100644
--- a/vipra-rest/.classpath
+++ b/vipra-rest/.classpath
@@ -28,10 +28,11 @@
 			<attribute name="org.eclipse.jst.component.dependency" value="/WEB-INF/lib"/>
 		</attributes>
 	</classpathentry>
-	<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.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.7">
 		<attributes>
-			<attribute name="maven.pomderived" value="true"/>
+			<attribute name="owner.project.facets" value="java"/>
 		</attributes>
 	</classpathentry>
+	<classpathentry combineaccessrules="false" kind="src" path="/vipra-util"/>
 	<classpathentry kind="output" path="target/classes"/>
 </classpath>
diff --git a/vipra-rest/.project b/vipra-rest/.project
index e9151f1e0a91e271e7af97b5faf74f81d3f160bf..e24244ea68a972f817781145661bc0723916096b 100644
--- a/vipra-rest/.project
+++ b/vipra-rest/.project
@@ -4,6 +4,7 @@
 	<comment></comment>
 	<projects>
 		<project>vipra-cmd</project>
+		<project>vipra-util</project>
 	</projects>
 	<buildSpec>
 		<buildCommand>
@@ -40,11 +41,4 @@
 		<nature>org.eclipse.wst.common.project.facet.core.nature</nature>
 		<nature>org.eclipse.wst.jsdt.core.jsNature</nature>
 	</natures>
-	<linkedResources>
-		<link>
-			<name>src/main/resources/config.properties</name>
-			<type>1</type>
-			<locationURI>PARENT-1-PROJECT_LOC/vipra-config/config.properties</locationURI>
-		</link>
-	</linkedResources>
 </projectDescription>
diff --git a/vipra-rest/.settings/org.eclipse.jdt.core.prefs b/vipra-rest/.settings/org.eclipse.jdt.core.prefs
index c07c252bc5d05edd0375e06b1d52f0a921ae65a0..7677f45f763923b768652ded0a1422b2b83c6d77 100644
--- a/vipra-rest/.settings/org.eclipse.jdt.core.prefs
+++ b/vipra-rest/.settings/org.eclipse.jdt.core.prefs
@@ -1,16 +1,16 @@
 eclipse.preferences.version=1
 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.targetPlatform=1.7
 org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
-org.eclipse.jdt.core.compiler.compliance=1.8
+org.eclipse.jdt.core.compiler.compliance=1.7
 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.problem.forbiddenReference=warning
-org.eclipse.jdt.core.compiler.source=1.8
+org.eclipse.jdt.core.compiler.source=1.7
 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
diff --git a/vipra-rest/.settings/org.eclipse.wst.common.component b/vipra-rest/.settings/org.eclipse.wst.common.component
index bfc7ecd2c55b87f9f307cc7ca345597974f27cb9..df9f1cfb7b6d2d1e0bfd7425e36690f2b9f64b0c 100644
--- a/vipra-rest/.settings/org.eclipse.wst.common.component
+++ b/vipra-rest/.settings/org.eclipse.wst.common.component
@@ -4,6 +4,9 @@
         <wb-resource deploy-path="/" source-path="/src/main/webapp" tag="defaultRootSource"/>
         <wb-resource deploy-path="/WEB-INF/classes" source-path="/src/main/java"/>
         <wb-resource deploy-path="/WEB-INF/classes" source-path="/src/main/resources"/>
+        <dependent-module archiveName="vipra-util.jar" deploy-path="/WEB-INF/lib" handle="module:/resource/vipra-util/vipra-util">
+            <dependency-type>uses</dependency-type>
+        </dependent-module>
         <property name="java-output-path" value="/vipra-rest/target/classes"/>
         <property name="context-root" value="vipra-rest"/>
     </wb-module>
diff --git a/vipra-rest/.settings/org.eclipse.wst.common.project.facet.core.xml b/vipra-rest/.settings/org.eclipse.wst.common.project.facet.core.xml
index d59fb58d14dd57692727e9b2e695dd99cd5929ce..984341746468874acc75524c80a2579ccee81217 100644
--- a/vipra-rest/.settings/org.eclipse.wst.common.project.facet.core.xml
+++ b/vipra-rest/.settings/org.eclipse.wst.common.project.facet.core.xml
@@ -4,5 +4,5 @@
   <installed facet="wst.jsdt.web" version="1.0"/>
   <installed facet="jst.jaxrs" version="2.0"/>
   <installed facet="jst.web" version="3.1"/>
-  <installed facet="java" version="1.8"/>
+  <installed facet="java" version="1.7"/>
 </faceted-project>
diff --git a/vipra-rest/pom.xml b/vipra-rest/pom.xml
index 804ffc3676547e48a94e764de5269de75487a2eb..a7b384aa66170c7f9ddcba6c7dadd4da23cb12af 100644
--- a/vipra-rest/pom.xml
+++ b/vipra-rest/pom.xml
@@ -12,8 +12,8 @@
 
 	<properties>
 		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
-		<maven.compiler.target>1.8</maven.compiler.target>
-		<maven.compiler.source>1.8</maven.compiler.source>
+		<maven.compiler.target>1.7</maven.compiler.target>
+		<maven.compiler.source>1.7</maven.compiler.source>
 		<jerseyVersion>2.22.1</jerseyVersion>
 		<jettyVersion>9.3.6.v20151106</jettyVersion>
 		<servletVersion>3.1.0</servletVersion>
@@ -29,7 +29,7 @@
 		</dependency>
 		<dependency>
 			<groupId>org.glassfish.jersey.media</groupId>
-			<!--<artifactId>jersey-media-moxy</artifactId>-->
+			<!--<artifactId>jersey-media-moxy</artifactId> -->
 			<artifactId>jersey-media-json-jackson</artifactId>
 			<version>${jerseyVersion}</version>
 		</dependency>
@@ -43,6 +43,11 @@
 			<artifactId>jersey-test-framework-provider-simple</artifactId>
 			<version>${jerseyVersion}</version>
 		</dependency>
+		<dependency>
+			<groupId>com.github.fge</groupId>
+			<artifactId>json-patch</artifactId>
+			<version>1.9</version>
+		</dependency>
 
 		<!-- Servlet API -->
 		<dependency>
@@ -50,7 +55,7 @@
 			<artifactId>javax.servlet-api</artifactId>
 			<version>${servletVersion}</version>
 		</dependency>
-		
+
 		<!-- Logging -->
 		<dependency>
 			<groupId>org.apache.logging.log4j</groupId>
diff --git a/vipra-rest/src/main/java/de/vipra/rest/Application.java b/vipra-rest/src/main/java/de/vipra/rest/Application.java
index 632b4c8fc73b985bd0f7063bf8901f32f276fded..3a105f81c74b4f98258b6d1d2db1b5e3d74412ff 100644
--- a/vipra-rest/src/main/java/de/vipra/rest/Application.java
+++ b/vipra-rest/src/main/java/de/vipra/rest/Application.java
@@ -6,6 +6,7 @@ import org.glassfish.jersey.server.ResourceConfig;
 import de.vipra.rest.provider.APIRequestFilter;
 import de.vipra.rest.provider.CORSResponseFilter;
 import de.vipra.rest.provider.ObjectMapperProvider;
+import de.vipra.rest.provider.PatchReaderInterceptor;
 
 public class Application extends ResourceConfig {
 
@@ -15,6 +16,7 @@ public class Application extends ResourceConfig {
 		register(CORSResponseFilter.class);
 		register(ObjectMapperProvider.class);
 		register(APIRequestFilter.class);
+		register(PatchReaderInterceptor.class);
 	}
 
 }
diff --git a/vipra-rest/src/main/java/de/vipra/rest/Configuration.java b/vipra-rest/src/main/java/de/vipra/rest/Configuration.java
deleted file mode 100644
index 30b9795d6f94592766796724333814ee5d5c6eca..0000000000000000000000000000000000000000
--- a/vipra-rest/src/main/java/de/vipra/rest/Configuration.java
+++ /dev/null
@@ -1,50 +0,0 @@
-package de.vipra.rest;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.Properties;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class Configuration extends Properties {
-
-	public static final Logger log = LoggerFactory.getLogger(Configuration.class);
-
-	private static final long serialVersionUID = 1L;
-
-	public static final String DEFAULT_HOST = "localhost";
-	public static final int DEFAULT_PORT = 27017;
-	public static final String DEFAULT_DB = "test";
-
-	public Configuration() {
-		this(Thread.currentThread().getContextClassLoader().getResourceAsStream("config.properties"));
-	}
-
-	public Configuration(InputStream in) {
-		if (in == null) {
-			log.error("configuration file stream not found");
-		} else {
-			try {
-				load(in);
-			} catch (IOException e) {}
-		}
-	}
-
-	public String getString(String key, String defaultValue) {
-		return getProperty(key, defaultValue);
-	}
-
-	public int getInt(String key, int defaultValue) {
-		try {
-			return Integer.parseInt(getProperty(key, Integer.toString(defaultValue)));
-		} catch (NumberFormatException e) {
-			return defaultValue;
-		}
-	}
-
-	public boolean getBool(String key, boolean defaultValue) {
-		return Boolean.parseBoolean(getProperty(key, Boolean.toString(defaultValue)));
-	}
-
-}
diff --git a/vipra-rest/src/main/java/de/vipra/rest/MongoDB.java b/vipra-rest/src/main/java/de/vipra/rest/MongoDB.java
deleted file mode 100644
index e219cf3934944a5f00d75bf3e2f923ec992159ad..0000000000000000000000000000000000000000
--- a/vipra-rest/src/main/java/de/vipra/rest/MongoDB.java
+++ /dev/null
@@ -1,45 +0,0 @@
-package de.vipra.rest;
-
-import com.mongodb.MongoClient;
-import com.mongodb.client.MongoDatabase;
-
-public class MongoDB {
-
-	private static MongoDB mongo;
-
-	private final MongoClient client;
-	private final MongoDatabase db;
-
-	private MongoDB(Configuration config) {
-		String host = config.getString("db.host", Configuration.DEFAULT_HOST);
-		Integer port = config.getInt("db.port", Configuration.DEFAULT_PORT);
-		String databaseName = config.getString("db.name", Configuration.DEFAULT_DB);
-
-		client = new MongoClient(host, port);
-		db = client.getDatabase(databaseName);
-	}
-
-	public MongoClient getClient() {
-		return client;
-	}
-
-	public MongoDatabase getDatabase() {
-		return db;
-	}
-
-	public static MongoDB getInstance() {
-		if (mongo == null) {
-			Configuration config = new Configuration();
-			mongo = new MongoDB(config);
-		}
-		return mongo;
-	}
-
-	public static MongoDB getInstance(Configuration config) {
-		if (mongo == null) {
-			mongo = new MongoDB(config);
-		}
-		return mongo;
-	}
-
-}
diff --git a/vipra-rest/src/main/java/de/vipra/rest/PATCH.java b/vipra-rest/src/main/java/de/vipra/rest/PATCH.java
new file mode 100644
index 0000000000000000000000000000000000000000..78b80504335a3d1dd80a1e8f17f8680477dc984f
--- /dev/null
+++ b/vipra-rest/src/main/java/de/vipra/rest/PATCH.java
@@ -0,0 +1,17 @@
+package de.vipra.rest;
+
+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.ws.rs.HttpMethod;
+import javax.ws.rs.NameBinding;
+
+@Target({ ElementType.METHOD, ElementType.TYPE })
+@Retention(RetentionPolicy.RUNTIME)
+@HttpMethod("PATCH")
+@Documented
+@NameBinding
+public @interface PATCH {}
\ No newline at end of file
diff --git a/vipra-rest/src/main/java/de/vipra/rest/provider/ObjectMapperProvider.java b/vipra-rest/src/main/java/de/vipra/rest/provider/ObjectMapperProvider.java
index b818a5f9d115f8ca5e9ea65115d6c2f5f6ba9a3c..7678b4b0ff9af5633917e3eeccab46fe0599c2d9 100644
--- a/vipra-rest/src/main/java/de/vipra/rest/provider/ObjectMapperProvider.java
+++ b/vipra-rest/src/main/java/de/vipra/rest/provider/ObjectMapperProvider.java
@@ -1,5 +1,7 @@
 package de.vipra.rest.provider;
 
+import java.text.SimpleDateFormat;
+
 import javax.ws.rs.ext.ContextResolver;
 import javax.ws.rs.ext.Provider;
 
@@ -9,11 +11,6 @@ import org.slf4j.LoggerFactory;
 import com.fasterxml.jackson.annotation.JsonInclude.Include;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.fasterxml.jackson.databind.SerializationFeature;
-import com.fasterxml.jackson.databind.module.SimpleModule;
-
-import de.vipra.rest.model.Article;
-import de.vipra.rest.serializer.ArticleDeserializer;
-import de.vipra.rest.serializer.ArticleSerializer;
 
 @Provider
 public class ObjectMapperProvider implements ContextResolver<ObjectMapper> {
@@ -32,14 +29,10 @@ public class ObjectMapperProvider implements ContextResolver<ObjectMapper> {
 	}
 
 	public static ObjectMapper createDefaultMapper() {
-		SimpleModule module = new SimpleModule();
-		module.addSerializer(Article.class, new ArticleSerializer());
-		module.addDeserializer(Article.class, new ArticleDeserializer());
-
 		final ObjectMapper mapper = new ObjectMapper();
 		mapper.enable(SerializationFeature.INDENT_OUTPUT);
 		mapper.setSerializationInclusion(Include.NON_NULL);
-		mapper.registerModule(module);
+		mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'"));
 		return mapper;
 	}
 
diff --git a/vipra-rest/src/main/java/de/vipra/rest/provider/PatchReaderInterceptor.java b/vipra-rest/src/main/java/de/vipra/rest/provider/PatchReaderInterceptor.java
new file mode 100644
index 0000000000000000000000000000000000000000..ea7f724260cff7dda1443bdb440733c32705a1ba
--- /dev/null
+++ b/vipra-rest/src/main/java/de/vipra/rest/provider/PatchReaderInterceptor.java
@@ -0,0 +1,113 @@
+package de.vipra.rest.provider;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+import com.github.fge.jsonpatch.JsonPatch;
+import com.github.fge.jsonpatch.JsonPatchException;
+
+import de.vipra.rest.PATCH;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Method;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.MultivaluedHashMap;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriInfo;
+import javax.ws.rs.ext.MessageBodyWriter;
+import javax.ws.rs.ext.Provider;
+import javax.ws.rs.ext.ReaderInterceptor;
+import javax.ws.rs.ext.ReaderInterceptorContext;
+
+import org.glassfish.jersey.message.MessageBodyWorkers;
+
+@Provider
+@PATCH
+public class PatchReaderInterceptor implements ReaderInterceptor {
+	private UriInfo info;
+	private MessageBodyWorkers workers;
+
+	@Context
+	public void setInfo(UriInfo info) {
+		this.info = info;
+	}
+
+	@Context
+	public void setWorkers(MessageBodyWorkers workers) {
+		this.workers = workers;
+	}
+
+	@Override
+	public Object aroundReadFrom(ReaderInterceptorContext readerInterceptorContext)
+			throws IOException, WebApplicationException {
+
+		// Get the resource we are being called on,
+		// and find the GET method
+		Object resource = info.getMatchedResources().get(0);
+
+		Method found = null;
+		for (Method next : resource.getClass().getMethods()) {
+			if (next.getAnnotation(GET.class) != null) {
+				found = next;
+				break;
+			}
+		}
+
+		if (found != null) {
+
+			// Invoke the get method to get the state we are trying to patch
+			//
+			Object bean;
+			try {
+				bean = found.invoke(resource);
+			} catch (Exception e) {
+				throw new WebApplicationException(e);
+			}
+
+			// Convert this object to a an aray of bytes
+			ByteArrayOutputStream baos = new ByteArrayOutputStream();
+			MessageBodyWriter<? super Object> bodyWriter = workers.getMessageBodyWriter(Object.class, bean.getClass(),
+					new Annotation[0], MediaType.APPLICATION_JSON_TYPE);
+
+			bodyWriter.writeTo(bean, bean.getClass(), bean.getClass(), new Annotation[0],
+					MediaType.APPLICATION_JSON_TYPE, new MultivaluedHashMap<String, Object>(), baos);
+
+			// Use the Jackson 2.x classes to convert both the incoming patch
+			// and the current state of the object into a JsonNode / JsonPatch
+			ObjectMapper mapper = new ObjectMapper();
+			JsonNode serverState = mapper.readValue(baos.toByteArray(), JsonNode.class);
+			JsonNode patchAsNode = mapper.readValue(readerInterceptorContext.getInputStream(), JsonNode.class);
+			JsonPatch patch = JsonPatch.fromJson(patchAsNode);
+
+			try {
+				// Apply the patch
+				JsonNode result = patch.apply(serverState);
+
+				// Stream the result & modify the stream on the
+				// readerInterceptor
+				ByteArrayOutputStream resultAsByteArray = new ByteArrayOutputStream();
+				mapper.writeValue(resultAsByteArray, result);
+				readerInterceptorContext.setInputStream(new ByteArrayInputStream(resultAsByteArray.toByteArray()));
+
+				// Pass control back to the Jersey code
+				return readerInterceptorContext.proceed();
+
+			} catch (JsonPatchException e) {
+				throw new WebApplicationException(
+						Response.serverError().type("text/plain").entity(e.getMessage()).build());
+			}
+
+		} else {
+			throw new IllegalArgumentException("No matching GET method on resource");
+		}
+
+	}
+}
diff --git a/vipra-rest/src/main/java/de/vipra/rest/resource/ArticleResource.java b/vipra-rest/src/main/java/de/vipra/rest/resource/ArticleResource.java
index 605a80ea488ed8988e6e6fd471db69ae0cbaabf4..cc3533782018f2f6217c46835ad878861dcddd6a 100644
--- a/vipra-rest/src/main/java/de/vipra/rest/resource/ArticleResource.java
+++ b/vipra-rest/src/main/java/de/vipra/rest/resource/ArticleResource.java
@@ -1,6 +1,6 @@
 package de.vipra.rest.resource;
 
-import java.io.InputStream;
+import java.io.IOException;
 import java.util.ArrayList;
 
 import javax.servlet.ServletContext;
@@ -19,13 +19,14 @@ import javax.ws.rs.core.Response;
 import javax.ws.rs.core.UriInfo;
 
 import de.vipra.rest.APIMediaType;
-import de.vipra.rest.Configuration;
 import de.vipra.rest.Messages;
-import de.vipra.rest.MongoDB;
 import de.vipra.rest.model.APIError;
 import de.vipra.rest.model.Article;
 import de.vipra.rest.model.ResponseWrapper;
 import de.vipra.rest.service.ArticleService;
+import de.vipra.util.Config;
+import de.vipra.util.ConfigException;
+import de.vipra.util.Mongo;
 
 @Path("articles")
 public class ArticleResource {
@@ -35,10 +36,9 @@ public class ArticleResource {
 
 	final ArticleService service;
 
-	public ArticleResource(@Context ServletContext servletContext) {
-		InputStream is = servletContext.getResourceAsStream("config.properties");
-		Configuration config = new Configuration(is);
-		MongoDB mongo = MongoDB.getInstance(config);
+	public ArticleResource(@Context ServletContext servletContext) throws ConfigException, IOException {
+		Config config = new Config();
+		Mongo mongo = Mongo.getInstance(config);
 		service = new ArticleService(mongo.getDatabase());
 	}
 
@@ -88,7 +88,8 @@ public class ArticleResource {
 	@Path("{id}")
 	public Response deleteArticle(@PathParam("id") String id) {
 		long deleted = service.deleteArticle(id);
-		switch (Math.toIntExact(deleted)) {
+		int del = deleted > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) deleted;
+		switch (del) {
 		case 0:
 			ResponseWrapper<Article> res = new ResponseWrapper<>();
 			res.addError(new APIError(Response.Status.NOT_FOUND, "Article not found",
@@ -107,8 +108,9 @@ public class ArticleResource {
 	@Path("{id}")
 	public Response updateArticle(@PathParam("id") String id, Article article) {
 		long updated = service.updateArticle(uri.getAbsolutePath(), article);
+		int upd = updated > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) updated;
 		ResponseWrapper<Article> res = new ResponseWrapper<>();
-		switch (Math.toIntExact(updated)) {
+		switch (upd) {
 		case 0:
 			res.addError(new APIError(Response.Status.NOT_FOUND, "Article not found",
 					String.format(Messages.NOT_FOUND, "article", id)));
diff --git a/vipra-rest/src/main/java/de/vipra/rest/serializer/ArticleDeserializer.java b/vipra-rest/src/main/java/de/vipra/rest/serializer/ArticleDeserializer.java
deleted file mode 100644
index 54152e0b54e4209de180e26bd008a4ad9d713d70..0000000000000000000000000000000000000000
--- a/vipra-rest/src/main/java/de/vipra/rest/serializer/ArticleDeserializer.java
+++ /dev/null
@@ -1,43 +0,0 @@
-package de.vipra.rest.serializer;
-
-import java.io.IOException;
-
-import com.fasterxml.jackson.core.JsonParser;
-import com.fasterxml.jackson.core.JsonProcessingException;
-import com.fasterxml.jackson.databind.DeserializationContext;
-import com.fasterxml.jackson.databind.JsonDeserializer;
-import com.fasterxml.jackson.databind.JsonNode;
-
-import de.vipra.rest.model.Article;
-
-import static de.vipra.rest.serializer.Helper.*;
-
-public class ArticleDeserializer extends JsonDeserializer<Article> {
-
-	@Override
-	public Article deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
-		Article article = null;
-
-		JsonNode node = p.readValueAsTree();
-		if (node != null) {
-			article = new Article();
-			if (node.has("id"))
-				article.setId(getString(node, "id"));
-
-			if (node.has("attributes")) {
-				JsonNode attrs = node.get("attributes");
-				if (attrs.has("title"))
-					article.setTitle(getString(attrs, "title"));
-				if (attrs.has("text"))
-					article.setText(getString(attrs, "text"));
-				if (attrs.has("url"))
-					article.setUrl(getString(attrs, "url"));
-				if (attrs.has("date"))
-					article.setDate(stringToDate(getString(attrs, "date")));
-			}
-		}
-
-		return article;
-	}
-
-}
diff --git a/vipra-rest/src/main/java/de/vipra/rest/serializer/ArticleSerializer.java b/vipra-rest/src/main/java/de/vipra/rest/serializer/ArticleSerializer.java
deleted file mode 100644
index b5ce97f963540a3da36c73ce26215290d696d2fd..0000000000000000000000000000000000000000
--- a/vipra-rest/src/main/java/de/vipra/rest/serializer/ArticleSerializer.java
+++ /dev/null
@@ -1,40 +0,0 @@
-package de.vipra.rest.serializer;
-
-import de.vipra.rest.model.Article;
-
-import java.io.IOException;
-
-import com.fasterxml.jackson.core.JsonGenerator;
-import com.fasterxml.jackson.core.JsonProcessingException;
-import com.fasterxml.jackson.databind.JsonSerializer;
-import com.fasterxml.jackson.databind.SerializerProvider;
-
-import static de.vipra.rest.serializer.Helper.*;
-
-public class ArticleSerializer extends JsonSerializer<Article> {
-
-	@Override
-	public void serialize(Article value, JsonGenerator gen, SerializerProvider serializers)
-			throws IOException, JsonProcessingException {
-		gen.writeStartObject();
-		gen.writeStringField("id", value.getId());
-		gen.writeStringField("type", value.getType());
-
-		if (value.getLinks() != null)
-			gen.writeObjectField("links", value.getLinks());
-
-		gen.writeObjectFieldStart("attributes");
-		if (value.getTitle() != null)
-			gen.writeStringField("title", value.getTitle());
-		if (value.getText() != null)
-			gen.writeStringField("text", value.getText());
-		if (value.getUrl() != null)
-			gen.writeStringField("url", value.getUrl());
-		if (value.getDate() != null)
-			gen.writeStringField("date", dateToString(value.getDate()));
-		gen.writeEndObject();
-
-		gen.writeEndObject();
-	}
-
-}
diff --git a/vipra-rest/src/main/java/de/vipra/rest/serializer/Helper.java b/vipra-rest/src/main/java/de/vipra/rest/serializer/Helper.java
deleted file mode 100644
index 09dd2d5ded3efa1c0b847c71628408c2edd898c4..0000000000000000000000000000000000000000
--- a/vipra-rest/src/main/java/de/vipra/rest/serializer/Helper.java
+++ /dev/null
@@ -1,61 +0,0 @@
-package de.vipra.rest.serializer;
-
-import java.text.DateFormat;
-import java.text.ParseException;
-import java.text.SimpleDateFormat;
-import java.util.Date;
-
-import com.fasterxml.jackson.databind.JsonNode;
-
-public class Helper {
-
-	public static <T> T get(JsonNode node, String name, T defaultValue, Class<T> type) {
-		if (node == null) {
-			return defaultValue;
-		}
-		node = node.get(name);
-		if (node == null) {
-			return defaultValue;
-		}
-		switch (type.getSimpleName()) {
-		case "String":
-			return type.cast(node.asText());
-		case "Integer":
-			return type.cast(node.asInt());
-		case "Long":
-			return type.cast(node.asLong());
-		}
-		return null;
-	}
-
-	public static String getString(JsonNode node, String name, String defaultValue) {
-		return get(node, name, defaultValue, String.class);
-	}
-
-	public static String getString(JsonNode node, String name) {
-		return getString(node, name, null);
-	}
-
-	public static long getLong(JsonNode node, String name, long defaultValue) {
-		return get(node, name, defaultValue, Long.class);
-	}
-
-	public static long getLong(JsonNode node, String name) {
-		return getLong(node, name, 0L);
-	}
-
-	public static String dateToString(Date date) {
-		DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
-		return df.format(date);
-	}
-
-	public static Date stringToDate(String source) {
-		DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
-		try {
-			return df.parse(source);
-		} catch (ParseException e) {
-			return null;
-		}
-	}
-
-}
diff --git a/vipra-rest/src/main/resources/config.properties b/vipra-rest/src/main/resources/config.properties
new file mode 100644
index 0000000000000000000000000000000000000000..07030840d45dd8fed8c2c2d5bff5fe0a54939a4f
--- /dev/null
+++ b/vipra-rest/src/main/resources/config.properties
@@ -0,0 +1,3 @@
+db.host=localhost
+db.port=27017
+db.name=test
\ No newline at end of file
diff --git a/vipra-rest/src/main/resources/log4j2.xml b/vipra-rest/src/main/resources/log4j2.xml
index 8abf1b196fcbb49c3df9551ecb1937bd6491200b..871334005580a7821f2a6e7f7c2517ab454b2e17 100644
--- a/vipra-rest/src/main/resources/log4j2.xml
+++ b/vipra-rest/src/main/resources/log4j2.xml
@@ -6,8 +6,9 @@
 		</Console>
 	</Appenders>
 	<Loggers>
-		<Root level="all">
+		<Root level="ALL">
 			<AppenderRef ref="Console" />
 		</Root>
+		<Logger name="org.mongodb" level="INFO"/>
 	</Loggers>
 </Configuration>
\ No newline at end of file
diff --git a/vipra-rest/src/main/webapp/WEB-INF/web.xml b/vipra-rest/src/main/webapp/WEB-INF/web.xml
index dc73bea3b07729290fc992520ea78d71bcc9bd74..3cfd9841c2652280fb1819e4b627b1cfb1c3405d 100644
--- a/vipra-rest/src/main/webapp/WEB-INF/web.xml
+++ b/vipra-rest/src/main/webapp/WEB-INF/web.xml
@@ -13,6 +13,6 @@
 	</servlet>
 	<servlet-mapping>
 		<servlet-name>jersey</servlet-name>
-		<url-pattern>/rest/*</url-pattern>
+		<url-pattern>/*</url-pattern>
 	</servlet-mapping>
 </web-app>
\ No newline at end of file
diff --git a/vipra-rest/src/main/webapp/index.jsp b/vipra-rest/src/main/webapp/index.jsp
deleted file mode 100644
index d4fb745c4314a31b867be2d5000cbd268f3d0533..0000000000000000000000000000000000000000
--- a/vipra-rest/src/main/webapp/index.jsp
+++ /dev/null
@@ -1 +0,0 @@
-<jsp:forward page="rest/application.wadl"/>
\ No newline at end of file
diff --git a/vipra-ui/.ember-cli b/vipra-ui/.ember-cli
index 4d87e572b4b8d4e7ff643158432ade4809e6b568..ee64cfed2a8905dc23506af1060ec80cf887582d 100644
--- a/vipra-ui/.ember-cli
+++ b/vipra-ui/.ember-cli
@@ -5,6 +5,5 @@
 
     Setting `disableAnalytics` to true will prevent any data from being sent.
   */
-  "disableAnalytics": false,
-  "liveReload": false
+  "disableAnalytics": false
 }
diff --git a/vipra-ui/.project b/vipra-ui/.project
new file mode 100644
index 0000000000000000000000000000000000000000..6f683a496d89c3c50ed5a40b7db8a94d7cc29afc
--- /dev/null
+++ b/vipra-ui/.project
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>vipra-ui</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+	</buildSpec>
+	<natures>
+	</natures>
+</projectDescription>
diff --git a/vipra-ui/app/adapters/application.js b/vipra-ui/app/adapters/application.js
index dff622652d8735502e01e424cba902813697b8b4..701dadac29a043297224620597aa145d32c1a728 100644
--- a/vipra-ui/app/adapters/application.js
+++ b/vipra-ui/app/adapters/application.js
@@ -1,6 +1,6 @@
 import DS from 'ember-data';
 
 export default DS.JSONAPIAdapter.extend({
-  host: 'http://localhost:8080',
-  namespace: 'vipra-rest/rest'
+  host: `http://${window.location.hostname}:8000`,
+  namespace: 'vipra-rest'
 });
diff --git a/vipra-ui/app/components/article-list.js b/vipra-ui/app/components/article-list.js
new file mode 100644
index 0000000000000000000000000000000000000000..afa75e431c88c2ffe6b51b07470e0f53a4be44be
--- /dev/null
+++ b/vipra-ui/app/components/article-list.js
@@ -0,0 +1,15 @@
+import Ember from 'ember';
+
+    export default Ember.Component.extend({
+
+      filteredArticles: Ember.computed('articles', 'filter', function() {
+        var keyword = this.get('filter');
+        var filtered = this.get('articles');
+        if (keyword) {
+          keyword = keyword.toLowerCase().trim();
+          filtered = this.get('articles').filter((item) => item.get('title').toLowerCase().includes(keyword));
+        }
+        return filtered;
+      })
+
+    });
diff --git a/vipra-ui/app/components/debounced-input.js b/vipra-ui/app/components/debounced-input.js
new file mode 100644
index 0000000000000000000000000000000000000000..5eee646f9195d06d4092541d6033baffb6dc641c
--- /dev/null
+++ b/vipra-ui/app/components/debounced-input.js
@@ -0,0 +1,14 @@
+import Ember from 'ember';
+
+export default Ember.TextField.extend({
+  debounce: 500,
+  fireAtStart: false,
+
+  _elementValueDidChange() {
+    Ember.run.debounce(this, this._setValue, this.debounce, this.fireAtStart);
+  },
+
+  _setValue() {
+    this.set('value', this.$().val());
+  }
+});
diff --git a/vipra-ui/app/components/dynamic-high-charts.js b/vipra-ui/app/components/dynamic-high-charts.js
new file mode 100644
index 0000000000000000000000000000000000000000..730778b19069c2e2471929011d0ae606ad879dec
--- /dev/null
+++ b/vipra-ui/app/components/dynamic-high-charts.js
@@ -0,0 +1,15 @@
+import Ember from 'ember';
+import EmberHighChartsComponent from 'ember-highcharts/components/high-charts';
+
+export default EmberHighChartsComponent.extend({
+
+  redrawChart: function() {
+    // add redraw logic here. ex:
+    var chart = this.get('chart');
+    var seriesName = this.get('content')[0].name;
+    chart.series[0].update({ name: seriesName, data: this.get('content')[0].data }, false);
+    chart.setTitle(null, { text: seriesName }, false);
+    chart.redraw();
+  }.observes('content.@each.isLoaded')
+
+});
diff --git a/vipra-ui/app/components/text-marker.js b/vipra-ui/app/components/text-marker.js
new file mode 100644
index 0000000000000000000000000000000000000000..0e0518bb943456c9325837bd59c848b9f5f4d435
--- /dev/null
+++ b/vipra-ui/app/components/text-marker.js
@@ -0,0 +1,18 @@
+import Ember from 'ember';
+
+export default Ember.Component.extend({
+
+  setup: function() {
+    this.updateTextMarker();
+  }.on('init'),
+
+  updateTextMarker: function() {
+    var text = this.get('text');
+    var mark = this.get('mark');
+    if(mark) {
+      text = text.replace(new RegExp(mark, 'ig'), '<b>$&</b>');
+    }
+    this.set('marked', text);
+  }.observes('text', 'mark')
+
+});
diff --git a/vipra-ui/app/index.html b/vipra-ui/app/index.html
index 5262fdc4819ad91fb2ffbe960c2e524b2a120d59..42eed3eb05d7c4f2e784b32e42d5c2a695a5b03f 100644
--- a/vipra-ui/app/index.html
+++ b/vipra-ui/app/index.html
@@ -3,10 +3,30 @@
   <head>
     <meta charset="utf-8">
     <meta http-equiv="X-UA-Compatible" content="IE=edge">
-    <title>VipraUi</title>
+    <title>Vipra</title>
     <meta name="description" content="">
     <meta name="viewport" content="width=device-width, initial-scale=1">
 
+    <link rel="apple-touch-icon" sizes="57x57" href="/apple-touch-icon-57x57.png">
+    <link rel="apple-touch-icon" sizes="60x60" href="/apple-touch-icon-60x60.png">
+    <link rel="apple-touch-icon" sizes="72x72" href="/apple-touch-icon-72x72.png">
+    <link rel="apple-touch-icon" sizes="76x76" href="/apple-touch-icon-76x76.png">
+    <link rel="apple-touch-icon" sizes="114x114" href="/apple-touch-icon-114x114.png">
+    <link rel="apple-touch-icon" sizes="120x120" href="/apple-touch-icon-120x120.png">
+    <link rel="apple-touch-icon" sizes="144x144" href="/apple-touch-icon-144x144.png">
+    <link rel="apple-touch-icon" sizes="152x152" href="/apple-touch-icon-152x152.png">
+    <link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon-180x180.png">
+    <link rel="icon" type="image/png" href="/favicon-32x32.png" sizes="32x32">
+    <link rel="icon" type="image/png" href="/favicon-194x194.png" sizes="194x194">
+    <link rel="icon" type="image/png" href="/favicon-96x96.png" sizes="96x96">
+    <link rel="icon" type="image/png" href="/android-chrome-192x192.png" sizes="192x192">
+    <link rel="icon" type="image/png" href="/favicon-16x16.png" sizes="16x16">
+    <link rel="manifest" href="/manifest.json">
+    <link rel="mask-icon" href="/safari-pinned-tab.svg" color="#5bbad5">
+    <meta name="msapplication-TileColor" content="#da532c">
+    <meta name="msapplication-TileImage" content="/mstile-144x144.png">
+    <meta name="theme-color" content="#ffffff">
+
     {{content-for 'head'}}
 
     <link rel="stylesheet" href="assets/vendor.css">
diff --git a/vipra-ui/app/models/article.js b/vipra-ui/app/models/article.js
index 064292d210b840ab925b226cd7d998cb3446996b..0d054ad31aafcc2f4856e01680fc6f74e5887866 100644
--- a/vipra-ui/app/models/article.js
+++ b/vipra-ui/app/models/article.js
@@ -4,5 +4,5 @@ export default DS.Model.extend({
   title: DS.attr(),
   text: DS.attr(),
   url: DS.attr(),
-  date: DS.attr()
+  date: DS.attr('date')
 });
diff --git a/vipra-ui/app/router.js b/vipra-ui/app/router.js
index 3bf38c00f7ebae4564f82ea90e57bbcdf7c2152b..0a0fb7055747ae093b2b52b9eef98df5277c9fb5 100644
--- a/vipra-ui/app/router.js
+++ b/vipra-ui/app/router.js
@@ -6,7 +6,11 @@ const Router = Ember.Router.extend({
 });
 
 Router.map(function() {
-  this.route('articles');
+  this.route('articles', function() {
+    this.route('list', { path: '/' });
+    this.route('show', { path: '/:article_id' });
+  });
+  this.route('not-found', { path: '/*:' });
 });
 
 export default Router;
diff --git a/vipra-ui/app/routes/articles.js b/vipra-ui/app/routes/articles.js
deleted file mode 100644
index 2009e33bf38909f55f13f802caced901f0c23e86..0000000000000000000000000000000000000000
--- a/vipra-ui/app/routes/articles.js
+++ /dev/null
@@ -1,7 +0,0 @@
-import Ember from 'ember';
-
-export default Ember.Route.extend({
-  model() {
-    return this.store.findAll('article');
-  }
-});
diff --git a/vipra-ui/app/routes/articles/list.js b/vipra-ui/app/routes/articles/list.js
new file mode 100644
index 0000000000000000000000000000000000000000..81b69808893707a30683a7ef1bfdb15a89be1f73
--- /dev/null
+++ b/vipra-ui/app/routes/articles/list.js
@@ -0,0 +1,61 @@
+import Ember from 'ember';
+
+var chartData = [];
+var chartOptions = {
+  chart: {
+    zoomType: 'x'
+  },
+  title: {
+    text: 'Articles per month'
+  },
+  legend: {
+    enabled: false
+  },
+  xAxis: {
+    type: 'datetime',
+    title: {
+      text: 'Dates'
+    }
+  },
+  yAxis: {
+    title: {
+      text: 'Articles'
+    }
+  },
+  tooltip: {
+    headerFormat: '',
+    pointFormat: '{point.x:%b %Y}: {point.y} article(s)'
+  }
+};
+
+export default Ember.Route.extend({
+  model() {
+    return Ember.RSVP.hash({
+      articles: this.store.findAll('article'),
+      chartOptions: chartOptions,
+      chartData: chartData
+    });
+  },
+
+  afterModel(model) {
+    var count = {};
+    model.articles.forEach(article => {
+      var date = article.get('date')
+      var month = date.getMonth()+1;
+      var dstr = date.getFullYear() + '-' + (month < 10 ? '0' + month : month);
+      if(count.hasOwnProperty(dstr)) {
+        count[dstr][1] += 1;
+      } else {
+        count[dstr] = [Date.UTC(date.getFullYear(), month), 1];
+      }
+    });
+    var data = [];
+    for(var key in count) {
+      data.push(count[key]);
+    }
+    model.chartData = [{
+      name: 'Articles',
+      data: data
+    }];
+  }
+});
diff --git a/vipra-ui/app/routes/index.js b/vipra-ui/app/routes/not-found.js
similarity index 100%
rename from vipra-ui/app/routes/index.js
rename to vipra-ui/app/routes/not-found.js
diff --git a/vipra-ui/app/templates/articles.hbs b/vipra-ui/app/templates/articles.hbs
index 35225d4ad2833a0d73a9706b20d4d174a5208d9d..c42a140eac368bb9661e1e5e77fe78ab056bc47c 100644
--- a/vipra-ui/app/templates/articles.hbs
+++ b/vipra-ui/app/templates/articles.hbs
@@ -1,5 +1,5 @@
 <h1>Articles</h1>
+{{#link-to 'articles.list'}}All{{/link-to}}
+<hr>
 
-{{#each model as |article|}}
-  <p>{{article.title}}</p>
-{{/each}}
\ No newline at end of file
+{{outlet}}
\ No newline at end of file
diff --git a/vipra-ui/app/templates/articles/list.hbs b/vipra-ui/app/templates/articles/list.hbs
new file mode 100644
index 0000000000000000000000000000000000000000..08f7ccb638bf957b5ca67cc5c53231837aeab3c5
--- /dev/null
+++ b/vipra-ui/app/templates/articles/list.hbs
@@ -0,0 +1,7 @@
+{{dynamic-high-charts content=model.chartData chartOptions=model.chartOptions}}
+
+<h2>Found articles</h2>
+
+{{debounced-input placeholder='Filter' size='50' valueBinding='filter' debounce='150'}}
+
+{{article-list articles=model.articles filter=filter}}
\ No newline at end of file
diff --git a/vipra-ui/app/templates/articles/new.hbs b/vipra-ui/app/templates/articles/new.hbs
new file mode 100644
index 0000000000000000000000000000000000000000..c1318fddb4debfa78918fc66c95283760fc470cd
--- /dev/null
+++ b/vipra-ui/app/templates/articles/new.hbs
@@ -0,0 +1 @@
+<h2>New article</h2>
\ No newline at end of file
diff --git a/vipra-ui/app/templates/articles/show.hbs b/vipra-ui/app/templates/articles/show.hbs
new file mode 100644
index 0000000000000000000000000000000000000000..a93a42bd788761f32cad7384ca38bef4c132a1e0
--- /dev/null
+++ b/vipra-ui/app/templates/articles/show.hbs
@@ -0,0 +1,10 @@
+<h2>{{model.title}}</h2>
+
+<dl>
+  <dt>Date</dt>
+  <dd>{{model.date}}</dd>
+  <dt>URL</dt>
+  <dd><a href="{{model.url}}">{{model.url}}</a></dd>
+</dl>
+
+{{model.text}}
\ No newline at end of file
diff --git a/vipra-ui/app/templates/components/article-list.hbs b/vipra-ui/app/templates/components/article-list.hbs
new file mode 100644
index 0000000000000000000000000000000000000000..8d3269ffb87a2266baece0abf9056f021d25a6c3
--- /dev/null
+++ b/vipra-ui/app/templates/components/article-list.hbs
@@ -0,0 +1,5 @@
+<ol>
+  {{#each filteredArticles as |article|}}
+    <li>{{#link-to 'articles.show' article.id}}{{text-marker text=article.title mark=filter}}{{/link-to}}</li>
+  {{/each}}
+</ol>
\ No newline at end of file
diff --git a/vipra-ui/app/templates/components/debounced-input.hbs b/vipra-ui/app/templates/components/debounced-input.hbs
new file mode 100644
index 0000000000000000000000000000000000000000..889d9eeadc1012bdf474d7ea123f9bff23e9d8f5
--- /dev/null
+++ b/vipra-ui/app/templates/components/debounced-input.hbs
@@ -0,0 +1 @@
+{{yield}}
diff --git a/vipra-ui/app/templates/components/dynamic-high-charts.hbs b/vipra-ui/app/templates/components/dynamic-high-charts.hbs
new file mode 100644
index 0000000000000000000000000000000000000000..889d9eeadc1012bdf474d7ea123f9bff23e9d8f5
--- /dev/null
+++ b/vipra-ui/app/templates/components/dynamic-high-charts.hbs
@@ -0,0 +1 @@
+{{yield}}
diff --git a/vipra-ui/app/templates/components/text-marker.hbs b/vipra-ui/app/templates/components/text-marker.hbs
new file mode 100644
index 0000000000000000000000000000000000000000..5fb15880633ca60fd96531b511b79b62127997ba
--- /dev/null
+++ b/vipra-ui/app/templates/components/text-marker.hbs
@@ -0,0 +1 @@
+{{{marked}}}
\ No newline at end of file
diff --git a/vipra-ui/app/templates/index.hbs b/vipra-ui/app/templates/index.hbs
index 2f733f8f8b8ee4c32a20a0335fead9d5619935b6..51b28c7ae97459acfa02b24e3afbe8260ea55896 100644
--- a/vipra-ui/app/templates/index.hbs
+++ b/vipra-ui/app/templates/index.hbs
@@ -1,3 +1 @@
-<h1>Vipra</h1>
-
-{{#link-to 'articles'}}Browse articles{{/link-to}}
\ No newline at end of file
+<h1>Vipra</h1>
\ No newline at end of file
diff --git a/vipra-ui/app/templates/loading.hbs b/vipra-ui/app/templates/loading.hbs
new file mode 100644
index 0000000000000000000000000000000000000000..37d709251262e861315c9da5f955b5600a1c6007
--- /dev/null
+++ b/vipra-ui/app/templates/loading.hbs
@@ -0,0 +1 @@
+Loading...
\ No newline at end of file
diff --git a/vipra-ui/app/templates/not-found.hbs b/vipra-ui/app/templates/not-found.hbs
new file mode 100644
index 0000000000000000000000000000000000000000..4ca64b93827b10496afabced2f19afef3a6111ed
--- /dev/null
+++ b/vipra-ui/app/templates/not-found.hbs
@@ -0,0 +1,3 @@
+<h1>404 - Not found</h1>
+
+<p>The requested resource was not found on this server</p>
\ No newline at end of file
diff --git a/vipra-ui/package.json b/vipra-ui/package.json
index 24ae137dc87eb14af2fef82e9c7c0106db5b69c0..fa584f24d50ce25b3c949cb3abc59c4631b3019b 100644
--- a/vipra-ui/package.json
+++ b/vipra-ui/package.json
@@ -34,6 +34,7 @@
     "ember-cli-uglify": "^1.2.0",
     "ember-data": "1.13.15",
     "ember-disable-proxy-controllers": "^1.0.1",
-    "ember-export-application-global": "^1.0.4"
+    "ember-export-application-global": "^1.0.4",
+    "ember-highcharts": "0.2.1"
   }
 }
diff --git a/vipra-ui/public/android-chrome-144x144.png b/vipra-ui/public/android-chrome-144x144.png
new file mode 100644
index 0000000000000000000000000000000000000000..a75a06d5e6943aee4c175213f6cf98b03fa3f85c
Binary files /dev/null and b/vipra-ui/public/android-chrome-144x144.png differ
diff --git a/vipra-ui/public/android-chrome-192x192.png b/vipra-ui/public/android-chrome-192x192.png
new file mode 100644
index 0000000000000000000000000000000000000000..38a70604dcb27a9ee3fbf79d71360c5d1bb30def
Binary files /dev/null and b/vipra-ui/public/android-chrome-192x192.png differ
diff --git a/vipra-ui/public/android-chrome-36x36.png b/vipra-ui/public/android-chrome-36x36.png
new file mode 100644
index 0000000000000000000000000000000000000000..fa55583e69edd38b9b9dc4b344610ce40f076014
Binary files /dev/null and b/vipra-ui/public/android-chrome-36x36.png differ
diff --git a/vipra-ui/public/android-chrome-48x48.png b/vipra-ui/public/android-chrome-48x48.png
new file mode 100644
index 0000000000000000000000000000000000000000..053cc4ed735d16d23ca7f7bfc06b8b419c5da221
Binary files /dev/null and b/vipra-ui/public/android-chrome-48x48.png differ
diff --git a/vipra-ui/public/android-chrome-72x72.png b/vipra-ui/public/android-chrome-72x72.png
new file mode 100644
index 0000000000000000000000000000000000000000..98c240493437e4f97f0c6e08d10ab1c174d792f2
Binary files /dev/null and b/vipra-ui/public/android-chrome-72x72.png differ
diff --git a/vipra-ui/public/android-chrome-96x96.png b/vipra-ui/public/android-chrome-96x96.png
new file mode 100644
index 0000000000000000000000000000000000000000..2d2202ca6ba65fba1402708be385110c13ca4606
Binary files /dev/null and b/vipra-ui/public/android-chrome-96x96.png differ
diff --git a/vipra-ui/public/apple-touch-icon-114x114.png b/vipra-ui/public/apple-touch-icon-114x114.png
new file mode 100644
index 0000000000000000000000000000000000000000..bc2a612c2e7e6a66e1f82d42722943a90e00e25f
Binary files /dev/null and b/vipra-ui/public/apple-touch-icon-114x114.png differ
diff --git a/vipra-ui/public/apple-touch-icon-120x120.png b/vipra-ui/public/apple-touch-icon-120x120.png
new file mode 100644
index 0000000000000000000000000000000000000000..fdaabce77f0024103256d92f819694892752aa5a
Binary files /dev/null and b/vipra-ui/public/apple-touch-icon-120x120.png differ
diff --git a/vipra-ui/public/apple-touch-icon-144x144.png b/vipra-ui/public/apple-touch-icon-144x144.png
new file mode 100644
index 0000000000000000000000000000000000000000..1d46bf72898e7a1d57e584e33166b4ab93ad1913
Binary files /dev/null and b/vipra-ui/public/apple-touch-icon-144x144.png differ
diff --git a/vipra-ui/public/apple-touch-icon-152x152.png b/vipra-ui/public/apple-touch-icon-152x152.png
new file mode 100644
index 0000000000000000000000000000000000000000..cf4fe5c4d8e00ade403c398bf6354c66dcb6f419
Binary files /dev/null and b/vipra-ui/public/apple-touch-icon-152x152.png differ
diff --git a/vipra-ui/public/apple-touch-icon-180x180.png b/vipra-ui/public/apple-touch-icon-180x180.png
new file mode 100644
index 0000000000000000000000000000000000000000..9349bc3006cbeae993227c4247526a2f5331bca3
Binary files /dev/null and b/vipra-ui/public/apple-touch-icon-180x180.png differ
diff --git a/vipra-ui/public/apple-touch-icon-57x57.png b/vipra-ui/public/apple-touch-icon-57x57.png
new file mode 100644
index 0000000000000000000000000000000000000000..404609005a57d079d934aeafb60e9f41c777303d
Binary files /dev/null and b/vipra-ui/public/apple-touch-icon-57x57.png differ
diff --git a/vipra-ui/public/apple-touch-icon-60x60.png b/vipra-ui/public/apple-touch-icon-60x60.png
new file mode 100644
index 0000000000000000000000000000000000000000..69090a0b6c4948749effbb3fe956c3caf72b6154
Binary files /dev/null and b/vipra-ui/public/apple-touch-icon-60x60.png differ
diff --git a/vipra-ui/public/apple-touch-icon-72x72.png b/vipra-ui/public/apple-touch-icon-72x72.png
new file mode 100644
index 0000000000000000000000000000000000000000..7e41b0928a7ca05b405ed7bce68b8e2099de6e03
Binary files /dev/null and b/vipra-ui/public/apple-touch-icon-72x72.png differ
diff --git a/vipra-ui/public/apple-touch-icon-76x76.png b/vipra-ui/public/apple-touch-icon-76x76.png
new file mode 100644
index 0000000000000000000000000000000000000000..29d14b903247e28ff96f6ea34bf3a38d50f5482e
Binary files /dev/null and b/vipra-ui/public/apple-touch-icon-76x76.png differ
diff --git a/vipra-ui/public/apple-touch-icon-precomposed.png b/vipra-ui/public/apple-touch-icon-precomposed.png
new file mode 100644
index 0000000000000000000000000000000000000000..4d110e9874af7700780f80bfeec4a287fa6d49b1
Binary files /dev/null and b/vipra-ui/public/apple-touch-icon-precomposed.png differ
diff --git a/vipra-ui/public/apple-touch-icon.png b/vipra-ui/public/apple-touch-icon.png
new file mode 100644
index 0000000000000000000000000000000000000000..9349bc3006cbeae993227c4247526a2f5331bca3
Binary files /dev/null and b/vipra-ui/public/apple-touch-icon.png differ
diff --git a/vipra-ui/public/browserconfig.xml b/vipra-ui/public/browserconfig.xml
new file mode 100644
index 0000000000000000000000000000000000000000..65380f3873df0b1efc837c390c3a91bd2c2c6a14
--- /dev/null
+++ b/vipra-ui/public/browserconfig.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8"?>
+<browserconfig>
+  <msapplication>
+    <tile>
+      <square70x70logo src="/mstile-70x70.png"/>
+      <square150x150logo src="/mstile-150x150.png"/>
+      <square310x310logo src="/mstile-310x310.png"/>
+      <wide310x150logo src="/mstile-310x150.png"/>
+      <TileColor>#da532c</TileColor>
+    </tile>
+  </msapplication>
+</browserconfig>
diff --git a/vipra-ui/public/favicon-16x16.png b/vipra-ui/public/favicon-16x16.png
new file mode 100644
index 0000000000000000000000000000000000000000..2142db750ebddec14220299d9b135ef67c086a8a
Binary files /dev/null and b/vipra-ui/public/favicon-16x16.png differ
diff --git a/vipra-ui/public/favicon-194x194.png b/vipra-ui/public/favicon-194x194.png
new file mode 100644
index 0000000000000000000000000000000000000000..21aebd21587c3e1e8ead181661abfd5c63b7520f
Binary files /dev/null and b/vipra-ui/public/favicon-194x194.png differ
diff --git a/vipra-ui/public/favicon-32x32.png b/vipra-ui/public/favicon-32x32.png
new file mode 100644
index 0000000000000000000000000000000000000000..5f02b4eddf4ea6a56bfcd19c8b61a406f99d9129
Binary files /dev/null and b/vipra-ui/public/favicon-32x32.png differ
diff --git a/vipra-ui/public/favicon-96x96.png b/vipra-ui/public/favicon-96x96.png
new file mode 100644
index 0000000000000000000000000000000000000000..db921e4ed2dcd5d09ed8c3feda59dbecdb4f6493
Binary files /dev/null and b/vipra-ui/public/favicon-96x96.png differ
diff --git a/vipra-ui/public/favicon.ico b/vipra-ui/public/favicon.ico
new file mode 100644
index 0000000000000000000000000000000000000000..5732db6037b1f85a34fb650544f2c844313a2855
Binary files /dev/null and b/vipra-ui/public/favicon.ico differ
diff --git a/vipra-ui/public/manifest.json b/vipra-ui/public/manifest.json
new file mode 100644
index 0000000000000000000000000000000000000000..fd248ba860774e85815f340dca3d7a91b00fc794
--- /dev/null
+++ b/vipra-ui/public/manifest.json
@@ -0,0 +1,41 @@
+{
+	"name": "Vipra",
+	"icons": [
+		{
+			"src": "\/android-chrome-36x36.png",
+			"sizes": "36x36",
+			"type": "image\/png",
+			"density": 0.75
+		},
+		{
+			"src": "\/android-chrome-48x48.png",
+			"sizes": "48x48",
+			"type": "image\/png",
+			"density": 1
+		},
+		{
+			"src": "\/android-chrome-72x72.png",
+			"sizes": "72x72",
+			"type": "image\/png",
+			"density": 1.5
+		},
+		{
+			"src": "\/android-chrome-96x96.png",
+			"sizes": "96x96",
+			"type": "image\/png",
+			"density": 2
+		},
+		{
+			"src": "\/android-chrome-144x144.png",
+			"sizes": "144x144",
+			"type": "image\/png",
+			"density": 3
+		},
+		{
+			"src": "\/android-chrome-192x192.png",
+			"sizes": "192x192",
+			"type": "image\/png",
+			"density": 4
+		}
+	]
+}
diff --git a/vipra-ui/public/mstile-144x144.png b/vipra-ui/public/mstile-144x144.png
new file mode 100644
index 0000000000000000000000000000000000000000..f8bbf5181ec917852ccc7d485261c378ccbc7585
Binary files /dev/null and b/vipra-ui/public/mstile-144x144.png differ
diff --git a/vipra-ui/public/mstile-150x150.png b/vipra-ui/public/mstile-150x150.png
new file mode 100644
index 0000000000000000000000000000000000000000..695de5e588f6771411672a7ab77d11ff9f7b19c0
Binary files /dev/null and b/vipra-ui/public/mstile-150x150.png differ
diff --git a/vipra-ui/public/mstile-310x150.png b/vipra-ui/public/mstile-310x150.png
new file mode 100644
index 0000000000000000000000000000000000000000..31d0d95b73f37cb775eaa1fbe11152400f961d5f
Binary files /dev/null and b/vipra-ui/public/mstile-310x150.png differ
diff --git a/vipra-ui/public/mstile-310x310.png b/vipra-ui/public/mstile-310x310.png
new file mode 100644
index 0000000000000000000000000000000000000000..632930e827817f36965e2402748adef9b9311d96
Binary files /dev/null and b/vipra-ui/public/mstile-310x310.png differ
diff --git a/vipra-ui/public/mstile-70x70.png b/vipra-ui/public/mstile-70x70.png
new file mode 100644
index 0000000000000000000000000000000000000000..e6ece63cb1b9caa78fc2cebb370e07d9f2e5db04
Binary files /dev/null and b/vipra-ui/public/mstile-70x70.png differ
diff --git a/vipra-ui/public/safari-pinned-tab.svg b/vipra-ui/public/safari-pinned-tab.svg
new file mode 100644
index 0000000000000000000000000000000000000000..93d972a555c1c94f9e87b83f856d2dfb05b9c5ab
--- /dev/null
+++ b/vipra-ui/public/safari-pinned-tab.svg
@@ -0,0 +1,36 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
+ "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
+<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
+ width="512.000000pt" height="512.000000pt" viewBox="0 0 512.000000 512.000000"
+ preserveAspectRatio="xMidYMid meet">
+<metadata>
+Created by potrace 1.11, written by Peter Selinger 2001-2013
+</metadata>
+<g transform="translate(0.000000,512.000000) scale(0.100000,-0.100000)"
+fill="#000000" stroke="none">
+<path d="M3010 5110 c-129 -17 -159 -22 -240 -40 -112 -26 -104 -24 -196 -55
+-184 -63 -388 -173 -539 -289 -82 -64 -103 -83 -202 -183 -298 -302 -477 -668
+-537 -1098 -14 -100 -15 -399 -1 -495 28 -199 96 -426 177 -586 l31 -61 -691
+-692 c-559 -559 -700 -705 -731 -759 -167 -282 -60 -647 233 -791 188 -93 409
+-76 576 42 14 10 337 329 718 709 l692 691 98 -46 c170 -80 379 -140 569 -165
+73 -9 367 -9 453 0 266 28 570 135 800 281 169 107 372 290 487 437 213 274
+356 613 399 945 9 72 11 387 3 458 -39 336 -165 653 -374 938 -63 87 -237 269
+-320 336 -155 126 -414 270 -586 327 -107 35 -259 72 -359 86 -97 14 -377 20
+-460 10z m455 -333 c391 -73 703 -251 961 -552 127 -147 236 -347 298 -544 58
+-185 75 -314 71 -526 -4 -161 -6 -176 -36 -305 -43 -185 -95 -316 -188 -472
+-233 -392 -621 -661 -1085 -754 -101 -20 -394 -26 -506 -11 -237 33 -509 142
+-709 285 -122 86 -288 252 -373 372 -121 171 -223 403 -262 596 -8 43 -18 93
+-21 109 -21 104 -8 467 20 554 3 11 8 31 10 43 3 13 15 59 29 103 147 483 534
+879 1016 1039 58 19 116 37 130 40 14 2 50 10 80 16 30 6 80 13 110 17 30 3
+57 7 58 9 10 8 329 -7 397 -19z m-1730 -2814 c70 -85 212 -223 279 -271 20
+-14 36 -28 36 -32 0 -10 -1285 -1295 -1325 -1326 -45 -34 -120 -54 -183 -49
+-100 7 -191 72 -235 165 -31 65 -29 168 4 235 19 38 177 203 680 707 360 361
+659 657 664 657 6 0 42 -39 80 -86z"/>
+<path d="M2995 4299 c-351 -67 -642 -288 -800 -607 -39 -80 -80 -197 -89 -256
+-4 -21 -8 -42 -11 -46 -3 -4 -8 -55 -11 -113 -6 -104 -6 -106 19 -131 45 -45
+119 -27 131 32 3 15 8 59 11 99 17 273 178 553 408 712 78 53 219 119 293 136
+10 2 37 9 59 14 45 10 130 20 188 21 72 0 110 74 67 130 -17 23 -26 25 -97 26
+-43 0 -118 -7 -168 -17z"/>
+</g>
+</svg>
diff --git a/vipra-ui/tests/integration/components/article-list-test.js b/vipra-ui/tests/integration/components/article-list-test.js
new file mode 100644
index 0000000000000000000000000000000000000000..bcc52965fc674e9690c7834e179c13b38bfe5caf
--- /dev/null
+++ b/vipra-ui/tests/integration/components/article-list-test.js
@@ -0,0 +1,25 @@
+import { moduleForComponent, test } from 'ember-qunit';
+import hbs from 'htmlbars-inline-precompile';
+
+moduleForComponent('article-list', 'Integration | Component | article list', {
+  integration: true
+});
+
+test('it renders', function(assert) {
+  
+  // Set any properties with this.set('myProperty', 'value');
+  // Handle any actions with this.on('myAction', function(val) { ... });" + EOL + EOL +
+
+  this.render(hbs`{{article-list}}`);
+
+  assert.equal(this.$().text().trim(), '');
+
+  // Template block usage:" + EOL +
+  this.render(hbs`
+    {{#article-list}}
+      template block text
+    {{/article-list}}
+  `);
+
+  assert.equal(this.$().text().trim(), 'template block text');
+});
diff --git a/vipra-ui/tests/integration/components/debounced-input-test.js b/vipra-ui/tests/integration/components/debounced-input-test.js
new file mode 100644
index 0000000000000000000000000000000000000000..323028be87c1069b493b592cbfd34e0f0ee65ea1
--- /dev/null
+++ b/vipra-ui/tests/integration/components/debounced-input-test.js
@@ -0,0 +1,25 @@
+import { moduleForComponent, test } from 'ember-qunit';
+import hbs from 'htmlbars-inline-precompile';
+
+moduleForComponent('debounced-input', 'Integration | Component | debounced input', {
+  integration: true
+});
+
+test('it renders', function(assert) {
+  
+  // Set any properties with this.set('myProperty', 'value');
+  // Handle any actions with this.on('myAction', function(val) { ... });" + EOL + EOL +
+
+  this.render(hbs`{{debounced-input}}`);
+
+  assert.equal(this.$().text().trim(), '');
+
+  // Template block usage:" + EOL +
+  this.render(hbs`
+    {{#debounced-input}}
+      template block text
+    {{/debounced-input}}
+  `);
+
+  assert.equal(this.$().text().trim(), 'template block text');
+});
diff --git a/vipra-ui/tests/integration/components/dynamic-high-charts-test.js b/vipra-ui/tests/integration/components/dynamic-high-charts-test.js
new file mode 100644
index 0000000000000000000000000000000000000000..07810b85074cac1214cd04b68efccc4eb6ef1794
--- /dev/null
+++ b/vipra-ui/tests/integration/components/dynamic-high-charts-test.js
@@ -0,0 +1,25 @@
+import { moduleForComponent, test } from 'ember-qunit';
+import hbs from 'htmlbars-inline-precompile';
+
+moduleForComponent('dynamic-high-charts', 'Integration | Component | dynamic high charts', {
+  integration: true
+});
+
+test('it renders', function(assert) {
+  
+  // Set any properties with this.set('myProperty', 'value');
+  // Handle any actions with this.on('myAction', function(val) { ... });" + EOL + EOL +
+
+  this.render(hbs`{{dynamic-high-charts}}`);
+
+  assert.equal(this.$().text().trim(), '');
+
+  // Template block usage:" + EOL +
+  this.render(hbs`
+    {{#dynamic-high-charts}}
+      template block text
+    {{/dynamic-high-charts}}
+  `);
+
+  assert.equal(this.$().text().trim(), 'template block text');
+});
diff --git a/vipra-ui/tests/integration/components/text-marker-test.js b/vipra-ui/tests/integration/components/text-marker-test.js
new file mode 100644
index 0000000000000000000000000000000000000000..1af17c61bc9e6b08df64bdaa001f22802d69825a
--- /dev/null
+++ b/vipra-ui/tests/integration/components/text-marker-test.js
@@ -0,0 +1,25 @@
+import { moduleForComponent, test } from 'ember-qunit';
+import hbs from 'htmlbars-inline-precompile';
+
+moduleForComponent('text-marker', 'Integration | Component | text marker', {
+  integration: true
+});
+
+test('it renders', function(assert) {
+  
+  // Set any properties with this.set('myProperty', 'value');
+  // Handle any actions with this.on('myAction', function(val) { ... });" + EOL + EOL +
+
+  this.render(hbs`{{text-marker}}`);
+
+  assert.equal(this.$().text().trim(), '');
+
+  // Template block usage:" + EOL +
+  this.render(hbs`
+    {{#text-marker}}
+      template block text
+    {{/text-marker}}
+  `);
+
+  assert.equal(this.$().text().trim(), 'template block text');
+});
diff --git a/vipra-ui/tests/unit/controllers/articles-test.js b/vipra-ui/tests/unit/controllers/articles-test.js
new file mode 100644
index 0000000000000000000000000000000000000000..2f09e3a9cfb428f7762f161885385c8da50f5983
--- /dev/null
+++ b/vipra-ui/tests/unit/controllers/articles-test.js
@@ -0,0 +1,12 @@
+import { moduleFor, test } from 'ember-qunit';
+
+moduleFor('controller:articles', 'Unit | Controller | articles', {
+  // Specify the other units that are required for this test.
+  // needs: ['controller:foo']
+});
+
+// Replace this with your real tests.
+test('it exists', function(assert) {
+  let controller = this.subject();
+  assert.ok(controller);
+});
diff --git a/vipra-ui/tests/unit/routes/articles-test.js b/vipra-ui/tests/unit/routes/article-test.js
similarity index 80%
rename from vipra-ui/tests/unit/routes/articles-test.js
rename to vipra-ui/tests/unit/routes/article-test.js
index 14d8ec8499d5da6db2902c3cb9f547c04b1fc68a..a9185964f142f77bed47257f75926240c781b292 100644
--- a/vipra-ui/tests/unit/routes/articles-test.js
+++ b/vipra-ui/tests/unit/routes/article-test.js
@@ -1,6 +1,6 @@
 import { moduleFor, test } from 'ember-qunit';
 
-moduleFor('route:articles', 'Unit | Route | articles', {
+moduleFor('route:article', 'Unit | Route | article', {
   // Specify the other units that are required for this test.
   // needs: ['controller:foo']
 });
diff --git a/vipra-ui/tests/unit/routes/not-found-test.js b/vipra-ui/tests/unit/routes/not-found-test.js
new file mode 100644
index 0000000000000000000000000000000000000000..2375b9bb75fd6d375431e81f000b518cc2ee6e8c
--- /dev/null
+++ b/vipra-ui/tests/unit/routes/not-found-test.js
@@ -0,0 +1,11 @@
+import { moduleFor, test } from 'ember-qunit';
+
+moduleFor('route:not-found', 'Unit | Route | not found', {
+  // Specify the other units that are required for this test.
+  // needs: ['controller:foo']
+});
+
+test('it exists', function(assert) {
+  let route = this.subject();
+  assert.ok(route);
+});
diff --git a/vipra-util/.classpath b/vipra-util/.classpath
new file mode 100644
index 0000000000000000000000000000000000000000..d38d831c96760fdab9ce81082bb658d298932a2c
--- /dev/null
+++ b/vipra-util/.classpath
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+	<classpathentry kind="src" path="src/main/java"/>
+	<classpathentry kind="src" path="src/main/resources"/>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8">
+		<attributes>
+			<attribute name="maven.pomderived" value="true"/>
+		</attributes>
+	</classpathentry>
+	<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
+		<attributes>
+			<attribute name="maven.pomderived" value="true"/>
+		</attributes>
+	</classpathentry>
+	<classpathentry kind="con" path="org.eclipse.jst.j2ee.internal.module.container"/>
+	<classpathentry kind="output" path="target/classes"/>
+</classpath>
diff --git a/vipra-util/.gitignore b/vipra-util/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..09e3bc9b241c477ea341af9ee029becad0c2148c
--- /dev/null
+++ b/vipra-util/.gitignore
@@ -0,0 +1,2 @@
+/bin/
+/target/
diff --git a/vipra-util/.project b/vipra-util/.project
new file mode 100644
index 0000000000000000000000000000000000000000..7e5c99aad3e63cb25e06c3a8510fc8cea87fdeef
--- /dev/null
+++ b/vipra-util/.project
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>vipra-util</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.m2e.core.maven2Builder</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.m2e.core.maven2Nature</nature>
+		<nature>org.eclipse.jdt.core.javanature</nature>
+		<nature>org.eclipse.wst.common.project.facet.core.nature</nature>
+	</natures>
+</projectDescription>
diff --git a/vipra-util/.settings/org.eclipse.jdt.core.prefs b/vipra-util/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000000000000000000000000000000000000..107056a36e4dc4b53aad1c866f7ff7b82068ddbc
--- /dev/null
+++ b/vipra-util/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,12 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=1.6
+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.problem.forbiddenReference=warning
+org.eclipse.jdt.core.compiler.source=1.6
diff --git a/vipra-util/.settings/org.eclipse.m2e.core.prefs b/vipra-util/.settings/org.eclipse.m2e.core.prefs
new file mode 100644
index 0000000000000000000000000000000000000000..f897a7f1cb2389f85fe6381425d29f0a9866fb65
--- /dev/null
+++ b/vipra-util/.settings/org.eclipse.m2e.core.prefs
@@ -0,0 +1,4 @@
+activeProfiles=
+eclipse.preferences.version=1
+resolveWorkspaceProjects=true
+version=1
diff --git a/vipra-util/.settings/org.eclipse.wst.common.component b/vipra-util/.settings/org.eclipse.wst.common.component
new file mode 100644
index 0000000000000000000000000000000000000000..217de769b1c939ce8569041d55e0227a3473b779
--- /dev/null
+++ b/vipra-util/.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="vipra-util">
+        <wb-resource deploy-path="/" source-path="/src/main/java"/>
+        <wb-resource deploy-path="/" source-path="/src/main/resources"/>
+    </wb-module>
+</project-modules>
diff --git a/vipra-util/.settings/org.eclipse.wst.common.project.facet.core.xml b/vipra-util/.settings/org.eclipse.wst.common.project.facet.core.xml
new file mode 100644
index 0000000000000000000000000000000000000000..926884d914bf20b850efed694a328543aa498e30
--- /dev/null
+++ b/vipra-util/.settings/org.eclipse.wst.common.project.facet.core.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<faceted-project>
+  <fixed facet="jst.utility"/>
+  <fixed facet="java"/>
+  <installed facet="java" version="1.6"/>
+  <installed facet="jst.utility" version="1.0"/>
+</faceted-project>
diff --git a/vipra-util/pom.xml b/vipra-util/pom.xml
new file mode 100644
index 0000000000000000000000000000000000000000..039cebdc7455794d59bdcd94a576ec29157018db
--- /dev/null
+++ b/vipra-util/pom.xml
@@ -0,0 +1,52 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+	<modelVersion>4.0.0</modelVersion>
+	<groupId>de.vipra</groupId>
+	<artifactId>vipra-util</artifactId>
+	<version>0.0.1-SNAPSHOT</version>
+
+	<properties>
+		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+		<log4jVersion>2.4.1</log4jVersion>
+	</properties>
+	
+	<dependencies>
+		<!-- Logging -->
+		<dependency>
+			<groupId>org.apache.logging.log4j</groupId>
+			<artifactId>log4j-api</artifactId>
+			<version>${log4jVersion}</version>
+		</dependency>
+		<dependency>
+			<groupId>org.apache.logging.log4j</groupId>
+			<artifactId>log4j-core</artifactId>
+			<version>${log4jVersion}</version>
+		</dependency>
+		<dependency>
+			<groupId>org.apache.logging.log4j</groupId>
+			<artifactId>log4j-slf4j-impl</artifactId>
+			<version>${log4jVersion}</version>
+		</dependency>
+
+		<!-- MongoDB Database Adapter -->
+		<dependency>
+			<groupId>org.mongodb</groupId>
+			<artifactId>mongodb-driver</artifactId>
+			<version>3.0.4</version>
+		</dependency>
+	</dependencies>
+	
+	<build>
+		<sourceDirectory>src</sourceDirectory>
+		<plugins>
+			<plugin>
+				<artifactId>maven-compiler-plugin</artifactId>
+				<version>3.3</version>
+				<configuration>
+					<source>1.8</source>
+					<target>1.8</target>
+				</configuration>
+			</plugin>
+		</plugins>
+	</build>
+</project>
\ No newline at end of file
diff --git a/vipra-util/src/main/java/META-INF/MANIFEST.MF b/vipra-util/src/main/java/META-INF/MANIFEST.MF
new file mode 100644
index 0000000000000000000000000000000000000000..5e9495128c0376427420c4189993b3851770b702
--- /dev/null
+++ b/vipra-util/src/main/java/META-INF/MANIFEST.MF
@@ -0,0 +1,3 @@
+Manifest-Version: 1.0
+Class-Path: 
+
diff --git a/vipra-util/src/main/java/de/vipra/util/Config.java b/vipra-util/src/main/java/de/vipra/util/Config.java
new file mode 100644
index 0000000000000000000000000000000000000000..f10013558603df1d99bcd1ad622071c508715bdc
--- /dev/null
+++ b/vipra-util/src/main/java/de/vipra/util/Config.java
@@ -0,0 +1,50 @@
+package de.vipra.util;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Properties;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class Config {
+
+	public static final Logger log = LoggerFactory.getLogger(Config.class);
+
+	private final Properties props = new Properties();
+
+	public Config() throws IOException, ConfigException {
+		this(Thread.currentThread().getContextClassLoader().getResourceAsStream("config.properties"));
+
+	}
+
+	public Config(InputStream is) throws IOException, ConfigException {
+		if (is == null) {
+			log.error("config file input stream is null");
+			throw new ConfigException("config file input stream is null");
+		} else {
+			props.load(is);
+		}
+	}
+
+	public String getString(String key) {
+		return getString(key, null);
+	}
+
+	public String getString(String key, String defaultValue) {
+		return props.getProperty(key, defaultValue);
+	}
+
+	public Integer getInt(String key) {
+		return getInt(key, null);
+	}
+
+	public Integer getInt(String key, Integer defaultValue) {
+		try {
+			return Integer.parseInt(props.getProperty(key));
+		} catch (NumberFormatException e) {
+			return defaultValue;
+		}
+	}
+
+}
diff --git a/vipra-util/src/main/java/de/vipra/util/ConfigException.java b/vipra-util/src/main/java/de/vipra/util/ConfigException.java
new file mode 100644
index 0000000000000000000000000000000000000000..d6404572e5f34f137c3e095ca1bb2e71d416ad9d
--- /dev/null
+++ b/vipra-util/src/main/java/de/vipra/util/ConfigException.java
@@ -0,0 +1,11 @@
+package de.vipra.util;
+
+public class ConfigException extends Exception {
+
+	private static final long serialVersionUID = 1L;
+
+	public ConfigException(String string) {
+		super(string);
+	}
+
+}
\ No newline at end of file
diff --git a/vipra-util/src/main/java/de/vipra/util/Mongo.java b/vipra-util/src/main/java/de/vipra/util/Mongo.java
new file mode 100644
index 0000000000000000000000000000000000000000..73628bd0be1064b622c2860f14b766ba7a671e03
--- /dev/null
+++ b/vipra-util/src/main/java/de/vipra/util/Mongo.java
@@ -0,0 +1,48 @@
+package de.vipra.util;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.mongodb.MongoClient;
+import com.mongodb.client.MongoDatabase;
+import de.vipra.util.Config;
+
+public class Mongo {
+
+	public static final Logger log = LoggerFactory.getLogger(Mongo.class);
+
+	private static Mongo instance;
+
+	private final MongoClient client;
+	private final MongoDatabase database;
+
+	private Mongo(Config config) throws ConfigException {
+		String host = config.getString("db.host");
+		Integer port = config.getInt("db.port");
+		String databaseName = config.getString("db.name");
+
+		if (host == null || port == null || databaseName == null) {
+			log.error("host/port/dbname missing in configuration");
+			throw new ConfigException("host/port/dbname missing in configuration");
+		}
+
+		client = new MongoClient(host, port);
+		database = client.getDatabase(databaseName);
+	}
+
+	public MongoClient getClient() {
+		return client;
+	}
+
+	public MongoDatabase getDatabase() {
+		return database;
+	}
+
+	public static Mongo getInstance(Config config) throws ConfigException {
+		if (instance == null) {
+			instance = new Mongo(config);
+		}
+		return instance;
+	}
+
+}
diff --git a/vipra-util/src/main/resources/config.properties b/vipra-util/src/main/resources/config.properties
new file mode 100644
index 0000000000000000000000000000000000000000..07030840d45dd8fed8c2c2d5bff5fe0a54939a4f
--- /dev/null
+++ b/vipra-util/src/main/resources/config.properties
@@ -0,0 +1,3 @@
+db.host=localhost
+db.port=27017
+db.name=test
\ No newline at end of file
diff --git a/vipra-util/src/main/resources/log4j2.xml b/vipra-util/src/main/resources/log4j2.xml
new file mode 100644
index 0000000000000000000000000000000000000000..871334005580a7821f2a6e7f7c2517ab454b2e17
--- /dev/null
+++ b/vipra-util/src/main/resources/log4j2.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Configuration>
+	<Appenders>
+		<Console name="Console" target="SYSTEM_OUT">
+			<PatternLayout pattern="%d{HH:mm:ss.SSS} %-5level %logger{36} - %msg%n" />
+		</Console>
+	</Appenders>
+	<Loggers>
+		<Root level="ALL">
+			<AppenderRef ref="Console" />
+		</Root>
+		<Logger name="org.mongodb" level="INFO"/>
+	</Loggers>
+</Configuration>
\ No newline at end of file
diff --git a/vm/bootstrap.sh b/vm/bootstrap.sh
index 5535f49a5719b7b8165dc745b27926aa3034693d..0b238ae423cec87d95814f685a590923e5f7ff4d 100644
--- a/vm/bootstrap.sh
+++ b/vm/bootstrap.sh
@@ -96,7 +96,7 @@ mvn -DskipTests -X clean -f ./mahout install
 
 # -----------------------------------------------------------------------------
 # install elasticsearch
-wget https://download.elasticsearch.org/elasticsearch/release/org/elasticsearch/distribution/deb/elasticsearch/2.1.0/elasticsearch-2.1.0.deb
+wget https://download.elasticsearch.org/elasticsearch/release/org/elasticsearch/distribution/deb/elasticsearch/2.1.1/elasticsearch-2.1.1.deb
 gdebi -n elasticsearch-2.1.0.deb
 rm elasticsearch-2.1.0.deb
 service start elasticsearch