Deployment preparation for testbed
diff --git a/lib/Korap/Plugin/KorapInfo.pm b/lib/Korap/Plugin/KorapInfo.pm
new file mode 100644
index 0000000..77a3061
--- /dev/null
+++ b/lib/Korap/Plugin/KorapInfo.pm
@@ -0,0 +1,41 @@
+package Korap::Plugin::KorapInfo;
+use Mojo::Base 'Mojolicious::Plugin';
+
+sub register {
+  my ($plugin, $mojo, $param) = @_;
+  $param ||= {};
+
+  # Load parameter from Config file
+  if (my $config_param = $mojo->config('KorAP')) {
+    $param = { %$param, %$config_param };
+  };
+
+  my $api = $param->{api};
+
+  # Todo: Make this recognize the user!
+  $mojo->helper(
+    info_on => sub {
+      my $c = shift;
+      my $src = shift;
+      $src = 'VirtualCollection' if $src eq 'collection';
+      $src = 'Corpus' if $src eq 'corpus';
+
+      my $url = Mojo::URL->new($api)->path('resource/' . $src);
+
+      my $chi = $c->chi;
+      if (my $json = $chi->get($url->to_string)) {
+	return $json;
+      }
+      elsif (my $response = $c->ua->get($url)->success) {
+	my $json = $response->json;
+	$c->chi->set($url->to_string => $json);
+	return $json;
+      };
+      $c->notify(error => 'Unable to retrieve resource');
+      return [];
+    }
+  );
+};
+
+
+1;
diff --git a/lib/Korap/Plugin/KorapMatchinfo.pm b/lib/Korap/Plugin/KorapMatchinfo.pm
new file mode 100644
index 0000000..6cd6a10
--- /dev/null
+++ b/lib/Korap/Plugin/KorapMatchinfo.pm
@@ -0,0 +1,44 @@
+package Korap::Plugin::KorapMatchInfo;
+use Mojo::Base 'Mojolicious::Plugin';
+
+sub register {
+  my ($plugin, $mojo, $param) = @_;
+  $param ||= {};
+
+  # Load parameter from Config file
+  if (my $config_param = $mojo->config('KorAP')) {
+    $param = { %$param, %$config_param };
+  };
+
+  my $api = $param->{api};
+
+  # Todo: Make this recognize the user!
+  $mojo->helper(
+    info_on => sub {
+      my $c = shift;
+      my $src = shift;
+
+/resource/matchInfo?id=match-WPD!WPD_TTT.07206-p151-152&f=treetagger&l=morpho&spans=true
+
+      $src = 'VirtualCollection' if $src eq 'collection';
+      $src = 'Corpus' if $src eq 'corpus';
+
+      my $url = Mojo::URL->new($api)->path('resource/' . $src);
+
+      my $chi = $c->chi;
+      if (my $json = $chi->get($url->to_string)) {
+	return $json;
+      }
+      elsif (my $response = $c->ua->get($url)->success) {
+	my $json = $response->json;
+	$c->chi->set($url->to_string => $json);
+	return $json;
+      };
+      $c->notify(error => 'Unable to retrieve resource');
+      return [];
+    }
+  );
+};
+
+
+1;
diff --git a/lib/Korap/Plugin/KorapSearch.pm b/lib/Korap/Plugin/KorapSearch.pm
index a6aaac1..b57e608 100644
--- a/lib/Korap/Plugin/KorapSearch.pm
+++ b/lib/Korap/Plugin/KorapSearch.pm
@@ -1,8 +1,10 @@
 package Korap::Plugin::KorapSearch;
 use Mojo::Base 'Mojolicious::Plugin';
+use Mojo::JSON qw/decode_json/;
 use Mojo::ByteStream 'b';
 
 # TODO: This will probably be an engine for M::P::Search
