Release preparation, documentation, fixing vc bugs
diff --git a/lib/Kalamar.pm b/lib/Kalamar.pm
index d05257e..d1d0049 100644
--- a/lib/Kalamar.pm
+++ b/lib/Kalamar.pm
@@ -5,6 +5,8 @@
 
 our $VERSION;
 
+# TODO: The FAQ-Page has a contact form for new questions
+
 # Start the application and register all routes and plugins
 sub startup {
   my $self = shift;
@@ -31,9 +33,9 @@
     'Search',                 # Abstract Search framework
     'CHI',                    # Global caching mechanism
     'TagHelpers::Pagination', # Pagination widget
-    'DocNavi',                # Navigation for documentation
-    'KalamarHelpers',         # Specific Helpers for Kalamar
-    'KalamarTagHelpers'       # Specific Taghelpers for Kalamar
+    'Number::Commify',        # Localize numbers
+    'KalamarHelpers'          # Specific Helpers for Kalamar
+
   ) {
     $self->plugin($_);
   };
@@ -42,8 +44,8 @@
   $self->plugin('MailException' => $self->config('MailException'));
 
   # Configure documentation navigation
-  my $navi = b($self->home . '/templates/doc/_nav.json')->slurp;
-  $self->config(navi => decode_json($navi));
+  my $navi = b($self->home . '/templates/doc/navigation.json')->slurp;
+  $self->config(navi => decode_json($navi)) if $navi;
 
   # Establish routes
   my $r = $self->routes;
@@ -52,109 +54,16 @@
   $r->get('/')->to('search#query')->name('index');
 
   # Documentation
-  $r->get('/doc')->to('documentation#page', page => 'korap');
+  $r->get('/doc')->to('documentation#page', page => 'korap')->name('doc_start');
   $r->get('/doc/:page')->to('documentation#page', scope => undef);
   $r->get('/doc/*scope/:page')->to('documentation#page')->name('doc');
-};
 
-
-1;
-
-
-__END__
-
-
-  # Set default totle
-#  $self->defaults(
-#    layout => 'main',
-#    title => 'KorAP - Corpus Analysis Platform'
-#  );
-
-
-  $self->hook(
-    before_dispatch => sub {
-      my $c = shift;
-      my $host = $c->req->headers->header('X-Forwarded-Host');
-      if ($host && $host eq 'korap.ids-mannheim.de') {
-	$c->req->url->base->path('/kalamar/');
-      };
-    }) if $self->mode eq 'production';
-
-
-
-  # Load plugins
-  foreach (qw/
-	      Number::Commify
-	      /) {
-    $self->plugin($_);
-  };
-
-  # $self->plugin(AssetPack => { minify => 1 });
-  $self->plugin('AssetPack');
-  $self->plugin('AssetPack::LibSass');
-
-  # Add assets for AssetPack
-  $self->asset(
-    'kalamar.css' => (
-
-      # Sass files
-      '/sass/style.scss',
-      '/sass/sidebar.scss',
-      '/sass/tutorial.scss',
-      '/sass/hint.scss',
-      '/sass/query.scss',
-      '/sass/matchinfo.scss',
-      '/sass/pagination.scss',
-      '/sass/kwic-4.0.scss',
-      '/sass/alertify.scss',
-
-      # CSS files
-      '/css/font-awesome.min.css',
-      '/css/media.css',
-      '/css/highlight.css',
-      $self->notifications->styles
-    )
-  );
-
-  $self->asset(
-    'kalamar.js' => (
-#      '/js/d3.v3.min.js',
-#      '/js/dagre-d3.min.js',
-#      '/js/dagre-d3.js',
-#      '/js/translateTree.js',
-      '/js/tutorialCookie.js',
-      '/js/translateTable.js',
-      '/js/hint.js',
-      '/js/highlight.pack.js',
-      '/js/ajax.js',
-      $self->notifications->scripts
-    )
-  );
-
-  $self->helper(
-    date_format => sub {
-      my ($c, $date) = @_;
-      return $date;
-    }
-  );
-
-
-  # Base search route
-  $r->get('/')->to('search#query')->name('index');
-
-  # Get match information
+  # Match route
   my $corpus = $r->route('/corpus/:corpus_id');
