Now working full non-blocking (maybe leaky here and there)
diff --git a/lib/Korap/API.pm b/lib/Korap/API.pm
index 59ea869..70ec277 100644
--- a/lib/Korap/API.pm
+++ b/lib/Korap/API.pm
@@ -8,7 +8,8 @@
 
 # Todo: Add fixtures
 # Todo: Support search in corpus and virtualcollection
-
+# Todo: Support caching everywhere!
+# Todo: Correct use of stash info everywhere!
 
 # Register the plugin
 sub register {
@@ -34,43 +35,30 @@
   my $self = shift;
   my $index = shift;
 
+  # Get controller
   my $c = $index->controller;
 
-  # No query defined
-  return unless $index->query;
-
   # If there is a callback, do async
   my $cb = pop if ref $_[-1] && ref $_[-1] eq 'CODE';
 
-  my %param = @_;
+  # No query defined
+  unless ($index->query) {
+    return $cb->($index) if $cb;
+    return;
+  };
 
-  # Set cutoff from param
-  $index->cutoff(delete $param{cutoff});
-
-  # Set query language
-  $index->query_language(delete $param{query_language} // 'poliqarp');
-
-  # TODO: This should also be a query parameter
-  $index->no_cache(1) if $param{no_cache} or $c->param('no_cache');
-
-  my %query;
-  $query{q}      = $index->query;
-  $query{ql}     = $index->query_language;
-  $query{page}   = $index->start_page;
-  $query{count}  = $index->items_per_page;
-  $query{cutoff} = 'true' if $index->cutoff;
-
-  # Todo: support corpus and collection
-  # Create query url
-  my $url = Mojo::URL->new($index->api);
-  $url->path('search');
-  $url->query(\%query);
+  # Get query url
+  my $url = _query_url($index, @_);
 
   # Cache based on URL
   $index->_api_cache('total-' . $url->to_string);
+  my %param = @_;
 
   # Set context based on parameter
-  $url->query({ context => $c->param('context') // 'paragraph' });
+  $url->query({ context => $param{'context'} // 'paragraph' });
+
+  # Set path to search
+  $url->path('search');
 
   # Check cache for total results
   my $total_results;
@@ -90,43 +78,186 @@
   $index->api_request($url->to_string);
 
   # Create new user agent and set timeout to 2 minutes
-  my $ua = Mojo::UserAgent->new;
+  my $ua = $c->ua; # Mojo::UserAgent->new;
   $ua->inactivity_timeout(120);
 
-  # Denugging
+  # Debugging
   $c->app->log->debug('Search for ' . $index->api_request);
 
   # Search non-blocking
   if ($cb) {
 
-    # Non-blocking request
     $ua->get(
-      $url->to_string => sub {
-	my ($ua, $tx) = @_;
-	unless ($tx->success) {
-	  if (my $e = $tx->error) {
-	    warn 'Problem: ' . $e->{message};
-	    return $cb->($index);
-	  };
-	};
-
-	$self->_process_response($index, pop);
+      $url => sub {
+	my $tx = pop;
+	$self->_process_response('matches', $index, $tx);
 	return $cb->($index);
       });
-
-    Mojo::IOLoop->wait unless Mojo::IOLoop->is_running;
   }
-
   # Search blocking
   else {
     my $tx = $ua->get($url);
-    return $self->_process_response($index, $tx);
+    return $self->_process_response('matches', $index, $tx);
   };
 };
 
 
+# Trace query serialization
+sub trace {
+  my $self = shift;
+  my $index = shift;
+
+  # Get controller
+  my $c = $index->controller;
+
+  # If there is a callback, do async
+  my $cb = pop if ref $_[-1] && ref $_[-1] eq 'CODE';
+
+  my %param = @_;
+
+  # No query defined
+  unless ($index->query(delete $param{query})) {
+    return $cb->($index) if $cb;
+    return;
+  };
+
+  # Get query url
+  my $url = _query_url($index, @_);
+
+  $url->path('search');
+
+  # Create new user agent and set timeout to 30 seconds
+  my $ua = $c->ua; # Mojo::UserAgent->new;
+  $ua->inactivity_timeout(30);
+
+  # Build transaction
+  my $tx = $ua->build_tx(TRACE => $url);
+
+  # non-blocking
+  if ($cb) {
+
+    # Trace non-blocking
+    $ua->start(
+      $tx => sub {
+	$self->_process_response('trace', $index, pop);
+	return $cb->($index);
+      });
+  }
+  # Trace blocking
+  else {
+    my $tx = $ua->start($url);
+    return $self->_process_response('trace', $index, $tx);
+  };
+};
+
+
+# Get match info
+sub match {
+  my $self = shift;
+  my $index = shift;
+
+  # Get controller
+  my $c = $index->controller;
+
+  # If there is a callback, do async
+  my $cb = pop if ref $_[-1] && ref $_[-1] eq 'CODE';
+
+  my %param = @_;
+
+  my $url = Mojo::URL->new($index->api);
+
+  # Use hash slice to create path
+  $url->path(join('/', 'corpus', @param{qw/corpus_id doc_id match_id/}, 'matchInfo'));
+
+  # Build match id
+  # $match = 'match-' . $corpus . '!' . $corpus . '_' . $doc . '-' . $match;
+
+  my %query;
+  $query{foundry} = $param{foundry};
+  $query{layer}   = $param{layer}   if defined $param{layer};
+  $query{spans}   = $param{spans} ? 'true' : 'false';
+
+  # Add query
+  $url->query(\%query);
+
+  $c->app->log->debug('Match info: ' . $url);
+
+  # Create new user agent and set timeout to 30 seconds
+  my $ua = $c->ua; # Mojo::UserAgent->new;
+  $ua->inactivity_timeout(30);
+
+  # non-blocking
+  if ($cb) {
+    $ua->get(
+      $url => sub {
+	my $tx = pop;
+	$self->_process_response('match', $index, $tx);
+	return $cb->($index);
+      });
+  }
+
+  # Match info blocking
+  else {
+    my $tx = $ua->get($url);
+    return $self->_process_response('match', $index, $tx);
+  };
+};
+
+
+# Trace query serialization
+sub resource {
+  my $self = shift;
+  my $index = shift;
+
+  # Get controller
+  my $c = $index->controller;
+
+  # If there is a callback, do async
+  my $cb = pop if ref $_[-1] && ref $_[-1] eq 'CODE';
+
+  my %param = @_;
+
+  # Rename info endpoints regarding resource
+  my $type = $param{type} // 'collection';
+  $type = 'virtualcollection' if $type eq 'collection';
+
+  my $url = Mojo::URL->new($index->api)->path($type);
+
+  $c->app->log->debug('Get resource info on '. $url);
+
+  # Check for cached information
+  if (my $json = $c->chi->get($url->to_string)) {
+
+    # TODO: That's unfortunate, as it prohibits multiple resources
+    $c->app->log->debug('Get resource info from cache');
+    $c->stash('search.resource' => $json);
+    return $cb->($index) if $cb;
+    return $json;
+  };
+
+  $c->stash('search._resource_cache' => $url->to_string);
+
+  # Create new user agent and set timeout to 30 seconds
+  my $ua = $c->ua; # Mojo::UserAgent->new;
+  $ua->inactivity_timeout(30);
+
+  if ($cb) {
+    $ua->get(
+      $url => sub {
+	$self->_process_response('resource', $index, pop);
+	return $cb->($index);
+      })
+  }
+  else {
+    my $tx = $ua->get($url);
+    $self->_process_response('resource', $index, $tx);
+  };
+};
+
+
+# Process response - especially error messages etc.
 sub _process_response {
-  my ($self, $index, $tx) = @_;
+  my ($self, $type, $index, $tx) = @_;
   my $c = $index->controller;
 
   # An error has occurded
@@ -152,33 +283,21 @@
       return;
     };
 
-    # Reformat benchmark counter
-    my $benchmark = $json->{benchmark};
-    if ($benchmark && $benchmark =~ s/\s+(m)?s$//) {
-      $benchmark = sprintf("%.2f", $benchmark) . ($1 ? $1 : '') . 's';
-    };
-    # Set benchmark
-    $index->benchmark($benchmark);
-
-    # Set time exceeded
-    if ($json->{timeExceeded} && $json->{timeExceeded} eq Mojo::JSON::true) {
-      $index->time_exceeded(1);
+    # expected response for matches
+    if ($type eq 'matches') {
+      $self->_process_response_matches($index, $json);
+    }
+    elsif ($type eq 'trace') {
+      $self->_process_response_trace($index, $json);
+    }
+    elsif ($type eq 'match') {
+      $self->_process_response_match($index, $json);
+    }
+    elsif ($type eq 'resource') {
+      $self->_process_response_resource($index, $json);
     };
 
-    # Set result values
-    $index->items_per_page($json->{itemsPerPage});
-    $index->query_jsonld($json->{request}->{query});
-    $index->results(_map_matches($json->{matches}));
-
-    # Total results not set by stash
-    if ($index->total_results == -1) {
-
-      if ($json->{totalResults} && $json->{totalResults} > -1) {
-	$c->app->log->debug('Cache total result');
-	$c->chi->set($index->_api_cache => $json->{totalResults}, '120min');
-	$index->total_results($json->{totalResults});
-      };
-    };
+    return 1 if ref $json ne 'HASH';
 
     # Add warnings (Legacy)
     if ($json->{warning}) {
@@ -197,19 +316,79 @@
 };
 
 
+sub _process_response_matches {
+  my ($self, $index, $json) = @_;
 
+  # Reformat benchmark counter
+  my $benchmark = $json->{benchmark};
+  if ($benchmark && $benchmark =~ s/\s+(m)?s$//) {
+    $benchmark = sprintf("%.2f", $benchmark) . ($1 ? $1 : '') . 's';
+  };
+
+  # Set benchmark
+  $index->benchmark($benchmark);
+
+  # Set time exceeded
+  if ($json->{timeExceeded} && $json->{timeExceeded} eq Mojo::JSON::true) {
+    $index->time_exceeded(1);
+  };
+
+  # Set result values
+  $index->items_per_page($json->{itemsPerPage});
+  $index->query_jsonld($json->{request}->{query});
+  $index->results(_map_matches($json->{matches}));
+
+  # Total results not set by stash
+  if ($index->total_results == -1) {
+
+    if ($json->{totalResults} && $json->{totalResults} > -1) {
+      my $c = $index->controller;
+
+      $c->app->log->debug('Cache total result');
+      $c->chi->set($index->_api_cache => $json->{totalResults}, '120min');
+      $index->total_results($json->{totalResults});
+    };
+  };
+};
+
+
+# Process query serialization response
+sub _process_response_match {
+  my ($self, $index, $json) = @_;
+  $index->results(_map_match($json));
+};
+
+
+# Process query serialization response
+sub _process_response_trace {
+  my ($self, $index, $json) = @_;
+  $index->query_jsonld($json);
+};
+
+sub _process_response_resource {
+  my ($self, $index, $json) = @_;
+  my $c = $index->controller;
+
+  # TODO: That's unfortunate, as it prohibits multiple resources
+  $c->stash('search.resource' => $json);
+  $c->app->log->debug('Cache resource info');
+  $c->chi->set($c->stash('search._resource_cache') => $json, '24 hours');
+};
+
+
+# Parse the error messages
 sub _notify_on_error {
   my ($self, $c, $failure, $res) = @_;
   my $json = $res;
 
   my $log = $c->app->log;
 
+  # Check if the response is already json
   if (blessed $res) {
-    if (blessed $res ne 'Mojo::JSON') {
-      $json = $res->json;
-    };
+    $json = $res->json if blessed $res ne 'Mojo::JSON';
   };
 
+  # Chec json response error message
   if ($json) {
     if ($json->{error}) {
       # Temp
@@ -233,6 +412,7 @@
     };
   };
 
+  # Doesn't matter what - there is a failure!
   if ($failure) {
     $c->notify(error => (
       ($res->{code}    ? $res->{code} . ': ' : '') .
@@ -243,18 +423,53 @@
 };
 
 
+# Cleanup array of matches
 sub _map_matches {
   return () unless $_[0];
-  map {
-    $_->{ID} =~ s/^match\-[^!]+![^-]+-//;
-    $_->{docID} =~ s/^[^_]+_//;
-    $_;
-  } @{ shift() };
+  map { _map_match($_) } @{ shift() };
+};
+
+
+# Cleanup single match
+sub _map_match {
+  my $x = shift or return;
+  $x->{ID} =~ s/^match\-[^!]+![^-]+-//;
+  $x->{docID} =~ s/^[^_]+_//;
+  $x;
+};
+
+
+sub _query_url {
+  my ($index, %param) = @_;
+
+  # Set cutoff from param
+  $index->cutoff(delete $param{cutoff});
+
+  # Set query language
+  $index->query_language(delete $param{query_language} // 'poliqarp');
+
+  # Should results be cached? Defaults to "yes"
+  $index->no_cache(1) if $param{no_cache};
+
+  # Init the query with stuff coming from the index
+  my %query;
+  $query{q}      = $index->query;
+  $query{ql}     = $index->query_language;
+  $query{page}   = $index->start_page if $index->start_page;
+  $query{count}  = $index->items_per_page if $index->items_per_page;
+  $query{cutoff} = 'true' if $index->cutoff;
+
+  # Todo: support corpus and collection
+  # Create query url
+  my $url = Mojo::URL->new($index->api);
+  $url->query(\%query);
+  return $url;
 };
 
 
 1;
 
+
 __END__
 
 =pod
diff --git a/lib/Korap/Controller/Search.pm b/lib/Korap/Controller/Search.pm
new file mode 100644
index 0000000..a94f0de
--- /dev/null
+++ b/lib/Korap/Controller/Search.pm
@@ -0,0 +1,113 @@
+package Korap::Controller::Search;
+use Mojo::Base 'Mojolicious::Controller';
+
+# Add X-Forwarded-For to user agent call everywhere
+
+
+# Query the KorAP backends and render a template
+sub query {
+  my $c = shift;
+  $c->layout('default');
+  $c->title('KorAP');
+
+  my $query = $c->param('q');
+
+  # Base parameters for remote access
+  my %param = (
+    query_language => scalar $c->param('ql'),
+    query => $query,
+  );
+
+  my $inspect = (scalar $c->param('action') // '') eq 'inspect' ? 1 : 0;
+
+  # Just check the serialization non-blocking
+  if ($inspect) {
+    $c->search->trace(
+      %param => sub {
+	return $c->render(template => 'query_info');
+      }
+    );
+    return;
+  };
+
+  my $template = scalar $c->param('snippet') ? 'snippet' : 'search';
+
+  # Search non-blocking
+  $c->delay(
+    sub {
+      my $delay = shift;
+      $c->search(
+	cutoff => scalar $c->param('cutoff'),
+	count => scalar $c->param('count'),
+	start_page => scalar $c->param('page'),
+	cb => $delay->begin,
+	%param
+      ) if $query;
+
+      $c->search->resource(
+	type => 'collection',
+	$delay->begin
+      );
+    },
+    sub {
+      return $c->render(template => $template);
+    }
+  );
+};
+
+
+# Get informations about a match
+sub match_info {
+  my $c = shift;
+
+  my $foundry = '*';
+  my %query = (foundry => '*');
+  if ($c->param('foundry')) {
+    $query{foundry} = $c->param('foundry');
+    if ($c->param('layer')) {
+      $query{layer} = $c->param('layer');
+    };
+    if ($c->param('spans')) {
+      $query{spans} = 'true';
+    };
+  };
+
+  $c->render_later;
+
+  # Use the API for fetching matching information non-blocking
+  $c->search->match(
+    corpus_id => $c->stash('corpus_id'),
+    doc_id    => $c->stash('doc_id'),
+    match_id  => $c->stash('match_id'),
+    %query,
+
+    # Callback for async search
+    sub {
+      my $index = shift;
+
+      return $c->respond_to(
+
+	# Render json if requested
+	json => sub {
+	  # Add notifications to the matching json
+	  # TODO: There should be a special notification engine doing that!
+	  my $notes = $c->notifications(json => $index->results->[0]);
+	  $c->render(json => $notes);
+	},
+
+	# Render html if requested
+	html => sub {
+	  return $c->render(
+	    layout   => 'default',
+	    template => 'match_info'
+	  )
+	}
+      );
+    }
+  );
+};
+
+1;
+
+
+__END__
diff --git a/lib/Korap/Controller/Tutorial.pm b/lib/Korap/Controller/Tutorial.pm
new file mode 100644
index 0000000..186439d
--- /dev/null
+++ b/lib/Korap/Controller/Tutorial.pm
@@ -0,0 +1,33 @@
+package Korap::Controller::Tutorial;
+use Mojo::Base 'Mojolicious::Controller';
+
+# Todo: Set title as defaults
+
+sub page {
+  my $c = shift;
+
+  # Show tutorial embedded
+  if ($c->param('embedded')) {
+    $c->layout('snippet');
+    $c->stash(embedded => 1);
+  }
+
+  # Show tutorial in full screen
+  else {
+    $c->layout('default');
+  };
+
+  # Title should be "KorAP"
+  $c->title('KorAP');
+
+  my $page = $c->stash('tutorial');
+  return $c->render(
+    template => 'tutorial/' . $page
+  );
+};
+
+
+1;
+
+
+__END__
diff --git a/lib/Korap/Info.pm b/lib/Korap/Info.pm
deleted file mode 100644
index bc8fc05..0000000
--- a/lib/Korap/Info.pm
+++ /dev/null
@@ -1,60 +0,0 @@
-package Korap::Info;
-use Mojo::Base 'Mojolicious::Controller';
-
-sub about_match {
-  my $c = shift;
-
-  my $corpus_id = $c->stash('corpus_id');
-  my $doc_id    = $c->stash('doc_id');
-  my $match_id  = $c->stash('match_id');
-
-  my $foundry = '*';
-  my %query = (foundry => '*');
-  if ($c->param('foundry')) {
-    $query{foundry} = $c->param('foundry');
-    if ($c->param('layer')) {
-      $query{layer} = $c->param('layer');
-    };
-    if ($c->param('spans')) {
-      $query{spans} = 'true';
-    };
-  };
-
-  return $c->respond_to(
-    json => sub {
-      $c->render(json => $c->notifications(
-	json => $c->match_info($corpus_id, $doc_id, $match_id, %query))
-      )
-    },
-    html => sub {
-      my $match = $c->match_info($corpus_id, $doc_id, $match_id, %query);
-      if ($match->{error}) {
-	$c->notify(error => $match->{error});
-	return $c->render_exception('error');
-      };
-
-      $c->render(
-	layout => 'default',
-	template => 'match_info',
-	match => $match
-      )
-    }
-  );
-};
-
-# Todo: Return info for all collections
-sub about_collection {
-  my $c = shift;
-  my $src = $c->stash('collection_id');
-  if ($src) {
-    $c->render(
-      json => $c->notifications(
-	json => $c->info_on($src)
-      )
-    );
-  };
-};
-
-1;
-
-__END__
diff --git a/lib/Korap/Plugin/KorapInfo.pm b/lib/Korap/Plugin/KorapInfo.pm
deleted file mode 100644
index 4de0406..0000000
--- a/lib/Korap/Plugin/KorapInfo.pm
+++ /dev/null
@@ -1,194 +0,0 @@
-package Korap::Plugin::KorapInfo;
-use Mojo::Base 'Mojolicious::Plugin';
-use Mojo::JSON qw/decode_json/;
-use Mojo::ByteStream 'b';
-
-# Todo: Make the requests non-blocking
-
-sub map_match {
-  my $x = shift or return;
-  $x->{ID} =~ s/^match\-[^!]+![^-]+-// if $x->{ID};
-  $x->{docID} =~ s/^[^_]+_// if $x->{docID};
-  $x;
-};
-
-# Register plugin
-sub register {
-  my ($plugin, $mojo, $param) = @_;
-  $param ||= {};
-
-  # Load parameter from Config file
-  if (my $config_param = $mojo->config('KorAP')) {
-    $param = { %$param, %$config_param };
-  };
-
-  # Temporary info data
-  state $json = decode_json(b(join('', <DATA>))->encode);
-
-  # Get the API endpoint
-  my $api = $param->{'api-0.1'};
-
-  # Todo: Make this recognize the user!
-  $mojo->helper(
-    resource_info => sub {
-      my $c = shift;
-      my $src = shift;
-
-      # Dispatch for test mode
-      if ($c->app->mode eq 'test') {
-	if ($src eq 'collection') {
-	  return $json->{collections};
-	};
-      };
-
-      # Rename info endpoints and build URL
-      $src = 'virtualcollection' if $src eq 'collection';
-      $src = 'corpus' if $src eq 'corpus';
-      my $url = Mojo::URL->new($api)->path($src);
-
-      $c->app->log->debug($url);
-
-      # Check for cached information
-      if (my $json = $c->chi->get($url->to_string)) {
-	return $json;
-      }
-
-      # Retrieve and set the cache
-      elsif (my $response = $c->ua->get($url)->success) {
-	my $json = $response->json;
-	$c->chi->set($url->to_string => $json, '24 hours');
-	return $json;
-      };
-
-      # Something went wrong
-      $c->notify(error => 'Unable to retrieve resource');
-      return [];
-    }
-  );
-
-  $mojo->helper(
-    match_info => sub {
-      my $c = shift;
-
-      my $corpus = shift;
-      my $doc = shift;
-      my $match = shift;
-      my %param = @_;
-
-      if ($c->app->mode eq 'test') {
-	return map_match($json->{treeInfo}) if $param{spans};
-	return map_match($json->{matchInfo2});
-      };
-
-      # Build url
-      my $temp_api = $c->config('KorAP')->{'api-0.1'};
-      my $url = Mojo::URL->new($temp_api)->path(
-	join('/', 'corpus', $corpus, $doc, $match, 'matchInfo')
-      );
-
-      # Build match id
-      # $match = 'match-' . $corpus . '!' . $corpus . '_' . $doc . '-' . $match;
-
-      my %query;
-      $query{foundry} = $param{foundry} if defined $param{foundry};
-      $query{layer}   = $param{layer}   if defined $param{layer};
-      $query{spans}   = $param{spans} ? 'true' : 'false';
-
-      # Add query
-      $url->query(\%query);
-
-      $c->app->log->debug($url);
-
-      if (my $response = $c->ua->get($url)->success) {
-	return map_match($response->json);
-      };
-
-      $c->notify(error => 'Unable to retrieve resource');
-      return {};
-    }
-  );
-};
-
-
-1;
-
-__DATA__
-{
-  "treeInfo": {
-    "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":false,
-    "endMore":false,
-    "docID":"WPD_NNN.02848",
-    "snippet" : "<span class=\"context-left\"><span class=\"more\"></span></span><span class=\"match\"><span title=\"xip/c:VERB\">enthält</span>, <span title=\"xip/c:CONJ\">aber</span> <span title=\"xip/c:PTCL\">an</span> <span title=\"xip/c:CONJ\">und</span> <span title=\"xip/c:PP\"><span title=\"xip/c:PREP\">für</span> <span title=\"xip/c:NP\"><span title=\"xip/c:PRON\">sich</span></span></span> <span title=\"xip/c:NP\"><span title=\"xip/c:DET\">keinen</span> <span title=\"xip/c:NPA\"><span title=\"xip/c:AP\"><span title=\"xip/c:ADJ\">weiteren</span></span> <span title=\"xip/c:NOUN\">Sinn</span></span></span> <span title=\"xip/c:VERB\">enthält</span></span><span class=\"context-right\"><span class=\"more\"></span></span>",
-    "ID":"match-WPD!WPD_NNN.02848-p1213-1224",
-    "pubDate":"2005-03-28",
-    "context":{
-      "left":["token",0],
-      "right":["token",0]
-    }
-  },
-  "matchInfo": {
-    "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":false,
-    "endMore":false,
-    "docID":"WPD_NNN.02848",
-    "snippet":"<span class=\"context-left\"></span><span class=\"match\"><span title=\"mate/l:besonders\"><span title=\"mate/p:ADV\">Besonders</span></span> <span title=\"mate/l:auffällig\"><span title=\"mate/m:degree:pos\"><span title=\"mate/p:ADJD\">auffällig</span></span></span> <span title=\"mate/l:sein\"><span title=\"mate/m:mood:ind\"><span title=\"mate/m:number:pl\"><span title=\"mate/m:person:3\"><span title=\"mate/m:tense:pres\"><span title=\"mate/p:VAFIN\">sind</span></span></span></span></span></span> <span title=\"mate/l:schließlich\"><span title=\"mate/p:ADV\">schließlich</span></span> <span title=\"mate/l:noch\"><span title=\"mate/p:ADV\">noch</span></span> <span title=\"mate/l:der\"><span title=\"mate/m:case:nom\"><span title=\"mate/m:gender:masc\"><span title=\"mate/m:number:sg\"><span title=\"mate/p:ART\">der</span></span></span></span></span> <span title=\"mate/l:pohutukawa\"><span title=\"mate/m:case:nom\"><span title=\"mate/m:gender:masc\"><span title=\"mate/m:number:sg\"><span title=\"mate/p:NE\">Pohutukawa</span></span></span></span></span> <span title=\"mate/l:und\"><span title=\"mate/p:KON\">und</span></span> <span title=\"mate/l:der\"><span title=\"mate/m:case:nom\"><span title=\"mate/m:gender:masc\"><span title=\"mate/m:number:sg\"><span title=\"mate/p:ART\">der</span></span></span></span></span> <span title=\"mate/l:cabbage\"><span title=\"mate/m:case:nom\"><span title=\"mate/m:gender:masc\"><span title=\"mate/m:number:sg\"><span title=\"mate/p:NE\">Cabbage</span></span></span></span></span> <span title=\"mate/l:tree\"><span title=\"mate/m:gender:masc\"><span title=\"mate/m:number:sg\"><span title=\"mate/p:NE\"><span title=\"mate/m:case:nom\">Tree</span></span></span></span></span></span><span class=\"context-right\"></span>",
-    "ID":"match-WPD!WPD_NNN.02848-p1213-1224",
-    "pubDate":"2005-03-28",
-    "context":{
-      "left":["token",0],
-      "right":["token",0]
-    }
-  },
-  "collections" : [
-    {
-      "shared":false,
-      "id":1,
-      "managed":true,
-      "created":1401193381119,
-      "statistics":{
-        "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"
-    }
-  ],
-  "matchInfo2" : {
-    "author":"AHZ,AkaBot,Zwobot",
-    "textClass":"freizeit-unterhaltung reisen",
-    "corpusID":"WPD",
-    "title":"Okres Hodonín",
-    "foundries":"opennlp opennlp/morpho base base/sentences base/paragraphs mate mate/morpho mate/dependency corenlp corenlp/namedentities corenlp/namedentities/ne_dewac_175m_600 corenlp/namedentities corenlp/namedentities/ne_hgc_175m_600 treetagger treetagger/morpho connexor connexor/morpho connexor/syntax connexor/phrase xip xip/morpho xip/constituency xip/dependency",
-    "tokenization":"opennlp#tokens",
-    "field":"tokens",
-    "startMore":false,
-    "endMore":false,
-    "docID":"WPD_OOO.01534",
-    "snippet":"<span class=\"context-left\"></span><span class=\"match\"><span title=\"mate/l:archlebov\"><span title=\"mate/p:NE\"><span title=\"tt/p:NE\"><span title=\"tt/p:NN\">Archlebov</span></span></span></span> - <span title=\"mate/l:blatnice\"><span title=\"mate/p:FM\"><span title=\"tt/p:NE\"><span title=\"tt/p:NN\">Blatnice</span></span></span></span> <span title=\"mate/l:pod\"><span title=\"mate/p:FM\"><span title=\"tt/l:pod\"><span title=\"tt/p:NE\">pod</span></span></span></span> <span title=\"mate/l:svatým\"><span title=\"mate/p:FM\"><span title=\"tt/p:NE\">Svatým</span></span></span> <span title=\"mate/l:antonínkem\"><span title=\"mate/p:FM\"><span title=\"tt/p:NE\"><span title=\"tt/p:NN\">Antonínkem</span></span></span></span> - <span title=\"mate/l:blatni\"><span title=\"mate/p:NE\"><span title=\"tt/p:NE\"><span title=\"tt/p:NN\">Blatni</span></span></span></span><span title=\"mate/l:?ka\"><span title=\"mate/p:NE\">čka</span></span> - <span title=\"mate/l:bukovany\"><span title=\"mate/p:NE\"><span title=\"tt/p:NE\"><span title=\"tt/p:NN\">Bukovany</span></span></span></span> - <span title=\"mate/l:bzenec\"><span title=\"mate/p:NE\"><span title=\"tt/p:NE\"><span title=\"tt/p:NN\">Bzenec</span></span></span></span> - <span title=\"mate/l:?ej\"><span title=\"mate/p:NE\">Čej</span></span>č - <span title=\"mate/l:?ejkovice\"><span title=\"mate/p:NE\">Čejkovice</span></span> - <span title=\"mate/l:?elo\"><span title=\"mate/p:NE\">Čelo</span></span><span title=\"mate/l:?nice\"><span title=\"mate/p:NE\">žnice</span></span> - <span title=\"mate/l:dambo\"><span title=\"mate/p:NE\"><span title=\"tt/p:NE\"><span title=\"tt/p:NN\">Dambo</span></span></span></span><span title=\"mate/l:?ice\"><span title=\"mate/p:NE\">řice</span></span> - <span title=\"mate/l:doln\"><span title=\"mate/p:NE\">Doln</span></span><span title=\"mate/l:í\"><span title=\"mate/p:NE\">í</span></span> <span title=\"mate/l:bojanovice\"><span title=\"mate/p:NE\"><span title=\"tt/p:NE\"><span title=\"tt/p:NN\">Bojanovice</span></span></span></span> - <span title=\"mate/l:domanín\"><span title=\"mate/p:NE\"><span title=\"tt/p:NE\"><span title=\"tt/p:NN\">Domanín</span></span></span></span> - <span title=\"mate/l:dra\"><span title=\"mate/p:NE\"><span title=\"tt/p:NE\">Dra</span></span></span><span title=\"mate/p:NE\">ž</span><span title=\"mate/l:?vky\"><span title=\"mate/p:NE\"><span title=\"tt/p:NE\"><span title=\"tt/p:NN\">ůvky</span></span></span></span> - <span title=\"mate/l:dub\"><span title=\"mate/p:NE\"><span title=\"tt/p:NE\">Dub</span></span></span><span title=\"mate/l:?any\"><span title=\"mate/p:NE\">ňany</span></span> - <span title=\"mate/l:hodonín\"><span title=\"mate/p:NE\"><span title=\"tt/p:NE\">Hodonín</span></span></span> - <span title=\"mate/l:hovorany\"><span title=\"mate/p:NE\"><span title=\"tt/p:NE\"><span title=\"tt/p:NN\">Hovorany</span></span></span></span> - <span title=\"mate/l:hroznová\"><span title=\"mate/p:NE\"><span title=\"tt/p:NE\">Hroznová</span></span></span> <span title=\"mate/l:lhota\"><span title=\"mate/p:NE\"><span title=\"tt/p:NE\">Lhota</span></span></span> - <span title=\"mate/l:hrubá\"><span title=\"mate/p:NE\"><span title=\"tt/p:NE\">Hrubá</span></span></span> <span title=\"mate/l:vrbka\"><span title=\"mate/p:NE\"><span title=\"tt/p:NE\">Vrbka</span></span></span> - <span title=\"mate/l:hýsly\"><span title=\"mate/p:NE\"><span title=\"tt/p:NE\"><span title=\"tt/p:NN\">Hýsly</span></span></span></span> - <span title=\"mate/l:javorník\"><span title=\"mate/p:NE\"><span title=\"tt/p:NE\"><span title=\"tt/p:NN\">Javorník</span></span></span></span> - <span title=\"mate/l:je\"><span title=\"mate/p:NE\"><span title=\"tt/l:Je\"><span title=\"tt/p:KOUS\">Je</span></span></span></span><span title=\"mate/l:?ov\"><span title=\"mate/p:NE\">žov</span></span> - <span title=\"mate/l:josefov\"><span title=\"mate/p:NE\"><span title=\"tt/p:NE\">Josefov</span></span></span> - <span title=\"mate/l:karlín\"><span title=\"mate/p:NE\"><span title=\"tt/p:NE\"><span title=\"tt/p:NN\">Karlín</span></span></span></span> - <span title=\"mate/l:kel\"><span title=\"mate/p:NE\"><span title=\"tt/p:NE\">Kel</span></span></span><span title=\"mate/l:?any\"><span title=\"mate/p:NE\">čany</span></span> - <span title=\"mate/l:kn\"><span title=\"mate/p:NN\"><span title=\"tt/p:NE\">Kn</span></span></span>ě<span title=\"mate/l:?dub\"><span title=\"mate/p:NE\"><span title=\"tt/p:NE\"><span title=\"tt/p:NN\">ždub</span></span></span></span> - <span title=\"mate/l:kostelec\"><span title=\"mate/p:NE\"><span title=\"tt/p:NE\">Kostelec</span></span></span> - <span title=\"mate/l:kozojídky\"><span title=\"mate/p:NE\"><span title=\"tt/p:NE\"><span title=\"tt/p:NN\">Kozojídky</span></span></span></span> - <span title=\"mate/l:ku\"><span title=\"mate/p:NE\"><span title=\"tt/p:NE\">Ku</span></span></span><span title=\"mate/l:?elov\"><span title=\"mate/p:NE\">želov</span></span> - <span title=\"mate/l:kyjov\"><span title=\"mate/p:NE\"><span title=\"tt/p:NE\">Kyjov</span></span></span> - <span title=\"mate/l:labuty\"><span title=\"mate/p:NE\"><span title=\"tt/p:NE\"><span title=\"tt/p:NN\">Labuty</span></span></span></span> - <span title=\"mate/l:lipov\"><span title=\"mate/p:NE\"><span title=\"tt/p:NE\">Lipov</span></span></span> - <span title=\"mate/l:louka\"><span title=\"mate/p:NE\"><span title=\"tt/p:NE\">Louka</span></span></span> - <span title=\"mate/l:lov\"><span title=\"mate/p:NE\"><span title=\"tt/p:NE\">Lov</span></span></span><span title=\"mate/l:?ice\"><span title=\"mate/p:NE\">čice</span></span> - <span title=\"mate/l:lu\"><span title=\"mate/p:NE\"><span title=\"tt/p:NE\"><span title=\"tt/l:Lu\">Lu</span></span></span></span><span title=\"mate/l:?ice\"><span title=\"mate/p:NE\">žice</span></span> - <span title=\"mate/l:malá\"><span title=\"mate/p:NE\"><span title=\"tt/p:NE\">Malá</span></span></span> <span title=\"mate/l:vrbka\"><span title=\"mate/p:NE\"><span title=\"tt/p:NE\">Vrbka</span></span></span> - <span title=\"mate/l:mikul\"><span title=\"mate/p:NE\"><span title=\"tt/p:NE\">Mikul</span></span></span><span title=\"mate/l:?ice\"><span title=\"mate/p:NE\">čice</span></span> - <span title=\"mate/l:milotice\"><span title=\"mate/p:NE\"><span title=\"tt/p:NE\"><span title=\"tt/p:NN\">Milotice</span></span></span></span> - <span title=\"mate/l:moravany\"><span title=\"mate/p:NE\"><span title=\"tt/p:NE\"><span title=\"tt/p:NN\">Moravany</span></span></span></span> - <span title=\"mate/l:moravský\"><span title=\"mate/p:NE\"><span title=\"tt/p:NE\">Moravský</span></span></span> <span title=\"mate/l:písek\"><span title=\"mate/p:NE\"><span title=\"tt/p:NE\">Písek</span></span></span> - <span title=\"mate/l:mut\"><span title=\"mate/p:NN\"><span title=\"tt/l:Mut\"><span title=\"tt/p:NN\">Mut</span></span></span></span><span title=\"mate/l:?nice\"><span title=\"mate/p:NE\">ěnice</span></span> - <span title=\"mate/l:násedlovice\"><span title=\"mate/p:NE\"><span title=\"tt/p:NE\"><span title=\"tt/p:NN\">Násedlovice</span></span></span></span> - <span title=\"mate/l:nechvalín\"><span title=\"mate/p:NE\"><span title=\"tt/p:NE\"><span title=\"tt/p:NN\">Nechvalín</span></span></span></span> - <span title=\"mate/l:nenkovice\"><span title=\"mate/p:NE\"><span title=\"tt/p:NE\"><span title=\"tt/p:NN\">Nenkovice</span></span></span></span> - <span title=\"mate/l:nová\"><span title=\"mate/p:NE\"><span title=\"tt/p:NE\">Nová</span></span></span> <span title=\"mate/l:lhota\"><span title=\"mate/p:NE\"><span title=\"tt/p:NE\">Lhota</span></span></span> - <span title=\"mate/l:nový\"><span title=\"mate/p:NE\"><span title=\"tt/p:NE\">Nový</span></span></span> <span title=\"mate/l:poddvorov\"><span title=\"mate/p:NE\"><span title=\"tt/p:NE\">Poddvorov</span></span></span> - <span title=\"mate/l:ostrovánky\"><span title=\"mate/p:NE\"><span title=\"tt/p:NE\"><span title=\"tt/p:NN\">Ostrovánky</span></span></span></span> - <span title=\"mate/l:petrov\"><span title=\"mate/p:NE\"><span title=\"tt/p:NE\">Petrov</span></span></span> - <span title=\"mate/l:pru\"><span title=\"mate/p:NE\"><span title=\"tt/p:NE\">Pru</span></span></span><span title=\"mate/l:?ánky\"><span title=\"mate/p:NE\">šánky</span></span> - <span title=\"mate/l:rad\"><span title=\"mate/p:NE\"><span title=\"tt/l:Rad\"><span title=\"tt/p:NN\">Rad</span></span></span></span><span title=\"mate/l:?jov\"><span title=\"mate/p:NE\">ějov</span></span> - <span title=\"mate/l:ratí\"><span title=\"mate/p:NE\"><span title=\"tt/p:NE\"><span title=\"tt/p:NN\">Ratí</span></span></span></span><span title=\"mate/l:?kovice\"><span title=\"mate/p:NE\">škovice</span></span> - <span title=\"mate/l:rohatec\"><span title=\"mate/p:NE\"><span title=\"tt/p:NE\"><span title=\"tt/p:NN\">Rohatec</span></span></span></span> - <span title=\"mate/l:skalka\"><span title=\"mate/p:NE\"><span title=\"tt/p:NE\">Skalka</span></span></span> - <span title=\"mate/l:skoronice\"><span title=\"mate/p:NE\"><span title=\"tt/p:NE\"><span title=\"tt/p:NN\">Skoronice</span></span></span></span> - <span title=\"mate/l:sob\"><span title=\"mate/p:NE\"><span title=\"tt/p:NE\">Sob</span></span></span><span title=\"mate/l:?lky\"><span title=\"mate/p:NE\">ůlky</span></span> - <span title=\"mate/l:starý\"><span title=\"mate/p:NE\"><span title=\"tt/p:NE\"><span title=\"tt/p:NN\">Starý</span></span></span></span> <span title=\"mate/l:poddvorov\"><span title=\"mate/p:NE\"><span title=\"tt/p:NE\">Poddvorov</span></span></span> - <span title=\"mate/l:stav\"><span title=\"mate/p:NE\"><span title=\"tt/p:NE\">Stav</span></span></span><span title=\"mate/p:NE\">ě</span><span title=\"mate/l:?ice\"><span title=\"mate/p:NE\"><span title=\"tt/p:NE\"><span title=\"tt/p:NN\">šice</span></span></span></span> - <span title=\"mate/l:strá\"><span title=\"mate/p:NE\"><span title=\"tt/p:NE\">Strá</span></span></span><span title=\"mate/l:?nice\"><span title=\"mate/p:NE\">žnice</span></span> - <span title=\"mate/l:strá\"><span title=\"mate/p:NE\"><span title=\"tt/p:NE\">Strá</span></span></span><span title=\"mate/l:?ovice\"><span title=\"mate/p:NE\">žovice</span></span> - <span title=\"mate/l:sudom\"><span title=\"mate/p:NE\"><span title=\"tt/p:NE\"><span title=\"tt/p:NN\">Sudom</span></span></span></span><span title=\"mate/p:NE\">ě</span><span title=\"mate/l:?ice\"><span title=\"mate/p:NE\"><span title=\"tt/p:NE\"><span title=\"tt/p:NN\">řice</span></span></span></span> - <span title=\"mate/l:suchov\"><span title=\"mate/p:NE\"><span title=\"tt/p:NE\">Suchov</span></span></span> - <span title=\"mate/l:svatobo\"><span title=\"mate/p:NE\"><span title=\"tt/p:NE\"><span title=\"tt/p:NN\">Svatobo</span></span></span></span><span title=\"mate/l:?ice-mist\"><span title=\"mate/p:NE\">řice-Mist</span></span><span title=\"mate/l:?ín\"><span title=\"mate/p:NE\">řín</span></span> - <span title=\"mate/l:syrovín\"><span title=\"mate/p:NE\"><span title=\"tt/p:NE\"><span title=\"tt/p:NN\">Syrovín</span></span></span></span> - <span title=\"mate/l:?ardice\"><span title=\"mate/p:NE\">Šardice</span></span> - <span title=\"mate/l:tasov\"><span title=\"mate/p:NE\"><span title=\"tt/p:NE\"><span title=\"tt/p:NN\">Tasov</span></span></span></span> - <span title=\"mate/l:t?mice\"><span title=\"mate/p:NE\">Těmice</span></span> - <span title=\"mate/l:terezín\"><span title=\"mate/p:NE\"><span title=\"tt/p:NE\">Terezín</span></span></span> - <span title=\"mate/l:tvaro\"><span title=\"mate/p:NE\"><span title=\"tt/p:NE\"><span title=\"tt/p:NN\">Tvaro</span></span></span></span><span title=\"mate/l:?ná\"><span title=\"mate/p:NE\">žná</span></span> <span title=\"mate/l:lhota\"><span title=\"mate/p:NE\"><span title=\"tt/p:NE\">Lhota</span></span></span> - <span title=\"mate/l:uh\"><span title=\"mate/p:NE\"><span title=\"tt/l:uh\"><span title=\"tt/p:ITJ\">Uh</span></span></span></span><span title=\"mate/l:?ice\"><span title=\"mate/p:NE\">řice</span></span> - <span title=\"mate/l:vacenovice\"><span title=\"mate/p:NE\"><span title=\"tt/p:NE\"><span title=\"tt/p:NN\">Vacenovice</span></span></span></span> - <span title=\"mate/l:velká\"><span title=\"mate/p:NE\"><span title=\"tt/p:NE\">Velká</span></span></span> <span title=\"mate/l:nad\"><span title=\"mate/p:NE\"><span title=\"tt/p:NE\"><span title=\"tt/l:nad\">nad</span></span></span></span> <span title=\"mate/l:veli\"><span title=\"mate/p:NE\"><span title=\"tt/p:NE\">Veli</span></span></span><span title=\"mate/l:?kou\"><span title=\"mate/p:NE\">čkou</span></span> - <span title=\"mate/l:veselí\"><span title=\"mate/p:NE\"><span title=\"tt/p:NE\">Veselí</span></span></span> <span title=\"mate/l:nad\"><span title=\"mate/p:NE\"><span title=\"tt/l:nad\"><span title=\"tt/p:NE\">nad</span></span></span></span> <span title=\"mate/l:moravou\"><span title=\"mate/p:NE\"><span title=\"tt/p:NE\">Moravou</span></span></span> - <span title=\"mate/l:v\"><span title=\"mate/p:CARD\"><span title=\"tt/l:V\"><span title=\"tt/p:NN\">V</span></span></span></span><span title=\"mate/l:?t\"><span title=\"mate/p:XY\">ěte</span></span><span title=\"mate/l:?ov\"><span title=\"mate/p:XY\">řov</span></span> - <span title=\"mate/p:FM\"><span title=\"mate/l:vlko\"><span title=\"tt/p:NE\"><span title=\"tt/p:NN\">Vlko</span></span></span></span>š - <span title=\"mate/l:vnorovy\"><span title=\"mate/p:NE\"><span title=\"tt/p:NE\"><span title=\"tt/p:NN\">Vnorovy</span></span></span></span> - <span title=\"mate/l:vracov\"><span title=\"mate/p:NE\"><span title=\"tt/p:NE\"><span title=\"tt/p:NN\">Vracov</span></span></span></span> - <span title=\"mate/l:v\"><span title=\"mate/p:NE\"><span title=\"tt/l:V\"><span title=\"tt/p:NN\">V</span></span></span></span><span title=\"mate/l:?esovice\"><span title=\"mate/p:NE\">řesovice</span></span> - <span title=\"mate/l:?ádovice\"><span title=\"mate/p:NE\">Žádovice</span></span> - <span title=\"mate/l:?aro\"><span title=\"mate/p:NE\">Žaro</span></span><span title=\"mate/l:?ice\"><span title=\"mate/p:NE\">šice</span></span> - <span title=\"mate/l:?dánice\"><span title=\"mate/p:NE\">Ždánice</span></span> - <span title=\"mate/l:?eletice\"><span title=\"mate/p:NE\">Želetice</span></span> - <span title=\"mate/l:?eravice\"><span title=\"mate/p:NE\">Žeravice</span></span> - <span title=\"mate/p:NE\"><span title=\"mate/l:?eraviny\">Žeraviny</span></span></span><span class=\"context-right\"></span>","ID":"match-WPD!WPD_OOO.01534-p328-462","pubDate":"2005-03-28","context":{"left":["token",0],"right":["token",0]}}
-}
diff --git a/lib/Korap/Plugin/KorapSearch.pm b/lib/Korap/Plugin/KorapSearch.pm
deleted file mode 100644
index 7aab520..0000000
--- a/lib/Korap/Plugin/KorapSearch.pm
+++ /dev/null
@@ -1,400 +0,0 @@
-package Korap::Plugin::KorapSearch;
-use Mojo::Base 'Mojolicious::Plugin';
-use Scalar::Util qw/blessed/;
-use Mojo::JSON qw/decode_json true/;
-use Mojo::ByteStream 'b';
-
-# TODO: This will probably be an engine for M::P::Search
-# cutoff has to be true or false
-# TODO: Write search snippet
-
-sub map_matches {
-  return [] unless $_[0];
-  [
-    map {
-      $_->{ID} =~ s/^match\-[^!]+![^-]+-//;
-      $_->{docID} =~ s/^[^_]+_//;
-      $_;
-    } @{ shift() }
-  ];
-};
-
-# Remove these attributes from stash after searching
-our @remove_from_stash =
-  qw/hits totalResults benchmark itemsPerPage error query/;
-
-
-# Register 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-0.1'};
-
-  # Create search endpoint
-  $mojo->routes->add_shortcut(
-    search => sub {
-      # Todo: Support TRACE
-      return shift->route('/search')->to('search#remote')
-    }
-  );
-
-  # TODO: Create a hash and either make these stash values
-  # or return the hash in case of non-blocking requests
-  $mojo->helper(
-    search => sub {
-      my $c = shift;
-
-      # If there is no callback, return the JSON object
-      my $cb = pop if ref $_[-1] && ref $_[-1] eq 'CODE';
-
-      my %param = @_;
-
-      # Test environment / Fixtures - set via config!
-      if ($c->app->mode eq 'test') {
-	state $json = decode_json(join(' ', <DATA>));
-
-	return $json unless $cb;
-
-	$c->stash('search.count' => 10);
-	$c->stash('search.startPage' => 1);
-	$c->stash('search.totalResults' => 666);
-	$c->stash('search.itemsPerPage' => 10);
-	$c->stash('search.bm.hit' => 20);
-	$c->stash('search.bm.result' => 10);
-	$c->stash('search.query' => $json->{request}->{query});
-	$c->stash('search.hits' => map_matches $json->{matches});
-	return $cb->();
-      };
-
-      $c->stash(
-	'search.count' =>
-	  delete($param{count}) //
-	    scalar($c->param('count')) //
-	      $param->{count}
-	    );
-
-      $c->stash('search.startPage' =>
-		  (delete($param{startPage}) //
-		     scalar $c->param('p') //
-		       1
-		     ));
-
-      my $query = $param{query}   // scalar $c->param('q');
-      my $cutoff = $param{cutoff} // scalar $c->param('cutoff') // undef;
-
-      return '' unless $query;
-
-      # Get stash information
-      my $count = $c->stash('search.count');
-      my $start_page = $c->stash('search.startPage');
-
-      foreach ($start_page, $count) {
-	$_ = undef if (!$_ || $_ !~ /^\d+$/);
-      };
-
-      my $url = Mojo::URL->new($api);
-
-      # Search in corpus
-      if ($c->stash('corpus_id')) {
-	$url->path('corpus/' . $c->stash('corpus_id') . '/search');
-      }
-
-      # search in collection
-      elsif ($c->stash('collection_id')) {
-	$url->path('virtualcollection/' . $c->stash('collection_id') . '/search');
-      }
-
-      # Just search
-      else {
-	$url->path('search');
-      };
-
-      #if ($c->stash('resource')) {
-      #$url->path($c->stash('resource'));
-      #if ($c->stash('cid')) {
-      #$url->path($c->stash('cid'));
-      #};
-      #};
-
-      my %query = (q => $query);
-      $query{ql} = $param{ql} // scalar $c->param('ql') // 'poliqarp';
-      $query{count} = $count if $count;
-      $query{cutoff} = 'true' if $cutoff;
-
-      $url->query(\%query);
-      my $cache_url = $url->to_string;
-
-      $url->query({context => 'paragraph'});
-
-      # Check cache for total results
-      my $total_results;
-      if (
-	# TODO: This should also be a query parameter
-	!$param{no_cache} &&
-	  defined ($total_results = $c->chi->get('total-' . $cache_url))) {
-	$c->stash('search.totalResults' => $total_results);
-	$c->app->log->debug('Get total result from cache');
-
-	# Set cutoff unless already set
-	$url->query({cutoff => 'true'}) unless defined $cutoff;
-      }
-
-      # No cache
-      else {
-	$c->stash('search.totalResults' => 0);
-      };
-
-      $url->query({page => $start_page});
-
-      # This may be incorrect
-      $c->stash('search.itemsPerPage' => $count);
-
-      # Only set this when on test port
-      if ($c->korap_test_port) {
-	$c->stash('search.apirequest' => $url->to_string);
-      };
-
-      my $ua = Mojo::UserAgent->new;
-
-      # Set timeout to 2 minutes
-      $ua->inactivity_timeout(120);
-
-      $c->app->log->debug('Search for ' . $url->to_string);
-
-      # Blocking request
-      # TODO: Make non-blocking
-      my $tx = $ua->get($url);
-
-      if (my $e = $tx->error) {
-	$c->notify(
-	  error =>
-	    ($e->{code} ? $e->{code} . ': ' : '') .
-	      $e->{message} . ' (remote)'
-        );
-	return;
-      };
-
-      # Request successful
-      if (my $res = $tx->success) {
-
-	$c->stash('search.apiresponse' => $res->body);
-
-	my $json = $res->json;
-	return $json unless $cb;
-
-	# Reformat benchmark counter
-	my $benchmark = $json->{benchmark};
-	if ($benchmark && $benchmark =~ s/\s+(m)?s$//) {
-	  $benchmark = sprintf("%.2f", $benchmark) . ($1 ? $1 : '') . 's';
-	};
-
-	for ($c->stash) {
-	  $_->{'search.benchmark'}    = $benchmark;
-	  $_->{'search.itemsPerPage'} = $json->{itemsPerPage};
-	  $_->{'search.timeExceeded'} = ($json->{timeExceeded} &&
-					 $json->{timeExceeded}
-					   eq Mojo::JSON::true) ? 1 : 0;
-	  $_->{'search.query'}        = $json->{request}->{query};
-	  $_->{'search.hits'}         = map_matches($json->{matches});
-	};
-
-	# Learn results
-	unless ($total_results) {
-	  if ($json->{totalResults} && $json->{totalResults} > -1) {
-	    $c->app->log->debug('Cache total result');
-	    $c->chi->set('total-' . $cache_url => $json->{totalResults}, '120min');
-	  };
-	  $c->stash('search.totalResults' => $json->{totalResults});
-	};
-
-	if ($json->{warning}) {
-	  # Temp
-	  $json->{warning} =~ s/;\s+null$//;
-	  $c->notify(warn => $json->{warning});
-	};
-
-	# Check for error
-	$plugin->_notify_on_error($c, 0, $res, $json);
-      }
-
-      # Request failed
-      else {
-	return unless $cb;
-	$plugin->_notify_on_error($c, 1, $tx->res);
-      };
-
-      # Run embedded template
-      my $v = $cb->();
-
-      # Delete useless stash keys
-      foreach (@remove_from_stash) {
-	delete $c->stash->{'search.' . $_};
-      };
-
-      return $v;
-    }
-  );
-
-
-  # Establish 'search_hits' helper
-  $mojo->helper(
-    search_hits => sub {
-      my $c = shift;
-      my $cb = pop;
-
-      if (!ref $cb || !(ref $cb eq 'CODE')) {
-	$mojo->log->error("search_hits expects a code block");
-	return '';
-      };
-
-      my $hits = delete $c->stash->{'search.hits'};
-      my $string;
-
-      # Iterate over all hits
-      foreach (@$hits) {
-	local $_ = $_;
-	$c->stash('search.hit' => $_);
-	$string .= $cb->($_);
-      };
-
-      # Delete unnecessary stash values
-      delete $c->stash->{'search.hit'};
-      return b($string || '');
-    }
-  );
-};
-
-sub _notify_on_error {
-  my ($self, $c, $failure, $res) = @_;
-  my $json = $res;
-
-  my $log = $c->app->log;
-
-  if (blessed $res) {
-    if (blessed $res ne 'Mojo::JSON') {
-      $json = $res->json;
-    };
-  }
-  else {
-    $json = undef;
-  };
-
-  if ($json) {
-    if ($json->{error}) {
-      # Temp
-      $json->{error} =~ s/;\s+null$//;
-      $c->notify(error => $json->{error});
-      return;
-    }
-
-    # New error messages
-    elsif ($json->{errstr}) {
-      # Temp
-      $json->{errstr} =~ s/;\s+null$//;
-      $c->notify(error => $json->{errstr});
-      return;
-    }
-
-    # policy service error messages
-    elsif ($json->{status}) {
-      $c->notify(error => 'Middleware error ' . $json->{status});
-      return;
-    };
-  };
-
-  if ($failure) {
-    $c->notify(error => (
-      ($res->{code}    ? $res->{code} . ': ' : '') .
-      ($res->{message} ? $res->{message}     : 'Unknown error') .
-      ' (remote)'
-    ));
-  };
-};
-
-
-1;
-
-__DATA__
-{
-  "query" : "tokens:s:baum",
-  "matches" : [ {
-    "author" : "ErikDunsing,Ninjamask,Magnus",
-    "textClass" : "freizeit-unterhaltung reisen",
-    "corpusID" : "WPD",
-    "title" : "Friedrich Wilhelm (Brandenburg)",
-    "foundries" : "opennlp opennlp/morpho xip xip/morpho xip/constituency xip/dependency base base/sentences base/paragraphs 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 treetagger treetagger/morpho",
-    "tokenization" : "opennlp#tokens",
-    "field" : "tokens",
-    "startMore" : true,
-    "endMore" : true,
-    "docID" : "WPD_WWW.04738",
-    "snippet" : "<span class=\"context-left\"><span class=\"more\"></span>wurde ihm der Mirabolanen frucht und </span><span class=\"match\">baum</span><span class=\"context-right\"> &lt;Terminalia catappa L. oder Terminalia citrina<span class=\"more\"></span></span>",
-    "ID" : "match-WPD!WPD_WWW.04738-p265-266",
-    "pubDate" : "2005-03-28"
-  }, {
-    "author" : "Sk-Bot,Wiegels,Katharina",
-    "textClass" : "freizeit-unterhaltung reisen",
-    "corpusID" : "WPD",
-    "title" : "Hans Heinrich von Wuthenau",
-    "foundries" : "corenlp corenlp/namedentities corenlp/namedentities/ne_dewac_175m_600 corenlp/namedentities corenlp/namedentities/ne_hgc_175m_600 opennlp opennlp/morpho connexor connexor/morpho connexor/syntax connexor/phrase base base/sentences base/paragraphs xip xip/morpho xip/constituency xip/dependency mate mate/morpho mate/dependency treetagger treetagger/morpho",
-    "tokenization" : "opennlp#tokens",
-    "field" : "tokens",
-    "startMore" : true,
-    "endMore" : true,
-    "docID" : "WPD_WWW.07095",
-    "snippet" : "<span class=\"context-left\"><span class=\"more\"></span>:Jch heisse drumb Gerad', das dieser </span><span class=\"match\">baum</span><span class=\"context-right\"> uns zeigetDas man aufrichtig sey, nichts<span class=\"more\"></span></span>",
-    "ID" : "match-WPD!WPD_WWW.07095-p154-155",
-    "pubDate" : "2005-03-28"
-  }, {
-    "author" : "Zwobot,Holdbold,WiseWoman",
-    "textClass" : "kultur literatur",
-    "corpusID" : "WPD",
-    "title" : "Johann Rist",
-    "foundries" : "mate mate/morpho mate/dependency xip xip/morpho xip/constituency xip/dependency corenlp corenlp/namedentities corenlp/namedentities/ne_dewac_175m_600 corenlp/namedentities corenlp/namedentities/ne_hgc_175m_600 treetagger treetagger/morpho connexor connexor/morpho connexor/syntax connexor/phrase opennlp opennlp/morpho base base/sentences base/paragraphs",
-    "tokenization" : "opennlp#tokens",
-    "field" : "tokens",
-    "startMore" : true,
-    "endMore" : true,
-    "docID" : "WPD_RRR.05363",
-    "snippet" : "<span class=\"context-left\"><span class=\"more\"></span>Emblem wird das heilige holtz der </span><span class=\"match\">baum</span><span class=\"context-right\"> Guajacum genant, fremde Brasilianische landschaft, der<span class=\"more\"></span></span>",
-    "ID" : "match-WPD!WPD_RRR.05363-p373-374",
-    "pubDate" : "2005-03-28"
-  } ],
-  "totalResults" : 3,
-  "startIndex" : 0,
-  "itemsPerPage" : 25,
-  "benchmarkSearchResults" : "1.638 ms",
-  "benchmarkHitCounter" : "4.332 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" : "orth",
-        "match" : "match:eq"
-      }
-    },
-    "collections" : [ {
-      "@type" : "korap:meta-filter",
-      "@value" : {
-        "@type" : "korap:term",
-        "@field" : "korap:field#corpusID",
-        "@value" : "WPD"
-      }
-    } ],
-    "meta" : { }
-  },
-  "context" : {
-    "left" : [ "token", 6 ],
-    "right" : [ "token", 6 ]
-  }
-}
diff --git a/lib/Korap/Search.pm b/lib/Korap/Search.pm
deleted file mode 100644
index 5980b3f..0000000
--- a/lib/Korap/Search.pm
+++ /dev/null
@@ -1,58 +0,0 @@
-package Korap::Search;
-use Mojo::Base 'Mojolicious::Controller';
-
-# Add X-Forwarded-For to user agent call everywhere
-
-
-# This action will render a template
-sub remote {
-  my $c = shift;
-  $c->layout('default');
-  $c->title('KorAP');
-
-  my $api = $c->config('KorAP')->{'api-0.1'};
-
-  # Todo: Support query building directly
-  if ((scalar $c->param('action') // '') eq 'inspect') {
-    my $url = Mojo::URL->new($api)->path('search');
-
-    $url->query({
-      q  => scalar $c->param('q') // '',
-      ql => scalar $c->param('ql') // 'poliqarp'
-    });
-
-    my $tx = $c->ua->build_tx(TRACE => $url);
-
-    $c->app->log->debug('Trace URL: ' . $url);
-    $c->app->log->debug('Trace Request: ' . $tx->req->url);
-
-    if (my $response = $c->ua->start($tx)->success) {
-      $c->stash('search.query' => $response->json);
-    }
-    else {
-      $c->notify(error => 'Unable to trace query');
-    };
-
-    $c->param(cutoff => 1);
-    return $c->render(template => 'query_info');
-  }
-
-  elsif ($c->param('snippet')) {
-    $c->layout('snippet');
-  };
-
-  $c->render(template => 'search');
-};
-
-
-1;
-
-
-__END__
-
-[{"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"}]
-
-
-http://10.0.10.13:8070/api/v1/resource/matchInfo?id=match-WPD!WPD_NNN.02848-p1223-1224&f=mate&l=
-
-{"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":false,"endMore":false,"docID":"WPD_NNN.02848","snippet":"<span class=\"context-left\"></span><span class=\"match\"><span title=\"mate/l:besonders\"><span title=\"mate/p:ADV\">Besonders</span></span> <span title=\"mate/l:auffällig\"><span title=\"mate/m:degree:pos\"><span title=\"mate/p:ADJD\">auffällig</span></span></span> <span title=\"mate/l:sein\"><span title=\"mate/m:mood:ind\"><span title=\"mate/m:number:pl\"><span title=\"mate/m:person:3\"><span title=\"mate/m:tense:pres\"><span title=\"mate/p:VAFIN\">sind</span></span></span></span></span></span> <span title=\"mate/l:schließlich\"><span title=\"mate/p:ADV\">schließlich</span></span> <span title=\"mate/l:noch\"><span title=\"mate/p:ADV\">noch</span></span> <span title=\"mate/l:der\"><span title=\"mate/m:case:nom\"><span title=\"mate/m:gender:masc\"><span title=\"mate/m:number:sg\"><span title=\"mate/p:ART\">der</span></span></span></span></span> <span title=\"mate/l:pohutukawa\"><span title=\"mate/m:case:nom\"><span title=\"mate/m:gender:masc\"><span title=\"mate/m:number:sg\"><span title=\"mate/p:NE\">Pohutukawa</span></span></span></span></span> <span title=\"mate/l:und\"><span title=\"mate/p:KON\">und</span></span> <span title=\"mate/l:der\"><span title=\"mate/m:case:nom\"><span title=\"mate/m:gender:masc\"><span title=\"mate/m:number:sg\"><span title=\"mate/p:ART\">der</span></span></span></span></span> <span title=\"mate/l:cabbage\"><span title=\"mate/m:case:nom\"><span title=\"mate/m:gender:masc\"><span title=\"mate/m:number:sg\"><span title=\"mate/p:NE\">Cabbage</span></span></span></span></span> <span title=\"mate/l:tree\"><span title=\"mate/m:gender:masc\"><span title=\"mate/m:number:sg\"><span title=\"mate/p:NE\"><span title=\"mate/m:case:nom\">Tree</span></span></span></span></span></span><span class=\"context-right\"></span>","ID":"match-WPD!WPD_NNN.02848-p1213-1224","pubDate":"2005-03-28","context":{"left":["token",0],"right":["token",0]}}
diff --git a/lib/Korap/Tutorial.pm b/lib/Korap/Tutorial.pm
deleted file mode 100644
index f9d99da..0000000
--- a/lib/Korap/Tutorial.pm
+++ /dev/null
@@ -1,24 +0,0 @@
-package Korap::Tutorial;
-use Mojo::Base 'Mojolicious::Controller';
-
-sub page {
-  my $c = shift;
-
-  if ($c->param('embedded')) {
-    $c->layout('snippet');
-    $c->stash(embedded => 1);
-  }
-  else {
-    $c->layout('default');
-  };
-  $c->title('KorAP');
-
-  my $page = $c->stash('tutorial');
-  return $c->render(template => 'tutorial/' . $page);
-};
-
-
-1;
-
-
-__END__