Added KrillMeta for coherence with KoralQuery
diff --git a/Changes b/Changes
index c54c996..2da2650 100644
--- a/Changes
+++ b/Changes
@@ -1,5 +1,6 @@
-0.50.1 2015-02-23
-	- Deserialization of arbitrary elements with attributes (margaretha)
+0.50.1 2015-02-25
+	- [feature] Deserialization of arbitrary elements with attributes (margaretha)
+	- [cleanup] Extract KrillMeta from Krill (diewald)
 
 0.50 2015-02-23
         - Project name is now "Krill"
diff --git a/pom.xml b/pom.xml
index 2659c86..56b7e06 100644
--- a/pom.xml
+++ b/pom.xml
@@ -3,14 +3,6 @@
   <modelVersion>4.0.0</modelVersion>
 
   <!--
-      ** Indexer
-      # install the indexer
-      $ mvn clean compile assembly:single
-      # Then run e.g.
-      $ java -jar target/Krill-X.XX.jar
-             src/main/resources/korap.conf
-             /data/hdd/lucene-new/WPD/
-
       ** Server
       # Start the server with
       $ mvn clean compile exec:java
@@ -19,6 +11,14 @@
       # Format the code with
       $ mvn java-formatter:format
 
+      ** Indexer
+         (This is not the preferred way to index new data!)
+      # install the indexer
+      $ mvn clean compile assembly:single
+      # Then run e.g.
+      $ java -jar target/Krill-X.XX.jar
+             src/main/resources/korap.conf
+             /data/hdd/lucene-new/WPD/
   -->
 
   <groupId>KorAP-modules</groupId>
@@ -190,7 +190,17 @@
       <artifactId>jackson-core</artifactId>
       <version>2.4.4</version>
     </dependency>
-<!--
+
+    <!-- JSON-LD support -->
+    <!--
+    <dependency>
+      <groupId>com.github.jsonld-java</groupId>
+      <artifactId>jsonld-java</artifactId>
+      <version>0.5.2-SNAPSHOT</version>
+    </dependency>
+    -->
+
+    <!--
     Temporarily disable @Experimental annotation
     <dependency>
       <groupId>KorapAnnotationProcessor</groupId>
@@ -198,7 +208,8 @@
       <version>0.0.1-SNAPSHOT</version>
       <scope>compile</scope>
     </dependency>
--->
+    -->
+
   </dependencies>
 
   <build>
diff --git a/src/main/java/de/ids_mannheim/korap/KorapIndex.java b/src/main/java/de/ids_mannheim/korap/KorapIndex.java
index a800f54..5efe1e6 100644
--- a/src/main/java/de/ids_mannheim/korap/KorapIndex.java
+++ b/src/main/java/de/ids_mannheim/korap/KorapIndex.java
@@ -29,6 +29,7 @@
 // KorAP classes
 import de.ids_mannheim.korap.*;
 import de.ids_mannheim.korap.index.*;
+import de.ids_mannheim.korap.meta.*;
 import de.ids_mannheim.korap.query.SpanElementQuery;
 import de.ids_mannheim.korap.util.QueryException;
 
@@ -835,7 +836,7 @@
                     log.trace("We've found a matching document");
 
                 HashSet<String> fields = (HashSet<String>)
-                    new Krill().getFields().clone();
+                    new Krill().getMeta().getFields().clone();
                 fields.add(field);
 
                 // Get terms from the document
@@ -852,6 +853,7 @@
                 if (DEBUG)
                     log.trace("The document has the id '{}'", match.getDocID());
 
+                // Todo:
                 SearchContext context = match.getContext();
 
                 // Search for minimal surrounding sentences
@@ -1081,9 +1083,9 @@
 
 
     public KorapResult search (SpanQuery query, short count) {
-        return this.search(
-            new Krill(query).setCount(count)
-        );
+        Krill krill = new Krill(query);
+        krill.getMeta().setCount(count);
+        return this.search(krill);
     };
 
 