-  my $doc    = $corpus->route('/#doc_id');
-  my $match = $doc->route('/:match_id')
-    ->to('search#match_info')
-      ->name('match');
-
-  # Tutorial data
-  $r->get('/tutorial')->to('tutorial#page', tutorial => 'index');
-  $r->get('/tutorial/(*tutorial)')->to('tutorial#page')->name('tutorial');
-
-
-  # Todo: The FAQ-Page has a contact form for new questions
+  my $doc    = $corpus->get('/:doc_id');
+  my $text   = $doc->get('/:text_id');
+  my $match  = $text->get('/:match_id');
+  $match->to('search#match_info')->name('match');
 };
 
 
diff --git a/lib/Kalamar/API.pm b/lib/Kalamar/API.pm
index 63362ea..9b8a529 100644
--- a/lib/Kalamar/API.pm
+++ b/lib/Kalamar/API.pm
@@ -1,4 +1,4 @@
-#package Kalamar::API;
+package Kalamar::API;
 use Mojo::Base 'Mojolicious::Plugin';
 use Scalar::Util qw/blessed weaken/;
 use strict;
@@ -6,10 +6,10 @@
 
 # KorAP Search engine for Mojolicious::Plugin::Search
 
-# Todo: Add fixtures
-# Todo: Support search in corpus and virtualcollection
-# Todo: Support caching everywhere!
-# Todo: Correct use of stash info everywhere!
+# 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 {
diff --git a/lib/Kalamar/Controller/Documentation.pm b/lib/Kalamar/Controller/Documentation.pm
index ef3b751..3588560 100644
--- a/lib/Kalamar/Controller/Documentation.pm
+++ b/lib/Kalamar/Controller/Documentation.pm
@@ -20,6 +20,7 @@
   my $page = $c->stash('page');
   push(@path, $page);
 
+  # Set navigation to sidebar
   $c->content_for(
     sidebar => '<nav>' . $c->doc_navi($c->config('navi')) . '</nav>'
   );
@@ -37,3 +38,54 @@
 
 
 __END__
