diff --git a/experimental/uloapi/README.md b/experimental/uloapi/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..9b93224b33a9fa044b1090e62d18e97f0ba3f31f
--- /dev/null
+++ b/experimental/uloapi/README.md
@@ -0,0 +1,24 @@
+uloapi
+======
+
+This repository contains the `uloapi` codebase, a JVM (Java) project
+that uses the RDF4J library [1] which I might end up using for
+connecting MMT to the data set extracted/indexed from MathHub.
+
+Running
+-------
+
+To build and start the demo, first make sure the configuration file
+`uloapi.properties` is to your liking. Once ready, simply run
+
+	mvn compile exec:java
+
+to run the demo. To compile all classes including dependencies in one
+single JAR, run
+
+	mvn install
+
+References
+----------
+
+[1] https://rdf4j.org/
diff --git a/experimental/uloapi/pom.xml b/experimental/uloapi/pom.xml
index 950618486c30fc1581c3df7abe8d5c39ddc75010..e30da410e63f73c685cdc190e8f849ab40784016 100644
--- a/experimental/uloapi/pom.xml
+++ b/experimental/uloapi/pom.xml
@@ -83,5 +83,10 @@
             <artifactId>spark-template-freemarker</artifactId>
             <version>2.7.1</version>
         </dependency>
+        <dependency>
+            <groupId>org.jetbrains</groupId>
+            <artifactId>annotations</artifactId>
+            <version>19.0.0</version>
+        </dependency>
     </dependencies>
 </project>
\ No newline at end of file
diff --git a/experimental/uloapi/src/main/java/info/mathhub/uloapi/html/Errors.java b/experimental/uloapi/src/main/java/info/mathhub/uloapi/html/Errors.java
index 23b78eadfd3d130fecbec56679087e406b34e2df..dce0b3aa40251aa7e7c05d7f21ca58989841aaaf 100644
--- a/experimental/uloapi/src/main/java/info/mathhub/uloapi/html/Errors.java
+++ b/experimental/uloapi/src/main/java/info/mathhub/uloapi/html/Errors.java
@@ -1,10 +1,9 @@
 package info.mathhub.uloapi.html;
 
 import org.eclipse.jetty.http.HttpStatus;
-import spark.ModelAndView;
-import spark.Request;
-import spark.Response;
-import spark.Route;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import spark.*;
 import spark.template.freemarker.FreeMarkerEngine;
 
 import java.util.HashMap;