+# cutoff has to be true or false
 
 sub register {
   my ($plugin, $mojo, $param) = @_;
@@ -24,6 +26,23 @@
 
       my %param = @_;
 
+      # Test envronment
+#      if ($c->app->mode eq 'test') {
+#	my $json = b(join(' ', <DATA>))->encode;
+#	$json = decode_json($json);
+#
+#	$c->stash('search.count' => 10);
+#	$c->stash('search.startPage' => 1);
+#	$c->stash('search.totalResults' => 666);
+#	$c->stash('search.itemsPerPage' => 10);
+#	$_->{'search.bm.hit'} = 20;
+#	$_->{'search.bm.result'} = 10;
+#	$_->{'search.query'} = $json->{request}->{query};
+#	$_->{'search.hits'} = $json->{matches};
+#	return $cb->();
+#      };
+
+
       $c->stash(
 	'search.count' =>
 	  delete($param{count}) //
@@ -60,29 +79,43 @@
 
       my %query = (q => $query);
       $query{ql} = scalar $c->param('ql') // 'poliqarp';
-      $query{startPage} = $start_page if $start_page;
       $query{count} = $count if $count;
 
-      $query{lctx} = 'chars';
-      $query{lctxs} = 120;
-      $query{rctx} = 'chars';
-      $query{rctxs} = 120;
-
-      $query{cutoff} = $param{cutoff} // $c->param('cutoff');
-
-
       $url->query(\%query);
+      my $cache_url = $url->to_string;
 
-      $c->stash('search.totalResults' => 0);
+      $url->query({ctx => 'paragraph'});
+
+      # Check cache for total results
+      my $total_results = $c->chi->get('total-' . $cache_url);
+      if (defined $total_results) {
+	$c->stash('search.totalResults' => $total_results);
+	$c->app->log->warn('Get total result from cache');
+	$url->query({cutoff => 'true'});
+	$url->query({cutOff => 'true'});
+      }
+      else {
+	$c->stash('search.totalResults' => 0);
+      };
+
+      $url->query({page => $start_page});
+
       $c->stash('search.itemsPerPage' => $count);
 
       my $ua = Mojo::UserAgent->new($url);
       $c->app->log->debug($url->to_string);
 
+      $c->app->log->debug("Start tx");
+
       # Blocking request
       # TODO: Make non-blocking
       my $tx = $ua->get($url);
 
+      if (my $e = $tx->error) {
+	$c->notify(error => $e->{code} . ': ' . $e->{message} . ' (remote)');
+	return;
+      };
+
       # Request successful
       if (my $res = $tx->success) {
 	my $json = $res->json;
@@ -103,7 +136,12 @@
 	  $_->{'search.itemsPerPage'} = $json->{itemsPerPage};
 	  $_->{'search.query'}        = $json->{request}->{query};
 	  $_->{'search.hits'}         = $json->{matches};
-	  $_->{'search.totalResults'} = $json->{totalResults};
+	};
+
+	if ($json->{totalResults} > -1) {
+	  $c->app->log->warn('Set total result from cache');
+	  $c->stash('search.totalResults' => $json->{totalResults});
+	  $c->chi->set('total-' . $cache_url => $json->{totalResults}, '30min');
 	};
 
 	if ($json->{error}) {
@@ -114,7 +152,7 @@
       # Request failed
       else {
 	my $res = $tx->res;
-	$c->notify('error' =>  $res->code . ': ' . $res->message);
+	$c->notify('error' =>  $res->{code} . ': ' . $res->{message} . ' (remote)');
       };
 
       # Run embedded template
@@ -159,3 +197,390 @@
 
 
 1;
+
+__DATA__
+{
+  "query" : "tokens:mate/l:baum",
+  "matches" : [ {
+    "author" : "Peter200,Srittau,AHoerstemeier",
+    "textClass" : "freizeit-unterhaltung reisen",
+    "corpusID" : "WPD",
+    "title" : "Palm Beach Gardens",
+    "foundries" : "corenlp corenlp/namedentities corenlp/namedentities/ne_dewac_175m_600 corenlp/namedentities corenlp/namedentities/ne_hgc_175m_600 xip xip/morpho xip/constituency xip/dependency treetagger treetagger/morpho connexor connexor/morpho connexor/syntax connexor/phrase mate mate/morpho mate/dependency opennlp opennlp/morpho base base/sentences base/paragraphs",
+    "tokenization" : "opennlp#tokens",
+    "field" : "tokens",
+    "startMore" : true,
+    "endMore" : true,
+    "docID" : "WPD_PPP.00430",
+    "snippet" : "<span class=\"context-left\">MacArtur stellte sich die Straßen der Stadt links und rechts gesäümt mit Blumen und </span><span class=\"match\">Bäumen</span><span class=\"context-right\"> vor. Millionen von USD wurden dafür verwendet um dies zu ermöglichen. Letztlich wurde an allen Straßen und Wasserstraßen mächtige Kiefern und andere schattenspendende Laubbäume gepflanzt. Da er ein Naturliebhaber war, mussten alle älteren Bäume stehen bleiben und Straßen darum herum geführt werden. Für die damalige Zeit für Amerika eine total neue Erfahrung. Dies verteuerte das Bauvorhaben erheblich, aber MacArthur ließ sich nicht beirren. Ebenso waren die ersten Gebäude, die gebaut wurden, Kirchen der verschiedensten Konfessionen, um sicher zu stellen, dass jeder Mensch nach seinem Glauben leben konnte.</span>",
+    "ID" : "match-WPD!WPD_PPP.00430-p189-190",
+    "pubDate" : "2005-03-28"
+  }, {
+    "author" : "Peter200,Srittau,AHoerstemeier",
+    "textClass" : "freizeit-unterhaltung reisen",
+    "corpusID" : "WPD",
+    "title" : "Palm Beach Gardens",
+    "foundries" : "corenlp corenlp/namedentities corenlp/namedentities/ne_dewac_175m_600 corenlp/namedentities corenlp/namedentities/ne_hgc_175m_600 xip xip/morpho xip/constituency xip/dependency treetagger treetagger/morpho connexor connexor/morpho connexor/syntax connexor/phrase mate mate/morpho mate/dependency opennlp opennlp/morpho base base/sentences base/paragraphs",
+    "tokenization" : "opennlp#tokens",
+    "field" : "tokens",
+    "startMore" : true,
+    "endMore" : true,
+    "docID" : "WPD_PPP.00430",
+    "snippet" : "<span class=\"context-left\">MacArtur stellte sich die Straßen der Stadt links und rechts gesäümt mit Blumen und Bäumen vor. Millionen von USD wurden dafür verwendet um dies zu ermöglichen. Letztlich wurde an allen Straßen und Wasserstraßen mächtige Kiefern und andere schattenspendende Laubbäume gepflanzt. Da er ein Naturliebhaber war, mussten alle älteren </span><span class=\"match\">Bäume</span><span class=\"context-right\"> stehen bleiben und Straßen darum herum geführt werden. Für die damalige Zeit für Amerika eine total neue Erfahrung. Dies verteuerte das Bauvorhaben erheblich, aber MacArthur ließ sich nicht beirren. Ebenso waren die ersten Gebäude, die gebaut wurden, Kirchen der verschiedensten Konfessionen, um sicher zu stellen, dass jeder Mensch nach seinem Glauben leben konnte.</span>",
+    "ID" : "match-WPD!WPD_PPP.00430-p223-224",
+    "pubDate" : "2005-03-28"
+  }, {
+    "author" : "Kdwnv,Doc Sleeve,Ninjamask",
+    "textClass" : "kultur film",
+    "corpusID" : "WPD",
+    "title" : "Mein Nachbar Totoro",
+    "foundries" : "opennlp opennlp/morpho treetagger treetagger/morpho xip xip/morpho xip/constituency xip/dependency connexor connexor/morpho connexor/syntax connexor/phrase corenlp corenlp/namedentities corenlp/namedentities/ne_dewac_175m_600 corenlp/namedentities corenlp/namedentities/ne_hgc_175m_600 base base/sentences base/paragraphs mate mate/morpho mate/dependency",
+    "tokenization" : "opennlp#tokens",
+    "field" : "tokens",
+    "startMore" : true,
+    "endMore" : true,
+    "docID" : "WPD_MMM.04644",
+    "snippet" : "<span class=\"context-left\">Ein Vater zieht mit seinen zwei Töchtern aufs Land, um in der Nähe seiner Frau sein zu können, die sich in einem Hospital von einer schweren Krankheit erholt. Nachdem sich die drei in dem anfangs etwas gruseligen Haus eingewöhnt haben, begegnet das jüngere Mädchen dem </span><span class=\"match\">Baum-</span><span class=\"context-right\"> und Naturgeist Totoro, und beide Mädchen schließen mit dem seltsamen Wesen schnell Freundschaft. Als sich das kleine Mädchen schließlich alleine aufmacht, um seine Mutter zu besuchen, hilft Totoro der älteren Schwester, die Ausreißerin wieder zu finden...</span>",
+    "ID" : "match-WPD!WPD_MMM.04644-p94-95",
+    "pubDate" : "2005-03-28"
+  }, {
+    "author" : "Nordelch,0",
+    "textClass" : "freizeit-unterhaltung reisen",
+    "corpusID" : "WPD",
+    "title" : "Norra Kvill Nationalpark",
+    "foundries" : "mate mate/morpho mate/dependency base base/sentences base/paragraphs opennlp opennlp/morpho treetagger treetagger/morpho xip xip/morpho xip/constituency xip/dependency corenlp corenlp/namedentities corenlp/namedentities/ne_dewac_175m_600 corenlp/namedentities corenlp/namedentities/ne_hgc_175m_600 connexor connexor/morpho connexor/syntax connexor/phrase",
+    "tokenization" : "opennlp#tokens",
+    "field" : "tokens",
+    "startMore" : true,
+    "endMore" : true,
+    "docID" : "WPD_NNN.05211",
+    "snippet" : "<span class=\"context-left\">Norra Kvill ist ein schwedischer Nationalpark der aus einem urwaldartigen Nadelwald im Hochland von Småland besteht. Seit über 150 Jahren wurde hier kein </span><span class=\"match\">Baum</span><span class=\"context-right\"> gefällt und manche Kiefern sind 350 Jahre alt, 35 m hoch und haben einen Umfang von 250 cm. Der wildnisartige Charakter entsteht durch umgefallene Bäume und gigantische Steinblöcke. Am Waldboden existiert eine reichhaltige Flora. 1986 wurde die Fläche des Nationalparks erweitert.</span>",
+    "ID" : "match-WPD!WPD_NNN.05211-p23-24",
+    "pubDate" : "2005-03-28"
+  }, {
+    "author" : "Nordelch,0",
+    "textClass" : "freizeit-unterhaltung reisen",
+    "corpusID" : "WPD",
+    "title" : "Norra Kvill Nationalpark",
+    "foundries" : "mate mate/morpho mate/dependency base base/sentences base/paragraphs opennlp opennlp/morpho treetagger treetagger/morpho xip xip/morpho xip/constituency xip/dependency corenlp corenlp/namedentities corenlp/namedentities/ne_dewac_175m_600 corenlp/namedentities corenlp/namedentities/ne_hgc_175m_600 connexor connexor/morpho connexor/syntax connexor/phrase",
+    "tokenization" : "opennlp#tokens",
+    "field" : "tokens",
+    "startMore" : true,
+    "endMore" : true,
+    "docID" : "WPD_NNN.05211",
+    "snippet" : "<span class=\"context-left\">Norra Kvill ist ein schwedischer Nationalpark der aus einem urwaldartigen Nadelwald im Hochland von Småland besteht. Seit über 150 Jahren wurde hier kein Baum gefällt und manche Kiefern sind 350 Jahre alt, 35 m hoch und haben einen Umfang von 250 cm. Der wildnisartige Charakter entsteht durch umgefallene </span><span class=\"match\">Bäume</span><span class=\"context-right\"> und gigantische Steinblöcke. Am Waldboden existiert eine reichhaltige Flora. 1986 wurde die Fläche des Nationalparks erweitert.</span>",
+    "ID" : "match-WPD!WPD_NNN.05211-p48-49",
+    "pubDate" : "2005-03-28"
+  }, {
+    "author" : "Vith-gilles,Head,Srbauer",
+    "textClass" : "wissenschaft populaerwissenschaft freizeit-unterhaltung reisen",
+    "corpusID" : "WPD",
+    "title" : "Rheindahlen",
+    "foundries" : "opennlp opennlp/morpho base base/sentences base/paragraphs xip xip/morpho xip/constituency xip/dependency treetagger treetagger/morpho mate mate/morpho mate/dependency corenlp corenlp/namedentities corenlp/namedentities/ne_dewac_175m_600 corenlp/namedentities corenlp/namedentities/ne_hgc_175m_600 connexor connexor/morpho connexor/syntax connexor/phrase",
+    "tokenization" : "opennlp#tokens",
+    "field" : "tokens",
+    "startMore" : true,
+    "endMore" : true,
+    "docID" : "WPD_RRR.04289",
+    "snippet" : "<span class=\"context-left\">Der Stadtteil Rheindahlen besteht aus folgenden Honschaften: Bau, </span><span class=\"match\">Baum</span><span class=\"context-right\">, Broich, Dorthausen, Eickelnberg, Gatzweiler, Genhausen, Genhodder, Genholland, Genhülsen, Gerkerath, Gerkerathmühle, Gerkerathwinkel, Griesbarth, Grotherath, Günhoven, Herdt, Hilderath, Knoor, Koch, Kothausen, Mennrath, Mennrathheide, Mennrathschmidt, Merreter, Peel, Saas, Schriefers, Schriefersmühle, Sittard, Sittardheide, Viehstrasse, Voosen, Wolfsittard, Woof, Wyenhütte und Rheindahlen.</span>",
+    "ID" : "match-WPD!WPD_RRR.04289-p99-100",
+    "pubDate" : "2005-03-28"
+  }, {
+    "author" : "OTTO.R.M.,Factumquintus,Necrophorus",
+    "textClass" : "wissenschaft populaerwissenschaft",
+    "corpusID" : "WPD",
+    "title" : "Chamäleons",
+    "foundries" : "base base/sentences base/paragraphs opennlp opennlp/morpho corenlp corenlp/namedentities corenlp/namedentities/ne_dewac_175m_600 corenlp/namedentities corenlp/namedentities/ne_hgc_175m_600 mate mate/morpho mate/dependency treetagger treetagger/morpho connexor connexor/morpho connexor/syntax connexor/phrase xip xip/morpho xip/constituency xip/dependency",
+    "tokenization" : "opennlp#tokens",
+    "field" : "tokens",
+    "startMore" : true,
+    "endMore" : true,
+    "docID" : "WPD_CCC.02337",
+    "snippet" : "<span class=\"context-left\">Sie sind </span><span class=\"match\">baum-</span><span class=\"context-right\"> oder strauchbewohnende, und zum Teil auch Erdbewohnende Echsen mit einem seitlich abgeflachten Rumpf. Ein charakteristisches Merkmal dieser Tiere ist die herausschleuderbare Zunge, der Schwanz, der eingerollt werden kann und die Augen, die sich unabhängig voneinander bewegen und gemeinsam ein Blickfeld von 342° ermöglichen.</span>",
+    "ID" : "match-WPD!WPD_CCC.02337-p37-38",
+    "pubDate" : "2005-03-28"
+  }, {
+    "author" : "ErikDunsing,Raymond,NiKo",
+    "textClass" : "freizeit-unterhaltung reisen",
+    "corpusID" : "WPD",
+    "title" : "Moerser Schloss",
+    "foundries" : "treetagger treetagger/morpho corenlp corenlp/namedentities corenlp/namedentities/ne_dewac_175m_600 corenlp/namedentities corenlp/namedentities/ne_hgc_175m_600 connexor connexor/morpho connexor/syntax connexor/phrase xip xip/morpho xip/constituency xip/dependency mate mate/morpho mate/dependency opennlp opennlp/morpho base base/sentences base/paragraphs",
+    "tokenization" : "opennlp#tokens",
+    "field" : "tokens",
+    "startMore" : true,
+    "endMore" : true,
+    "docID" : "WPD_MMM.08381",
+    "snippet" : "<span class=\"context-left\">Der östliche Teil des Schlosses wurde abgerissen und eine Windmühle sowie ein Wohnhaus sollten dort gebaut werden. Durch Probleme der Besitzverhältnisse der zum Schlosskauf gehörenden Grundstücke wurde es 1810 wieder weiterverkauft. Der Textilunternehmer Witgens, welcher der bedeutendste Unternehmer in Moers war, kaufte es für 2000 Franc. Er hatte schon zuvor in die östlich des Schlosses gelegenen Gebäude Wohnhaus und Fabrik gebaut. Die inneren Festungsanlagen wurden abgerissen und mit </span><span class=\"match\">Bäumen</span><span class=\"context-right\"> bepflanzt. Teile des Schlossgrundstückes wurden verkauft und von den neuen Besitzern in Gärten und Parkanlagen umgewandelt. Witgens ließ die mit Gräben durchzogene Wildnis 1838 in den heutigen Schlosspark umbauen. Das Schloss und der Park gingen 1905 in die Hand der Stadt über, die sie heute noch besitzt.</span>",
+    "ID" : "match-WPD!WPD_MMM.08381-p1449-1450",
+    "pubDate" : "2005-03-28"
+  }, {
+    "author" : "ErikDunsing,Raymond,NiKo",
+    "textClass" : "freizeit-unterhaltung reisen",
+    "corpusID" : "WPD",
+    "title" : "Moerser Schloss",
+    "foundries" : "treetagger treetagger/morpho corenlp corenlp/namedentities corenlp/namedentities/ne_dewac_175m_600 corenlp/namedentities corenlp/namedentities/ne_hgc_175m_600 connexor connexor/morpho connexor/syntax connexor/phrase xip xip/morpho xip/constituency xip/dependency mate mate/morpho mate/dependency opennlp opennlp/morpho base base/sentences base/paragraphs",
+    "tokenization" : "opennlp#tokens",
+    "field" : "tokens",
+    "startMore" : true,
+    "endMore" : true,
+    "docID" : "WPD_MMM.08381",
+    "snippet" : "<span class=\"context-left\">Seit der Schleifung der Festungsanlagen durch Friedrich den Großen im Jahre 1762 waren die Festungsinsel und die einstigen Steinwälle und Gräben immer mehr verkommen. Dorngestrüpp wucherte über der verfallenen Insel und der Moerser Bürger mied es, dort entlang zu wandern. Nur vereinzelte Ziegenherden, die anspruchslos genug waren, wurden zum Grasen in die Wildnis geschickt. Wintgens, der den größten Teil der Anlage bereits gekauft hatte, ließ die Wildnis in einen Schlosspark, den heutigen Stadtpark, umbauen. Eigens zu diesem Zwecke ließ er den Hofarchitekten Maximilian Weyhe aus Düsseldorf kommen. Dieser hatte schon einige bedeutende Parkanlagen gestaltet, sein Abbild ist heute auf einer Bronzeplatte im Stadtpark verewigt. Weyhe wollte aber keinen Park in barocken geometrischen Formen bauen. Der Geschmack der Zeit war viel mehr hin zum Naturpark gewandert. Man legte Wert auf runde Formen, wilde freie </span><span class=\"match\">Bäume</span><span class=\"context-right\"> und große Steine im Park. Alles sollte natürlich wirken und nicht mit dem Zeichenbrett konstruiert. Weyhe ließ sogar eine beträchtliche Anzahl an exotischen Bäumen pflanzen. Interessant ist auch, dass er eine Turmruine anlegen ließ, da dies zu dieser Zeit als &quot;schick&quot; im Garten galt (genau wie Säulen oder Ähnliches). Auch wurden die Wasserläufe gekonnt in die Anlage integriert, und auf den einstigen Verteidigungswällen und Dämmen wurden Wege angelegt, die der Moerser Bürger heute noch gerne für einen Spaziergang durch den wunderbaren Park nutzt. Erstmals konnte der Bürger den Park jedoch im Jahre 1905 betreten, denn in diesem Jahre fiel der Besitz des Schlosses und des Parks in die Hände der Stadt Moers.</span>",
+    "ID" : "match-WPD!WPD_MMM.08381-p2076-2077",
+    "pubDate" : "2005-03-28"
+  }, {
+    "author" : "ErikDunsing,Raymond,NiKo",
+    "textClass" : "freizeit-unterhaltung reisen",
+    "corpusID" : "WPD",
+    "title" : "Moerser Schloss",
+    "foundries" : "treetagger treetagger/morpho corenlp corenlp/namedentities corenlp/namedentities/ne_dewac_175m_600 corenlp/namedentities corenlp/namedentities/ne_hgc_175m_600 connexor connexor/morpho connexor/syntax connexor/phrase xip xip/morpho xip/constituency xip/dependency mate mate/morpho mate/dependency opennlp opennlp/morpho base base/sentences base/paragraphs",
+    "tokenization" : "opennlp#tokens",
+    "field" : "tokens",
+    "startMore" : true,
+    "endMore" : true,
+    "docID" : "WPD_MMM.08381",
+    "snippet" : "<span class=\"context-left\">Seit der Schleifung der Festungsanlagen durch Friedrich den Großen im Jahre 1762 waren die Festungsinsel und die einstigen Steinwälle und Gräben immer mehr verkommen. Dorngestrüpp wucherte über der verfallenen Insel und der Moerser Bürger mied es, dort entlang zu wandern. Nur vereinzelte Ziegenherden, die anspruchslos genug waren, wurden zum Grasen in die Wildnis geschickt. Wintgens, der den größten Teil der Anlage bereits gekauft hatte, ließ die Wildnis in einen Schlosspark, den heutigen Stadtpark, umbauen. Eigens zu diesem Zwecke ließ er den Hofarchitekten Maximilian Weyhe aus Düsseldorf kommen. Dieser hatte schon einige bedeutende Parkanlagen gestaltet, sein Abbild ist heute auf einer Bronzeplatte im Stadtpark verewigt. Weyhe wollte aber keinen Park in barocken geometrischen Formen bauen. Der Geschmack der Zeit war viel mehr hin zum Naturpark gewandert. Man legte Wert auf runde Formen, wilde freie Bäume und große Steine im Park. Alles sollte natürlich wirken und nicht mit dem Zeichenbrett konstruiert. Weyhe ließ sogar eine beträchtliche Anzahl an exotischen </span><span class=\"match\">Bäumen</span><span class=\"context-right\"> pflanzen. Interessant ist auch, dass er eine Turmruine anlegen ließ, da dies zu dieser Zeit als &quot;schick&quot; im Garten galt (genau wie Säulen oder Ähnliches). Auch wurden die Wasserläufe gekonnt in die Anlage integriert, und auf den einstigen Verteidigungswällen und Dämmen wurden Wege angelegt, die der Moerser Bürger heute noch gerne für einen Spaziergang durch den wunderbaren Park nutzt. Erstmals konnte der Bürger den Park jedoch im Jahre 1905 betreten, denn in diesem Jahre fiel der Besitz des Schlosses und des Parks in die Hände der Stadt Moers.</span>",
+    "ID" : "match-WPD!WPD_MMM.08381-p2100-2101",
+    "pubDate" : "2005-03-28"
+  }, {
+    "author" : "Gabor,Asb,ChristophDemmer",
+    "textClass" : "wissenschaft populaerwissenschaft",
+    "corpusID" : "WPD",
+    "title" : "Ramismus",
+    "foundries" : "corenlp corenlp/namedentities corenlp/namedentities/ne_dewac_175m_600 corenlp/namedentities corenlp/namedentities/ne_hgc_175m_600 base base/sentences base/paragraphs opennlp opennlp/morpho treetagger treetagger/morpho mate mate/morpho mate/dependency xip xip/morpho xip/constituency xip/dependency connexor connexor/morpho connexor/syntax connexor/phrase",
+    "tokenization" : "opennlp#tokens",
+    "field" : "tokens",
+    "startMore" : true,
+    "endMore" : true,
+    "docID" : "WPD_RRR.00717",
+    "snippet" : "<span class=\"context-left\">Siehe auch: Ramifizierung, Ramifikation, Organon, Kategorienlehre, </span><span class=\"match\">Baum</span><span class=\"context-right\"> des Wissens, Arbor porphyriana, Philippismus, Neuaristotelismus, Melanchthonismus, Calvinismus, Reformation</span>",
+    "ID" : "match-WPD!WPD_RRR.00717-p159-160",
+    "pubDate" : "2005-03-28"
+  }, {
+    "author" : "Martin-vogel,Sybilla,Gorgodon",
+    "textClass" : "freizeit-unterhaltung reisen",
+    "corpusID" : "WPD",
+    "title" : "Khasi",
+    "foundries" : "base base/sentences base/paragraphs connexor connexor/morpho connexor/syntax connexor/phrase opennlp opennlp/morpho xip xip/morpho xip/constituency xip/dependency corenlp corenlp/namedentities corenlp/namedentities/ne_dewac_175m_600 corenlp/namedentities corenlp/namedentities/ne_hgc_175m_600 mate mate/morpho mate/dependency treetagger treetagger/morpho",
+    "tokenization" : "opennlp#tokens",
+    "field" : "tokens",
+    "startMore" : true,
+    "endMore" : true,
+    "docID" : "WPD_KKK.03618",
+    "snippet" : "<span class=\"context-left\">nur alleinstehende </span><span class=\"match\">Bäume</span><span class=\"context-right\"> dürfen geschlagen werden, keine Bäume aus einem Wald heraus</span>",
+    "ID" : "match-WPD!WPD_KKK.03618-p830-831",
+    "pubDate" : "2005-03-28"
+  }, {
+    "author" : "Martin-vogel,Sybilla,Gorgodon",
+    "textClass" : "freizeit-unterhaltung reisen",
+    "corpusID" : "WPD",
+    "title" : "Khasi",
+    "foundries" : "base base/sentences base/paragraphs connexor connexor/morpho connexor/syntax connexor/phrase opennlp opennlp/morpho xip xip/morpho xip/constituency xip/dependency corenlp corenlp/namedentities corenlp/namedentities/ne_dewac_175m_600 corenlp/namedentities corenlp/namedentities/ne_hgc_175m_600 mate mate/morpho mate/dependency treetagger treetagger/morpho",
+    "tokenization" : "opennlp#tokens",
+    "field" : "tokens",
+    "startMore" : true,
+    "endMore" : true,
+    "docID" : "WPD_KKK.03618",
+    "snippet" : "<span class=\"context-left\">nur alleinstehende Bäume dürfen geschlagen werden, keine </span><span class=\"match\">Bäume</span><span class=\"context-right\"> aus einem Wald heraus</span>",
+    "ID" : "match-WPD!WPD_KKK.03618-p835-836",
+    "pubDate" : "2005-03-28"
+  }, {
+    "author" : "Stechlin,Orchi,Vlado",
+    "textClass" : "freizeit-unterhaltung reisen",
+    "corpusID" : "WPD",
+    "title" : "Waldvöglein",
+    "foundries" : "xip xip/morpho xip/constituency xip/dependency corenlp corenlp/namedentities corenlp/namedentities/ne_dewac_175m_600 corenlp/namedentities corenlp/namedentities/ne_hgc_175m_600 connexor connexor/morpho connexor/syntax connexor/phrase mate mate/morpho mate/dependency base base/sentences base/paragraphs treetagger treetagger/morpho opennlp opennlp/morpho",
+    "tokenization" : "opennlp#tokens",
+    "field" : "tokens",
+    "startMore" : true,
+    "endMore" : true,
+    "docID" : "WPD_WWW.00689",
+    "snippet" : "<span class=\"context-left\">Cephalanthera schaberi </span><span class=\"match\">Baum</span><span class=\"context-right\">.</span>",
+    "ID" : "match-WPD!WPD_WWW.00689-p158-159",
+    "pubDate" : "2005-03-28"
+  }, {
+    "author" : "Boris Kaiser,Plattmaster,Semon",
+    "textClass" : "freizeit-unterhaltung reisen",
+    "corpusID" : "WPD",
+    "title" : "Unterliek",
+    "foundries" : "connexor connexor/morpho connexor/syntax connexor/phrase opennlp opennlp/morpho corenlp corenlp/namedentities corenlp/namedentities/ne_dewac_175m_600 corenlp/namedentities corenlp/namedentities/ne_hgc_175m_600 mate mate/morpho mate/dependency treetagger treetagger/morpho base base/sentences base/paragraphs xip xip/morpho xip/constituency xip/dependency",
+    "tokenization" : "opennlp#tokens",
+    "field" : "tokens",
+    "startMore" : true,
+    "endMore" : true,
+    "docID" : "WPD_UUU.01708",
+    "snippet" : "<span class=\"context-left\">Befindet sich das Unterliek an einem </span><span class=\"match\">Baum</span><span class=\"context-right\"> (z.B. beim Großsegel), spricht man auch von dem Baumliek. Dessen Spannung, d.h. der Zug, unter dem das Segeltuch im Bereich des Unterlieks steht, wird über den Unterliekstrecker (eine Leine) gesteuert, der am Schothorn befestigt wird. Wird der Unterliekstrecker stark durchgesetzt (d.h. viel Zug mit dieser Leine ausgeübt), erhält das Unterliek ein flaches Profil (d.h. ist bei seitlichem Winddruck wenig gewölbt).</span>",
+    "ID" : "match-WPD!WPD_UUU.01708-p25-26",
+    "pubDate" : "2005-03-28"
+  }, {
+    "author" : "Boris Kaiser,Plattmaster,Semon",
+    "textClass" : "freizeit-unterhaltung reisen",
+    "corpusID" : "WPD",
+    "title" : "Unterliek",
+    "foundries" : "connexor connexor/morpho connexor/syntax connexor/phrase opennlp opennlp/morpho corenlp corenlp/namedentities corenlp/namedentities/ne_dewac_175m_600 corenlp/namedentities corenlp/namedentities/ne_hgc_175m_600 mate mate/morpho mate/dependency treetagger treetagger/morpho base base/sentences base/paragraphs xip xip/morpho xip/constituency xip/dependency",
+    "tokenization" : "opennlp#tokens",
+    "field" : "tokens",
+    "startMore" : true,
+    "endMore" : true,
+    "docID" : "WPD_UUU.01708",
+    "snippet" : "<span class=\"context-left\">Man kann ein Segel an einem </span><span class=\"match\">Baum</span><span class=\"context-right\"> mit losem Unterliek fahren (z.B. bei Rollgroßanlagen): Dann ist das Segel im Bereich des Unterlieks nur am Hals und Schothorn mit dem Baum verbunden. Oder das Unterliek ist auf seiner ganzen Länge am Baum befestigt. Dies geschieht häufig, indem in das Unterliek zur Verdickung desselben ein Tau eingenäht wird und dieses dann in eine Keep (d.h. eine Nut) im Baum eingeführt wird.</span>",
+    "ID" : "match-WPD!WPD_UUU.01708-p92-93",
+    "pubDate" : "2005-03-28"
+  }, {
+    "author" : "Boris Kaiser,Plattmaster,Semon",
+    "textClass" : "freizeit-unterhaltung reisen",
+    "corpusID" : "WPD",
+    "title" : "Unterliek",
+    "foundries" : "connexor connexor/morpho connexor/syntax connexor/phrase opennlp opennlp/morpho corenlp corenlp/namedentities corenlp/namedentities/ne_dewac_175m_600 corenlp/namedentities corenlp/namedentities/ne_hgc_175m_600 mate mate/morpho mate/dependency treetagger treetagger/morpho base base/sentences base/paragraphs xip xip/morpho xip/constituency xip/dependency",
+    "tokenization" : "opennlp#tokens",
+    "field" : "tokens",
+    "startMore" : true,
+    "endMore" : true,
+    "docID" : "WPD_UUU.01708",
+    "snippet" : "<span class=\"context-left\">Man kann ein Segel an einem Baum mit losem Unterliek fahren (z.B. bei Rollgroßanlagen): Dann ist das Segel im Bereich des Unterlieks nur am Hals und Schothorn mit dem </span><span class=\"match\">Baum</span><span class=\"context-right\"> verbunden. Oder das Unterliek ist auf seiner ganzen Länge am Baum befestigt. Dies geschieht häufig, indem in das Unterliek zur Verdickung desselben ein Tau eingenäht wird und dieses dann in eine Keep (d.h. eine Nut) im Baum eingeführt wird.</span>",
+    "ID" : "match-WPD!WPD_UUU.01708-p115-116",
+    "pubDate" : "2005-03-28"
+  }, {
+    "author" : "Boris Kaiser,Plattmaster,Semon",
+    "textClass" : "freizeit-unterhaltung reisen",
+    "corpusID" : "WPD",
+    "title" : "Unterliek",
+    "foundries" : "connexor connexor/morpho connexor/syntax connexor/phrase opennlp opennlp/morpho corenlp corenlp/namedentities corenlp/namedentities/ne_dewac_175m_600 corenlp/namedentities corenlp/namedentities/ne_hgc_175m_600 mate mate/morpho mate/dependency treetagger treetagger/morpho base base/sentences base/paragraphs xip xip/morpho xip/constituency xip/dependency",
+    "tokenization" : "opennlp#tokens",
+    "field" : "tokens",
+    "startMore" : true,
+    "endMore" : true,
+    "docID" : "WPD_UUU.01708",
+    "snippet" : "<span class=\"context-left\">Man kann ein Segel an einem Baum mit losem Unterliek fahren (z.B. bei Rollgroßanlagen): Dann ist das Segel im Bereich des Unterlieks nur am Hals und Schothorn mit dem Baum verbunden. Oder das Unterliek ist auf seiner ganzen Länge am </span><span class=\"match\">Baum</span><span class=\"context-right\"> befestigt. Dies geschieht häufig, indem in das Unterliek zur Verdickung desselben ein Tau eingenäht wird und dieses dann in eine Keep (d.h. eine Nut) im Baum eingeführt wird.</span>",
+    "ID" : "match-WPD!WPD_UUU.01708-p126-127",
+    "pubDate" : "2005-03-28"
+  }, {
+    "author" : "Boris Kaiser,Plattmaster,Semon",
+    "textClass" : "freizeit-unterhaltung reisen",
+    "corpusID" : "WPD",
+    "title" : "Unterliek",
+    "foundries" : "connexor connexor/morpho connexor/syntax connexor/phrase opennlp opennlp/morpho corenlp corenlp/namedentities corenlp/namedentities/ne_dewac_175m_600 corenlp/namedentities corenlp/namedentities/ne_hgc_175m_600 mate mate/morpho mate/dependency treetagger treetagger/morpho base base/sentences base/paragraphs xip xip/morpho xip/constituency xip/dependency",
+    "tokenization" : "opennlp#tokens",
+    "field" : "tokens",
+    "startMore" : true,
+    "endMore" : true,
+    "docID" : "WPD_UUU.01708",
+    "snippet" : "<span class=\"context-left\">Man kann ein Segel an einem Baum mit losem Unterliek fahren (z.B. bei Rollgroßanlagen): Dann ist das Segel im Bereich des Unterlieks nur am Hals und Schothorn mit dem Baum verbunden. Oder das Unterliek ist auf seiner ganzen Länge am Baum befestigt. Dies geschieht häufig, indem in das Unterliek zur Verdickung desselben ein Tau eingenäht wird und dieses dann in eine Keep (d.h. eine Nut) im </span><span class=\"match\">Baum</span><span class=\"context-right\"> eingeführt wird.</span>",
+    "ID" : "match-WPD!WPD_UUU.01708-p152-153",
+    "pubDate" : "2005-03-28"
+  }, {
+    "author" : "Boris Kaiser,Plattmaster,Semon",
+    "textClass" : "freizeit-unterhaltung reisen",
+    "corpusID" : "WPD",
+    "title" : "Unterliek",
+    "foundries" : "connexor connexor/morpho connexor/syntax connexor/phrase opennlp opennlp/morpho corenlp corenlp/namedentities corenlp/namedentities/ne_dewac_175m_600 corenlp/namedentities corenlp/namedentities/ne_hgc_175m_600 mate mate/morpho mate/dependency treetagger treetagger/morpho base base/sentences base/paragraphs xip xip/morpho xip/constituency xip/dependency",
+    "tokenization" : "opennlp#tokens",
+    "field" : "tokens",
+    "startMore" : true,
+    "endMore" : true,
+    "docID" : "WPD_UUU.01708",
+    "snippet" : "<span class=\"context-left\">Wird das Segel ohne </span><span class=\"match\">Baum</span><span class=\"context-right\"> gefahren (z.B: Fock oder Genua bei Amwindkursen), wird die Schot direkt am Schothorn befestigt. Die Profilierung des Unterlieks, d.h. ob es flacher oder gewölbter ist, wird dann über den Zug der Schot und die Lage des Holepunktes gesteuert.</span>",
+    "ID" : "match-WPD!WPD_UUU.01708-p159-160",
+    "pubDate" : "2005-03-28"
+  }, {
+    "author" : "Crux,Vic Fontaine,BS Thurner Hof",
+    "textClass" : "freizeit-unterhaltung reisen",
+    "corpusID" : "WPD",
+    "title" : "Ananasrenette",
+    "foundries" : "connexor connexor/morpho connexor/syntax connexor/phrase base base/sentences base/paragraphs corenlp corenlp/namedentities corenlp/namedentities/ne_dewac_175m_600 corenlp/namedentities corenlp/namedentities/ne_hgc_175m_600 mate mate/morpho mate/dependency treetagger treetagger/morpho xip xip/morpho xip/constituency xip/dependency opennlp opennlp/morpho",
+    "tokenization" : "opennlp#tokens",
+    "field" : "tokens",
+    "startMore" : true,
+    "endMore" : true,
+    "docID" : "WPD_AAA.07202",
+    "snippet" : "<span class=\"context-left\">Die Früchte der Ananasrenette mit ihrem besonderem, sortentypischen Aroma bleiben eher klein. Sie reifen Mitte bis Ende Oktober und bleiben bei entsprechender Lagerung bis Februar genussreif. Der </span><span class=\"match\">Baum</span><span class=\"context-right\"> ist anfällig für Mehltau und Obstbaumkrebs und reagiert auf trockene Witterungsverhältnisse mit der Ausbildung sehr kleiner, wenig aromatischer Früchte.</span>",
+    "ID" : "match-WPD!WPD_AAA.07202-p78-79",
+    "pubDate" : "2005-03-28"
+  }, {
+    "author" : "Feinschreiber,Triebtäter,Stefan Kühn",
+    "textClass" : "sport fussball",
+    "corpusID" : "WPD",
+    "title" : "Anita Kulcsár",
+    "foundries" : "xip xip/morpho xip/constituency xip/dependency mate mate/morpho mate/dependency corenlp corenlp/namedentities corenlp/namedentities/ne_dewac_175m_600 corenlp/namedentities corenlp/namedentities/ne_hgc_175m_600 opennlp opennlp/morpho base base/sentences base/paragraphs connexor connexor/morpho connexor/syntax connexor/phrase treetagger treetagger/morpho",
+    "tokenization" : "opennlp#tokens",
+    "field" : "tokens",
+    "startMore" : true,
+    "endMore" : true,
+    "docID" : "WPD_KKK.10701",
+    "snippet" : "<span class=\"context-left\">Anita Kulcsár war am Morgen des 19. Januar 2005 von ihrer Wohnung in Sukoró aus unterwegs zum Vormittagstraining nach Dunaújváros. Auf der Landstraße 6207 zwischen Velence und Pusztaszabolcs kam sie auf der glatten Fahrbahn ins Schleudern. Der Wagen kam von der Straße ab und prallte unkontrolliert gegen einen </span><span class=\"match\">Baum</span><span class=\"context-right\">. Sie starb sofort am Unfallort.</span>",
+    "ID" : "match-WPD!WPD_KKK.10701-p193-194",
+    "pubDate" : "2005-03-28"
+  }, {
+    "author" : "Franz Xaver,Rosenzweig,Naddy",
+    "textClass" : "wissenschaft populaerwissenschaft",
+    "corpusID" : "WPD",
+    "title" : "Bussardartige",
+    "foundries" : "base base/sentences base/paragraphs xip xip/morpho xip/constituency xip/dependency mate mate/morpho opennlp opennlp/morpho treetagger treetagger/morpho corenlp corenlp/namedentities corenlp/namedentities/ne_dewac_175m_600 corenlp/namedentities corenlp/namedentities/ne_hgc_175m_600 connexor connexor/morpho connexor/syntax connexor/phrase",
+    "tokenization" : "opennlp#tokens",
+    "field" : "tokens",
+    "startMore" : true,
+    "endMore" : true,
+    "docID" : "WPD_BBB.15757",
+    "snippet" : "<span class=\"context-left\">Die Flugfähigkeit der Bussardartigen ist wesentlich schwerfälliger als die der wendigen Habichte oder Falken. Dafür ist ihr Körperbau besonders gut für lange Gleitflüge geeignet. Außerdem sind sie in der Wahl ihres Futters anpassungsfähig. In der Regel werden kleine bis mittlere Säugetiere, von manchen Arten (beispielsweise dem Seeadler (Haliaeetus)) Fische oder Wasservögel gejagt. Der südostasiatische Affenadler (Pithecophaga jefferyi) oder der südamerikanische Würgadler (Morphnus guianensis) jagen auch in </span><span class=\"match\">Bäumen</span><span class=\"context-right\"> lebende Affen und Vögel.</span>",
+    "ID" : "match-WPD!WPD_BBB.15757-p162-163",
+    "pubDate" : "2005-03-28"
+  }, {
+    "author" : "Steschke,Asb,Paethon",
+    "textClass" : "freizeit-unterhaltung reisen",
+    "corpusID" : "WPD",
+    "title" : "Kudzu (Pflanze)",
+    "foundries" : "base base/sentences base/paragraphs opennlp opennlp/morpho mate mate/morpho mate/dependency connexor connexor/morpho connexor/syntax connexor/phrase xip xip/morpho xip/constituency xip/dependency treetagger treetagger/morpho corenlp corenlp/namedentities corenlp/namedentities/ne_dewac_175m_600 corenlp/namedentities corenlp/namedentities/ne_hgc_175m_600",
+    "tokenization" : "opennlp#tokens",
+    "field" : "tokens",
+    "startMore" : true,
+    "endMore" : true,
+    "docID" : "WPD_KKK.10525",
+    "snippet" : "<span class=\"context-left\">Leider fand Kudzu im Südosten sehr gute Wachstumsbedingungen und ohne die natürlichen Feinde die in Japan vorkommen breitete er sich explosionsartig aus. Heute sind ca. 30.000 km² von Kudzu überwuchert und man wird der Plage, wegen der enormen Wachstumsgeschwindigkeit von bis zu 30cm am Tag, kaum noch Herr. Die Pflanze überwuchert in kürzester Zeit Häuser, </span><span class=\"match\">Bäume</span><span class=\"context-right\"> und alles was ihr im Weg steht. Sie kann (wenn sie nicht bekämpft wird) innerhalb weniger Monate ein Haus komplett überwuchern.</span>",
+    "ID" : "match-WPD!WPD_KKK.10525-p136-137",
+    "pubDate" : "2005-03-28"
+  }, {
+    "author" : "Filzstift,Alexander Sommer,TheK",
+    "textClass" : "freizeit-unterhaltung reisen",
+    "corpusID" : "WPD",
+    "title" : "Neuseeland",
+    "foundries" : "xip xip/morpho xip/constituency xip/dependency corenlp corenlp/namedentities corenlp/namedentities/ne_dewac_175m_600 corenlp/namedentities corenlp/namedentities/ne_hgc_175m_600 mate mate/morpho mate/dependency connexor connexor/morpho connexor/syntax connexor/phrase treetagger treetagger/morpho base base/sentences base/paragraphs opennlp opennlp/morpho",
+    "tokenization" : "opennlp#tokens",
+    "field" : "tokens",
+    "startMore" : true,
+    "endMore" : true,
+    "docID" : "WPD_NNN.02848",
+    "snippet" : "<span class=\"context-left\">Als die Europäer ins Land kamen, waren etwa 70 % der Landesfläche bewaldet. Mittlerweile sind noch etwa 15 % des Landes von einheimischen Wäldern bedeckt, dazu kommen weitere etwa 5 % Fläche mit schnellwachsenden importierten </span><span class=\"match\">Bäumen</span><span class=\"context-right\"> wie Monterey Pine und Redwood für die neuseeländische Forstwirtschaft. Wesentliche Teile der ursprünglichen Wälder stehen unter Naturschutz, zu guten Teilen in Nationalparks und so genannten Forest Parks.</span>",
+    "ID" : "match-WPD!WPD_NNN.02848-p1139-1140",
+    "pubDate" : "2005-03-28"
+  } ],
+  "totalResults" : 4053,
+  "startIndex" : 0,
+  "itemsPerPage" : 25,
+  "benchmarkSearchResults" : "6.02 ms",
+  "benchmarkHitCounter" : "6.795 ms",
+  "error" : null,
+  "request" : {
+    "@context" : "http://ids-mannheim.de/ns/KorAP/json-ld/v0.1/context.jsonld",
+    "query" : {
+      "@type" : "korap:token",
+      "wrap" : {
+        "@type" : "korap:term",
+        "key" : "baum",
+        "layer" : "lemma",
+        "match" : "match:eq"
+      }
+    },
+    "collections" : [ {
+      "@type" : "korap:meta-filter",
+      "@value" : {
+        "@type" : "korap:term",
+        "@field" : "korap:field#corpusID",
+        "@value" : "WPD"
+      }
+    } ],
+    "meta" : {
+      "startPage" : 1,
+      "context" : "paragraph"
+    }
+  },
+  "context" : "p"
+}
diff --git a/lib/Korap/Plugin/KorapTagHelpers.pm b/lib/Korap/Plugin/KorapTagHelpers.pm
new file mode 100644
index 0000000..b54161c
--- /dev/null
+++ b/lib/Korap/Plugin/KorapTagHelpers.pm
@@ -0,0 +1,20 @@
+package Korap::Plugin::KorapTagHelpers;
+use Mojo::Base 'Mojolicious::Plugin';
+use Mojo::ByteStream 'b';
+use Mojo::Util qw/xml_escape/;
+
+sub register {
+  my ($plugin, $mojo) = @_;
+
+  $mojo->helper(
+    korap_tut_query => sub {
+      my ($c, $ql, $q) = @_;
+      $q = xml_escape $q;
+      b('<code class="query tutorial" onclick="top.useQuery(this)" ' .
+	  qq!data-query="$q" data-query-language="$ql"><pre>! .
+	    $q . '</pre></code>');
+    }
+  );
+};
+
+1;
diff --git a/lib/Korap/Search.pm b/lib/Korap/Search.pm
index 4773649..fd9e6d5 100644
--- a/lib/Korap/Search.pm
+++ b/lib/Korap/Search.pm
@@ -4,8 +4,10 @@
 # This action will render a template
 sub remote {
   my $c = shift;
+  $c->layout('default');
+  $c->title('KorAP');
 
-  if ($c->param('action') eq 'inspect') {
+  if ((scalar $c->param('action') // '') eq 'inspect') {
     my $api = $c->config('KorAP')->{api};
     my $url = Mojo::URL->new($api)->path('resource/query');
     $url->query({
@@ -20,29 +22,29 @@
     };
 
     $c->param(cutoff => 1);
-    return $c->render(template => 'query', layout => 'default', title => 'KorAP');
+    return $c->render(template => 'query');
+  }
+
+  elsif ($c->param('snippet')) {
+    $c->layout('snippet');
   };
 
-  # Render template "example/welcome.html.ep" with message
   $c->render(template => 'search');
 };
 
+
+
 sub info {
   my $c = shift;
   my $api = $c->config('KorAP')->{api};
   my $src = $c->stash('resource');
-  $src = 'VirtualCollection' if $src eq 'collection';
-  $src = 'Corpus' if $src eq 'corpus';
-
-  my $url = Mojo::URL->new($api)->path('resource/' . $src);
-  if (my $response = $c->ua->get($url)->success) {
-    $c->render(json => $c->notifications(json => $response->json));
-  };
+  $c->render(json => $c->notifications(json => $c->info_on($src)));
 };
 
+
 1;
 
 
 __END__
 
-[{"id":1,"name":"Wikipedia","description":"Die freie Enzyklopädie","owner":0,"created":1401193381119,"managed":true,"shared":false,"foundries":"base;corenlp;mate;mpt;opennlp;tt;xip","refCorpus":"","query":"[{\"@type\":\"korap:meta-filter\",\"@value\":{\"@type\":\"korap:term\",\"@field\":\"korap:field#corpusID\",\"@value\":\"WPD\"}}]","cache":false,"stats":"{\"documents\":196510,\"tokens\":51545081,\"sentences\":4116282,\"paragraphs\":2034752}"}]
+[{"shared":false,"id":1,"managed":true,"created":1401193381119,"stats":{"documents":196510,"tokens":51545081,"sentences":4116282,"paragraphs":2034752},"query":[{"@type":"korap:meta-filter","@value":{"@type":"korap:term","@field":"korap:field#corpusID","@value":"WPD"}}],"description":"Die freie Enzyklopädie","name":"Wikipedia","foundries":"base;corenlp;mate;mpt;opennlp;tt;xip"}]
diff --git a/lib/Korap/Tutorial.pm b/lib/Korap/Tutorial.pm
new file mode 100644
index 0000000..224190f
--- /dev/null
+++ b/lib/Korap/Tutorial.pm
@@ -0,0 +1,17 @@
+package Korap::Tutorial;
+use Mojo::Base 'Mojolicious::Controller';
+
+sub page {
+  my $c = shift;
+  $c->layout('snippet');
+  $c->title('KorAP');
+
+  my $page = $c->stash('tutorial');
+
+  $c->render(template => 'tutorial');
+};
+
+1;
+
+
+__END__