diff --git a/ma-impl.sublime-workspace b/ma-impl.sublime-workspace
index 0b75fa13f7a32cb8e9bfc3bd2566f078e749bdb0..bd0a79efd0dac011c7b923562854f37b2b355aed 100644
--- a/ma-impl.sublime-workspace
+++ b/ma-impl.sublime-workspace
@@ -288,10 +288,10 @@
 	"buffers":
 	[
 		{
-			"file": "vipra-ui/js/controllers.js",
+			"file": "vipra-ui/css/app.less",
 			"settings":
 			{
-				"buffer_size": 1591,
+				"buffer_size": 1761,
 				"line_ending": "Unix"
 			}
 		}
@@ -475,25 +475,33 @@
 	[
 		"/home/eike/repos/master/ma-impl",
 		"/home/eike/repos/master/ma-impl/vipra-ui",
-		"/home/eike/repos/master/ma-impl/vipra-ui/bower_components/angular-ui-router/release",
-		"/home/eike/repos/master/ma-impl/vipra-ui/bower_components/bootstrap/dist",
-		"/home/eike/repos/master/ma-impl/vipra-ui/bower_components/jquery/dist",
 		"/home/eike/repos/master/ma-impl/vipra-ui/css",
 		"/home/eike/repos/master/ma-impl/vipra-ui/html",
+		"/home/eike/repos/master/ma-impl/vipra-ui/html/articles",
+		"/home/eike/repos/master/ma-impl/vipra-ui/html/topics",
+		"/home/eike/repos/master/ma-impl/vipra-ui/html/words",
 		"/home/eike/repos/master/ma-impl/vipra-ui/js"
 	],
 	"file_history":
 	[
-		"/home/eike/repos/master/ma-impl/vipra-ui/js/app.js",
 		"/home/eike/repos/master/ma-impl/vipra-ui/html/index.html",
+		"/home/eike/repos/master/ma-impl/vipra-ui/html/words/index.html",
+		"/home/eike/repos/master/ma-impl/vipra-ui/html/topics/index.html",
+		"/home/eike/repos/master/ma-impl/vipra-ui/html/articles/index.html",
+		"/home/eike/repos/master/ma-impl/vipra-ui/js/directives.js",
+		"/home/eike/repos/master/ma-impl/vipra-ui/js/app.js",
+		"/home/eike/repos/master/ma-impl/vipra-ui/js/controllers.js",
+		"/home/eike/repos/master/ma-impl/vipra-ui/html/articles/show.html",
 		"/home/eike/repos/master/ma-impl/vipra-ui/css/app.less",
+		"/home/eike/repos/master/ma-impl/vipra-ui/js/filters.js",
 		"/home/eike/repos/master/ma-impl/vipra-ui/index.html",
-		"/run/user/1000/gvfs/smb-share:server=eike-ain,share=share/interceptors.js",
+		"/home/eike/repos/master/ma-impl/vm/data/data.json",
+		"/home/eike/repos/master/ma-impl/vm/data/test-1.json",
+		"/home/eike/repos/master/ma-impl/vm/data/test-2.json",
+		"/home/eike/repos/master/ma-impl/vm/data/test-10.json",
 		"/home/eike/repos/master/ma-impl/vipra-ui/js/factories.js",
-		"/home/eike/repos/master/ma-impl/vipra-ui/js/controllers.js",
-		"/home/eike/repos/master/ma-impl/vipra-ui/html/topics/index.html",
+		"/run/user/1000/gvfs/smb-share:server=eike-ain,share=share/interceptors.js",
 		"/home/eike/repos/master/ma-impl/vipra-ui/html/topics/show.html",
-		"/home/eike/repos/master/ma-impl/vipra-ui/html/words/index.html",
 		"/home/eike/repos/master/ma-impl/vipra-ui/html/words/show.html",
 		"/home/eike/repos/master/ma-impl/vipra-ui/gulpfile.js",
 		"/home/eike/repos/master/ma-impl/vipra-ui/css/footer.less",
@@ -503,10 +511,7 @@
 		"/home/eike/repos/master/ma-impl/vipra-ui/public/index.html",
 		"/home/eike/repos/master/ma-impl/vipra-ui/js/vendor.js",
 		"/home/eike/repos/master/ma-impl/vipra-ui/less/main.less",
-		"/home/eike/repos/master/ma-impl/vipra-ui/js/directives.js",
 		"/home/eike/repos/master/ma-impl/vipra-ui/js/services.js",
-		"/home/eike/repos/master/ma-impl/vipra-ui/html/articles/show.html",
-		"/home/eike/repos/master/ma-impl/vipra-ui/html/articles/index.html",
 		"/home/eike/repos/master/ma-impl/vipra-ui/css/main.less",
 		"/home/eike/.config/sublime-text-3/Packages/User/Preferences.sublime-settings",
 		"/home/eike/repos/master/ma-impl/vipra-ui/app/adapters/application.js",
@@ -563,13 +568,10 @@
 		"/home/eike/repos/master/ma-impl/vipra-ui/app/routes/words",
 		"/home/eike/repos/master/ma-impl/vipra-ui/app/models/topic.js",
 		"/home/eike/repos/master/ma-impl/vipra-ui/app/models/article.js",
-		"/home/eike/repos/master/ma-impl/vm/data/test-10.json",
 		"/home/eike/repos/master/ma-impl/vipra-ui/app/components/topic-link.js",
 		"/home/eike/.local/share/vipra/jgibb/jgibb.twords",
 		"/home/eike/.local/share/vipra/jgibb/jgibb.tassign",
 		"/home/eike/Downloads/FRITZ.Box 7490 113.06.30_17.01.16_2147.export",
-		"/home/eike/repos/master/ma-impl/vm/data/test-1.json",
-		"/home/eike/repos/master/ma-impl/vm/data/test-2.json",
 		"/home/eike/.local/share/vipra/jgibb/jgibb",
 		"/home/eike/repos/master/ma-doc/thesis/thesis.tex",
 		"/home/eike/repos/master/ma-impl/vm/bootstrap.sh",
@@ -609,9 +611,7 @@
 		"/home/eike/repos/master/ma-impl/vm/webapps/vipra-rest/WEB-INF/web.xml",
 		"/core",
 		"/home/eike/repos/master/ma-impl/vm/config/environment",
-		"/home/eike/repos/master/ma-impl/vm/config/initd-tomcat",
-		"/home/eike/Repositories/fu/ss15/ma/impl/TODO",
-		"/home/eike/.local/share/vipra/jgibb/vocab"
+		"/home/eike/repos/master/ma-impl/vm/config/initd-tomcat"
 	],
 	"find":
 	{
@@ -662,6 +662,7 @@
 		"case_sensitive": false,
 		"find_history":
 		[
+			"00:00Z",
 			" ",
 			"\\n\\n",
 			"\\n",
@@ -788,8 +789,7 @@
 			"all",
 			"right",
 			"select_all",
-			"category.new",
-			"Account"
+			"category.new"
 		],
 		"highlight": true,
 		"in_selection": false,
@@ -797,6 +797,7 @@
 		"regex": true,
 		"replace_history":
 		[
+			"00:00.000Z",
 			"\", \"",
 			" ",
 			"",
@@ -923,8 +924,7 @@
 			"\"",
 			"ul.menu",
 			"<br>",
-			"@append$1",
-			"survey"
+			"@append$1"
 		],
 		"reverse": false,
 		"show_context": true,
@@ -940,29 +940,29 @@
 			[
 				{
 					"buffer": 0,
-					"file": "vipra-ui/js/controllers.js",
+					"file": "vipra-ui/css/app.less",
 					"semi_transient": false,
 					"settings":
 					{
-						"buffer_size": 1591,
+						"buffer_size": 1761,
 						"regions":
 						{
 						},
 						"selection":
 						[
 							[
-								1057,
-								1057
+								492,
+								492
 							]
 						],
 						"settings":
 						{
-							"syntax": "Packages/JavaScriptNext - ES6 Syntax/JavaScriptNext.tmLanguage",
+							"syntax": "Packages/LESS/LESS.tmLanguage",
 							"tab_size": 2,
 							"translate_tabs_to_spaces": true
 						},
-						"translation.x": 0.0,
-						"translation.y": 0.0,
+						"translation.x": -0.0,
+						"translation.y": 102.0,
 						"zoom_level": 1.0
 					},
 					"stack_index": 0,
@@ -1117,7 +1117,7 @@
 	},
 	"select_symbol":
 	{
-		"height": 263.0,
+		"height": 375.0,
 		"last_filter": "",
 		"selected_items":
 		[
diff --git a/vipra-rest/src/main/java/de/vipra/rest/resource/SearchResource.java b/vipra-rest/src/main/java/de/vipra/rest/resource/SearchResource.java
index 530ec3610d78b560292547c59aed293e315b1c03..5df5c56b1ba5cef1252e58a18034630e24faf6b7 100644
--- a/vipra-rest/src/main/java/de/vipra/rest/resource/SearchResource.java
+++ b/vipra-rest/src/main/java/de/vipra/rest/resource/SearchResource.java
@@ -2,8 +2,11 @@ package de.vipra.rest.resource;
 
 import java.io.IOException;
 import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
 import javax.servlet.ServletContext;
 import javax.ws.rs.GET;
@@ -47,6 +50,7 @@ public class SearchResource {
 	@GET
 	@Produces(MediaType.APPLICATION_JSON)
 	public Response doSearch(@QueryParam("skip") Integer skip, @QueryParam("limit") Integer limit,
+			@QueryParam("excerpt") Integer excerpt, @QueryParam("fields") String fields,
 			@QueryParam("query") String query) {
 		Wrapper<List<ArticleFull>> res = new Wrapper<>();
 
@@ -56,6 +60,9 @@ public class SearchResource {
 		if (limit == null || limit < 0)
 			limit = 20;
 
+		if (excerpt == null || excerpt < 0)
+			excerpt = 250;
+
 		if (query == null || query.isEmpty() || limit == 0)
 			return res.noContent();
 
@@ -68,14 +75,24 @@ public class SearchResource {
 			return res.badRequest();
 		}
 
+		Set<String> allowedFields = null;
+		if (fields != null) {
+			allowedFields = new HashSet<>(Arrays.asList(fields.split(",")));
+		}
+
 		SearchHits hits = response.getHits();
 		List<ArticleFull> articles = new ArrayList<>(10);
 		for (SearchHit hit : hits) {
 			Map<String, Object> source = hit.getSource();
 			ArticleFull article = new ArticleFull();
 			article.setId(MongoUtils.objectId(hit.getId()));
-			article.setTitle(source.get("title").toString());
-			article.setText(StringUtils.ellipsize(source.get("text").toString(), 150));
+			if (allowedFields == null || allowedFields.contains("title"))
+				article.setTitle(source.get("title").toString());
+			if (allowedFields == null || allowedFields.contains("text"))
+				article.setText(StringUtils.ellipsize(source.get("text").toString(), excerpt));
+			if (allowedFields == null || allowedFields.contains("date"))
+				article.setDate(source.get("date").toString());
+			article.addMeta("score", hit.getScore());
 			articles.add(article);
 		}
 
diff --git a/vipra-ui/css/app.css b/vipra-ui/css/app.css
index dd2e3404b6c36783e3eb7f46be657a3b84e4e14b..c138c2d10f7dd9006bdc1cd8ad760a61fe37196b 100644
--- a/vipra-ui/css/app.css
+++ b/vipra-ui/css/app.css
@@ -1,2 +1,2 @@
-html{position:relative;min-height:100%}body{padding-bottom:20px;margin-bottom:60px}.word{cursor:pointer;padding-right:5px}.center{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%)}.loading{background:url(/assets/images/squares.gif) no-repeat center center;width:120px;height:120px}.heading{-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;cursor:default;font-size:82px;margin:30px 0;background:transparent url(/img/logo.png) no-repeat 50% 50%;min-width:272px;min-height:216px;padding-top:90px}.ellipsize{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.search-result{margin-bottom:5px}.navbar-default .collapse:not(.in) .navbar-nav>.active>a,.navbar-default .collapse:not(.in) .navbar-nav>.active>a:focus,.navbar-default .collapse:not(.in) .navbar-nav>.active>a:hover{border-bottom:3px solid;padding-bottom:12px}.footer{position:absolute;bottom:0;width:100%;height:50px;border-top-width:1px;border-top-style:solid}.noselect{-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;cursor:default}
-/*# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImFwcC5sZXNzIiwiYXBwLmNzcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxLQUNFLGtCQUFBLEFBQ0EsZUFBQSxDQ0NELEFERUQsS0FDRSxvQkFBQSxBQUVBLGtCQUFBLENDQUQsQURHRCxNQUNFLGVBQUEsQUFDQSxpQkFBQSxDQ0RELEFESUQsUUFDRSxrQkFBQSxBQUNBLFFBQUEsQUFDQSxTQUFBLEFBQ0EsOEJBQUEsQ0NGRCxBREtELFNBQ0UsbUVBQUEsQUFDQSxZQUFBLEFBQ0EsWUFBQSxDQ0hELEFETUQsU0E0Q0UsMkJBQUEsQUFDQSx5QkFBQSxBQUNBLHNCQUFBLEFBQ0EscUJBQUEsQUFDQSxpQkFBQSxBQUNBLGVBQUEsQUEvQ0EsZUFBQSxBQUNBLGNBQUEsQUFDQSw0REFBQSxBQUNBLGdCQUFBLEFBQ0EsaUJBQUEsQUFDQSxnQkFBQSxDQ0NELEFERUQsV0FDRSxtQkFBQSxBQUNBLGdCQUFBLEFBQ0Esc0JBQUEsQ0NBRCxBREdELGVBQ0UsaUJBQUEsQ0NERCxBRE9LLHVMQUdFLHdCQUFBLEFBQ0EsbUJBQUEsQ0NMUCxBRFdELFFBQ0Usa0JBQUEsQUFDQSxTQUFBLEFBQ0EsV0FBQSxBQUVBLFlBQUEsQUFDQSxxQkFBQSxBQUNBLHNCQUFBLENDVEQsQURZRCxVQUNFLDJCQUFBLEFBQ0EseUJBQUEsQUFDQSxzQkFBQSxBQUNBLHFCQUFBLEFBQ0EsaUJBQUEsQUFDQSxjQUFBLENDVkQiLCJmaWxlIjoiYXBwLmNzcyIsInNvdXJjZXNDb250ZW50IjpbImh0bWwge1xuICBwb3NpdGlvbjogcmVsYXRpdmU7XG4gIG1pbi1oZWlnaHQ6IDEwMCU7XG59XG5cbmJvZHkge1xuICBwYWRkaW5nLWJvdHRvbTogMjBweDtcbiAgLyogTWFyZ2luIGJvdHRvbSBieSBmb290ZXIgaGVpZ2h0ICovXG4gIG1hcmdpbi1ib3R0b206IDYwcHg7XG59XG5cbi53b3JkIHtcbiAgY3Vyc29yOiBwb2ludGVyO1xuICBwYWRkaW5nLXJpZ2h0OiA1cHg7XG59XG5cbi5jZW50ZXIge1xuICBwb3NpdGlvbjogYWJzb2x1dGU7XG4gIHRvcDogNTAlO1xuICBsZWZ0OiA1MCU7XG4gIHRyYW5zZm9ybTogdHJhbnNsYXRlKC01MCUsIC01MCUpO1xufVxuXG4ubG9hZGluZyB7XG4gIGJhY2tncm91bmQ6IHVybCgvYXNzZXRzL2ltYWdlcy9zcXVhcmVzLmdpZikgbm8tcmVwZWF0IGNlbnRlciBjZW50ZXI7XG4gIHdpZHRoOiAxMjBweDtcbiAgaGVpZ2h0OiAxMjBweDtcbn1cblxuLmhlYWRpbmcge1xuICAubm9zZWxlY3Q7XG4gIGZvbnQtc2l6ZTogODJweDtcbiAgbWFyZ2luOiAzMHB4IDA7XG4gIGJhY2tncm91bmQ6IHRyYW5zcGFyZW50IHVybCgvaW1nL2xvZ28ucG5nKSBuby1yZXBlYXQgNTAlIDUwJTtcbiAgbWluLXdpZHRoOiAyNzJweDtcbiAgbWluLWhlaWdodDogMjE2cHg7XG4gIHBhZGRpbmctdG9wOiA5MHB4O1xufVxuXG4uZWxsaXBzaXplIHtcbiAgd2hpdGUtc3BhY2U6IG5vd3JhcDtcbiAgb3ZlcmZsb3c6IGhpZGRlbjtcbiAgdGV4dC1vdmVyZmxvdzogZWxsaXBzaXM7XG59XG5cbi5zZWFyY2gtcmVzdWx0IHtcbiAgbWFyZ2luLWJvdHRvbTogNXB4O1xufVxuXG4ubmF2YmFyLWRlZmF1bHQge1xuICAuY29sbGFwc2U6bm90KC5pbikge1xuICAgIC5uYXZiYXItbmF2ID4gLmFjdGl2ZSB7XG4gICAgICAmPiBhLFxuICAgICAgJj4gYTpob3ZlcixcbiAgICAgICY+IGE6Zm9jdXMge1xuICAgICAgICBib3JkZXItYm90dG9tOiAzcHggc29saWQ7XG4gICAgICAgIHBhZGRpbmctYm90dG9tOiAxMnB4O1xuICAgICAgfVxuICAgIH1cbiAgfVxufVxuXG4uZm9vdGVyIHtcbiAgcG9zaXRpb246IGFic29sdXRlO1xuICBib3R0b206IDA7XG4gIHdpZHRoOiAxMDAlO1xuICAvKiBTZXQgdGhlIGZpeGVkIGhlaWdodCBvZiB0aGUgZm9vdGVyIGhlcmUgKi9cbiAgaGVpZ2h0OiA1MHB4O1xuICBib3JkZXItdG9wLXdpZHRoOiAxcHg7XG4gIGJvcmRlci10b3Atc3R5bGU6IHNvbGlkO1xufVxuXG4ubm9zZWxlY3Qge1xuICAtd2Via2l0LXRvdWNoLWNhbGxvdXQ6IG5vbmU7XG4gIC13ZWJraXQtdXNlci1zZWxlY3Q6IG5vbmU7XG4gIC1tb3otdXNlci1zZWxlY3Q6IG5vbmU7XG4gIC1tcy11c2VyLXNlbGVjdDogbm9uZTtcbiAgdXNlci1zZWxlY3Q6IG5vbmU7XG4gIGN1cnNvcjogZGVmYXVsdDtcbn0iLCJodG1sIHtcbiAgcG9zaXRpb246IHJlbGF0aXZlO1xuICBtaW4taGVpZ2h0OiAxMDAlO1xufVxuYm9keSB7XG4gIHBhZGRpbmctYm90dG9tOiAyMHB4O1xuICAvKiBNYXJnaW4gYm90dG9tIGJ5IGZvb3RlciBoZWlnaHQgKi9cbiAgbWFyZ2luLWJvdHRvbTogNjBweDtcbn1cbi53b3JkIHtcbiAgY3Vyc29yOiBwb2ludGVyO1xuICBwYWRkaW5nLXJpZ2h0OiA1cHg7XG59XG4uY2VudGVyIHtcbiAgcG9zaXRpb246IGFic29sdXRlO1xuICB0b3A6IDUwJTtcbiAgbGVmdDogNTAlO1xuICB0cmFuc2Zvcm06IHRyYW5zbGF0ZSgtNTAlLCAtNTAlKTtcbn1cbi5sb2FkaW5nIHtcbiAgYmFja2dyb3VuZDogdXJsKC9hc3NldHMvaW1hZ2VzL3NxdWFyZXMuZ2lmKSBuby1yZXBlYXQgY2VudGVyIGNlbnRlcjtcbiAgd2lkdGg6IDEyMHB4O1xuICBoZWlnaHQ6IDEyMHB4O1xufVxuLmhlYWRpbmcge1xuICAtd2Via2l0LXRvdWNoLWNhbGxvdXQ6IG5vbmU7XG4gIC13ZWJraXQtdXNlci1zZWxlY3Q6IG5vbmU7XG4gIC1tb3otdXNlci1zZWxlY3Q6IG5vbmU7XG4gIC1tcy11c2VyLXNlbGVjdDogbm9uZTtcbiAgdXNlci1zZWxlY3Q6IG5vbmU7XG4gIGN1cnNvcjogZGVmYXVsdDtcbiAgZm9udC1zaXplOiA4MnB4O1xuICBtYXJnaW46IDMwcHggMDtcbiAgYmFja2dyb3VuZDogdHJhbnNwYXJlbnQgdXJsKC9pbWcvbG9nby5wbmcpIG5vLXJlcGVhdCA1MCUgNTAlO1xuICBtaW4td2lkdGg6IDI3MnB4O1xuICBtaW4taGVpZ2h0OiAyMTZweDtcbiAgcGFkZGluZy10b3A6IDkwcHg7XG59XG4uZWxsaXBzaXplIHtcbiAgd2hpdGUtc3BhY2U6IG5vd3JhcDtcbiAgb3ZlcmZsb3c6IGhpZGRlbjtcbiAgdGV4dC1vdmVyZmxvdzogZWxsaXBzaXM7XG59XG4uc2VhcmNoLXJlc3VsdCB7XG4gIG1hcmdpbi1ib3R0b206IDVweDtcbn1cbi5uYXZiYXItZGVmYXVsdCAuY29sbGFwc2U6bm90KC5pbikgLm5hdmJhci1uYXYgPiAuYWN0aXZlID4gYSxcbi5uYXZiYXItZGVmYXVsdCAuY29sbGFwc2U6bm90KC5pbikgLm5hdmJhci1uYXYgPiAuYWN0aXZlID4gYTpob3Zlcixcbi5uYXZiYXItZGVmYXVsdCAuY29sbGFwc2U6bm90KC5pbikgLm5hdmJhci1uYXYgPiAuYWN0aXZlID4gYTpmb2N1cyB7XG4gIGJvcmRlci1ib3R0b206IDNweCBzb2xpZDtcbiAgcGFkZGluZy1ib3R0b206IDEycHg7XG59XG4uZm9vdGVyIHtcbiAgcG9zaXRpb246IGFic29sdXRlO1xuICBib3R0b206IDA7XG4gIHdpZHRoOiAxMDAlO1xuICAvKiBTZXQgdGhlIGZpeGVkIGhlaWdodCBvZiB0aGUgZm9vdGVyIGhlcmUgKi9cbiAgaGVpZ2h0OiA1MHB4O1xuICBib3JkZXItdG9wLXdpZHRoOiAxcHg7XG4gIGJvcmRlci10b3Atc3R5bGU6IHNvbGlkO1xufVxuLm5vc2VsZWN0IHtcbiAgLXdlYmtpdC10b3VjaC1jYWxsb3V0OiBub25lO1xuICAtd2Via2l0LXVzZXItc2VsZWN0OiBub25lO1xuICAtbW96LXVzZXItc2VsZWN0OiBub25lO1xuICAtbXMtdXNlci1zZWxlY3Q6IG5vbmU7XG4gIHVzZXItc2VsZWN0OiBub25lO1xuICBjdXJzb3I6IGRlZmF1bHQ7XG59XG4iXSwic291cmNlUm9vdCI6Ii9zb3VyY2UvIn0= */
+html{position:relative;min-height:100%}body{padding-bottom:20px;margin-bottom:60px}.heading{-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;cursor:default;font-size:120px;text-align:center;background:transparent url(/img/logo.svg) no-repeat 50% 50%;background-size:contain;height:200px;line-height:200px;margin:35px 0}.search-results{padding:15px}.search-results .search-result{margin-bottom:20px}.search-results .search-result a{font-size:1.5rem}.ellipsize{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.navbar-default .collapse:not(.in) .navbar-nav>.active>a,.navbar-default .collapse:not(.in) .navbar-nav>.active>a:focus,.navbar-default .collapse:not(.in) .navbar-nav>.active>a:hover{border-bottom:3px solid;padding-bottom:12px}.navbar-default .navbar-header{padding:0 10px}.navbar-default .navbar-brand{background:transparent url(/img/logo.svg) no-repeat 50% 50%;background-size:contain}.navbar-default .navbar-brand.spin,.navbar-default .navbar-brand:hover:not(.spin){-webkit-animation:a 4s linear infinite;animation:a 4s linear infinite}.row-spaced{margin-top:15px;margin-bottom:15px}.footer{position:absolute;bottom:0;width:100%;height:50px;border-top-width:1px;border-top-style:solid}.noselect{-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;cursor:default}@-webkit-keyframes a{to{-webkit-transform:rotateY(1turn)}}@keyframes a{to{-webkit-transform:rotateY(1turn);transform:rotateY(1turn)}}
+/*# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImFwcC5sZXNzIiwiYXBwLmNzcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxLQUNFLGtCQUFBLEFBQ0EsZUFBQSxDQ0NELEFERUQsS0FDRSxvQkFBQSxBQUVBLGtCQUFBLENDQUQsQURHRCxTQXlFRSwyQkFBQSxBQUNBLHlCQUFBLEFBQ0Esc0JBQUEsQUFDQSxxQkFBQSxBQUNBLGlCQUFBLEFBQ0EsZUFBQSxBQTVFQSxnQkFBQSxBQUNBLGtCQUFBLEFBQ0EsNERBQUEsQUFDQSx3QkFBQSxBQUNBLGFBQUEsQUFDQSxrQkFBQSxBQUNBLGFBQUEsQ0NJRCxBRERELGdCQUNFLFlBQUEsQ0NHRCxBREpELCtCQUlJLGtCQUFBLENDR0gsQURQRCxpQ0FPTSxnQkFBQSxDQ0dMLEFERUQsV0FDRSxtQkFBQSxBQUNBLGdCQUFBLEFBQ0Esc0JBQUEsQ0NBRCxBRE1LLHVMQUdFLHdCQUFBLEFBQ0EsbUJBQUEsQ0NKUCxBREhELCtCQWFJLGNBQUEsQ0NQSCxBRE5ELDhCQWlCSSw0REFBQSxBQUNBLHVCQUFBLENDUkgsQURTRyxrRkFFRSx1Q0FBQSxBQUVBLDhCQUFBLENDUEwsQURZRCxZQUNFLGdCQUFBLEFBQ0Esa0JBQUEsQ0NWRCxBRGFELFFBQ0Usa0JBQUEsQUFDQSxTQUFBLEFBQ0EsV0FBQSxBQUVBLFlBQUEsQUFDQSxxQkFBQSxBQUNBLHNCQUFBLENDWEQsQURjRCxVQUNFLDJCQUFBLEFBQ0EseUJBQUEsQUFDQSxzQkFBQSxBQUNBLHFCQUFBLEFBQ0EsaUJBQUEsQUFDQSxjQUFBLENDWkQsQURnQkQscUJBQTBCLEdBQU8sZ0NBQUEsQ0NQOUIsQ0FDRixBRE9ELGFBQWtCLEdBQU8saUNBQUEsQUFBb0Msd0JBQUEsQ0NGMUQsQ0FDRiIsImZpbGUiOiJhcHAuY3NzIiwic291cmNlc0NvbnRlbnQiOlsiaHRtbCB7XG4gIHBvc2l0aW9uOiByZWxhdGl2ZTtcbiAgbWluLWhlaWdodDogMTAwJTtcbn1cblxuYm9keSB7XG4gIHBhZGRpbmctYm90dG9tOiAyMHB4O1xuICAvKiBNYXJnaW4gYm90dG9tIGJ5IGZvb3RlciBoZWlnaHQgKi9cbiAgbWFyZ2luLWJvdHRvbTogNjBweDtcbn1cblxuLmhlYWRpbmcge1xuICAubm9zZWxlY3Q7XG4gIGZvbnQtc2l6ZTogMTIwcHg7XG4gIHRleHQtYWxpZ246IGNlbnRlcjtcbiAgYmFja2dyb3VuZDogdHJhbnNwYXJlbnQgdXJsKC9pbWcvbG9nby5zdmcpIG5vLXJlcGVhdCA1MCUgNTAlO1xuICBiYWNrZ3JvdW5kLXNpemU6IGNvbnRhaW47XG4gIGhlaWdodDogMjAwcHg7XG4gIGxpbmUtaGVpZ2h0OiAyMDBweDtcbiAgbWFyZ2luOiAzNXB4IDA7XG59XG5cbi5zZWFyY2gtcmVzdWx0cyB7XG4gIHBhZGRpbmc6IDE1cHg7XG5cbiAgLnNlYXJjaC1yZXN1bHQge1xuICAgIG1hcmdpbi1ib3R0b206IDIwcHg7XG5cbiAgICBhIHtcbiAgICAgIGZvbnQtc2l6ZTogMS41cmVtO1xuICAgIH1cbiAgfVxufVxuXG4uZWxsaXBzaXplIHtcbiAgd2hpdGUtc3BhY2U6IG5vd3JhcDtcbiAgb3ZlcmZsb3c6IGhpZGRlbjtcbiAgdGV4dC1vdmVyZmxvdzogZWxsaXBzaXM7XG59XG5cbi5uYXZiYXItZGVmYXVsdCB7XG4gIC5jb2xsYXBzZTpub3QoLmluKSB7XG4gICAgLm5hdmJhci1uYXYgPiAuYWN0aXZlIHtcbiAgICAgICY+IGEsXG4gICAgICAmPiBhOmhvdmVyLFxuICAgICAgJj4gYTpmb2N1cyB7XG4gICAgICAgIGJvcmRlci1ib3R0b206IDNweCBzb2xpZDtcbiAgICAgICAgcGFkZGluZy1ib3R0b206IDEycHg7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgLm5hdmJhci1oZWFkZXIge1xuICAgIHBhZGRpbmc6IDAgMTBweDtcbiAgfVxuXG4gIC5uYXZiYXItYnJhbmQge1xuICAgIGJhY2tncm91bmQ6IHRyYW5zcGFyZW50IHVybCgvaW1nL2xvZ28uc3ZnKSBuby1yZXBlYXQgNTAlIDUwJTtcbiAgICBiYWNrZ3JvdW5kLXNpemU6IGNvbnRhaW47XG4gICAgJi5zcGluLFxuICAgICY6aG92ZXI6bm90KC5zcGluKSB7XG4gICAgICAtd2Via2l0LWFuaW1hdGlvbjpzcGluIDRzIGxpbmVhciBpbmZpbml0ZTtcbiAgICAgIC1tb3otYW5pbWF0aW9uOnNwaW4gNHMgbGluZWFyIGluZmluaXRlO1xuICAgICAgYW5pbWF0aW9uOnNwaW4gNHMgbGluZWFyIGluZmluaXRlO1xuICAgIH1cbiAgfVxufVxuXG4ucm93LXNwYWNlZCB7XG4gIG1hcmdpbi10b3A6IDE1cHg7XG4gIG1hcmdpbi1ib3R0b206IDE1cHg7XG59XG5cbi5mb290ZXIge1xuICBwb3NpdGlvbjogYWJzb2x1dGU7XG4gIGJvdHRvbTogMDtcbiAgd2lkdGg6IDEwMCU7XG4gIC8qIFNldCB0aGUgZml4ZWQgaGVpZ2h0IG9mIHRoZSBmb290ZXIgaGVyZSAqL1xuICBoZWlnaHQ6IDUwcHg7XG4gIGJvcmRlci10b3Atd2lkdGg6IDFweDtcbiAgYm9yZGVyLXRvcC1zdHlsZTogc29saWQ7XG59XG5cbi5ub3NlbGVjdCB7XG4gIC13ZWJraXQtdG91Y2gtY2FsbG91dDogbm9uZTtcbiAgLXdlYmtpdC11c2VyLXNlbGVjdDogbm9uZTtcbiAgLW1vei11c2VyLXNlbGVjdDogbm9uZTtcbiAgLW1zLXVzZXItc2VsZWN0OiBub25lO1xuICB1c2VyLXNlbGVjdDogbm9uZTtcbiAgY3Vyc29yOiBkZWZhdWx0O1xufVxuXG5ALW1vei1rZXlmcmFtZXMgc3BpbiB7IDEwMCUgeyAtbW96LXRyYW5zZm9ybTogcm90YXRlWSgzNjBkZWcpOyB9IH1cbkAtd2Via2l0LWtleWZyYW1lcyBzcGluIHsgMTAwJSB7IC13ZWJraXQtdHJhbnNmb3JtOiByb3RhdGVZKDM2MGRlZyk7IH0gfVxuQGtleWZyYW1lcyBzcGluIHsgMTAwJSB7IC13ZWJraXQtdHJhbnNmb3JtOiByb3RhdGVZKDM2MGRlZyk7IHRyYW5zZm9ybTpyb3RhdGVZKDM2MGRlZyk7IH0gfSIsImh0bWwge1xuICBwb3NpdGlvbjogcmVsYXRpdmU7XG4gIG1pbi1oZWlnaHQ6IDEwMCU7XG59XG5ib2R5IHtcbiAgcGFkZGluZy1ib3R0b206IDIwcHg7XG4gIC8qIE1hcmdpbiBib3R0b20gYnkgZm9vdGVyIGhlaWdodCAqL1xuICBtYXJnaW4tYm90dG9tOiA2MHB4O1xufVxuLmhlYWRpbmcge1xuICAtd2Via2l0LXRvdWNoLWNhbGxvdXQ6IG5vbmU7XG4gIC13ZWJraXQtdXNlci1zZWxlY3Q6IG5vbmU7XG4gIC1tb3otdXNlci1zZWxlY3Q6IG5vbmU7XG4gIC1tcy11c2VyLXNlbGVjdDogbm9uZTtcbiAgdXNlci1zZWxlY3Q6IG5vbmU7XG4gIGN1cnNvcjogZGVmYXVsdDtcbiAgZm9udC1zaXplOiAxMjBweDtcbiAgdGV4dC1hbGlnbjogY2VudGVyO1xuICBiYWNrZ3JvdW5kOiB0cmFuc3BhcmVudCB1cmwoL2ltZy9sb2dvLnN2Zykgbm8tcmVwZWF0IDUwJSA1MCU7XG4gIGJhY2tncm91bmQtc2l6ZTogY29udGFpbjtcbiAgaGVpZ2h0OiAyMDBweDtcbiAgbGluZS1oZWlnaHQ6IDIwMHB4O1xuICBtYXJnaW46IDM1cHggMDtcbn1cbi5zZWFyY2gtcmVzdWx0cyB7XG4gIHBhZGRpbmc6IDE1cHg7XG59XG4uc2VhcmNoLXJlc3VsdHMgLnNlYXJjaC1yZXN1bHQge1xuICBtYXJnaW4tYm90dG9tOiAyMHB4O1xufVxuLnNlYXJjaC1yZXN1bHRzIC5zZWFyY2gtcmVzdWx0IGEge1xuICBmb250LXNpemU6IDEuNXJlbTtcbn1cbi5lbGxpcHNpemUge1xuICB3aGl0ZS1zcGFjZTogbm93cmFwO1xuICBvdmVyZmxvdzogaGlkZGVuO1xuICB0ZXh0LW92ZXJmbG93OiBlbGxpcHNpcztcbn1cbi5uYXZiYXItZGVmYXVsdCAuY29sbGFwc2U6bm90KC5pbikgLm5hdmJhci1uYXYgPiAuYWN0aXZlID4gYSxcbi5uYXZiYXItZGVmYXVsdCAuY29sbGFwc2U6bm90KC5pbikgLm5hdmJhci1uYXYgPiAuYWN0aXZlID4gYTpob3Zlcixcbi5uYXZiYXItZGVmYXVsdCAuY29sbGFwc2U6bm90KC5pbikgLm5hdmJhci1uYXYgPiAuYWN0aXZlID4gYTpmb2N1cyB7XG4gIGJvcmRlci1ib3R0b206IDNweCBzb2xpZDtcbiAgcGFkZGluZy1ib3R0b206IDEycHg7XG59XG4ubmF2YmFyLWRlZmF1bHQgLm5hdmJhci1oZWFkZXIge1xuICBwYWRkaW5nOiAwIDEwcHg7XG59XG4ubmF2YmFyLWRlZmF1bHQgLm5hdmJhci1icmFuZCB7XG4gIGJhY2tncm91bmQ6IHRyYW5zcGFyZW50IHVybCgvaW1nL2xvZ28uc3ZnKSBuby1yZXBlYXQgNTAlIDUwJTtcbiAgYmFja2dyb3VuZC1zaXplOiBjb250YWluO1xufVxuLm5hdmJhci1kZWZhdWx0IC5uYXZiYXItYnJhbmQuc3Bpbixcbi5uYXZiYXItZGVmYXVsdCAubmF2YmFyLWJyYW5kOmhvdmVyOm5vdCguc3Bpbikge1xuICAtd2Via2l0LWFuaW1hdGlvbjogc3BpbiA0cyBsaW5lYXIgaW5maW5pdGU7XG4gIC1tb3otYW5pbWF0aW9uOiBzcGluIDRzIGxpbmVhciBpbmZpbml0ZTtcbiAgYW5pbWF0aW9uOiBzcGluIDRzIGxpbmVhciBpbmZpbml0ZTtcbn1cbi5yb3ctc3BhY2VkIHtcbiAgbWFyZ2luLXRvcDogMTVweDtcbiAgbWFyZ2luLWJvdHRvbTogMTVweDtcbn1cbi5mb290ZXIge1xuICBwb3NpdGlvbjogYWJzb2x1dGU7XG4gIGJvdHRvbTogMDtcbiAgd2lkdGg6IDEwMCU7XG4gIC8qIFNldCB0aGUgZml4ZWQgaGVpZ2h0IG9mIHRoZSBmb290ZXIgaGVyZSAqL1xuICBoZWlnaHQ6IDUwcHg7XG4gIGJvcmRlci10b3Atd2lkdGg6IDFweDtcbiAgYm9yZGVyLXRvcC1zdHlsZTogc29saWQ7XG59XG4ubm9zZWxlY3Qge1xuICAtd2Via2l0LXRvdWNoLWNhbGxvdXQ6IG5vbmU7XG4gIC13ZWJraXQtdXNlci1zZWxlY3Q6IG5vbmU7XG4gIC1tb3otdXNlci1zZWxlY3Q6IG5vbmU7XG4gIC1tcy11c2VyLXNlbGVjdDogbm9uZTtcbiAgdXNlci1zZWxlY3Q6IG5vbmU7XG4gIGN1cnNvcjogZGVmYXVsdDtcbn1cbkAtbW96LWtleWZyYW1lcyBzcGluIHtcbiAgMTAwJSB7XG4gICAgLW1vei10cmFuc2Zvcm06IHJvdGF0ZVkoMzYwZGVnKTtcbiAgfVxufVxuQC13ZWJraXQta2V5ZnJhbWVzIHNwaW4ge1xuICAxMDAlIHtcbiAgICAtd2Via2l0LXRyYW5zZm9ybTogcm90YXRlWSgzNjBkZWcpO1xuICB9XG59XG5Aa2V5ZnJhbWVzIHNwaW4ge1xuICAxMDAlIHtcbiAgICAtd2Via2l0LXRyYW5zZm9ybTogcm90YXRlWSgzNjBkZWcpO1xuICAgIHRyYW5zZm9ybTogcm90YXRlWSgzNjBkZWcpO1xuICB9XG59XG4iXSwic291cmNlUm9vdCI6Ii9zb3VyY2UvIn0= */
diff --git a/vipra-ui/css/app.less b/vipra-ui/css/app.less
index f08068ef03252e4220fffabfe9fea63ad1914870..df90b12850eb7f3be4a55f92bb49e0da6e50e436 100644
--- a/vipra-ui/css/app.less
+++ b/vipra-ui/css/app.less
@@ -9,32 +9,27 @@ body {
   margin-bottom: 60px;
 }
 
-.word {
-  cursor: pointer;
-  padding-right: 5px;
+.heading {
+  .noselect;
+  font-size: 120px;
+  text-align: center;
+  background: transparent url(/img/logo.svg) no-repeat 50% 50%;
+  background-size: contain;
+  height: 200px;
+  line-height: 200px;
+  margin: 35px 0;
 }
 
-.center {
-  position: absolute;
-  top: 50%;
-  left: 50%;
-  transform: translate(-50%, -50%);
-}
+.search-results {
+  padding: 15px;
 
-.loading {
-  background: url(/assets/images/squares.gif) no-repeat center center;
-  width: 120px;
-  height: 120px;
-}
+  .search-result {
+    margin-bottom: 20px;
 
-.heading {
-  .noselect;
-  font-size: 82px;
-  margin: 30px 0;
-  background: transparent url(/img/logo.png) no-repeat 50% 50%;
-  min-width: 272px;
-  min-height: 216px;
-  padding-top: 90px;
+    a {
+      font-size: 1.5rem;
+    }
+  }
 }
 
 .ellipsize {
@@ -43,10 +38,6 @@ body {
   text-overflow: ellipsis;
 }
 
-.search-result {
-  margin-bottom: 5px;
-}
-
 .navbar-default {
   .collapse:not(.in) {
     .navbar-nav > .active {
@@ -58,6 +49,26 @@ body {
       }
     }
   }
+
+  .navbar-header {
+    padding: 0 10px;
+  }
+
+  .navbar-brand {
+    background: transparent url(/img/logo.svg) no-repeat 50% 50%;
+    background-size: contain;
+    &.spin,
+    &:hover:not(.spin) {
+      -webkit-animation:spin 4s linear infinite;
+      -moz-animation:spin 4s linear infinite;
+      animation:spin 4s linear infinite;
+    }
+  }
+}
+
+.row-spaced {
+  margin-top: 15px;
+  margin-bottom: 15px;
 }
 
 .footer {
@@ -77,4 +88,8 @@ body {
   -ms-user-select: none;
   user-select: none;
   cursor: default;
-}
\ No newline at end of file
+}
+
+@-moz-keyframes spin { 100% { -moz-transform: rotateY(360deg); } }
+@-webkit-keyframes spin { 100% { -webkit-transform: rotateY(360deg); } }
+@keyframes spin { 100% { -webkit-transform: rotateY(360deg); transform:rotateY(360deg); } }
\ No newline at end of file
diff --git a/vipra-ui/favicon/android-chrome-144x144.png b/vipra-ui/favicon/android-chrome-144x144.png
index 23b3628a1c53b9d711e044621691e0230d960282..35fc4d1fbbe7cd92f8f5c8d106efc4b09968a5f0 100644
Binary files a/vipra-ui/favicon/android-chrome-144x144.png and b/vipra-ui/favicon/android-chrome-144x144.png differ
diff --git a/vipra-ui/favicon/android-chrome-192x192.png b/vipra-ui/favicon/android-chrome-192x192.png
index ca42e62464c1d62bc966768bbad7a9719fd6cc47..edf00c720525dff80172704bf41ddeec61f151b8 100644
Binary files a/vipra-ui/favicon/android-chrome-192x192.png and b/vipra-ui/favicon/android-chrome-192x192.png differ
diff --git a/vipra-ui/favicon/android-chrome-36x36.png b/vipra-ui/favicon/android-chrome-36x36.png
index cf4620b3bb98a754e90415e7ad468b0e72dfa960..b2dcce75b1aa62a00be07b99d3d00bbc43c86e18 100644
Binary files a/vipra-ui/favicon/android-chrome-36x36.png and b/vipra-ui/favicon/android-chrome-36x36.png differ
diff --git a/vipra-ui/favicon/android-chrome-48x48.png b/vipra-ui/favicon/android-chrome-48x48.png
index e9ee2f0428f4a37b2faf5c06770d6c77b656f19a..a2f307cb300e37cfbdf6fe4e2a5e96c5ec090047 100644
Binary files a/vipra-ui/favicon/android-chrome-48x48.png and b/vipra-ui/favicon/android-chrome-48x48.png differ
diff --git a/vipra-ui/favicon/android-chrome-72x72.png b/vipra-ui/favicon/android-chrome-72x72.png
index 4f29e40d75691511cafb15f3bb6735f9c456ed67..4532e378a1bc95c519fb3c1b277895654e816060 100644
Binary files a/vipra-ui/favicon/android-chrome-72x72.png and b/vipra-ui/favicon/android-chrome-72x72.png differ
diff --git a/vipra-ui/favicon/android-chrome-96x96.png b/vipra-ui/favicon/android-chrome-96x96.png
index e42b114b5412839588e78595707b410fdcb7868e..b80b7a1ea0c51657850f6a921bd7d6f86c32bd77 100644
Binary files a/vipra-ui/favicon/android-chrome-96x96.png and b/vipra-ui/favicon/android-chrome-96x96.png differ
diff --git a/vipra-ui/favicon/apple-touch-icon-114x114.png b/vipra-ui/favicon/apple-touch-icon-114x114.png
index 3ce8caf70ec12fcadd16e355b9d43971eb7d8de9..de086270b88f2472f5df996e5dec702409e84f37 100644
Binary files a/vipra-ui/favicon/apple-touch-icon-114x114.png and b/vipra-ui/favicon/apple-touch-icon-114x114.png differ
diff --git a/vipra-ui/favicon/apple-touch-icon-120x120.png b/vipra-ui/favicon/apple-touch-icon-120x120.png
index 3ed93796b41ae1522cc0467f1078fb97da48d46f..4e5b2035822991992c2d22db2a7a09b6e3150134 100644
Binary files a/vipra-ui/favicon/apple-touch-icon-120x120.png and b/vipra-ui/favicon/apple-touch-icon-120x120.png differ
diff --git a/vipra-ui/favicon/apple-touch-icon-144x144.png b/vipra-ui/favicon/apple-touch-icon-144x144.png
index 57956a0277ff1eb295a7a44ee33965831de36d93..e46a3605acd1729eafa48332e21e38b645286073 100644
Binary files a/vipra-ui/favicon/apple-touch-icon-144x144.png and b/vipra-ui/favicon/apple-touch-icon-144x144.png differ
diff --git a/vipra-ui/favicon/apple-touch-icon-152x152.png b/vipra-ui/favicon/apple-touch-icon-152x152.png
index d5004ac03673398fe6f7d418b00d2eea02bd0c42..b5cf5b09157af3268cccc109a36398e33ca71580 100644
Binary files a/vipra-ui/favicon/apple-touch-icon-152x152.png and b/vipra-ui/favicon/apple-touch-icon-152x152.png differ
diff --git a/vipra-ui/favicon/apple-touch-icon-180x180.png b/vipra-ui/favicon/apple-touch-icon-180x180.png
index c3de5f5a7023e83ec308380a38f385afa05de5f2..bc2b1c0e1905c6ee157b55d52641bce1ccf77090 100644
Binary files a/vipra-ui/favicon/apple-touch-icon-180x180.png and b/vipra-ui/favicon/apple-touch-icon-180x180.png differ
diff --git a/vipra-ui/favicon/apple-touch-icon-57x57.png b/vipra-ui/favicon/apple-touch-icon-57x57.png
index a44ba21162954e0bcc774d6745522175bb55e898..06f1cff1143a12e78c6b462b01f81942bfc3b3e3 100644
Binary files a/vipra-ui/favicon/apple-touch-icon-57x57.png and b/vipra-ui/favicon/apple-touch-icon-57x57.png differ
diff --git a/vipra-ui/favicon/apple-touch-icon-60x60.png b/vipra-ui/favicon/apple-touch-icon-60x60.png
index aad2e11b045c59e009a994ed274c0b3f5a682a80..d6d718bb57b578523b1eb2736e023708c3829aae 100644
Binary files a/vipra-ui/favicon/apple-touch-icon-60x60.png and b/vipra-ui/favicon/apple-touch-icon-60x60.png differ
diff --git a/vipra-ui/favicon/apple-touch-icon-72x72.png b/vipra-ui/favicon/apple-touch-icon-72x72.png
index 8b4b2fcdaa5f0cd53c169b699db48c63e28b40cf..39078d9b4a0252002432dc9234a8bc6d62a55e1f 100644
Binary files a/vipra-ui/favicon/apple-touch-icon-72x72.png and b/vipra-ui/favicon/apple-touch-icon-72x72.png differ
diff --git a/vipra-ui/favicon/apple-touch-icon-76x76.png b/vipra-ui/favicon/apple-touch-icon-76x76.png
index e015e2a1bc495c1a39e8c5c7ab39d3187d9dd67b..6b2e781056e2e135341c00f512bb81cf08026712 100644
Binary files a/vipra-ui/favicon/apple-touch-icon-76x76.png and b/vipra-ui/favicon/apple-touch-icon-76x76.png differ
diff --git a/vipra-ui/favicon/apple-touch-icon-precomposed.png b/vipra-ui/favicon/apple-touch-icon-precomposed.png
index cf4d130553bb1d08464f0e2576bb7cc1203d94d3..75b1b793c1e298934b0b241dab4fe0248699103c 100644
Binary files a/vipra-ui/favicon/apple-touch-icon-precomposed.png and b/vipra-ui/favicon/apple-touch-icon-precomposed.png differ
diff --git a/vipra-ui/favicon/apple-touch-icon.png b/vipra-ui/favicon/apple-touch-icon.png
index c3de5f5a7023e83ec308380a38f385afa05de5f2..bc2b1c0e1905c6ee157b55d52641bce1ccf77090 100644
Binary files a/vipra-ui/favicon/apple-touch-icon.png and b/vipra-ui/favicon/apple-touch-icon.png differ
diff --git a/vipra-ui/favicon/favicon-16x16.png b/vipra-ui/favicon/favicon-16x16.png
index df7bc123350e7b54707f457eb2c623591914e1ed..cd9277e981ffaca17b3010e74baeb0861fd0bb2f 100644
Binary files a/vipra-ui/favicon/favicon-16x16.png and b/vipra-ui/favicon/favicon-16x16.png differ
diff --git a/vipra-ui/favicon/favicon-194x194.png b/vipra-ui/favicon/favicon-194x194.png
deleted file mode 100644
index e956726d2909bb3095e52cecc1311d0102706f5a..0000000000000000000000000000000000000000
Binary files a/vipra-ui/favicon/favicon-194x194.png and /dev/null differ
diff --git a/vipra-ui/favicon/favicon-32x32.png b/vipra-ui/favicon/favicon-32x32.png
index 54a622eb15653b7821540cf0f4c3a0d9ac602c40..ac93ee5254e126147384f6a6f30578ee2a9f42a3 100644
Binary files a/vipra-ui/favicon/favicon-32x32.png and b/vipra-ui/favicon/favicon-32x32.png differ
diff --git a/vipra-ui/favicon/favicon-96x96.png b/vipra-ui/favicon/favicon-96x96.png
index 984784f51e26962ecfa7eed0390f6d71f8bc2d86..66e04f1997bd50b225757701610f394cb26e5e0e 100644
Binary files a/vipra-ui/favicon/favicon-96x96.png and b/vipra-ui/favicon/favicon-96x96.png differ
diff --git a/vipra-ui/favicon/favicon.ico b/vipra-ui/favicon/favicon.ico
index 82069d823ecf0ce9130f015ba9c2f54df0764982..6444887cb42005b7163bb67e6ad9750e6a2bd8bf 100644
Binary files a/vipra-ui/favicon/favicon.ico and b/vipra-ui/favicon/favicon.ico differ
diff --git a/vipra-ui/favicon/mstile-144x144.png b/vipra-ui/favicon/mstile-144x144.png
index fe6ee38a065d4a60c239b34159cabe2657ca786f..f10800b99bcd049b06d3832091a7ce793220c682 100644
Binary files a/vipra-ui/favicon/mstile-144x144.png and b/vipra-ui/favicon/mstile-144x144.png differ
diff --git a/vipra-ui/favicon/mstile-150x150.png b/vipra-ui/favicon/mstile-150x150.png
index a7f5e77e38a09a5d124327aea41e3851a36776e7..7acea22fab7e04fd351fb2ab3698de0f355b8d0a 100644
Binary files a/vipra-ui/favicon/mstile-150x150.png and b/vipra-ui/favicon/mstile-150x150.png differ
diff --git a/vipra-ui/favicon/mstile-310x150.png b/vipra-ui/favicon/mstile-310x150.png
index 313f68de8d63dfb214085770fa47082d9310d3d9..65a1916cd2595592b5fa740ae407309755c6fc69 100644
Binary files a/vipra-ui/favicon/mstile-310x150.png and b/vipra-ui/favicon/mstile-310x150.png differ
diff --git a/vipra-ui/favicon/mstile-310x310.png b/vipra-ui/favicon/mstile-310x310.png
index 59bd91e2e6f1bf335f24980050838a670c37df2b..11738d66dceb8156eefd73c72595f0673c2ce6c0 100644
Binary files a/vipra-ui/favicon/mstile-310x310.png and b/vipra-ui/favicon/mstile-310x310.png differ
diff --git a/vipra-ui/favicon/mstile-70x70.png b/vipra-ui/favicon/mstile-70x70.png
index bab8744d95ae3da4e74d41dd65c312975443d5e0..71b9f8901a61b41bafc6ad8d90633591b8200a92 100644
Binary files a/vipra-ui/favicon/mstile-70x70.png and b/vipra-ui/favicon/mstile-70x70.png differ
diff --git a/vipra-ui/favicon/safari-pinned-tab.svg b/vipra-ui/favicon/safari-pinned-tab.svg
index a4fbb7ddd7e9e63ad948cb3545cc57cdb7b8b66f..e8228a317e06bbb96fe61b8f8273f7bd20214b22 100644
--- a/vipra-ui/favicon/safari-pinned-tab.svg
+++ b/vipra-ui/favicon/safari-pinned-tab.svg
@@ -2,42 +2,36 @@
 <!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="272.000000pt" height="272.000000pt" viewBox="0 0 272.000000 272.000000"
+ width="1000.000000pt" height="1000.000000pt" viewBox="0 0 1000.000000 1000.000000"
  preserveAspectRatio="xMidYMid meet">
 <metadata>
 Created by potrace 1.11, written by Peter Selinger 2001-2013
 </metadata>
-<g transform="translate(0.000000,272.000000) scale(0.100000,-0.100000)"
+<g transform="translate(0.000000,1000.000000) scale(0.100000,-0.100000)"
 fill="#000000" stroke="none">
-<path d="M78 2334 c18 -21 32 -44 32 -51 0 -7 5 -13 10 -13 6 0 10 -5 10 -11
-0 -6 13 -30 30 -54 17 -24 30 -48 30 -53 0 -6 3 -12 8 -14 9 -4 192 -297 192
--308 0 -5 3 -10 8 -12 10 -4 62 -86 62 -98 0 -5 4 -10 10 -10 5 0 12 -11 16
--25 3 -14 10 -25 15 -25 5 0 9 -5 9 -10 0 -6 5 -16 10 -23 32 -37 101 -158 95
--167 -4 -6 -2 -9 5 -8 6 2 18 -10 28 -27 9 -16 20 -32 23 -35 5 -5 70 -109
-116 -188 12 -20 25 -41 30 -47 5 -5 18 -26 29 -45 10 -19 24 -38 29 -42 7 -5
-7 -8 0 -8 -6 0 -6 -3 0 -8 12 -8 72 -98 101 -152 10 -19 22 -37 25 -40 7 -7
-230 -361 249 -397 8 -15 18 -30 21 -33 3 -3 22 -33 43 -68 21 -34 41 -62 46
--62 6 0 144 213 200 309 8 14 18 28 22 29 5 2 8 8 8 12 0 9 110 184 130 207 5
-7 10 15 10 19 0 3 18 33 40 66 22 33 40 62 40 65 0 2 23 38 50 80 28 42 50 79
-50 82 0 4 8 16 18 27 9 10 23 30 30 44 7 14 26 45 42 70 16 25 39 61 50 80 11
-19 29 49 40 65 11 17 27 43 36 59 9 16 20 34 25 40 19 23 58 86 53 86 -2 0 4
-9 14 20 10 11 25 33 33 48 7 15 31 54 53 87 21 33 39 66 39 73 0 6 3 12 7 12
-7 0 106 156 111 175 2 6 11 19 21 29 10 11 18 26 18 33 0 7 5 13 10 13 6 0 10
-4 10 10 0 5 20 38 45 73 25 36 45 72 45 81 0 10 5 14 10 11 5 -3 10 -1 10 6 0
-7 10 24 23 38 22 24 22 24 -28 -4 -27 -15 -53 -33 -56 -38 -4 -5 -15 -7 -25
--3 -10 4 -15 4 -12 0 9 -8 -9 -25 -47 -44 -16 -8 -33 -19 -37 -25 -4 -5 -8 -6
--8 -1 0 5 -8 2 -18 -6 -9 -9 -35 -26 -57 -38 -81 -45 -260 -155 -263 -162 -2
--5 -12 -8 -21 -8 -10 0 -26 -9 -36 -20 -10 -11 -24 -20 -32 -20 -7 0 -13 -4
--13 -8 0 -4 -12 -13 -27 -19 -31 -13 -105 -55 -113 -64 -11 -12 -279 -169
--288 -169 -6 0 -16 -8 -21 -17 -6 -10 -11 -14 -11 -9 0 6 -7 1 -16 -10 -8 -10
--13 -13 -9 -6 3 7 -14 -1 -38 -18 -25 -16 -50 -30 -56 -30 -6 0 -11 -4 -11 -8
-0 -5 -11 -14 -25 -20 -23 -11 -41 -3 -198 90 -94 56 -174 105 -177 108 -3 3
--16 11 -30 18 -14 7 -38 21 -55 32 -54 34 -80 49 -97 56 -10 3 -18 10 -18 15
-0 5 -6 9 -13 9 -7 0 -23 9 -35 20 -12 12 -22 19 -22 16 0 -6 -32 11 -87 47
--24 15 -47 27 -53 27 -5 0 -10 5 -10 10 0 6 -6 10 -13 10 -7 0 -22 7 -32 15
--52 41 -134 82 -143 73 -7 -7 -10 -4 -9 8 1 11 -4 18 -10 17 -7 -2 -13 1 -13
-6 0 5 -22 20 -50 32 -27 12 -50 26 -50 30 0 4 -19 16 -42 28 -48 24 -81 43
--88 52 -3 4 -25 16 -49 29 l-44 22 31 -38z m1816 -532 c3 -5 -1 -9 -9 -9 -8 0
--12 4 -9 9 3 4 7 8 9 8 2 0 6 -4 9 -8z"/>
+<path d="M9935 8020 c-33 -15 -217 -101 -410 -190 -192 -89 -392 -182 -444
+-206 -51 -24 -95 -44 -96 -44 -2 0 -60 -27 -130 -60 -70 -33 -128 -60 -130
+-60 -2 0 -46 -20 -97 -44 -51 -24 -118 -55 -148 -69 -67 -31 -578 -267 -675
+-312 -38 -18 -272 -126 -520 -240 -548 -253 -534 -246 -674 -312 -62 -29 -115
+-53 -117 -53 -2 0 -60 -27 -130 -60 -69 -33 -128 -60 -130 -60 -2 0 -60 -27
+-130 -60 -69 -33 -128 -60 -129 -60 -2 0 -39 -16 -82 -36 -143 -67 -217 -101
+-298 -139 -44 -20 -163 -75 -265 -122 -102 -47 -217 -100 -257 -119 l-72 -33
+-813 375 c-919 425 -847 391 -1113 514 -110 50 -242 112 -294 136 -51 24 -95
+44 -97 44 -2 0 -45 20 -96 44 -51 24 -120 56 -153 71 -96 44 -175 80 -245 113
+-78 36 -442 204 -520 240 -30 13 -118 54 -195 89 -77 36 -187 87 -245 113 -58
+26 -143 66 -190 88 -47 22 -139 64 -205 95 -66 30 -149 68 -185 85 -306 142
+-634 291 -636 289 -2 -2 87 -113 197 -247 448 -547 1051 -1282 1154 -1410 61
+-74 120 -146 132 -160 80 -96 137 -165 188 -230 33 -41 62 -77 65 -80 3 -3 77
+-93 165 -200 88 -107 162 -197 165 -200 3 -3 43 -52 90 -110 47 -58 92 -114
+102 -125 15 -18 238 -290 516 -630 63 -77 130 -158 148 -180 18 -22 121 -148
+229 -280 108 -132 219 -267 247 -300 27 -33 55 -67 61 -75 39 -48 252 -309
+270 -330 12 -14 40 -47 61 -75 22 -27 48 -58 57 -70 19 -22 131 -158 488 -594
+128 -157 247 -302 263 -321 16 -19 109 -133 206 -252 l177 -217 21 22 c12 12
+188 225 390 472 432 527 822 1003 869 1060 18 22 234 285 479 585 246 300 462
+563 480 585 19 22 210 256 426 520 216 264 414 505 439 535 26 30 73 89 106
+130 33 41 63 77 66 80 4 3 32 37 63 75 70 87 43 53 290 355 115 140 225 275
+246 300 21 25 104 126 185 225 81 99 162 198 181 220 18 22 90 110 159 195 70
+85 134 164 143 175 10 11 89 108 176 215 139 169 217 265 274 333 18 21 20 21
+-53 -13z"/>
 </g>
 </svg>
diff --git a/vipra-ui/html/articles/index.html b/vipra-ui/html/articles/index.html
index f3476ca851c6080072a12c494aa8af4ff852d82b..1ac91c5cf946f62e3c2379012914535e9e2831f0 100644
--- a/vipra-ui/html/articles/index.html
+++ b/vipra-ui/html/articles/index.html
@@ -1,4 +1,8 @@
-<ul>
+<p>
+  Found <span ng-bind="articlesMeta.total"></span> articles in the database <query-time/>.
+</p>
+
+<ul class="list-unstyled">
   <li ng-repeat="article in articles">
     <a ui-sref="articles.show({id: article.id})">{{article.title}}</a>
   </li>
diff --git a/vipra-ui/html/articles/show.html b/vipra-ui/html/articles/show.html
index d5b6176cab5ea25d863f6b34364f8ef7cb53e25d..3800387d7e761c83c67ef57dc3f9b73080698957 100644
--- a/vipra-ui/html/articles/show.html
+++ b/vipra-ui/html/articles/show.html
@@ -1,5 +1,34 @@
 <h1 ng-bind="article.title"></h1>
 
-<p ng-bind="article.date"></p>
+<p ng-bind="(article.date | formatDate)"></p>
+
+<table class="table table-bordered table-condensed">
+  <tbody>
+    <tr>
+      <th>URL</th>
+      <td><a ng-href="{{article.url}}" ng-bind="article.url"></a></td>
+    </tr>
+    <tr>
+      <th>Topics</th>
+      <td class="topic-links">
+        <topic-link topic="topic.topic" ng-repeat="topic in article.topics">
+          <span ng-bind-template="({{topic.count / article.stats.wordCount | toPercent}}%)"></span>
+        </topic-link>
+      </td>
+    </tr>
+    <tr>
+      <th>Created</th>
+      <td ng-bind="(article.created | formatDateTime)"></td>
+    </tr>
+    <tr>
+      <th>Last modified</th>
+      <td ng-bind="(article.modified | formatDateTime)"></td>
+    </tr>
+    <tr>
+      <th>Word count</th>
+      <td ng-bind="article.stats.wordCount"></td>
+    </tr>
+  </tbody>
+</table>
 
 <p ng-bind="article.text"></p>
\ No newline at end of file
diff --git a/vipra-ui/html/index.html b/vipra-ui/html/index.html
index 45a05c583cade5eda1d5837acabf9310c718ba0c..b8d0f89256e1c1dcb31c75d3f87e6d3202605040 100644
--- a/vipra-ui/html/index.html
+++ b/vipra-ui/html/index.html
@@ -2,16 +2,12 @@
 
   <div class="row">
     <div class="col-md-12">
-      <div class="text-center">
-        <h1 class="heading">'v&#618;pr&#601;</h1>
+      <div class="heading">
+        'v&#618;pr&#601;
       </div>
-
-      <br>
-      <input type="text" class="form-control input-lg" placeholder="Search..." ng-model="search" ng-model-options="{debounce:500}">
     </div>
   </div>
 
-  <br><br>
   <div class="row">
     <div class="col-md-6 text-center">
       <h4>Latest articles</h4>
@@ -39,15 +35,26 @@
     </div>
   </div>
 
-  <div class="row" ng-show="searchResults.length > 0">
-    <hr>
-    <h4>Results</h4>
-    <ul class="list-unstyled">
-      <li class="search-result" ng-repeat="article in searchResults">
-        <a ui-sref="articles.show({id:article.id})" ng-bind="article.title"></a><br>
-        <p ng-bind="article.text"></p>
-      </li>
-    </ul>
+  <div class="row row-spaced">
+    <div class="col-md-12">
+      <input type="text" class="form-control input-lg" placeholder="Search..." ng-model="search" ng-model-options="{debounce:500}">
+    </div>
+  </div>
+
+  <div class="row row-spaced" ng-show="searchResults.length > 0">
+    <div class="col-md-12">
+      <h4>Results <query-time/></h4>
+      <ul class="list-unstyled search-results">
+        <li class="search-result" ng-repeat="article in searchResults">
+          <a ui-sref="articles.show({id:article.id})" ng-bind="article.title"></a>
+          <p>
+            <span class="text" ng-bind="article.text"></span>
+            <br>
+            <small class="text-muted" ng-bind-template="{{article.meta.score | toPercent}}% &ndash; {{article.date | formatDate}}"></small>
+          </p>
+        </li>
+      </ul>
+    </div>
   </div>
 
 </div>
\ No newline at end of file
diff --git a/vipra-ui/html/topics/index.html b/vipra-ui/html/topics/index.html
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..5b604e0e7257e2e4bf63e51cf250cfb549b28553 100644
--- a/vipra-ui/html/topics/index.html
+++ b/vipra-ui/html/topics/index.html
@@ -0,0 +1,9 @@
+<p>
+  Found <span ng-bind="topicsMeta.total"></span> topics in the database <query-time/>.
+</p>
+
+<ul class="list-unstyled">
+  <li ng-repeat="topic in topics">
+    <a ui-sref="topics.show({id: topic.id})">{{topic.name}}</a>
+  </li>
+</ul>
\ No newline at end of file
diff --git a/vipra-ui/html/words/index.html b/vipra-ui/html/words/index.html
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..9581521f2fd9fc81740a6dbaea19de968c8cda14 100644
--- a/vipra-ui/html/words/index.html
+++ b/vipra-ui/html/words/index.html
@@ -0,0 +1,9 @@
+<p>
+  Found <span ng-bind="wordsMeta.total"></span> words in the database <query-time/>.
+</p>
+
+<ul class="list-unstyled">
+  <li ng-repeat="word in words">
+    <a ui-sref="words.show({id: word.id})">{{word.id}}</a>
+  </li>
+</ul>
\ No newline at end of file
diff --git a/vipra-ui/img/logo-inkscape.svg b/vipra-ui/img/logo-inkscape.svg
new file mode 100644
index 0000000000000000000000000000000000000000..05e51bac5ac3be7165ff26abe05a9a2ae31b48b2
--- /dev/null
+++ b/vipra-ui/img/logo-inkscape.svg
@@ -0,0 +1,186 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:xlink="http://www.w3.org/1999/xlink"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="91.637482mm"
+   height="55.924236mm"
+   viewBox="0 0 324.69974 198.15674"
+   id="svg2"
+   version="1.1"
+   inkscape:version="0.91 r13725"
+   sodipodi:docname="logo-inkscape.svg">
+  <defs
+     id="defs4">
+    <linearGradient
+       inkscape:collect="always"
+       id="linearGradient4221">
+      <stop
+         style="stop-color:#0079a2;stop-opacity:1"
+         offset="0"
+         id="stop4223" />
+      <stop
+         style="stop-color:#009abf;stop-opacity:1"
+         offset="1"
+         id="stop4225" />
+    </linearGradient>
+    <linearGradient
+       inkscape:collect="always"
+       id="linearGradient4213">
+      <stop
+         style="stop-color:#006491;stop-opacity:1"
+         offset="0"
+         id="stop4215" />
+      <stop
+         style="stop-color:#00a4c0;stop-opacity:1"
+         offset="1"
+         id="stop4217" />
+    </linearGradient>
+    <linearGradient
+       inkscape:collect="always"
+       id="linearGradient4205">
+      <stop
+         style="stop-color:#0079a2;stop-opacity:1"
+         offset="0"
+         id="stop4207" />
+      <stop
+         style="stop-color:#009abf;stop-opacity:1"
+         offset="1"
+         id="stop4209" />
+    </linearGradient>
+    <linearGradient
+       inkscape:collect="always"
+       id="linearGradient4197">
+      <stop
+         style="stop-color:#006491;stop-opacity:1"
+         offset="0"
+         id="stop4199" />
+      <stop
+         style="stop-color:#00a4c0;stop-opacity:1"
+         offset="1"
+         id="stop4201" />
+    </linearGradient>
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient4197"
+       id="linearGradient4203"
+       x1="283.92856"
+       y1="203.43364"
+       x2="445.40039"
+       y2="203.43364"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(86.138062,74.953319)" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient4205"
+       id="linearGradient4211"
+       x1="283.42285"
+       y1="203.43364"
+       x2="121.42857"
+       y2="203.43364"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(86.267027,74.953319)" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient4213"
+       id="linearGradient4219"
+       x1="283.92856"
+       y1="203.43364"
+       x2="121.54656"
+       y2="79.678802"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(86.267027,75.095251)" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient4221"
+       id="linearGradient4227"
+       x1="284.43472"
+       y1="203.43364"
+       x2="446.31104"
+       y2="79.67881"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(86.138062,75.095251)" />
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="1.4142136"
+     inkscape:cx="216.30244"
+     inkscape:cy="55.76913"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer1"
+     showgrid="false"
+     showguides="true"
+     inkscape:guide-bbox="true"
+     inkscape:object-paths="true"
+     inkscape:snap-intersection-paths="true"
+     inkscape:object-nodes="true"
+     inkscape:snap-smooth-nodes="true"
+     inkscape:snap-midpoints="true"
+     inkscape:snap-object-midpoints="true"
+     inkscape:snap-center="true"
+     fit-margin-top="0"
+     fit-margin-left="0"
+     fit-margin-right="0"
+     fit-margin-bottom="0"
+     inkscape:showpageshadow="false"
+     inkscape:window-width="2505"
+     inkscape:window-height="1416"
+     inkscape:window-x="55"
+     inkscape:window-y="24"
+     inkscape:window-maximized="1" />
+  <metadata
+     id="metadata7">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Ebene 1"
+     inkscape:groupmode="layer"
+     id="layer1"
+     transform="translate(-207.74933,-154.63212)">
+    <path
+       style="fill:#006491;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       d="M 207.74933,154.84502 370.13131,229.75464 532.38477,154.70309 370.00275,352.78885 207.74933,154.70309"
+       id="path4289"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:url(#linearGradient4227);fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       d="m 370.06703,229.68368 162.38202,-74.90962 -162.38202,124.14146 0,-49.23184"
+       id="path3363"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:url(#linearGradient4203);fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       d="m 370.06703,278.77359 0,73.9443 162.38202,-198.08576 -162.38202,124.14146"
+       id="path3365"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:url(#linearGradient4219);fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       d="m 370.1956,229.68368 -162.38201,-74.90963 162.38201,124.14146 0,-49.23183"
+       id="path3363-9"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:url(#linearGradient4211);fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       d="m 370.1956,278.77358 0,73.9443 L 207.81359,154.63212 370.1956,278.77358"
+       id="path3365-8"
+       inkscape:connector-curvature="0" />
+  </g>
+</svg>
diff --git a/vipra-ui/img/logo.png b/vipra-ui/img/logo.png
index 76f867cc2335f6b8c77feb78c80504be1cb9387d..51fd6e5373495b87b757dea086067314f482fa8b 100644
Binary files a/vipra-ui/img/logo.png and b/vipra-ui/img/logo.png differ
diff --git a/vipra-ui/img/logo.svg b/vipra-ui/img/logo.svg
new file mode 100644
index 0000000000000000000000000000000000000000..70bfa448be8a6b90293a9146294e9b338018790a
--- /dev/null
+++ b/vipra-ui/img/logo.svg
@@ -0,0 +1,133 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:xlink="http://www.w3.org/1999/xlink"
+   version="1.1"
+   id="svg2"
+   viewBox="0 0 324.69974 198.15674"
+   height="55.924236mm"
+   width="91.637482mm">
+  <defs
+     id="defs4">
+    <linearGradient
+       id="linearGradient4221">
+      <stop
+         id="stop4223"
+         offset="0"
+         style="stop-color:#0079a2;stop-opacity:1" />
+      <stop
+         id="stop4225"
+         offset="1"
+         style="stop-color:#009abf;stop-opacity:1" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient4213">
+      <stop
+         id="stop4215"
+         offset="0"
+         style="stop-color:#006491;stop-opacity:1" />
+      <stop
+         id="stop4217"
+         offset="1"
+         style="stop-color:#00a4c0;stop-opacity:1" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient4205">
+      <stop
+         id="stop4207"
+         offset="0"
+         style="stop-color:#0079a2;stop-opacity:1" />
+      <stop
+         id="stop4209"
+         offset="1"
+         style="stop-color:#009abf;stop-opacity:1" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient4197">
+      <stop
+         id="stop4199"
+         offset="0"
+         style="stop-color:#006491;stop-opacity:1" />
+      <stop
+         id="stop4201"
+         offset="1"
+         style="stop-color:#00a4c0;stop-opacity:1" />
+    </linearGradient>
+    <linearGradient
+       gradientTransform="translate(86.138062,74.953319)"
+       gradientUnits="userSpaceOnUse"
+       y2="203.43364"
+       x2="445.40039"
+       y1="203.43364"
+       x1="283.92856"
+       id="linearGradient4203"
+       xlink:href="#linearGradient4197" />
+    <linearGradient
+       gradientTransform="translate(86.267027,74.953319)"
+       gradientUnits="userSpaceOnUse"
+       y2="203.43364"
+       x2="121.42857"
+       y1="203.43364"
+       x1="283.42285"
+       id="linearGradient4211"
+       xlink:href="#linearGradient4205" />
+    <linearGradient
+       gradientTransform="translate(86.267027,75.095251)"
+       gradientUnits="userSpaceOnUse"
+       y2="79.678802"
+       x2="121.54656"
+       y1="203.43364"
+       x1="283.92856"
+       id="linearGradient4219"
+       xlink:href="#linearGradient4213" />
+    <linearGradient
+       gradientTransform="translate(86.138062,75.095251)"
+       gradientUnits="userSpaceOnUse"
+       y2="79.67881"
+       x2="446.31104"
+       y1="203.43364"
+       x1="284.43472"
+       id="linearGradient4227"
+       xlink:href="#linearGradient4221" />
+  </defs>
+  <metadata
+     id="metadata7">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     transform="translate(-207.74933,-154.63212)"
+     id="layer1">
+    <path
+       id="path4289"
+       d="M 207.74933,154.84502 370.13131,229.75464 532.38477,154.70309 370.00275,352.78885 207.74933,154.70309"
+       style="fill:#006491;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+    <path
+       id="path3363"
+       d="m 370.06703,229.68368 162.38202,-74.90962 -162.38202,124.14146 0,-49.23184"
+       style="fill:url(#linearGradient4227);fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+    <path
+       id="path3365"
+       d="m 370.06703,278.77359 0,73.9443 162.38202,-198.08576 -162.38202,124.14146"
+       style="fill:url(#linearGradient4203);fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+    <path
+       id="path3363-9"
+       d="m 370.1956,229.68368 -162.38201,-74.90963 162.38201,124.14146 0,-49.23183"
+       style="fill:url(#linearGradient4219);fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+    <path
+       id="path3365-8"
+       d="m 370.1956,278.77358 0,73.9443 L 207.81359,154.63212 370.1956,278.77358"
+       style="fill:url(#linearGradient4211);fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+  </g>
+</svg>
diff --git a/vipra-ui/index.html b/vipra-ui/index.html
index f1a83eec3051398daeab4b94d094f0f92ddf78f8..e9759f89731f6d1f6e3120c7602bccc964c8aa89 100644
--- a/vipra-ui/index.html
+++ b/vipra-ui/index.html
@@ -16,9 +16,8 @@
     <link rel="apple-touch-icon" sizes="152x152" href="/favicon/apple-touch-icon-152x152.png">
     <link rel="apple-touch-icon" sizes="180x180" href="/favicon/apple-touch-icon-180x180.png">
     <link rel="icon" type="image/png" href="/favicon/favicon-32x32.png" sizes="32x32">
-    <link rel="icon" type="image/png" href="/favicon/favicon-194x194.png" sizes="194x194">
-    <link rel="icon" type="image/png" href="/favicon/favicon-96x96.png" sizes="96x96">
     <link rel="icon" type="image/png" href="/favicon/android-chrome-192x192.png" sizes="192x192">
+    <link rel="icon" type="image/png" href="/favicon/favicon-96x96.png" sizes="96x96">
     <link rel="icon" type="image/png" href="/favicon/favicon-16x16.png" sizes="16x16">
     <link rel="manifest" href="/favicon/manifest.json">
     <link rel="mask-icon" href="/favicon/safari-pinned-tab.svg" color="#5bbad5">
@@ -42,6 +41,7 @@
     <script src="js/controllers.js"></script>
     <script src="js/directives.js"></script>
     <script src="js/factories.js"></script>
+    <script src="js/filters.js"></script>
     <script src="js/services.js"></script>
   </head>
   <body>
@@ -55,15 +55,15 @@
             <span class="icon-bar"></span>
             <span class="icon-bar"></span>
           </button>
-          <a ui-sref="index" class="navbar-brand">vipra</a>
+          <a ui-sref="index" class="navbar-brand" ng-class="{spin:loading.any}"></a>
         </div>
 
         <!-- Collect the nav links, forms, and other content for toggling -->
         <div class="collapse navbar-collapse" id="vipra-navbar-collapse-1">
           <ul class="nav navbar-nav">
-            <li><a ui-sref="articles.index">Articles</a></li>
-            <li><a ui-sref="topics.index">Topics</a></li>
-            <li><a ui-sref="words.index">Words</a></li>
+            <li ui-sref-active="active"><a ui-sref="articles.index">Articles</a></li>
+            <li ui-sref-active="active"><a ui-sref="topics.index">Topics</a></li>
+            <li ui-sref-active="active"><a ui-sref="words.index">Words</a></li>
             <div id="testi"></div>
           </ul>
         </div><!-- /.navbar-collapse -->
diff --git a/vipra-ui/js/app.js b/vipra-ui/js/app.js
index 66b7d3b4936ca75ed3fe66a83055b57f5a9e0063..a48c4a7e41f17e32c2e3f0c3fb78ec827b980378 100644
--- a/vipra-ui/js/app.js
+++ b/vipra-ui/js/app.js
@@ -6,6 +6,7 @@
     'vipra.controllers',
     'vipra.directives',
     'vipra.factories',
+    'vipra.filters',
     'vipra.services'
   ]);
 
@@ -55,13 +56,13 @@
     $stateProvider.state('topics.index', {
       url: '',
       templateUrl: tplBase + '/topics/index.html',
-      controller: 'ArticlesIndexController'
+      controller: 'TopicsIndexController'
     });
 
     $stateProvider.state('topics.show', {
       url: '/:id',
       templateUrl: tplBase + '/topics/show.html',
-      controller: 'ArticlesShowController'
+      controller: 'TopicsShowController'
     });
 
     // states: words
@@ -75,13 +76,13 @@
     $stateProvider.state('words.index', {
       url: '',
       templateUrl: tplBase + '/words/index.html',
-      controller: 'ArticlesIndexController'
+      controller: 'WordsIndexController'
     });
 
     $stateProvider.state('words.show', {
       url: '/:id',
       templateUrl: tplBase + '/words/show.html',
-      controller: 'ArticlesShowController'
+      controller: 'WordsShowController'
     });
 
   }]);
@@ -92,16 +93,19 @@
       var requestIncrement = function(config) {
         $rootScope.loading.requests = ++$rootScope.loading.requests || 1;
         $rootScope.loading[config.method] = ++$rootScope.loading[config.method] || 1;
+        $rootScope.loading.any = true;
       };
 
       var requestDecrement = function(config) {
         $rootScope.loading.requests = Math.max(--$rootScope.loading.requests, 0);
         $rootScope.loading[config.method] = Math.max(--$rootScope.loading[config.method], 0);
+        $rootScope.loading.any = $rootScope.loading.requests > 0;
       };
 
       return {
         request: function(config) {
           requestIncrement(config);
+          config.$queryTime = performance.now();
           return config;
         },
 
@@ -112,6 +116,7 @@
 
         response: function(response) {
           requestDecrement(response.config);
+          response.data.$queryTime = (performance.now() - response.config.$queryTime).toFixed(2);
           return response;
         },
 
diff --git a/vipra-ui/js/controllers.js b/vipra-ui/js/controllers.js
index 42300697efa7050097dd57b92a41d8007ab424cd..14b33503685f424103ab556a2f5b7ea58872ffbc 100644
--- a/vipra-ui/js/controllers.js
+++ b/vipra-ui/js/controllers.js
@@ -5,44 +5,113 @@
     'vipra.factories'
   ]);
 
-  app.controller('IndexController', ['$scope', '$location', 'ArticleFactory', 'TopicFactory', 'WordFactory', 'SearchFactory',function($scope, $location, ArticleFactory, TopicFactory, WordFactory, SearchFactory) {
-    $scope.search = $location.search().query;
+  var latestItemsCount = 3,
+      searchItemsCount = 10;
 
-    ArticleFactory.query({limit:3, sort:'-created'}, function(response) {
+  app.controller('IndexController', ['$scope', '$location', 'ArticleFactory', 'TopicFactory', 'WordFactory', 'SearchFactory',
+    function($scope, $location, ArticleFactory, TopicFactory, WordFactory, SearchFactory) {
+
+    ArticleFactory.query({limit:latestItemsCount, sort:'-created'}, function(response) {
       $scope.latestArticles = response.data;
     });
 
-    TopicFactory.query({limit:3, sort:'-created'}, function(response) {
+    TopicFactory.query({limit:latestItemsCount, sort:'-created'}, function(response) {
       $scope.latestTopics = response.data;
     });
 
-    WordFactory.query({limit:3, sort:'-created'}, function(response) {
+    WordFactory.query({limit:latestItemsCount, sort:'-created'}, function(response) {
       $scope.latestWords = response.data;
     });
 
     $scope.$watch('search', function() {
       if($scope.search) {
-        $location.search('query', $scope.search);
-        SearchFactory.query({limit:10, query:$scope.search}, function(response) {
+        SearchFactory.query({limit:searchItemsCount, query:$scope.search}, function(response) {
           $scope.searchResults = response.data;
+          $scope.queryTime = response.$queryTime;
         });
       } else {
-        $location.search('query', null);
         $scope.searchResults = [];
       }
     });
+
   }]);
 
-  app.controller('ArticlesIndexController', ['$scope', 'ArticleFactory', function($scope, ArticleFactory) {
+  /*
+   * ARTICLES
+   */
+
+  app.controller('ArticlesIndexController', ['$scope', 'ArticleFactory',
+    function($scope, ArticleFactory) {
+
     ArticleFactory.query(function(response) {
       $scope.articles = response.data;
+      $scope.articlesMeta = response.meta;
+      $scope.queryTime = response.$queryTime;
     });
+
   }]);
 
-  app.controller('ArticlesShowController', ['$scope', '$stateParams', 'ArticleFactory', function($scope, $stateParams, ArticleFactory) {
+  app.controller('ArticlesShowController', ['$scope', '$stateParams', 'ArticleFactory',
+    function($scope, $stateParams, ArticleFactory) {
+
     ArticleFactory.get({id: $stateParams.id}, function(response) {
       $scope.article = response.data;
+      $scope.articleMeta = response.meta;
+      $scope.queryTime = response.$queryTime;
     });
+
+  }]);
+
+  /*
+   * TOPICS
+   */
+
+  app.controller('TopicsIndexController', ['$scope', 'TopicFactory',
+    function($scope, TopicFactory) {
+
+    TopicFactory.query(function(response) {
+      $scope.topics = response.data;
+      $scope.topicsMeta = response.meta;
+      $scope.queryTime = response.$queryTime;
+    });
+
+  }]);
+
+  app.controller('TopicsShowController', ['$scope', '$stateParams', 'TopicFactory',
+    function($scope, $stateParams, TopicFactory) {
+
+    TopicFactory.get({id: $stateParams.id}, function(response) {
+      $scope.topic = response.data;
+      $scope.topicMeta = response.meta;
+      $scope.queryTime = response.$queryTime;
+    });
+
+  }]);
+
+  /*
+   * WORDS
+   */
+
+  app.controller('WordsIndexController', ['$scope', 'WordFactory',
+    function($scope, WordFactory) {
+
+    WordFactory.query(function(response) {
+      $scope.words = response.data;
+      $scope.wordsMeta = response.meta;
+      $scope.queryTime = response.$queryTime;
+    });
+
+  }]);
+
+  app.controller('WordsShowController', ['$scope', '$stateParams', 'WordFactory',
+    function($scope, $stateParams, WordFactory) {
+
+    WordFactory.get({id: $stateParams.id}, function(response) {
+      $scope.word = response.data;
+      $scope.wordMeta = response.meta;
+      $scope.queryTime = response.$queryTime;
+    });
+
   }]);
 
 })();
\ No newline at end of file
diff --git a/vipra-ui/js/directives.js b/vipra-ui/js/directives.js
index 05b64aefd11b6771f2b6e9194caec1710896db86..e421c434fefd94b2cf8f4c9fed2a652380fd6557 100644
--- a/vipra-ui/js/directives.js
+++ b/vipra-ui/js/directives.js
@@ -2,4 +2,24 @@
 
   var app = angular.module('vipra.directives', []);
 
+  app.directive('topicLink', function() {
+    return {
+      scope: {
+        topic: '='
+      },
+      restrict: 'E',
+      replace: true,
+      transclude: true,
+      template: '<a class="topic-link" ui-sref="topics.show({id:topic.id})"><span ng-bind="topic.name"></span><ng-transclude/></a>'
+    }
+  });
+
+  app.directive('queryTime', function() {
+    return {
+      restrict: 'E',
+      replace: true,
+      template: '<small class="text-muted">(took <span ng-bind-template="{{queryTime}}ms"></span>)</small>'
+    };
+  });
+
 })();
\ No newline at end of file
diff --git a/vipra-ui/js/factories.js b/vipra-ui/js/factories.js
index 62564fd739a65b6d70cf4898c80ad5fbd2674c7f..6eb0807ae2e7f3d86566f82bf88d3427d21270d8 100644
--- a/vipra-ui/js/factories.js
+++ b/vipra-ui/js/factories.js
@@ -6,25 +6,25 @@
 
   app.factory('ArticleFactory', ['$resource', function($resource) {
     return $resource(endpoint + '/vipra-rest/articles/:id', {}, {
-      query: { isArray: false }
+      query: { isArray: false, cache: true }
     });
   }]);
 
   app.factory('TopicFactory', ['$resource', function($resource) {
     return $resource(endpoint + '/vipra-rest/topics/:id', {}, {
-      query: { isArray: false }
+      query: { isArray: false, cache: true }
     });
   }]);
 
   app.factory('WordFactory', ['$resource', function($resource) {
     return $resource(endpoint + '/vipra-rest/words/:id', {}, {
-      query: { isArray: false }
+      query: { isArray: false, cache: true }
     });
   }]);
 
   app.factory('SearchFactory', ['$resource', function($resource) {
     return $resource(endpoint + '/vipra-rest/search', {}, {
-      query: { isArray: false }
+      query: { isArray: false, cache: true }
     });
   }]);
 
diff --git a/vipra-ui/js/filters.js b/vipra-ui/js/filters.js
new file mode 100644
index 0000000000000000000000000000000000000000..a4233098d28b5e1984301ff35c61ee44861256c6
--- /dev/null
+++ b/vipra-ui/js/filters.js
@@ -0,0 +1,26 @@
+(function() {
+
+  var app = angular.module('vipra.filters', []);
+
+  app.filter('toPercent', function() {
+    return function(input) {
+      if(typeof input !== 'number')
+        input = parseInt(input, 10);
+      return Math.round(input * 100);
+    };
+  });
+
+  app.filter('formatDate', function() {
+    return function(input) {
+      return new Date(input).toLocaleDateString();
+    };
+  });
+
+  app.filter('formatDateTime', function() {
+    return function(input) {
+      var date = new Date(input);
+      return date.toLocaleDateString() + " " + date.toLocaleTimeString();
+    };
+  });
+
+})();
\ No newline at end of file
diff --git a/vipra-util/src/main/java/de/vipra/util/Constants.java b/vipra-util/src/main/java/de/vipra/util/Constants.java
index 0accb717a83e44eb7dfee3cdf4837edab0d9f197..ca915f4c37676455f629bfe405439fe8b56b3165 100644
--- a/vipra-util/src/main/java/de/vipra/util/Constants.java
+++ b/vipra-util/src/main/java/de/vipra/util/Constants.java
@@ -189,7 +189,7 @@ public class Constants {
 	 * The global date time format. Will be used for conversion from and to
 	 * database and frontend dates.
 	 */
-	public static final String DATETIME_FORMAT = "yyyy-MM-dd'T'HH:mm:ss'Z'";
+	public static final String DATETIME_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'";
 
 	/**
 	 * The text processors available, including the default text processor
diff --git a/vipra-util/src/main/java/de/vipra/util/model/ArticleFull.java b/vipra-util/src/main/java/de/vipra/util/model/ArticleFull.java
index 5dc4c422e16db29516df5fee2791659206a42c09..a55d0f8b5c6e208f6f6d4b3f05126bf314cc72dc 100644
--- a/vipra-util/src/main/java/de/vipra/util/model/ArticleFull.java
+++ b/vipra-util/src/main/java/de/vipra/util/model/ArticleFull.java
@@ -6,7 +6,9 @@ import java.io.Serializable;
 import java.text.ParseException;
 import java.text.SimpleDateFormat;
 import java.util.Date;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
 import org.bson.types.ObjectId;
 import org.mongodb.morphia.annotations.Embedded;
@@ -15,10 +17,14 @@ import org.mongodb.morphia.annotations.Id;
 import org.mongodb.morphia.annotations.Index;
 import org.mongodb.morphia.annotations.Indexes;
 import org.mongodb.morphia.annotations.PrePersist;
+import org.mongodb.morphia.annotations.Transient;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 import de.vipra.util.Constants;
 import de.vipra.util.FileUtils;
 import de.vipra.util.MongoUtils;
+import de.vipra.util.NestedMap;
 import de.vipra.util.StringUtils;
 import de.vipra.util.an.QueryIgnore;
 
@@ -27,6 +33,8 @@ import de.vipra.util.an.QueryIgnore;
 @Indexes({ @Index("title"), @Index("date"), @Index("-created") })
 public class ArticleFull extends FileModel<ObjectId> implements Serializable {
 
+	public static final Logger log = LoggerFactory.getLogger(ArticleFull.class);
+
 	@Id
 	private ObjectId id;
 
@@ -51,6 +59,12 @@ public class ArticleFull extends FileModel<ObjectId> implements Serializable {
 
 	private Date modified;
 
+	@Transient
+	private Map<String, String> links;
+
+	@Transient
+	private NestedMap meta;
+
 	@Override
 	public ObjectId getId() {
 		return id;
@@ -101,7 +115,9 @@ public class ArticleFull extends FileModel<ObjectId> implements Serializable {
 		SimpleDateFormat df = new SimpleDateFormat(Constants.DATETIME_FORMAT);
 		try {
 			setDate(df.parse(date));
-		} catch (ParseException e) {}
+		} catch (ParseException e) {
+			log.error("could not parse date " + date);
+		}
 	}
 
 	public List<TopicRef> getTopics() {
@@ -136,6 +152,34 @@ public class ArticleFull extends FileModel<ObjectId> implements Serializable {
 		this.modified = modified;
 	}
 
+	public Map<String, String> getLinks() {
+		return links;
+	}
+
+	public void setLinks(Map<String, String> links) {
+		this.links = links;
+	}
+
+	public void addLink(String key, String link) {
+		if (links == null)
+			links = new HashMap<>();
+		links.put(key, link);
+	}
+
+	public NestedMap getMeta() {
+		return meta;
+	}
+
+	public void setMeta(NestedMap meta) {
+		this.meta = meta;
+	}
+
+	public void addMeta(String key, Object value) {
+		if (meta == null)
+			meta = new NestedMap();
+		meta.put(key, value);
+	}
+
 	@Override
 	public void fromFile(File file) throws IOException {
 		List<String> lines = FileUtils.readFile(file);