@@ -13,6 +12,8 @@ import java.util.Map;
 public class Errors {
     private Errors() {};
 
+    private static final Logger log = LoggerFactory.getLogger(Errors.class);
+
     /**
      * Singleton instance of the Freemarker engine for use with errors.
      * Used in {@link Errors#createError}.
@@ -35,7 +36,22 @@ public class Errors {
         return createError(HttpStatus.INTERNAL_SERVER_ERROR_500).handle(request, response);
     };
 
-    private static Route createError(int status) {
+    public static final ExceptionHandler<Exception> exceptionHandler = (exception, request, response) -> {
+        final Map<String, Object> model = new HashMap<>();
+        model.put("exception_message", exception.getMessage());
+
+        try {
+            createError(HttpStatus.INTERNAL_SERVER_ERROR_500, model).handle(request, response);
+        } catch (Exception e) {
+            log.error(e.getMessage());
+            for (final StackTraceElement element : e.getStackTrace()) {
+                log.error(element.toString());
+            }
+        }
+    };
+
+    @SafeVarargs
+    private static Route createError(int status, Map<String, Object> ...additionalModels) {
         return (Request request, Response response) -> {
             // set content type
 
@@ -44,8 +60,12 @@ public class Errors {
             // prepare model
 
             final Map<String, Object> model = new HashMap<>();
-            model.put("status", status);
-            model.put("description", HttpStatus.getMessage(status));
+            model.put("http_status", status);
+            model.put("http_description", HttpStatus.getMessage(status));
+
+            for (final Map<String, Object> additionalModel : additionalModels) {
+                model.putAll(additionalModel);
+            }
 
             // render
 
diff --git a/experimental/uloapi/src/main/java/info/mathhub/uloapi/html/Main.java b/experimental/uloapi/src/main/java/info/mathhub/uloapi/html/Main.java
index 16812fb32ad8e3c5bd90787a42a645e01c747c35..f84bdfcd6d28fa221ef14b83ced3e75d2dc0c9b8 100644
--- a/experimental/uloapi/src/main/java/info/mathhub/uloapi/html/Main.java
+++ b/experimental/uloapi/src/main/java/info/mathhub/uloapi/html/Main.java
@@ -12,9 +12,10 @@ public class Main {
 
     public static void main(String[] args) {
         get("/", Routes.index, new FreeMarkerEngine());
+        get("/statistics", Routes.statistics, new FreeMarkerEngine());
 
-        notFound(Errors.notFound);
         internalServerError(Errors.internalServerError);
+        notFound(Errors.notFound);
 
         after(Filters.setHtmlContentType);
     }
diff --git a/experimental/uloapi/src/main/java/info/mathhub/uloapi/html/Routes.java b/experimental/uloapi/src/main/java/info/mathhub/uloapi/html/Routes.java
index 4371cf7151bf824d625ce8b335da31855f30d9ec..1776d2b9d2ddcbac7c0564f9cbea0bd9063636d8 100644
--- a/experimental/uloapi/src/main/java/info/mathhub/uloapi/html/Routes.java
+++ b/experimental/uloapi/src/main/java/info/mathhub/uloapi/html/Routes.java
@@ -1,6 +1,7 @@
 package info.mathhub.uloapi.html;
 
 import info.mathhub.uloapi.query.Query;
+import info.mathhub.uloapi.query.Statistics;
 import spark.*;
 
 import java.util.HashMap;
@@ -15,4 +16,16 @@ public class Routes {
     public static final TemplateViewRoute index = (Request request, Response response) -> {
         return new ModelAndView(null, "index.flt");
     };
+
+    public static final TemplateViewRoute statistics = (Request request, Response response) -> {
+        final Query query = Query.getSingleton();
+        final Statistics statistics = query.getStatistics();
+
+        final Map<String, Object> model = new HashMap<>();
+        model.put("statistics_num_triplets", statistics.numTriplets);
+        model.put("statistics_is_writeable", Boolean.toString(statistics.isWriteable));
+        model.put("statistics_data_dir", statistics.dataDir);
+
+        return new ModelAndView(model, "statistics.flt");
+    };
 }
diff --git a/experimental/uloapi/src/main/java/info/mathhub/uloapi/query/Query.java b/experimental/uloapi/src/main/java/info/mathhub/uloapi/query/Query.java
index 70175d7ee0b7dd5866e132e0876b71fb9f0a4b24..8369c91dfa3b5d90f6a430dce769895c9db8d121 100644
--- a/experimental/uloapi/src/main/java/info/mathhub/uloapi/query/Query.java
+++ b/experimental/uloapi/src/main/java/info/mathhub/uloapi/query/Query.java
@@ -2,6 +2,8 @@ package info.mathhub.uloapi.query;
 
 import info.mathhub.uloapi.config.Config;
 
+import java.io.File;
+
 public class Query {
     private final String serverUrl;
     private final String repository;
@@ -22,11 +24,23 @@ public class Query {
     }
 
     public Statistics getStatistics() {
-        final GraphDB.Operation<Long> operation = (manager, repository, connection) -> {
-            return connection.size();
+        final GraphDB.Operation<Statistics> operation = (manager, repository, connection) -> {
+            final Statistics statistics = new Statistics();
+
+            statistics.isWriteable = repository.isWritable();
+            statistics.numTriplets = connection.size();
+
+            {
+                final File dataDir = repository.getDataDir();
+
+                if (dataDir != null) {
+                    statistics.dataDir = dataDir.getAbsolutePath();
+                }
+            }
+
+            return statistics;
         };
 
-        final long numTriplets = GraphDB.execute(this.serverUrl, this.repository, operation);
-        return new Statistics(numTriplets);
+        return GraphDB.execute(this.serverUrl, this.repository, operation);
     }
 }
diff --git a/experimental/uloapi/src/main/java/info/mathhub/uloapi/query/Statistics.java b/experimental/uloapi/src/main/java/info/mathhub/uloapi/query/Statistics.java
index 380e6ca9d46f6c31d9c247c943d25f563ce77e3f..a5735868b8edf2e49d831851625dc3504522d5b8 100644
--- a/experimental/uloapi/src/main/java/info/mathhub/uloapi/query/Statistics.java
+++ b/experimental/uloapi/src/main/java/info/mathhub/uloapi/query/Statistics.java
@@ -1,5 +1,7 @@
 package info.mathhub.uloapi.query;
 
+import org.jetbrains.annotations.NotNull;
+
 /**
  * Contains statistic information about the backing storage.
  */
@@ -9,7 +11,15 @@ public class Statistics {
      */
     public long numTriplets;
 
-    Statistics(long numTriplets) {
-        this.numTriplets = numTriplets;
-    }
+    /**
+     * Whether the data in this repository is writeable. If it isn't,
+     * it is only readable.
+     */
+    public boolean isWriteable;
+
+    /**
+     * The directory on the server where the data is stored.
+     */
+    @NotNull
+    public String dataDir = "unknown";
 }
diff --git a/experimental/uloapi/src/main/resources/spark/template/freemarker/base.flt b/experimental/uloapi/src/main/resources/spark/template/freemarker/base.flt
index 00db730910a21bcef2d729cd062a81f5ccd55be8..a0d1317491b573468964f577969c6b2fe067f9aa 100644
--- a/experimental/uloapi/src/main/resources/spark/template/freemarker/base.flt
+++ b/experimental/uloapi/src/main/resources/spark/template/freemarker/base.flt
@@ -18,12 +18,30 @@
                     font-size: 12pt;
                 }
 