@@ -1097,8 +1099,9 @@
                                short rightContext) {
 
         Krill ks = new Krill(query);
-        ks.setStartIndex(startIndex).setCount(count);
-        ks.setContext(
+        KrillMeta meta = ks.getMeta();
+        meta.setStartIndex(startIndex).setCount(count);
+        meta.setContext(
             new SearchContext(
                 leftTokenContext,
                 leftContext,
@@ -1120,7 +1123,7 @@
                                boolean rightTokenContext,
                                short rightContext) {
         Krill ks = new Krill(query);
-        ks.setContext(
+        ks.getMeta().setContext(
             new SearchContext(
                 leftTokenContext,
                 leftContext,
@@ -1151,12 +1154,14 @@
         // Get the field of textual data and annotations ("tokens")
         String field = query.getField();
 
+        KrillMeta meta = ks.getMeta();
+
         // Todo: Make kr subclassing ks - so ks has a method for a new KorapResult!
         KorapResult kr = new KorapResult(
             query.toString(),
-            ks.getStartIndex(),
-            ks.getCount(),
-            ks.getContext()
+            meta.getStartIndex(),
+            meta.getCount(),
+            meta.getContext()
         );
 
         // Set version info to result
@@ -1164,7 +1169,7 @@
             kr.setVersion(this.getVersion());
 
         // The following fields should be lifted for matches
-        HashSet<String> fields = (HashSet<String>) ks.getFields().clone();
+        HashSet<String> fields = (HashSet<String>) meta.getFields().clone();
         fields.add(field);
 
         // Some initializations ...
@@ -1172,12 +1177,13 @@
             startIndex              = kr.getStartIndex(),
             count                   = kr.getItemsPerPage(),
             hits                    = kr.getItemsPerPage() + startIndex,
-            limit                   = ks.getLimit(),
+            limit                   = meta.getLimit(),
             itemsPerResourceCounter = 0;
-        boolean cutoff              = ks.doCutOff();
-        short itemsPerResource      = ks.getItemsPerResource();
+        boolean cutoff              = meta.doCutOff();
+        short itemsPerResource      = meta.getItemsPerResource();
 
         // Check if there is work to do at all
+        // TODO: Deprecated
         if (limit > 0) {
             if (hits > limit)
                 hits = limit;
@@ -1188,12 +1194,13 @@
         };
 
         // Collect matches from atomic readers
-        ArrayList<KorapMatch> atomicMatches = new ArrayList<KorapMatch>(kr.getItemsPerPage());
+        ArrayList<KorapMatch> atomicMatches =
+            new ArrayList<KorapMatch>(kr.getItemsPerPage());
         
         // Start time out thread
         TimeOutThread tthread = new TimeOutThread();
         tthread.start();
-        long timeout = ks.getTimeOut();
+        long timeout = meta.getTimeOut();
 
         // See: http://www.ibm.com/developerworks/java/library/j-benchmark1/index.html
         long t1 = System.nanoTime();
@@ -1310,6 +1317,8 @@
 
                 // Can be disabled TEMPORARILY
                 while (!cutoff && spans.next()) {
+
+                    // TODO: Deprecated
                     if (limit > 0 && i >= limit)
                         break;
                     
diff --git a/src/main/java/de/ids_mannheim/korap/KorapMatch.java b/src/main/java/de/ids_mannheim/korap/KorapMatch.java
index e0e033e..883cea76 100644
--- a/src/main/java/de/ids_mannheim/korap/KorapMatch.java
+++ b/src/main/java/de/ids_mannheim/korap/KorapMatch.java
@@ -11,7 +11,9 @@
 import com.fasterxml.jackson.databind.node.*;
 
 import de.ids_mannheim.korap.index.PositionsToOffset;
-import de.ids_mannheim.korap.index.SearchContext;
+
+// Todo:
+import de.ids_mannheim.korap.meta.SearchContext;
 
 import de.ids_mannheim.korap.match.HighlightCombinator;
 import de.ids_mannheim.korap.match.HighlightCombinatorElement;
diff --git a/src/main/java/de/ids_mannheim/korap/KorapQuery.java b/src/main/java/de/ids_mannheim/korap/KorapQuery.java
index f3b499e..eaa52bc 100644
--- a/src/main/java/de/ids_mannheim/korap/KorapQuery.java
+++ b/src/main/java/de/ids_mannheim/korap/KorapQuery.java
@@ -12,21 +12,7 @@
 import com.fasterxml.jackson.databind.ObjectMapper;
 
 import de.ids_mannheim.korap.query.SpanWithinQuery;
-import de.ids_mannheim.korap.query.wrap.SpanAlterQueryWrapper;
-import de.ids_mannheim.korap.query.wrap.SpanAttributeQueryWrapper;
-import de.ids_mannheim.korap.query.wrap.SpanClassQueryWrapper;
-import de.ids_mannheim.korap.query.wrap.SpanElementQueryWrapper;
-import de.ids_mannheim.korap.query.wrap.SpanFocusQueryWrapper;
-import de.ids_mannheim.korap.query.wrap.SpanQueryWrapper;
-import de.ids_mannheim.korap.query.wrap.SpanRegexQueryWrapper;
-import de.ids_mannheim.korap.query.wrap.SpanRepetitionQueryWrapper;
-import de.ids_mannheim.korap.query.wrap.SpanSegmentQueryWrapper;
-import de.ids_mannheim.korap.query.wrap.SpanSequenceQueryWrapper;
-import de.ids_mannheim.korap.query.wrap.SpanSimpleQueryWrapper;
-import de.ids_mannheim.korap.query.wrap.SpanSubspanQueryWrapper;
-import de.ids_mannheim.korap.query.wrap.SpanWildcardQueryWrapper;
-import de.ids_mannheim.korap.query.wrap.SpanWithAttributeQueryWrapper;
-import de.ids_mannheim.korap.query.wrap.SpanWithinQueryWrapper;
+import de.ids_mannheim.korap.query.wrap.*;
 import de.ids_mannheim.korap.response.Notifications;
 import de.ids_mannheim.korap.util.QueryException;
 
@@ -54,9 +40,10 @@
  * </pre></blockquote>
  *
  * @author diewald
- *
  */
 /*
+  Todo: Use full-blown jsonld processor
+
   Todo: All queries with a final right expansion
   e.g. der alte []
   should be wrapped in a contains(<base/s=t>) to ensure
@@ -80,7 +67,7 @@
     // This advices the java compiler to ignore all loggings
     public static final boolean DEBUG = false;
 
-    // This is obsolete!
+    // <legacy>
     public static final byte
         OVERLAP      = SpanWithinQuery.OVERLAP,
         REAL_OVERLAP = SpanWithinQuery.REAL_OVERLAP,
@@ -89,11 +76,20 @@
         ENDSWITH     = SpanWithinQuery.ENDSWITH,
         STARTSWITH   = SpanWithinQuery.STARTSWITH,
         MATCH        = SpanWithinQuery.MATCH;
+    // </legacy>
 
     private static final int MAX_CLASS_NUM = 255; // 127;
 
     /**
      * Constructs a new object for query generation.
+     */
+    public KorapQuery () {
+        this.mapper = new ObjectMapper();
+    };
+
+
+    /**
+     * Constructs a new object for query generation.
      *
      * @param field The specific index field for the query.
      */
@@ -195,7 +191,8 @@
         if (!json.has("@type"))
             throw new QueryException(701, "JSON-LD group has no @type attribute");
 
-        // Set this for serialization
+        // Set this for reserialization
+        // This may be changed later on
         this.json = json;
 
         // Get @type for branching
diff --git a/src/main/java/de/ids_mannheim/korap/KorapResult.java b/src/main/java/de/ids_mannheim/korap/KorapResult.java
index 18c6cdd..40232ae 100644
--- a/src/main/java/de/ids_mannheim/korap/KorapResult.java
+++ b/src/main/java/de/ids_mannheim/korap/KorapResult.java
@@ -9,7 +9,9 @@
 import com.fasterxml.jackson.databind.node.ArrayNode;
 
 import de.ids_mannheim.korap.index.PositionsToOffset;
-import de.ids_mannheim.korap.index.SearchContext;
+
+// Remove:
+import de.ids_mannheim.korap.meta.SearchContext;
 import de.ids_mannheim.korap.response.KorapResponse;
 
 import org.slf4j.Logger;
diff --git a/src/main/java/de/ids_mannheim/korap/Krill.java b/src/main/java/de/ids_mannheim/korap/Krill.java
index c168f3b..3fd3e12 100644
--- a/src/main/java/de/ids_mannheim/korap/Krill.java
+++ b/src/main/java/de/ids_mannheim/korap/Krill.java
@@ -5,11 +5,10 @@
 
 import org.apache.lucene.search.spans.SpanQuery;
 import de.ids_mannheim.korap.query.wrap.SpanQueryWrapper;
-import de.ids_mannheim.korap.KorapCollection;
 import de.ids_mannheim.korap.KorapIndex;
 import de.ids_mannheim.korap.KorapResult;
 import de.ids_mannheim.korap.util.QueryException;
-import de.ids_mannheim.korap.index.SearchContext;
+import de.ids_mannheim.korap.response.Notifications;
 import de.ids_mannheim.korap.response.KorapResponse;
 
 import com.fasterxml.jackson.databind.ObjectMapper;
@@ -20,78 +19,39 @@
 
 /**
  * Krill is a corpus data retrieval index using Lucene for Look-Ups.
- * It is the reference implementation for KoralQuery consumption.
+ * It is the reference implementation for KoralQuery consumption,
+ * and supports specified query and collection objects,
+ * and proprietary meta objects.
  *
  * <blockquote><pre>
  *   // Create a new krill search object passing a KoralQuery string
- *   Krill krill = new Krill(jsonString);
+ *   Krill krill = new Krill(koralQueryString);
  *
- *   // Run the query on an index
+ *   // Run the query on an index - receive a search result
  *   KrillResult kr = krill.apply(new KrillIndex());
  * </pre></blockquote>
  *
  * @author diewald
  * @author margaretha
+ *
+ * @see KrillMeta
+ * @see KorapCollection
+ * @see KorapQuery
+ * @see KorapIndex
  */
 /*
  * Todo: Use a configuration file
- * Todo: Let this class extend KorapResult!
- *   KorapResult = new Krill(String json).run(KorapIndex ki);
- * Todo: Set timeout default value per config file
  */
 public class Krill extends KorapResponse {
-    private int startIndex = 0, limit = 0;
-    private short count = 25, countMax = 50, itemsPerResource = 0;
-    private boolean cutOff = false;
-
-    private KorapCollection collection;
     private KorapIndex index;
-
-    // Timeout search after milliseconds
-    private long timeout = (long) 120_000;
-
-    private HashSet<String> fields;
-            HashSet<Integer> highlights;
-
     private SpanQuery spanQuery;
     private JsonNode request;
-
-    public SearchContext context;
     private String spanContext;
 
-    private long timeoutStart = Long.MIN_VALUE;
-
     // Logger
     private final static Logger log = LoggerFactory.getLogger(Krill.class);
-
-    {
-        context  = new SearchContext();
-
-        fields = new HashSet<String>(16);
-
-        // LEGACY: Lift following fields per default
-        for (String field : new String[]{
-                "ID",
-                "UID",
-                "textSigle",
-                "corpusID",
-                "author",
-                "title",
-                "subTitle",
-                "textClass",
-                "pubPlace",
-                "pubDate",
-                "foundries",
-                "layerInfo",
-                "tokenization"}) {
-            fields.add(field);
-        };
-
-        // Classes used for highlights
-        highlights = new HashSet<Integer>(3);
-    };
-
     
+
     /**
      * Construct a new Krill object.
      */
@@ -100,6 +60,28 @@
 
     /**
      * Construct a new Krill object,
+     * consuming a KoralQuery json string.
+     *
+     * @param query The KoralQuery json string.
+     */
+    public Krill (String query) {
+        this.fromJson(query);
+    };
+
+
+    /**
+     * Construct a new Krill object,
+     * consuming a KoralQuery {@link JsonNode} object.
+     *
+     * @param query The KoralQuery {@link JsonNode} object.
+     */
+    public Krill (JsonNode query) {
+        this.fromJson(query);
+    };
+
+
+    /**
+     * Construct a new Krill object,
      * consuming a {@link SpanQueryWrapper} object.
      *
      * @param query The {@link SpanQueryWrapper} object.
@@ -126,29 +108,6 @@
 
 
     /**
-     * Construct a new Krill object,
-     * consuming a KoralQuery json string.
-     *
-     * @param query The KoralQuery json string.
-     */
-    public Krill (String query) {
-        // Parse json string
-        this.fromJson(query);
-    };
-
-
-    /**
-     * Construct a new Krill object,
-     * consuming a KoralQuery {@link JsonNode} object.
-     *
-     * @param query The KoralQuery {@link JsonNode} object.
-     */
-    public Krill (JsonNode query) {
-        this.fromJson(query);
-    };
-
-
-    /**
      * Parse KoralQuery as a json string.
      *
      * @param query The KoralQuery json string.
@@ -156,8 +115,9 @@
      * @throws QueryException
      */
     public Krill fromJson (String query) {
-        ObjectMapper mapper = new ObjectMapper();
+        // Parse query string
         try {
+            ObjectMapper mapper = new ObjectMapper();
             this.request = mapper.readTree(query);
             this.fromJson(this.request);
         }
@@ -187,27 +147,29 @@
                 SpanQueryWrapper qw = kq.fromJson(json.get("query"));
                 this.setQuery(kq);
 
-                // Unable to process result
+                // Throw an error, in case the query matches everywhere
                 if (qw.isEmpty())
                     this.addError(780, "This query matches everywhere");
+
                 else {
+                    // Serialize a Lucene SpanQuery based on the SpanQueryWrapper
                     this.spanQuery = qw.toQuery();
+
+                    // Throw a warning in case the root object is optional
                     if (qw.isOptional())
                         this.addWarning(781, "Optionality of query is ignored");
+
+                    // Throw a warning in case the root object is negative
                     if (qw.isNegative())
                         this.addWarning(782, "Exclusivity of query is ignored");
                 };
-                // Copy notifications from query
-                this.copyNotificationsFrom(kq);
-                kq.clearNotifications();
             }
             catch (QueryException q) {
                 this.addError(q.getErrorCode(), q.getMessage());
             };
         }
-        else {
+        else
             this.addError(700, "No query given");
-        };
 
         // <legacycode>
         if (json.has("warning") &&
@@ -216,19 +178,10 @@
         };
         // </legacycode>
 
-        // <legacycode>
-        if (json.has("warnings")) {
-            JsonNode warnings = json.get("warnings");
-            for (JsonNode node : warnings)
-                if (node.asText().length() > 0)
-                    this.addWarning(799, node.asText());
-        };
-        // </legacycode>
-
         // Copy notifications from request
         this.copyNotificationsFrom(json);
 	    
-        // virtual collections
+        // Parse virtual collections
         try {
             if (json.has("collection")) {
                 this.setCollection(
@@ -251,226 +204,31 @@
             this.addError(q.getErrorCode(), q.getMessage());
         };
 
+        // No errors occured - parse meta object
+        if (!this.hasErrors() && json.has("meta"))
+            this.setMeta(new KrillMeta(json.get("meta")));
 
-        // No errors
-        if (!this.hasErrors()) {
-
-            // Parse meta section
-            if (json.has("meta")) {
-                JsonNode meta = json.get("meta");
-
-                // Defined count
-                if (meta.has("count"))
-                    this.setCount(meta.get("count").asInt());
-
-                // Defined startIndex
-                if (meta.has("startIndex"))
-                    this.setStartIndex(meta.get("startIndex").asInt());
-
-                // Defined startPage
-                if (meta.has("startPage"))
-                    this.setStartPage(meta.get("startPage").asInt());
-
-                // Defined cutOff
-                if (meta.has("cutOff"))
-                    this.setCutOff(meta.get("cutOff").asBoolean());
-
-                // Defined contexts
-                if (meta.has("context"))
-                    this.context.fromJson(meta.get("context"));
-
-                // Defined resource count
-                if (meta.has("timeout"))
-                    this.setTimeOut(meta.get("timeout").asLong());
-
-                // Defined resource count
-                if (meta.has("itemsPerResource"))
-                    this.setItemsPerResource(
-                        meta.get("itemsPerResource").asInt()
-                    );
-
-                // Defined highlights
-                if (meta.has("highlight")) {
-
-                    // Add highlights
-                    if (meta.get("highlight").isArray()) {
-                        for (JsonNode highlight : (JsonNode) meta.get("highlight")) {
-                            this.addHighlight(highlight.asInt());
-                        };
-                    }
-                    else
-                        this.addHighlight(meta.get("highlight").asInt());
-                };
-
-                // Only lift a limited amount of fields from the metadata
-                if (meta.has("fields")) {
-                        
-                    // Remove legacy default fields
-                    this.fields.clear();
-
-                    // Add fields
-                    if (meta.get("fields").isArray()) {
-                        for (JsonNode field : (JsonNode) meta.get("fields")) {
-                            this.addField(field.asText());
-                        };
-                    }
-                    else
-                        this.addField(meta.get("fields").asText());
-                };
-            };
-        };
         return this;
     };
 
-    public long getTimeOut () {
-        return this.timeout;
-    };
-
-    public void setTimeOut (long timeout) {
-        this.timeout = timeout;
-    };
-
-
-    public JsonNode getRequest () {
-        return this.request;
-    };
-
-
-    public SearchContext getContext () {
-        return this.context;
-    };
-
-    public Krill setContext (SearchContext context) {
-        this.context = context;
-        return this;
-    };
-
-    public int getStartIndex () {
-        return this.startIndex;
-    };
-    
-    public Krill setStartIndex (int value) {
-        this.startIndex = (value >= 0) ? value : 0;
-        return this;
-    };
-
-    public Krill setStartPage (int value) {
-        if (value >= 0)
-            this.setStartIndex((value * this.getCount()) - this.getCount());
-        else
-            this.startIndex = 0;
-        return this;
-    };
-
-    public short getCount () {
-        return this.count;
-    };
-
-    public short getCountMax () {
-        return this.countMax;
-    };
-
-    public int getLimit () {
-        return this.limit;
-    };
-
-    public Krill setLimit (int limit) {
-        if (limit > 0)
-            this.limit = limit;
-        return this;
-    };
-
-    public boolean doCutOff () {
-        return this.cutOff;
-    };
-
-    public Krill setCutOff (boolean cutOff) {
-        this.cutOff = cutOff;
-        return this;
-    };
-
-    public Krill setCount (int value) {
-        // Todo: Maybe update startIndex with known startPage!
-        this.setCount((short) value);
-        return this;
-    };
-
-    public Krill setCount (short value) {
-        if (value > 0)
-            this.count = (value <= this.countMax) ? value : this.countMax;
-        return this;
-    };
-
-    public Krill setItemsPerResource (short value) {
-        if (value >= 0)
-            this.itemsPerResource = value;
-        return this;
-    };
-
-    public Krill setItemsPerResource (int value) {
-        return this.setItemsPerResource((short) value);
-    };
-
-    public short getItemsPerResource () {
-        return this.itemsPerResource;
-    };
-
-
-    // Get set of fields
-    /**
-     * Get the fields as a set
-     */
-    public HashSet<String> getFields () {
-        return this.fields;
-    };
-
 
     /**
-     * Add a field to the set of fields to retrieve.
+     * Get the associated {@link KorapIndex} object.
      *
-     * @param field The field to retrieve.
-     * @return The {@link Krill} object for chaining.
+     * @return The associated {@link KorapIndex} object.
      */
-    public Krill addField (String field) {
-        this.fields.add(field);
-        return this;
-    };
-
-
-    /**
-     * Add class numbers to highlight in KWIC view.
-     *
-     * @param classNumber The number of a class to highlight.
-     * @return The {@link Krill} object for chaining.
-     */
-    public Krill addHighlight (int classNumber) {
-        this.highlights.add(classNumber);
-        return this;
-    };
-
-
-    public Krill setCollection (KorapCollection kc) {
-        this.collection = kc;
-        
-        // Move messages from the collection
-        this.copyNotificationsFrom(kc);
-        kc.clearNotifications();
-        return this;
-    };
-
-    public KorapCollection getCollection () {
-        if (this.collection == null)
-            this.collection = new KorapCollection();
-        return this.collection;
-    };
-
-
     public KorapIndex getIndex () {
         return this.index;
     };
 
-    public Krill setIndex (KorapIndex ki) {
-        this.index = ki;
+
+    /**
+     * Set the associated {@link KorapIndex} object.
+     *
+     * @param index The associated {@link KorapIndex} object.
+     */
+    public Krill setIndex (KorapIndex index) {
+        this.index = index;
         return this;
     };
 
@@ -521,6 +279,13 @@
         return kr;
     };
 
+
+    @Deprecated
+    public JsonNode getRequest () {
+        return this.request;
+    };
+
+
     @Deprecated
     public SpanQuery getSpanQuery () {
         return this.spanQuery;
@@ -529,7 +294,6 @@
 
     @Deprecated
     public Krill setSpanQuery (SpanQueryWrapper sqwi) {
-        // this.copyNotifications(sqwi);
         try {
             this.spanQuery = sqwi.toQuery();
         }
@@ -539,7 +303,7 @@
         return this;
     };
 
-
+    
     @Deprecated
     public Krill setSpanQuery (SpanQuery sq) {
         this.spanQuery = sq;
diff --git a/src/main/java/de/ids_mannheim/korap/KrillMeta.java b/src/main/java/de/ids_mannheim/korap/KrillMeta.java
new file mode 100644
index 0000000..ccb836d
--- /dev/null
+++ b/src/main/java/de/ids_mannheim/korap/KrillMeta.java
@@ -0,0 +1,356 @@
+package de.ids_mannheim.korap;
+
+import java.io.*;
+import java.util.*;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.*;
+
+
+import de.ids_mannheim.korap.meta.SearchContext;
+import de.ids_mannheim.korap.util.QueryException;
+import de.ids_mannheim.korap.response.Notifications;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+//  Todo: Set timeout default value per config file
+public class KrillMeta extends Notifications {
+    // <legacy>
+    private boolean cutOff = false;
+    // </legacy>
+
+    private int limit = 0;
+    private short count = 25, countMax = 50;
+    private int startIndex = 0;
+    private short itemsPerResource = 0;
+    private SearchContext context;
+
+    private HashSet<String> fields;
+            HashSet<Integer> highlights;
+
+    // Timeout search after milliseconds
+    private long timeout = (long) 120_000;
+    // private long timeoutStart = Long.MIN_VALUE;
+
+    // Logger
+    private final static Logger log = LoggerFactory.getLogger(Krill.class);
+
+    {
+        fields = new HashSet<String>(16);
+
+        // Lift following fields per default
+        // These fields are chosen for <legacy /> reasons
+        for (String field : new String[]{
+                "ID",
+                "UID",
+                "textSigle",
+                "corpusID",
+                "author",
+                "title",
+                "subTitle",
+                "textClass",
+                "pubPlace",
+                "pubDate",
+                "foundries",
+                "layerInfo",
+                "tokenization"}) {
+            fields.add(field);
+        };
+
+        // Classes used for highlights
+        highlights = new HashSet<Integer>(3);
+        context  = new SearchContext();
+    };
+
+
+    public KrillMeta () {};
+
+    public KrillMeta (JsonNode json) {
+        this.fromJson(json);
+    };
+
+    public KrillMeta (String json) {
+        try {
+            this.fromJson(json);
+        }
+        catch (QueryException q) {
+            this.addError(q.getErrorCode(), q.getMessage());
+        };
+    };
+
+    public KrillMeta fromJson (String json) throws QueryException {
+        JsonNode jsonN;
+        try {
+            // Read Json string
+            jsonN = new ObjectMapper().readValue(json, JsonNode.class);
+        }
+
+        // Something went wrong
+        catch (IOException e) {
+            String msg = e.getMessage();
+            log.warn("Unable to parse JSON: " + msg.split("\n")[0]);
+            throw new QueryException(621, "Unable to parse JSON");
+        };
+
+        // Deserialize from node
+        return this.fromJson(jsonN);
+    };
+
+
+    public KrillMeta fromJson (JsonNode json) {
+        // The object type of meta is undefined in KoralQuery,
+        // so it may or may have no @type
+
+        // The query is nested in a parent query
+        if (!json.has("@type") && json.has("meta"))
+            json = json.get("meta");
+
+        // Defined cutOff
+        // <legacy>
+        if (json.has("cutOff"))
+            this.setCutOff(json.get("cutOff").asBoolean());
+        // </legacy>
+
+        // Defined count
+        if (json.has("count"))
+            this.setCount(json.get("count").asInt());
+
+        // Defined startIndex
+        if (json.has("startIndex"))
+            this.setStartIndex(json.get("startIndex").asInt());
+
+        // Defined startPage
+        if (json.has("startPage"))
+            this.setStartPage(json.get("startPage").asInt());
+
+        // Defined timeout
+        if (json.has("timeout"))
+            this.setTimeOut(json.get("timeout").asLong());
+
+        // Defined resource count
+        if (json.has("itemsPerResource"))
+            this.setItemsPerResource(json.get("itemsPerResource").asInt());
+
+        // Defined context
+        if (json.has("context"))
+            this.context.fromJson(json.get("context"));
+
+        // Defined highlights
+        if (json.has("highlight")) {
+
+            // Add highlights
+            if (json.get("highlight").isArray()) {
+                for (JsonNode highlight : (JsonNode) json.get("highlight")) {
+                    this.addHighlight(highlight.asInt());
+                };
+            }
+            else
+                this.addHighlight(json.get("highlight").asInt());
+        };
+        
+        // Defined fields to lift from the index
+        if (json.has("fields")) {
+                        
+            // Remove default fields
+            this.fields.clear();
+            
+            // Add fields
+            if (json.get("fields").isArray()) {
+                for (JsonNode field : (JsonNode) json.get("fields")) {
+                    this.addField(field.asText());
+                };
+            }
+            else
+                this.addField(json.get("fields").asText());
+        };
+
+        return this;
+    };
+
+
+    public short getCount () {
+        return this.count;
+    };
+
+    public KrillMeta setCount (int value) {
+        // Todo: Maybe update startIndex with known startPage!
+        this.setCount((short) value);
+        return this;
+    };
+
+    public KrillMeta setCount (short value) {
+        if (value > 0)
+            this.count = (value <= this.countMax) ? value : this.countMax;
+        return this;
+    };
+
+    public short getCountMax () {
+        return this.countMax;
+    };
+
+
+    public int getStartIndex () {
+        return this.startIndex;
+    };
+    
+    public KrillMeta setStartIndex (int value) {
+        this.startIndex = (value >= 0) ? value : 0;
+        return this;
+    };
+
+    public KrillMeta setStartPage (int value) {
+        if (value >= 0)
+            this.setStartIndex((value * this.getCount()) - this.getCount());
+        else
+            this.startIndex = 0;
+        return this;
+    };
+
+
+    public long getTimeOut () {
+        return this.timeout;
+    };
+
+    public void setTimeOut (long timeout) {
+        this.timeout = timeout;
+    };
+
+    public KrillMeta setItemsPerResource (short value) {
+        if (value >= 0)
+            this.itemsPerResource = value;
+        return this;
+    };
+
+    public KrillMeta setItemsPerResource (int value) {
+        return this.setItemsPerResource((short) value);
+    };
+
+    public short getItemsPerResource () {
+        return this.itemsPerResource;
+    };
+
+
+    public SearchContext getContext () {
+        return this.context;
+    };
+
+    public KrillMeta setContext (SearchContext context) {
+        this.context = context;
+        return this;
+    };
+
+
+    // Get set of fields
+    /**
+     * Get the fields as a set
+     */
+    public HashSet<String> getFields () {
+        return this.fields;
+    };
+
+
+    /**
+     * Add a field to the set of fields to retrieve.
+     *
+     * @param field The field to retrieve.
+     * @return The {@link Krill} object for chaining.
+     */
+    public KrillMeta addField (String field) {
+        this.fields.add(field);
+        return this;
+    };
+
+
+    /**
+     * Add class numbers to highlight in KWIC view.
+     *
+     * @param classNumber The number of a class to highlight.
+     * @return The {@link Krill} object for chaining.
+     */
+    public KrillMeta addHighlight (int classNumber) {
+        this.highlights.add(classNumber);
+        return this;
+    };
+
+
+    @Deprecated
+    public boolean doCutOff () {
+        return this.cutOff;
+    };
+
+    @Deprecated
+    public KrillMeta setCutOff (boolean cutOff) {
+        this.cutOff = cutOff;
+        return this;
+    };
+
+
+    // TODO:
+    // This limits the search results with offset
+    // Maybe can be deprecated!
+    @Deprecated
+    public int getLimit () {
+        return this.limit;
+    };
+
+    // TODO:
+    // This limits the search results with offset
+    // Maybe can be deprecated!
+    @Deprecated
+    public KrillMeta setLimit (int limit) {
+        if (limit > 0)
+            this.limit = limit;
+        return this;
+    };
+
+
+    @Override
+    public JsonNode toJsonNode () {
+        ObjectMapper mapper = new ObjectMapper();
+        ObjectNode json =  mapper.createObjectNode();
+        // json.put("@type", "koral:meta");
+
+        ArrayNode fieldNode = mapper.createArrayNode();
+        fieldNode.addPOJO(this.fields);
+
+        // <legacy>
+        // Add cutOff attribute
+        if (this.cutOff)
+            json.put("cutOff", this.doCutOff());
+
+        // Add limit attribute
+        if (this.limit > 0)
+            json.put("limit",  this.getLimit());
+        // </legacy>
+
+        // Add count attribute
+        json.put("count",      this.getCount());
+
+        // Add startindex attribute
+        json.put("startIndex", this.getStartIndex());
+
+        // Add timeout attribute
+        json.put("timeout",    this.getTimeOut());
+
+        // Add context attribute
+        json.put("context",    this.getContext().toJsonNode());
+
+        // Add fields attribute
+        json.put("fields",     fieldNode); 
+
+        // Add itemsPerResource attribute
+        if (this.itemsPerResource > 0)
+            json.put("itemsPerResource", (int) this.getItemsPerResource());
+
+        // Add highlight attribute
+        if (!this.highlights.isEmpty()) {
+            ArrayNode highlightNode = mapper.createArrayNode();
+            highlightNode.addPOJO(this.highlights);
+            json.put("highlight", highlightNode);
+        };
+
+        return json;
+    };
+};
diff --git a/src/main/java/de/ids_mannheim/korap/index/SearchContext.java b/src/main/java/de/ids_mannheim/korap/index/SearchContext.java
deleted file mode 100644
index 37fda27..0000000
--- a/src/main/java/de/ids_mannheim/korap/index/SearchContext.java
+++ /dev/null
@@ -1,155 +0,0 @@
-package de.ids_mannheim.korap.index;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.fasterxml.jackson.databind.SerializationFeature;
-import com.fasterxml.jackson.databind.JsonNode;
-import com.fasterxml.jackson.databind.node.*;
-import com.fasterxml.jackson.annotation.*;
-
-
-public class SearchContext {
-    ObjectMapper mapper = new ObjectMapper();
-
-    
-    private boolean spanType = false;
-
-    @JsonIgnore
-    public SearchContextSide left, right;
-
-    @JsonIgnore
-    public String spanContext;
-
-    {
-	left  = new SearchContextSide();
-	right = new SearchContextSide();
-    };
-
-    public SearchContext () {};
-
-    public SearchContext (String spanContext) {
-	this.spanType = true;
-	this.spanContext = spanContext;
-    };
-
-    public SearchContext (boolean leftTokenContext,
-			  short leftContext,
-			  boolean rightTokenContext,
-			  short rightContext) {
-	this.spanType = false;
-	this.left.setToken(leftTokenContext);
-	this.left.setLength(leftContext);
-	this.right.setToken(leftTokenContext);
-	this.right.setLength(rightContext);
-    };
-
-    public boolean isSpanDefined () {
-	return this.spanType;
-    };
-
-    public String getSpanContext () {
-	return this.spanContext;
-    };
-
-    public SearchContext setSpanContext (String spanContext) {
-	this.spanType = true;
-
-	if (spanContext.equals("sentence")) {
-	    spanContext = "s";
-	}
-	else if (spanContext.equals("paragraph")) {
-	    spanContext = "p";
-	};
-	
-	this.spanContext = spanContext;
-	return this;
-    };
-
-    public class SearchContextSide {
-	private boolean type = true;
-	private short length = 6;
-	private short maxLength = 500;
-	
-	public boolean isToken () {
-	    return this.type;
-	};
-	
-	public boolean isCharacter () {
-	    return !(this.type);
-	};
-
-	public SearchContextSide setToken (boolean value) {
-	    this.type = value;
-	    return this;
-	};
-
-	public SearchContextSide setCharacter (boolean value) {
-	    this.type = !(value);
-	    return this;
-	};
-
-	public short getLength() {
-	    return this.length;
-	};
-	
-	public SearchContextSide setLength (short value) {
-	    if (value >= 0) {
-		if (value <= maxLength) {
-		    this.length = value;
-		}
-		else {
-		    this.length = this.maxLength;
-		};
-	    };
-	    return this;
-	};
-
-	public SearchContextSide setLength (int value) {
-	    return this.setLength((short) value);
-	};
-
-	public void fromJson (JsonNode json) {
-	    String type = json.get(0).asText();
-	    if (type.equals("token")) {
-		this.setToken(true);
-	    }
-	    else if (type.equals("char")) {
-		this.setCharacter(true);
-	    };
-	    this.setLength(json.get(1).asInt(this.length));
-	};
-    };
-
-
-    public void fromJson (JsonNode context) {
-	if (context.isContainerNode()) {
-	    if (context.has("left"))
-		this.left.fromJson(context.get("left"));
-	    
-	    if (context.has("right"))
-		this.right.fromJson(context.get("right"));
-	}
-	else if (context.isValueNode()) {
-	    this.setSpanContext(context.asText());
-	};
-    };
-
-    public JsonNode toJsonNode () {
-
-	if (this.isSpanDefined())
-	    return new TextNode(this.spanContext);
-	
-	ArrayNode leftContext = mapper.createArrayNode();
-	leftContext.add(this.left.isToken() ? "token" : "char");
-	leftContext.add(this.left.getLength());
-
-	ArrayNode rightContext = mapper.createArrayNode();
-	rightContext.add(this.right.isToken() ? "token" : "char");
-	rightContext.add(this.right.getLength());
-
-	ObjectNode context = mapper.createObjectNode();
-	context.put("left", leftContext);
-	context.put("right", rightContext);
-
-	return context;
-    };
-
-};
diff --git a/src/main/java/de/ids_mannheim/korap/meta/SearchContext.java b/src/main/java/de/ids_mannheim/korap/meta/SearchContext.java
new file mode 100644
index 0000000..437d726
--- /dev/null
+++ b/src/main/java/de/ids_mannheim/korap/meta/SearchContext.java
@@ -0,0 +1,153 @@
+package de.ids_mannheim.korap.meta;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.SerializationFeature;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.node.*;
+import com.fasterxml.jackson.annotation.*;
+
+
+public class SearchContext {
+    ObjectMapper mapper = new ObjectMapper();
+
+    private boolean spanType = false;
+
+    @JsonIgnore
+    public SearchContextSide left, right;
+
+    @JsonIgnore
+    public String spanContext;
+
+    {
+        left  = new SearchContextSide();
+        right = new SearchContextSide();
+    };
+
+    public SearchContext () {};
+
+    public SearchContext (String spanContext) {
+        this.spanType = true;
+        this.spanContext = spanContext;
+    };
+
+    public SearchContext (boolean leftTokenContext,
+                          short leftContext,
+                          boolean rightTokenContext,
+                          short rightContext) {
+        this.spanType = false;
+        this.left.setToken(leftTokenContext);
+        this.left.setLength(leftContext);
+        this.right.setToken(leftTokenContext);
+        this.right.setLength(rightContext);
+    };
+
+    public boolean isSpanDefined () {
+        return this.spanType;
+    };
+
+    public String getSpanContext () {
+        return this.spanContext;
+    };
+
+    public SearchContext setSpanContext (String spanContext) {
+        this.spanType = true;
+        
+        if (spanContext.equals("sentence")) {
+            spanContext = "s";
+        }
+        else if (spanContext.equals("paragraph")) {
+            spanContext = "p";
+        };
+	
+        this.spanContext = spanContext;
+        return this;
+    };
+
+    public class SearchContextSide {
+        private boolean type = true;
+        private short length = 6;
+        private short maxLength = 500;
+        
+        public boolean isToken () {
+            return this.type;
+        };
+        
+        public boolean isCharacter () {
+            return !(this.type);
+        };
+
+        public SearchContextSide setToken (boolean value) {
+            this.type = value;
+            return this;
+        };
+
+        public SearchContextSide setCharacter (boolean value) {
+            this.type = !(value);
+            return this;
+        };
+
+        public short getLength() {
+            return this.length;
+        };
+	
+        public SearchContextSide setLength (short value) {
+            if (value >= 0) {
+                if (value <= maxLength) {
+                    this.length = value;
+                }
+                else {
+                    this.length = this.maxLength;
+                };
+            };
+            return this;
+        };
+        
+        public SearchContextSide setLength (int value) {
+            return this.setLength((short) value);
+        };
+
+        public void fromJson (JsonNode json) {
+            String type = json.get(0).asText();
+            if (type.equals("token")) {
+                this.setToken(true);
+            }
+            else if (type.equals("char")) {
+                this.setCharacter(true);
+            };
+            this.setLength(json.get(1).asInt(this.length));
+        };
+    };
+
+
+    public void fromJson (JsonNode context) {
+        if (context.isContainerNode()) {
+            if (context.has("left"))
+                this.left.fromJson(context.get("left"));
+            
+            if (context.has("right"))
+                this.right.fromJson(context.get("right"));
+        }
+        else if (context.isValueNode()) {
+            this.setSpanContext(context.asText());
+        };
+    };
+
+    public JsonNode toJsonNode () {
+        
+        if (this.isSpanDefined())
+            return new TextNode(this.spanContext);
+	
+        ArrayNode leftContext = mapper.createArrayNode();
+        leftContext.add(this.left.isToken() ? "token" : "char");
+        leftContext.add(this.left.getLength());
+        
+        ArrayNode rightContext = mapper.createArrayNode();
+        rightContext.add(this.right.isToken() ? "token" : "char");
+        rightContext.add(this.right.getLength());
+
+        ObjectNode context = mapper.createObjectNode();
+        context.put("left", leftContext);
+        context.put("right", rightContext);
+        
+        return context;
+    };
+};
diff --git a/src/main/java/de/ids_mannheim/korap/node/Resource.java b/src/main/java/de/ids_mannheim/korap/node/Resource.java
index 0bdcc23..986aad8 100644
--- a/src/main/java/de/ids_mannheim/korap/node/Resource.java
+++ b/src/main/java/de/ids_mannheim/korap/node/Resource.java
@@ -241,7 +241,7 @@
                 ks.setCollection(kc);
 
                 // Only return the first match per text
-                ks.setItemsPerResource(1);
+                ks.getMeta().setItemsPerResource(1);
 
                 return ks.apply(index).toJsonString();
             };
diff --git a/src/main/java/de/ids_mannheim/korap/response/KorapResponse.java b/src/main/java/de/ids_mannheim/korap/response/KorapResponse.java
index b082f29..e4b0359 100644
--- a/src/main/java/de/ids_mannheim/korap/response/KorapResponse.java
+++ b/src/main/java/de/ids_mannheim/korap/response/KorapResponse.java
@@ -8,12 +8,16 @@
 import com.fasterxml.jackson.databind.JsonNode;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.fasterxml.jackson.databind.node.ObjectNode;
+import de.ids_mannheim.korap.KorapCollection;
+import de.ids_mannheim.korap.KrillMeta;
+
 
 import de.ids_mannheim.korap.KorapQuery;
 import de.ids_mannheim.korap.response.Notifications;
 
 /**
  * Base class for objects meant to be responded by the server.
+ * This inherits KoralQuery requests.
  *
  * <p>
  * <blockquote><pre>
@@ -31,6 +35,9 @@
 public class KorapResponse extends Notifications {
     ObjectMapper mapper = new ObjectMapper();
 
+    private KrillMeta meta;
+    private KorapCollection collection;
+
     private String version, name, node, listener;
     private KorapQuery query;
 
@@ -323,6 +330,8 @@
      */
     @JsonIgnore
     public KorapQuery getQuery () {
+        if (this.query == null)
+            this.query = new KorapQuery();
         return this.query;
     };
 
@@ -332,11 +341,74 @@
      *
      * @param query The {@link KorapQuery} object,
      *        representing the KoralQuery query object.
+     * @return The {@link KorapResponse} object for chaining
      */
     @JsonIgnore
     public KorapResponse setQuery (KorapQuery query) {
         this.query = query;
-        return this;
+
+        // Move messages from the query
+        return (KorapResponse) this.moveNotificationsFrom(query);
+    };
+
+
+    /**
+     * Get the associated collection object.
+     * In case no collection information was defined yet,
+     * a new {@link KorapCollection} object will be created.
+     *
+     * @return The attached {@link KorapCollection} object.
+     */
+    @JsonIgnore
+    public KorapCollection getCollection () {
+        if (this.collection == null)
+            this.collection = new KorapCollection();
+        return this.collection;
+    };
+
+
+    /**
+     * Set a new {@link KorapCollection} object.
+     *
+     * @param collection A {@link KorapCollection} object.
+     * @return The {@link KorapResponse} object for chaining
+     */
+    @JsonIgnore
+    public KorapResponse setCollection (KorapCollection collection) {
+        this.collection = collection;
+        
+        // Move messages from the collection
+        return (KorapResponse) this.moveNotificationsFrom(collection);
+    };
+
+    
+    /**
+     * Get the associated meta object.
+     * In case no meta information was defined yet,
+     * a new {@link KrillMeta} object will be created.
+     *
+     * @return The attached {@link KrillMeta} object.
+     */
+    @JsonIgnore
+    public KrillMeta getMeta () {
+        if (this.meta == null)
+            this.meta = new KrillMeta();
+        return this.meta;
+    };
+
+
+    /**
+     * Set a new {@link KrillMeta} object.
+     *
+     * @param meta A {@link KrillMeta} object.
+     * @return The {@link KorapResponse} object for chaining
+     */
+    @JsonIgnore
+    public KorapResponse setMeta (KrillMeta meta) {
+        this.meta = meta;
+        
+        // Move messages from the collection
+        return (KorapResponse) this.moveNotificationsFrom(meta);
     };
 
 
@@ -378,7 +450,7 @@
         if (this.getBenchmark() != null)
             json.put("benchmark", this.getBenchmark());
 
-        // totalTexts is set
+        // totalResources is set
         if (this.totalResources != -2)
             json.put("totalResources", this.totalResources);
         
@@ -387,13 +459,27 @@
             json.put("totalResults", this.totalResults);
 
         // KoralQuery query object
-        if (this.getQuery() != null) {
-            JsonNode queryNode =
-                this.getQuery().toJsonNode();
+        if (this.query != null) {
+            JsonNode queryNode = this.getQuery().toJsonNode();
             if (queryNode != null)
                 json.put("query", queryNode);
         };
 
+        // KoralQuery meta object
+        if (this.meta != null) {
+            JsonNode metaNode = this.meta.toJsonNode();
+            if (metaNode != null)
+                json.put("meta", metaNode);
+        };
+
+        // KoralQuery collection object
+        if (this.collection != null &&
+            this.collection.getFilters().toArray().length > 0) {
+            JsonNode collNode = this.collection.toJsonNode();
+            if (collNode != null)
+                json.put("collection", collNode);
+        };
+
         return (JsonNode) json;
     };
 
diff --git a/src/main/java/de/ids_mannheim/korap/response/Notifications.java b/src/main/java/de/ids_mannheim/korap/response/Notifications.java
index 8ecf0b3..e99d515 100644
--- a/src/main/java/de/ids_mannheim/korap/response/Notifications.java
+++ b/src/main/java/de/ids_mannheim/korap/response/Notifications.java
@@ -47,7 +47,6 @@
 
     private Messages warnings, errors, messages;
 
-
     /**
      * Check for warnings.
      *
@@ -369,7 +368,7 @@
     /**
      * Copy notifications from a {@link JsonNode} object.
      *
-     * @param request Notifications containing {@lin JsonNode}.
+     * @param request Notifications containing {@link JsonNode}.
      * @return Notification object for chaining
      */
     public Notifications copyNotificationsFrom (JsonNode request) {
@@ -405,6 +404,20 @@
 
 
     /**
+     * Move notifications from a passed {@link Notification} object
+     * to the invocant.
+     *
+     * @param notes Notification object.
+     * @return The invocant object for chaining
+     */
+    public Notifications moveNotificationsFrom (Notifications notes) {
+        this.copyNotificationsFrom(notes);
+        notes.clearNotifications();
+        return this;
+    };
+
+
+    /**
      * Clear all notifications.
      *
      * @return Notification object for chaining
@@ -420,6 +433,7 @@
     };
 
 
+
     /**
      * Serialize Notifications as a {@link JsonNode}.
      *
diff --git a/src/test/java/de/ids_mannheim/korap/highlight/TestHighlight.java b/src/test/java/de/ids_mannheim/korap/highlight/TestHighlight.java
index 1fd999f..31f7b05 100644
--- a/src/test/java/de/ids_mannheim/korap/highlight/TestHighlight.java
+++ b/src/test/java/de/ids_mannheim/korap/highlight/TestHighlight.java
@@ -212,8 +212,8 @@
         kq = new KorapQuery("base");
         q = (SpanQuery) kq.or(kq._(1, kq.seg("i:a"))).or(kq._(2, kq.seg("i:c"))).toQuery();
         Krill qs = new Krill(q);
-        qs.getContext().left.setToken(true).setLength((short) 1);
-        qs.getContext().right.setToken(true).setLength((short) 1);
+        qs.getMeta().getContext().left.setToken(true).setLength((short) 1);
+        qs.getMeta().getContext().right.setToken(true).setLength((short) 1);
         kr = ki.search(qs);
         assertEquals((long) 10, kr.getTotalResults());
 
@@ -228,8 +228,8 @@
         assertEquals("[{1:a}]b ...", kr.getMatch(8).getSnippetBrackets());
         assertEquals("... b[{2:a}]", kr.getMatch(9).getSnippetBrackets());
 
-        qs.getContext().left.setToken(true).setLength((short) 0);
-        qs.getContext().right.setToken(true).setLength((short) 0);
+        qs.getMeta().getContext().left.setToken(true).setLength((short) 0);
+        qs.getMeta().getContext().right.setToken(true).setLength((short) 0);
         kr = ki.search(qs);
         assertEquals((long) 10, kr.getTotalResults());
 
@@ -248,8 +248,8 @@
             3, kq.or(kq._(1, kq.seg("i:a"))).or(kq._(2, kq.seg("i:c")))
         ).toQuery();
         qs = new Krill(q);
-        qs.getContext().left.setToken(true).setLength((short) 0);
-        qs.getContext().right.setToken(true).setLength((short) 0);
+        qs.getMeta().getContext().left.setToken(true).setLength((short) 0);
+        qs.getMeta().getContext().right.setToken(true).setLength((short) 0);
         kr = ki.search(qs);
         assertEquals((long) 10, kr.getTotalResults());
 
diff --git a/src/test/java/de/ids_mannheim/korap/index/TestFieldDocument.java b/src/test/java/de/ids_mannheim/korap/index/TestFieldDocument.java
index 7eebc61..6cda8de 100644
--- a/src/test/java/de/ids_mannheim/korap/index/TestFieldDocument.java
+++ b/src/test/java/de/ids_mannheim/korap/index/TestFieldDocument.java
@@ -20,6 +20,7 @@
 import de.ids_mannheim.korap.KorapQuery;
 import de.ids_mannheim.korap.KorapResult;
 import de.ids_mannheim.korap.Krill;
+import de.ids_mannheim.korap.KrillMeta;
 import de.ids_mannheim.korap.KorapMatch;
 import de.ids_mannheim.korap.KorapDocument;
 import de.ids_mannheim.korap.query.SpanNextQuery;
@@ -192,11 +193,12 @@
 	      )
             ));
 	
-	ks.setCount(1);
-	ks.setCutOff(true);
+    KrillMeta meta = ks.getMeta();
+	meta.setCount(1);
+	meta.setCutOff(true);
 
-	ks.context.left.setCharacter(true).setLength(6);
-	ks.context.right.setToken(true).setLength(6);
+	meta.getContext().left.setCharacter(true).setLength(6);
+	meta.getContext().right.setToken(true).setLength(6);
 
 	assertEquals("... okal. [Der Buchstabe A hat in {1:deutschen Texten} eine durchschnittliche Häufigkeit von 6,51 %.] Er ist damit der sechsthäufigste Buchstabe ...", ks.apply(ki).getMatch(0).getSnippetBrackets());
     };
diff --git a/src/test/java/de/ids_mannheim/korap/index/TestMatchCollector.java b/src/test/java/de/ids_mannheim/korap/index/TestMatchCollector.java
index 62781d2..f2a159d 100644
--- a/src/test/java/de/ids_mannheim/korap/index/TestMatchCollector.java
+++ b/src/test/java/de/ids_mannheim/korap/index/TestMatchCollector.java
@@ -76,8 +76,10 @@
 	SpanQuery sq;
 
 	sq = new SpanTermQuery(new Term("base", "s:b"));
+    Krill krill = new Krill(sq);
+    krill.getMeta().setCount((short) 10);
 	MatchCollector mc = ki.collect(
-	  new Krill(sq).setCount((short) 10),
+	  krill,
 	  new MatchCollector()
 	);
 
diff --git a/src/test/java/de/ids_mannheim/korap/index/TestRealIndex.java b/src/test/java/de/ids_mannheim/korap/index/TestRealIndex.java
index 8b86c7f..ba3d299 100644
--- a/src/test/java/de/ids_mannheim/korap/index/TestRealIndex.java
+++ b/src/test/java/de/ids_mannheim/korap/index/TestRealIndex.java
@@ -23,23 +23,23 @@
     KorapQuery kq;
 	
     public TestRealIndex() throws IOException {
-	InputStream is = getClass().getResourceAsStream("/server.properties");
-	Properties prop = new Properties();
-	prop.load(is);
+        InputStream is = getClass().getResourceAsStream("/server.properties");
+        Properties prop = new Properties();
+        prop.load(is);
 	
-	String indexPath = prop.getProperty("lucene.indexDir");
-	System.err.println(indexPath);
-	MMapDirectory md = new MMapDirectory(new File(indexPath));
-	ki = new KorapIndex(md);
+        String indexPath = prop.getProperty("lucene.indexDir");
+        System.err.println(indexPath);
+        MMapDirectory md = new MMapDirectory(new File(indexPath));
+        ki = new KorapIndex(md);
     };
 
     @Test
     public void testCase1() throws IOException, QueryException {
-	KorapQuery kq = new KorapQuery("tokens");
-	ks = new Krill(kq.within(kq.tag("base/s:s"), kq.seq(kq.re("s:.*")).append(kq._(kq.re("s:.*")))).toQuery());
-	ks.setTimeOut(10000);
-	kr = ks.apply(ki);
-	System.err.println(kr.toJsonString());
-	assertEquals(8, kr.getTotalResults());
+        KorapQuery kq = new KorapQuery("tokens");
+        ks = new Krill(kq.within(kq.tag("base/s:s"), kq.seq(kq.re("s:.*")).append(kq._(kq.re("s:.*")))).toQuery());
+        ks.getMeta().setTimeOut(10000);
+        kr = ks.apply(ki);
+        System.err.println(kr.toJsonString());
+        assertEquals(8, kr.getTotalResults());
     };
 }
diff --git a/src/test/java/de/ids_mannheim/korap/index/TestRegexWildcardIndex.java b/src/test/java/de/ids_mannheim/korap/index/TestRegexWildcardIndex.java
index 6815a49..bc7fc80 100644
--- a/src/test/java/de/ids_mannheim/korap/index/TestRegexWildcardIndex.java
+++ b/src/test/java/de/ids_mannheim/korap/index/TestRegexWildcardIndex.java
@@ -53,8 +53,8 @@
 	assertEquals("SpanMultiTermQueryWrapper(base:/s:af*e/)", sq.toString());
 			
 	Krill ks = new Krill(sq);
-	ks.context.left.setToken(true).setLength(1);
-	ks.context.right.setToken(true).setLength(1);
+	ks.getMeta().getContext().left.setToken(true).setLength(1);
+	ks.getMeta().getContext().right.setToken(true).setLength(1);
 
 	KorapResult kr = ki.search(ks);
 	assertEquals((long) 2, kr.getTotalResults());
@@ -110,8 +110,8 @@
 	assertEquals("SpanMultiTermQueryWrapper(base:s:af*e)", sq.toString());
 
 	Krill ks = new Krill(sq);
-	ks.context.left.setToken(true).setLength(1);
-	ks.context.right.setToken(true).setLength(1);
+	ks.getMeta().getContext().left.setToken(true).setLength(1);
+	ks.getMeta().getContext().right.setToken(true).setLength(1);
 
 	KorapResult kr = ki.search(ks);
 	assertEquals((long) 2, kr.getTotalResults());
@@ -169,8 +169,8 @@
 	assertEquals("SpanMultiTermQueryWrapper(base:/i:af*e/)", sq.toString());
 
 	Krill ks = new Krill(sq);
-	ks.context.left.setToken(true).setLength(1);
-	ks.context.right.setToken(true).setLength(1);
+	ks.getMeta().getContext().left.setToken(true).setLength(1);
+	ks.getMeta().getContext().right.setToken(true).setLength(1);
 
 	KorapResult kr = ki.search(ks);
 	assertEquals((long) 2, kr.getTotalResults());
@@ -234,8 +234,8 @@
 	assertEquals("spanNext(base:s:affe, SpanMultiTermQueryWrapper(base:/s:af*e/))", sq.toString());
 
 	Krill ks = new Krill(sq);
-	ks.context.left.setToken(true).setLength(1);
-	ks.context.right.setToken(true).setLength(1);
+	ks.getMeta().getContext().left.setToken(true).setLength(1);
+	ks.getMeta().getContext().right.setToken(true).setLength(1);
 
 	KorapResult kr = ki.search(ks);
 	assertEquals((long) 1, kr.getTotalResults());
@@ -275,8 +275,8 @@
 				   kq.seg("s:affe")).toQuery();
 	assertEquals("spanContain(spanNext(SpanMultiTermQueryWrapper(base:/s:a.*e/), SpanMultiTermQueryWrapper(base:/s:af*e/)), base:s:affe)", sq.toString());
 	Krill ks = new Krill(sq);
-	ks.context.left.setToken(true).setLength(1);
-	ks.context.right.setToken(true).setLength(1);
+	ks.getMeta().getContext().left.setToken(true).setLength(1);
+	ks.getMeta().getContext().right.setToken(true).setLength(1);
 
 	KorapResult kr = ki.search(ks);
 	assertEquals((long) 1, kr.getTotalResults());
diff --git a/src/test/java/de/ids_mannheim/korap/search/TestKrill.java b/src/test/java/de/ids_mannheim/korap/search/TestKrill.java
index 3079718..ed04f53 100644
--- a/src/test/java/de/ids_mannheim/korap/search/TestKrill.java
+++ b/src/test/java/de/ids_mannheim/korap/search/TestKrill.java
@@ -6,11 +6,12 @@
 import static de.ids_mannheim.korap.TestSimple.*;
 
 import de.ids_mannheim.korap.Krill;
+import de.ids_mannheim.korap.KrillMeta;
 import de.ids_mannheim.korap.KorapCollection;
 import de.ids_mannheim.korap.KorapQuery;
 import de.ids_mannheim.korap.KorapIndex;
 import de.ids_mannheim.korap.index.FieldDocument;
-import de.ids_mannheim.korap.index.SearchContext;
+import de.ids_mannheim.korap.meta.SearchContext;
 import de.ids_mannheim.korap.collection.CollectionBuilder;
 import de.ids_mannheim.korap.KorapResult;
 import java.nio.file.Files;
@@ -32,36 +33,42 @@
 public class TestKrill {
     @Test
     public void searchCount () {
-        Krill ks = new Krill(
-            new KorapQuery("field1").seg("a").with("b")
+        Krill k = new Krill(
+          new KorapQuery("field1").seg("a").with("b")
         );
+
+        KrillMeta meta = k.getMeta();
+
         // Count:
-        ks.setCount(30);
-        assertEquals(ks.getCount(), 30);
-        ks.setCount(20);
-        assertEquals(ks.getCount(), 20);
-        ks.setCount(-50);
-        assertEquals(ks.getCount(), 20);
-        ks.setCount(500);
-        assertEquals(ks.getCount(), ks.getCountMax());
+        meta.setCount(30);
+        assertEquals(meta.getCount(), 30);
+        meta.setCount(20);
+        assertEquals(meta.getCount(), 20);
+        meta.setCount(-50);
+        assertEquals(meta.getCount(), 20);
+        meta.setCount(500);
+        assertEquals(meta.getCount(), meta.getCountMax());
     };
 
     @Test
     public void searchStartIndex () {
-        Krill ks = new Krill(
+        Krill k = new Krill(
             new KorapQuery("field1").seg("a").with("b")
         );
+
+        KrillMeta meta = k.getMeta();
+
         // startIndex
-        ks.setStartIndex(5);
-        assertEquals(ks.getStartIndex(), 5);
-        ks.setStartIndex(1);
-        assertEquals(ks.getStartIndex(), 1);
-        ks.setStartIndex(0);
-        assertEquals(ks.getStartIndex(), 0);
-        ks.setStartIndex(70);
-        assertEquals(ks.getStartIndex(), 70);
-        ks.setStartIndex(-5);
-        assertEquals(ks.getStartIndex(), 0);
+        meta.setStartIndex(5);
+        assertEquals(meta.getStartIndex(), 5);
+        meta.setStartIndex(1);
+        assertEquals(meta.getStartIndex(), 1);
+        meta.setStartIndex(0);
+        assertEquals(meta.getStartIndex(), 0);
+        meta.setStartIndex(70);
+        assertEquals(meta.getStartIndex(), 70);
+        meta.setStartIndex(-5);
+        assertEquals(meta.getStartIndex(), 0);
     };
 
     @Test
@@ -96,19 +103,32 @@
         Krill ks = new Krill(
 	        new KorapQuery("tokens").seg("s:Buchstaben")
         );
+
+        // Todo: This is not an acceptable collection, but sigh
         ks.getCollection().filter(
             new CollectionBuilder().and("textClass", "reisen")
         );
-        ks.setCount(3);
-        ks.setStartIndex(5);
-        ks.context.left.setLength(1);
-        ks.context.right.setLength(1);
+
+        KrillMeta meta = ks.getMeta();
+        meta.setCount(3);
+        meta.setStartIndex(5);
+        meta.getContext().left.setLength(1);
+        meta.getContext().right.setLength(1);
+        
         KorapResult kr = ks.apply(ki);
         assertEquals(kr.getTotalResults(), 6);
         assertEquals(
             kr.getMatch(0).getSnippetBrackets(),
             "... dem [Buchstaben] A ..."
         );
+
+        JsonNode res = ks.toJsonNode();
+        assertEquals(3, res.at("/meta/count").asInt());
+        assertEquals(5, res.at("/meta/startIndex").asInt());
+        assertEquals("token", res.at("/meta/context/left/0").asText());
+        assertEquals(1, res.at("/meta/context/left/1").asInt());
+        assertEquals("token", res.at("/meta/context/right/0").asText());
+        assertEquals(1, res.at("/meta/context/right/1").asInt());
     };
 
 
@@ -323,8 +343,8 @@
                      " eine durchschnittliche Häufigkeit  ...",
                      kr.getMatch(0).getSnippetBrackets());
 
-        ks.setCount(5);
-        ks.setStartPage(2);
+        ks.getMeta().setCount(5);
+        ks.getMeta().setStartPage(2);
         kr = ks.apply(ki);
         assertEquals(kr.getTotalResults(), 10);
         assertEquals(5, kr.getStartIndex());
@@ -436,7 +456,7 @@
         assertEquals("WPD_AAA.00004", kr.getMatch(9).getDocID());
 
         ks = new Krill(json);
-        ks.setItemsPerResource(1);
+        ks.getMeta().setItemsPerResource(1);
 
         kr = ks.apply(ki);
 
@@ -449,7 +469,7 @@
         assertEquals(20, kr.getItemsPerPage());
         
         ks = new Krill(json);
-        ks.setItemsPerResource(2);
+        ks.getMeta().setItemsPerResource(2);
 
         kr = ks.apply(ki);
 
@@ -464,9 +484,10 @@
         assertEquals(20, kr.getItemsPerPage());
 
         ks = new Krill(json);
-        ks.setItemsPerResource(1);
-        ks.setStartIndex(1);
-        ks.setCount(1);
+        KrillMeta meta = ks.getMeta();
+        meta.setItemsPerResource(1);
+        meta.setStartIndex(1);
+        meta.setCount(1);
 
         kr = ks.apply(ki);
 	
@@ -512,7 +533,8 @@
         );
 
         Krill ks = new Krill(json);
-        ks.setItemsPerResource(1);
+        ks.getMeta().setItemsPerResource(1);
+
         KorapCollection kc = new KorapCollection();
         kc.filterUIDs(new String[]{"1", "4"});
         kc.setIndex(ki);
@@ -1081,8 +1103,8 @@
         );
 	
         Krill ks = new Krill(json);
-        ks.setCutOff(false);
-        SearchContext sc = ks.getContext();
+        ks.getMeta().setCutOff(false);
+        SearchContext sc = ks.getMeta().getContext();
         sc.left.setLength((short) 10);
         sc.right.setLength((short) 10);
         
diff --git a/src/test/java/de/ids_mannheim/korap/search/TestMetaFields.java b/src/test/java/de/ids_mannheim/korap/search/TestMetaFields.java
index f8994b0..8b5c530 100644
--- a/src/test/java/de/ids_mannheim/korap/search/TestMetaFields.java
+++ b/src/test/java/de/ids_mannheim/korap/search/TestMetaFields.java
@@ -10,7 +10,7 @@
 import de.ids_mannheim.korap.KorapQuery;
 import de.ids_mannheim.korap.KorapIndex;
 import de.ids_mannheim.korap.index.FieldDocument;
-import de.ids_mannheim.korap.index.SearchContext;
+import de.ids_mannheim.korap.meta.SearchContext;
 import de.ids_mannheim.korap.KorapResult;
 import java.nio.file.Files;
 import java.nio.file.FileSystem;