+
+=pod
+
+=encoding utf8
+
+=head1 NAME
+
+Kalamar::Controller::Documentation
+
+
+=head1 DESCRIPTION
+
+L<Kalamar::Controller::Documentation> is the controller class for
+documentation related endpoints in Kalamar.
+
+
+=head1 METHODS
+
+L<Kalamar::Controller::Documentation> inherits all methods from
+L<Mojolicious::Controller> and implements the following new ones.
+
+=head2 page
+
+Action for all documentation pages. The following stash parameters are supported:
+
+=head3 doc_base
+
+=head3 scope
+
+=head3 page
+
+=head3 embedded
+
+=head1 COPYRIGHT AND LICENSE
+
+Copyright (C) 2015, L<IDS Mannheim|http://www.ids-mannheim.de/>
+Author: L<Nils Diewald|http://nils-diewald.de/>
+
+Kalamar is developed as part of the L<KorAP|http://korap.ids-mannheim.de/>
+Corpus Analysis Platform at the Institute for German Language
+(L<IDS|http://ids-mannheim.de/>),
+funded by the
+L<Leibniz-Gemeinschaft|http://www.leibniz-gemeinschaft.de/en/about-us/leibniz-competition/projekte-2011/2011-funding-line-2/>
+and supported by the L<KobRA|http://www.kobra.tu-dortmund.de> project,
+funded by the Federal Ministry of Education and Research
+(L<BMBF|http://www.bmbf.de/en/>).
+
+Kalamar is free software published under the
+L<BSD-2 License|https://raw.githubusercontent.com/KorAP/Kalamar/master/LICENSE).
+
+=cut
diff --git a/lib/Kalamar/Controller/Search.pm b/lib/Kalamar/Controller/Search.pm
index 494634f..09ab580 100644
--- a/lib/Kalamar/Controller/Search.pm
+++ b/lib/Kalamar/Controller/Search.pm
@@ -66,17 +66,8 @@
 };
 
 
-1;
 
-
-__END__
-
-
-
-
-
-
-# Get informations about a match
+# Get information about a match
 sub match_info {
   my $c = shift;
 
@@ -97,8 +88,8 @@
   # Use the API for fetching matching information non-blocking
   $c->search->match(
     corpus_id => $c->stash('corpus_id'),
-    text_id   => $c->stash('text_id'),
     doc_id    => $c->stash('doc_id'),
+    text_id   => $c->stash('text_id'),
     match_id  => $c->stash('match_id'),
     %query,
 
@@ -127,18 +118,98 @@
   );
 };
 
+
 1;
 
 
 __END__
 
+=pod
 
-# Todo: Add X-Forwarded-For to user agent call everywhere
-  $self->hook(before_dispatch => sub {
-      my $c = shift;
-      my $h = $c->res->headers;
-      $h->header( 'Access-Control-Allow-Origin' => '*' );
-      $h->header( 'Access-Control-Allow-Methods' => 'GET, PUT, POST, DELETE, OPTIONS' );
-      $h->header( 'Access-Control-Max-Age' => 3600 );
-      $h->header( 'Access-Control-Allow-Headers' => 'Content-Type, Authorization, X-Requested-With' );
-    });
+=encoding utf8
+
+=head1 NAME
+
+Kalamar::Controller::Search
+
+
+=head1 DESCRIPTION
+
+L<Kalamar::Controller::Search> is the controller class for
+search related endpoints in Kalamar.
+
+
+=head1 METHODS
+
+L<Kalamar::Controller::Search> inherits all methods from
+L<Mojolicious::Controller> and implements the following new ones.
+
+=head2 search
+
+Action for all documentation pages.
+
+=head3 q
+
+Query parameter
+
+=head3 ql
+
+Query language
+
+=head3 action
+
+May be C<inspect>.
+
+=head3 snippet
+
+=head3 cutoff
+
+=head3 count
+
+=head3 p
+
+Number of page
+
+
+=head2 match
+
+/:corpus_id/:doc_id/:text_id/:match_id
+
+=head3 foundry
+
+=head3 layer
+
+=head3 spans
+
+true or false
+
+=head3 corpus_id
+
+
+stash value
+
+=head3 doc_id
+
+=head3 text_id
+
+=head3 match_id
+
+
+=head1 COPYRIGHT AND LICENSE
+
+Copyright (C) 2015, L<IDS Mannheim|http://www.ids-mannheim.de/>
+Author: L<Nils Diewald|http://nils-diewald.de/>
+
+Kalamar is developed as part of the L<KorAP|http://korap.ids-mannheim.de/>
+Corpus Analysis Platform at the Institute for German Language
+(L<IDS|http://ids-mannheim.de/>),
+funded by the
+L<Leibniz-Gemeinschaft|http://www.leibniz-gemeinschaft.de/en/about-us/leibniz-competition/projekte-2011/2011-funding-line-2/>
+and supported by the L<KobRA|http://www.kobra.tu-dortmund.de> project,
+funded by the Federal Ministry of Education and Research
+(L<BMBF|http://www.bmbf.de/en/>).
+
+Kalamar is free software published under the
+L<BSD-2 License|https://raw.githubusercontent.com/KorAP/Kalamar/master/LICENSE).
+
+=cut
diff --git a/lib/Kalamar/Plugin/KalamarHelpers.pm b/lib/Kalamar/Plugin/KalamarHelpers.pm
index d514ceb..5434cd1 100644
--- a/lib/Kalamar/Plugin/KalamarHelpers.pm
+++ b/lib/Kalamar/Plugin/KalamarHelpers.pm
@@ -1,11 +1,164 @@
 package Kalamar::Plugin::KalamarHelpers;
 use Mojo::Base 'Mojolicious::Plugin';
+use Mojo::JSON 'decode_json';
+use Mojo::JSON::Pointer;
+use Mojo::ByteStream 'b';
+use Mojo::Util qw/xml_escape/;
 
-
-# Helpers for Kalamar
 sub register {
   my ($plugin, $mojo) = @_;
 
+  # Embed the korap architecture image
+  $mojo->helper(
+    korap_overview => sub {
+      my $c = shift;
+      my $scope = shift;
+
+      my $url = $c->url_with('/img/korap-overview.svg');
+
+      # If there is a different base - append this as a base
+      # $url->query([base => $c->stash('doc_base') // '/']);
+      $url->query([base => $c->url_for('doc_start')->to_abs // '/']);
+
+      $url->fragment($scope);
+
+      return $c->tag('object',
+	data => $url,
+	type => 'image/svg+xml',
+	alt  => $c->loc('korap_overview'),
+	id   => 'overview'
+      );
+    }
+  );
+
+  # Documentation link
+  $mojo->helper(
+    doc_link_to => sub {
+      my $c = shift;
+      my $title = shift;
+      my $page = pop;
+      my $scope = shift;
+      return $c->link_to(
+	$title,
+	$c->url_with('doc', scope => $scope, page => $page)
+      );
+    }
+  );
+
+
+  # Documentation alert - Under Construction!
+  $mojo->helper(
+    doc_uc => sub {
+      return shift->tag('p', 'Under Construction!')
+    }
+  );
+
+
+  # Documentation navigation helper
+  $mojo->helper(
+    doc_navi => sub {
+      my $c = shift;
+      my $items = pop;
+      my $scope = shift;
+
+      # Create unordered list
+      my $html = "<ul>\n";
+
+      # Embed all link tags
+      foreach (@$items) {
+
+	my ($active, $url) = 0;
+
+	# There is a fragment!
+	if (index($_->{id}, '#') == 0) {
+
+	  my $part_scope = scalar($scope);
+	  $part_scope =~ s!\/([^\/]+)$!!;
+	  my $page = $1;
+	  my $id = $_->{id};
+	  $id =~ s/^#//;
+
+	  $url = $c->url_with(
+	    'doc',
+	    'scope' => $part_scope,
+	    'page' => $page
+	  );
+
+	  $url->fragment($id);
+	}
+
+	# There is no fragment
+	else {
+
+	  # The item is active
+	  if ($c->stash('page') && $c->stash('page') eq $_->{id}) {
+	    $active = 1;
+	  };
+
+	  # Generate url with query parameter inheritance
+	  $url = $c->url_with(
+	    'doc',
+	    'scope' => $scope,
+	    'page' => $_->{id}
+	  );
+
+	  # Canonicalize (for empty scopes)
+	  $url->path->canonicalize;
+	};
+
+	my @classes;
+	push(@classes, $_->{'class'}) if $_->{'class'};
+	push(@classes, 'active') if $active;
+
+
+	# New list item
+	$html .= '<li';
+	if (@classes) {
+	  $html .= ' class="' . join(' ', @classes) . '"';
+	};
+	$html .= '>';
+
+
+	# Generate link
+	$html .= $c->link_to($_->{title}, $url);
+
+	# Set sub entries
+	if ($_->{items} && ref($_->{items}) eq 'ARRAY') {
+	  $html .= "\n";
+	  my $subscope = $scope ? scalar($scope) . '/' . $_->{id} : $_->{id};
+	  $html .= $c->doc_navi($subscope, $_->{items});
+	  $html .= "</li>\n";
+	}
+	else {
+	  $html .= "</li>\n";
+	};
+      };
+      return $html . "</ul>\n";
+    }
+  );
+
+
+  # Create helper for queries in the tutorial
+  $mojo->helper(
+    kalamar_tut_query => sub {
+      my ($c, $ql, $q, %param) = @_;
+
+      # Escape query for html embedding
+      $q = xml_escape $q;
+
+      # Return tag
+      b('<pre class="query tutorial" ' .
+	  qq!data-query="$q" data-query-cutoff="! .
+	    ($param{cutoff} ? 1 : 0) .
+	      '"' .
+		qq! data-query-language="$ql">! .
+		  '<code>' . $q . '</code>' .
+		    '</pre>'
+		);
+    }
+  );
+
+
   # Check for test port
   $mojo->helper(
     kalamar_test_port => sub {
@@ -29,4 +182,169 @@
     });
 };
 
+
 1;
+
+
+__END__
+
+
+
+
+
+  # Create links in the tutorial that make sure the current position is preserved,
+  # in case the tutorial was opened embedded
+  $mojo->helper(
+    kalamar_tut_link_to => sub {
+      my $c = shift;
+      my $title = shift;
+      my $link = shift;
+      my $host = $c->req->headers->header('X-Forwarded-Host');
+      my $url = $c->url_for($link);
+
+      # Link is part of the embedded tutorial
+      if ($c->param('embedded')) {
+	$url->query({ embedded => 1 });
+	return $c->link_to(
+	  $title,
+	  $url,
+	  onclick => qq!setTutorialPage("$url")!
+	);
+      };
+
+      # Build link
+      return $c->link_to($title, $url);
+    }
+  );
+
+
+
+  # Create helper for queries in the tutorial
+  $mojo->helper(
+    kalamar_tut_query => sub {
+      my ($c, $ql, $q, %param) = @_;
+      my $onclick = 'top.useQuery(this)';
+
+      my ($fail, $pass, @report) = (0,0);
+
+      if ($c->param('testing')) {
+	$c->res->headers->cache_control('max-age=1, no-cache');
+      };
+
+      # Store current tutorial position
+      if ($c->param('embedded')) {
+	$onclick = 'setTutorialPage(this);' . $onclick;
+      }
+
+      # Tutorial wasn't embedded - but opened for testing
+ #     elsif ($c->param('testing') &&
+#	       $c->kalamar_test_port &&
+#		 $param{tests}) {
+#
+# Currently disabled
+
+#	my $tests = $param{tests} // [];
+#	my $index = $c->search(
+#	  query => $q,
+#	  ql => $ql,
+#	  cutoff => 'true',
+#	  no_cache => 1
+#	);
+#
+#	# Get the raw results
+#	my $json = decode_json($index->api_response);
+#
+#	# There is a response
+#	if ($json) {
+#	  my $json_pointer = Mojo::JSON::Pointer->new($json);
+#	  foreach my $test (@$tests) {
+#	    my ($type, $path, @rest) = @$test;
+#
+#	    # Check for equality
+#	    if ($type eq 'is') {
+#	      my $found = $json_pointer->get($path);
+#	      if ($found && $found eq $rest[0]) {
+#		$pass++;
+#	      }
+#	      else {
+#		my $result = $path . q! isn't ! . shift @rest;
+#		$result .= ' but was ' . $found if $found;
+#		$result .= '; ' . join('; ', @rest);
+#		push(@report, $result);
+#		$fail++;
+#	      };
+#	    }
+#
+#	    # Check for inequality
+#	    elsif ($type eq 'isnt') {
+#	      if ($json_pointer->get($path) ne $rest[0]) {
+#		$pass++;
+#	      }
+#	      else {
+#		push(@report, $path . q! is ! . join('; ', @rest));
+#		$fail++;
+#	      };
+#	    }
+#
+#	    # Check for existence
+#	    elsif ($type eq 'ok') {
+#	      if ($json_pointer->contains($path)) {
+#		$pass++;
+#	      }
+#	      else {
+#		push(@report, $path . q! doesn't exist; ! . join('; ', @rest));
+#		$fail++;
+#	      };
+#	    }
+#
+#	    # Check for inexistence
+#	    elsif ($type eq 'not_ok') {
+#	      unless ($json_pointer->contains($path)) {
+#		$pass++;
+#	      }
+#	      else {
+#		push(@report, $path . q! doesn't exist; ! . join('; ', @rest));
+#		$fail++;
+#	      };
+#	    };
+#	  };
+#	}
+#	else {
+#	  # There may be notifications here!
+#	  $fail++ foreach @$tests;
+#	};
+#
+#	# Emit hook to possible subscribers
+#	# This is used for self-testing
+#	# $plugin->emit_hook(kalamar_tut_query => (
+#	#   query_language => $ql,
+#	#   query => $q,
+#	#   %param
+#	# ));
+ #     };
+
+      # Escape query for html embedding
+      $q = xml_escape $q;
+
+      # There is something to talk about
+      my $msg = '';
+      if (($pass + $fail) > 0) {
+	$msg .= '<div class="test">';
+	$msg .= qq!<p class="pass">Pass: $pass</p>!;
+	$msg .= qq!<p class="fail">Fail: $fail</p>! if $fail;
+	foreach (@report) {
+	  $msg .= qq!<p class="fail">${_}</p>!;
+	};
+	$msg .= '</div>';
+      };
+
+      # Return tag
+      b('<pre class="query tutorial" onclick="' . $onclick . '" ' .
+	  qq!data-query="$q" data-query-cutoff="! .
+	    ($param{cutoff} ? 1 : 0) .
+	      '"' .
+		qq! data-query-language="$ql"><code>! .
+		  $q .
+		    '</code></pre>' . $msg);
+    }
+  );
diff --git a/lib/Kalamar/Plugin/KalamarTagHelpers.pm b/lib/Kalamar/Plugin/KalamarTagHelpers.pm
deleted file mode 100644
index d039604..0000000
--- a/lib/Kalamar/Plugin/KalamarTagHelpers.pm
+++ /dev/null
@@ -1,235 +0,0 @@
-package Kalamar::Plugin::KalamarTagHelpers;
-use Mojo::Base 'Mojolicious::Plugin';
-use Mojo::JSON 'decode_json';
-use Mojo::JSON::Pointer;
-use Mojo::ByteStream 'b';
-use Mojo::Util qw/xml_escape/;
-
-sub register {
-  my ($plugin, $mojo) = @_;
-
-  # Embed the korap architecture image
-  $mojo->helper(
-    korap_overview => sub {
-      my $c = shift;
-      my $scope = shift;
-
-      my $url = $c->url_with('/img/korap-overview.svg');
-
-      # If there is a different base - append this as a base
-      $url->query([base => $c->stash('doc_base') // '/']);
-
-      $url->fragment($scope);
-
-      return $c->tag('object',
-	data => $url,
-	type => 'image/svg+xml',
-	alt  => $c->loc('korap_overview'),
-	id   => 'overview'
-      );
-    }
-  );
-
-
-
-  $mojo->helper(
-    doc_link_to => sub {
-      my $c = shift;
-      my $title = shift;
-      my $page = pop;
-      my $scope = shift;
-      return $c->link_to($title, $c->url_with('doc', scope => $scope, page => $page));
-    }
-  );
-
-  $mojo->helper(
-    doc_uc => sub {
-      return shift->tag('p', 'Under Construction!')
-    }
-  );
-
-
-  # Create helper for queries in the tutorial
-  $mojo->helper(
-    kalamar_tut_query => sub {
-      my ($c, $ql, $q, %param) = @_;
-
-      # Escape query for html embedding
-      $q = xml_escape $q;
-
-      # Return tag
-      b('<pre class="query tutorial" ' .
-	  qq!data-query="$q" data-query-cutoff="! .
-	    ($param{cutoff} ? 1 : 0) .
-	      '"' .
-		qq! data-query-language="$ql">! .
-		  '<code>' . $q . '</code>' .
-		    '</pre>'
-		);
-    }
-  );
-
-
-  # Create links in the tutorial that make sure the current position is preserved,
-  # in case the tutorial was opened embedded
-  $mojo->helper(
-    kalamar_tut_link_to => sub {
-      my $c = shift;
-      my $title = shift;
-      my $link = shift;
-      my $host = $c->req->headers->header('X-Forwarded-Host');
-      my $url = $c->url_for($link);
-
-      # Link is part of the embedded tutorial
-      if ($c->param('embedded')) {
-	$url->query({ embedded => 1 });
-	return $c->link_to(
-	  $title,
-	  $url,
-	  onclick => qq!setTutorialPage("$url")!
-	);
-      };
-
-      # Build link
-      return $c->link_to($title, $url);
-    }
-  );
-};
-
-1;
-
-
-__END__
-
-
-
-
-  # Create helper for queries in the tutorial
-  $mojo->helper(
-    kalamar_tut_query => sub {
-      my ($c, $ql, $q, %param) = @_;
-      my $onclick = 'top.useQuery(this)';
-
-      my ($fail, $pass, @report) = (0,0);
-
-      if ($c->param('testing')) {
-	$c->res->headers->cache_control('max-age=1, no-cache');
-      };
-
-      # Store current tutorial position
-      if ($c->param('embedded')) {
-	$onclick = 'setTutorialPage(this);' . $onclick;
-      }
-
-      # Tutorial wasn't embedded - but opened for testing
- #     elsif ($c->param('testing') &&
-#	       $c->kalamar_test_port &&
-#		 $param{tests}) {
-#
-# Currently disabled
-
-#	my $tests = $param{tests} // [];
-#	my $index = $c->search(
-#	  query => $q,
-#	  ql => $ql,
-#	  cutoff => 'true',
-#	  no_cache => 1
-#	);
-#
-#	# Get the raw results
-#	my $json = decode_json($index->api_response);
-#
-#	# There is a response
-#	if ($json) {
-#	  my $json_pointer = Mojo::JSON::Pointer->new($json);
-#	  foreach my $test (@$tests) {
-#	    my ($type, $path, @rest) = @$test;
-#
-#	    # Check for equality
-#	    if ($type eq 'is') {
-#	      my $found = $json_pointer->get($path);
-#	      if ($found && $found eq $rest[0]) {
-#		$pass++;
-#	      }
-#	      else {
-#		my $result = $path . q! isn't ! . shift @rest;
-#		$result .= ' but was ' . $found if $found;
-#		$result .= '; ' . join('; ', @rest);
-#		push(@report, $result);
-#		$fail++;
-#	      };
-#	    }
-#
-#	    # Check for inequality
-#	    elsif ($type eq 'isnt') {
-#	      if ($json_pointer->get($path) ne $rest[0]) {
-#		$pass++;
-#	      }
-#	      else {
-#		push(@report, $path . q! is ! . join('; ', @rest));
-#		$fail++;
-#	      };
-#	    }
-#
-#	    # Check for existence
-#	    elsif ($type eq 'ok') {
-#	      if ($json_pointer->contains($path)) {
-#		$pass++;
-#	      }
-#	      else {
-#		push(@report, $path . q! doesn't exist; ! . join('; ', @rest));
-#		$fail++;
-#	      };
-#	    }
-#
-#	    # Check for inexistence
-#	    elsif ($type eq 'not_ok') {
-#	      unless ($json_pointer->contains($path)) {
-#		$pass++;
-#	      }
-#	      else {
-#		push(@report, $path . q! doesn't exist; ! . join('; ', @rest));
-#		$fail++;
-#	      };
-#	    };
-#	  };
-#	}
-#	else {
-#	  # There may be notifications here!
-#	  $fail++ foreach @$tests;
-#	};
-#
-#	# Emit hook to possible subscribers
-#	# This is used for self-testing
-#	# $plugin->emit_hook(kalamar_tut_query => (
-#	#   query_language => $ql,
-#	#   query => $q,
-#	#   %param
-#	# ));
- #     };
-
-      # Escape query for html embedding
-      $q = xml_escape $q;
-
-      # There is something to talk about
-      my $msg = '';
-      if (($pass + $fail) > 0) {
-	$msg .= '<div class="test">';
-	$msg .= qq!<p class="pass">Pass: $pass</p>!;
-	$msg .= qq!<p class="fail">Fail: $fail</p>! if $fail;
-	foreach (@report) {
-	  $msg .= qq!<p class="fail">${_}</p>!;
-	};
-	$msg .= '</div>';
-      };
-
-      # Return tag
-      b('<pre class="query tutorial" onclick="' . $onclick . '" ' .
-	  qq!data-query="$q" data-query-cutoff="! .
-	    ($param{cutoff} ? 1 : 0) .
-	      '"' .
-		qq! data-query-language="$ql"><code>! .
-		  $q .
-		    '</code></pre>' . $msg);
-    }
-  );