+                nav {
+                    border-bottom: solid 1px;
+                    padding-bottom: 1em;
+                    padding-top: 1em;
+                }
+
+                code {
+                    font-family: monospace;
+                }
+
                 a {
                     color: blue;
                 }
+
+                h1 {
+                    display: inline-block;
+                    font-weight: bold;
+                }
             </style>
         </head>
         <body>
+            <nav>
+                <h1><a href="/">uloapi</a></h1> | <a href="/statistics">Statistics</a> | <a href="/queries">Queries</a>
+            </nav>
             <main>
                 <@page_main/>
             </main>
diff --git a/experimental/uloapi/src/main/resources/spark/template/freemarker/error.flt b/experimental/uloapi/src/main/resources/spark/template/freemarker/error.flt
index aab46438a25ba64d3a5c06602f3fa4719e9cf52f..810c1695682b05f2700eb2ecc5ed72dcf7d5b45f 100644
--- a/experimental/uloapi/src/main/resources/spark/template/freemarker/error.flt
+++ b/experimental/uloapi/src/main/resources/spark/template/freemarker/error.flt
@@ -1,12 +1,17 @@
 <#include "base.flt">
 
 <#macro page_title>
-    Error ${status}
+    Error ${http_status}
 </#macro>
 
 <#macro page_main>
-    <h1>Error ${status}: ${description}</h1>
-    <p>Grow old or die trying.</p>
+    <h2>Error ${http_status}: ${http_description}</h2>
+
+    <#if message?has_content>
+        <code>
+            ${exception_message}
+        </code>
+    </#if>
 </#macro>
 
 <@display_page/>
diff --git a/experimental/uloapi/src/main/resources/spark/template/freemarker/index.flt b/experimental/uloapi/src/main/resources/spark/template/freemarker/index.flt
index 9f0757657d6a33ef790a760c752b7fff48827c55..6a0791ec765a2edd3ddbbbfc630b2f2fb88f927a 100644
--- a/experimental/uloapi/src/main/resources/spark/template/freemarker/index.flt
+++ b/experimental/uloapi/src/main/resources/spark/template/freemarker/index.flt
@@ -5,9 +5,9 @@
 </#macro>
 
 <#macro page_main>
-    <h1>ULO/RDF Endpoint</h1>
+    <h2>ULO/RDF Endpoint</h2>
     <p>This is a technology demo of an ULO/RDF Endpoint.</p>
-    <h2>Introduction</h2>
+    <h3>Introduction</h3>
     <p>
         Working with RDF triplets is somewhat easy with the <a href="https://rdf4j.org">RDF4J</a> library.
         This demo uses RDF4J to illustrate that (1) a connection to an existing database can be established
@@ -18,10 +18,6 @@
         It is no incident that this demo is hacked together with a JVM-based stack. Potential integration
         into MMT should be easier with lessons learned from this demo.
     </p>
-    <h2>Demos</h2>
-    <ul>
-        <li><a href="/statistics">Show (not every interesting) Statistics</a> about the imported ULO/RDF dataset.</li>
-    </ul>
 </#macro>
 
 <@display_page/>
\ No newline at end of file
diff --git a/experimental/uloapi/src/main/resources/spark/template/freemarker/statistics.flt b/experimental/uloapi/src/main/resources/spark/template/freemarker/statistics.flt
new file mode 100644
index 0000000000000000000000000000000000000000..750b534a437ca4d54bbb661616019a4aac39d535
--- /dev/null
+++ b/experimental/uloapi/src/main/resources/spark/template/freemarker/statistics.flt
@@ -0,0 +1,24 @@
+<#include "base.flt">
+
+<#macro page_title>
+    Statistics
+</#macro>
+
+<#macro page_main>
+    <h2>Statistics</h2>
+
+    <p>
+        Show not very interesting statistics about the connected database. Illustrates
+        that we made a connection and can take a look at imported data.
+    </p>
+
+    <h3>Counts</h3>
+
+    <ul>
+        <li>Total Triplets in Repository: <code>${statistics_num_triplets}</code></li>
+        <li>Repository Writeable: <code>${statistics_is_writeable}</code></li>
+        <li>Repository Data directory: <code>${statistics_data_dir}</code></li>
+    </ul>
+</#macro>
+
+<@display_page/>