Merge "Merge branch 'master' of ssh://korap.ids-mannheim.de:29418/KorAP/Koral"
diff --git a/Changes b/Changes
index 8c6defd..739f58c 100644
--- a/Changes
+++ b/Changes
@@ -4,7 +4,7 @@
 	  now serialize to unordered sequences (diewald)
 	- Cleanup POM (diewald)
 	- Fix deserialization of unnecessary brackets
-	  around terms in Poliqarp (diewald)
+	  around terms and termGroups in Poliqarp (diewald)
 
 0.21 2015-10-27
         - Improved meta query builder (hanl)
diff --git a/README.md b/README.md
index db6206e..e9ab53e 100644
--- a/README.md
+++ b/README.md
@@ -97,13 +97,20 @@
 
     git clone https://github.com/korap/Koral [install-dir]
     cd [install-dir]
-    mvn test
+    mvn test -Dhttps.protocols=TLSv1.2
     mvn install
 
 There is also a command line version. After installation, simply run
 
     java -jar target/Koral-0.2.jar [query] [queryLanguage]
-    
+   
+## Prerequisites
+
+* Java 7 (OpenJDK or Oracle JDK with [JCE] (http://www.oracle.com/technetwork/java/javase/downloads/jce-7-download-432124.html))
+* [Git](http://git-scm.com/)
+* At least [Maven 3.2.1](https://maven.apache.org/)
+* Further dependencies are resolved by Maven.
+
 ## Authorship
 
 Koral and KoralQuery were developed by Joachim Bingel,
diff --git a/pom.xml b/pom.xml
index e59fd5c..17b0666 100644
--- a/pom.xml
+++ b/pom.xml
@@ -1,271 +1,318 @@
 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-	 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
-  <modelVersion>4.0.0</modelVersion>
+	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+	<modelVersion>4.0.0</modelVersion>
 
-  <groupId>de.ids_mannheim.korap</groupId>
-  <artifactId>Koral</artifactId>
-  <version>0.22</version>
-  <packaging>jar</packaging>
-  <name>Koral</name>
-  <url>http://maven.apache.org</url>
+	<groupId>de.ids_mannheim.korap</groupId>
+	<artifactId>Koral</artifactId>
+	<version>0.22</version>
+	<packaging>jar</packaging>
+	<name>Koral</name>
+	<url>http://maven.apache.org</url>
 
-  <organization>
-    <name>IDS Mannheim</name>
-    <url>http://www.ids-mannheim.de/</url>
-  </organization>
+	<organization>
+		<name>IDS Mannheim</name>
+		<url>http://www.ids-mannheim.de/</url>
+	</organization>
 
-  <developers>
-    <developer>
-      <name>Joachim Bingel</name>
-      <email>bingel@ids-mannheim.de</email>
-    </developer>
-    <developer>
-      <name>Nils Diewald</name>
-      <email>diewald@ids-mannheim.de</email>
-      <url>http://nils-diewald.de</url>
-    </developer>
-    <developer>
-      <name>Michael Hanl</name>
-      <email>hanl@ids-mannheim.de</email>
-    </developer>
-    <developer>
-      <name>Eliza Margaretha</name>
-      <email>margaretha@ids-mannheim.de</email>
-    </developer>
-  </developers>
+	<developers>
+		<developer>
+			<name>Joachim Bingel</name>
+			<email>bingel@ids-mannheim.de</email>
+		</developer>
+		<developer>
+			<name>Nils Diewald</name>
+			<email>diewald@ids-mannheim.de</email>
+			<url>http://nils-diewald.de</url>
+		</developer>
+		<developer>
+			<name>Michael Hanl</name>
+			<email>hanl@ids-mannheim.de</email>
+		</developer>
+		<developer>
+			<name>Eliza Margaretha</name>
+			<email>margaretha@ids-mannheim.de</email>
+		</developer>
+	</developers>
 
-  <properties>
-    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
-  </properties>
-
-  <repositories>
-    <repository>
-      <id>id-maven-repo</id>
-      <url>http://maven.indexdata.com</url>
-    </repository>
-  </repositories>
-  <dependencies>
-    <dependency>
-      <groupId>org.antlr</groupId>
-      <artifactId>antlr4-runtime</artifactId>
-      <version>4.2</version>
-    </dependency>
-    <dependency>
-      <groupId>org.antlr</groupId>
-      <artifactId>antlr4-runtime</artifactId>
-      <version>4.5.1</version>
-    </dependency>
-    <dependency>
-      <groupId>org.antlr</groupId>
-      <artifactId>antlr4-maven-plugin</artifactId>
-      <version>4.2</version>
-    </dependency>
-    <dependency>
-      <groupId>org.antlr</groupId>
-      <artifactId>antlr-runtime</artifactId>
-      <version>3.5</version>
-      <scope>compile</scope>
-    </dependency>
-    <dependency>
-      <groupId>com.google.guava</groupId>
-      <artifactId>guava</artifactId>
-      <version>15.0</version>
-    </dependency>
-    <dependency>
-      <groupId>com.fasterxml.jackson.core</groupId>
-      <artifactId>jackson-core</artifactId>
-      <version>2.3.3</version>
-    </dependency>
-    <dependency>
-      <groupId>com.fasterxml.jackson.core</groupId>
-      <artifactId>jackson-annotations</artifactId>
-      <version>2.3.3</version>
-    </dependency>
-    <dependency>
-      <groupId>com.fasterxml.jackson.core</groupId>
-      <artifactId>jackson-databind</artifactId>
-      <version>2.3.3</version>
-    </dependency>
-    <dependency>
-      <groupId>junit</groupId>
-      <artifactId>junit</artifactId>
-      <version>4.11</version>
-      <scope>test</scope>
-    </dependency>
-    <dependency>
-      <groupId>commons-lang</groupId>
-      <artifactId>commons-lang</artifactId>
-      <version>2.6</version>
-    </dependency>
-    <dependency>
-      <groupId>org.z3950.zing</groupId>
-      <artifactId>cql-java</artifactId>
-      <version>1.12</version>
-    </dependency>
-    <dependency>
-      <groupId>log4j</groupId>
-      <artifactId>log4j</artifactId>
-      <version>1.2.17</version>
-    </dependency>
-    <dependency>
-      <groupId>log4j</groupId>
-      <artifactId>apache-log4j-extras</artifactId>
-      <version>1.2.17</version>
-    </dependency>
-    <dependency>
-      <groupId>org.slf4j</groupId>
-      <artifactId>slf4j-api</artifactId>
-      <version>1.7.5</version>
-    </dependency>
-    <dependency>
-      <groupId>org.slf4j</groupId>
-      <artifactId>slf4j-log4j12</artifactId>
-      <version>1.7.5</version>
-    </dependency>
-    <dependency>
-      <groupId>eu.clarin.sru.fcs</groupId>
-      <artifactId>fcs-simple-endpoint</artifactId>
-      <version>1.3.0</version>
-    </dependency>
-    <dependency>
-      <groupId>org.apache.lucene</groupId>
-      <artifactId>lucene-core</artifactId>
-      <version>5.2.1</version>
-    </dependency>
-    <dependency>
-      <groupId>org.apache.lucene</groupId>
-      <artifactId>lucene-analyzers-common</artifactId>
-      <version>5.2.1</version>
-    </dependency>
-    <dependency>
-      <groupId>org.apache.lucene</groupId>
-      <artifactId>lucene-queryparser</artifactId>
-      <version>5.2.1</version>
-    </dependency>
-  </dependencies>
-  <build>
-    <sourceDirectory>${basedir}/src/main/java</sourceDirectory>
-    <outputDirectory>${basedir}/target/classes</outputDirectory>
-    <plugins>
-      <plugin>
-        <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-compiler-plugin</artifactId>
-        <version>3.3</version>
-        <configuration>
-          <compilerVersion>1.7</compilerVersion>
-          <source>1.7</source>
-          <target>1.7</target>
-        </configuration>
-      </plugin>
-      <!--
-	  Formatter plugin for Eclipse based coding conventions
-	  http://maven-java-formatter-plugin.googlecode.com/svn/site/0.4/usage.html
-      -->      
-      <plugin>
-	<groupId>com.googlecode.maven-java-formatter-plugin</groupId>
-	<artifactId>maven-java-formatter-plugin</artifactId>
-	<version>0.4</version>
-	<configuration>
-	  <configFile>${project.basedir}/Format.xml</configFile>
-	  <overrideConfigCompilerVersion>true</overrideConfigCompilerVersion>
-	  <compilerSource>1.7</compilerSource>
-	  <compilerCompliance>1.7</compilerCompliance>
-	  <compilerTargetPlatform>1.7</compilerTargetPlatform>
-	</configuration>
-      </plugin>
-      <plugin>
-	<artifactId>maven-dependency-plugin</artifactId>
-	<executions>
-	  <execution>
-	    <phase>install</phase>
-	    <goals>
-	      <goal>copy-dependencies</goal>
-	    </goals>
-	    <configuration>
-	      <outputDirectory>${project.build.directory}/../lib</outputDirectory>
-	    </configuration>
-	  </execution>
-	</executions>
-      </plugin>
-      <plugin>
-	<groupId>org.apache.maven.plugins</groupId>
-	<artifactId>maven-jar-plugin</artifactId>
-	<version>2.5</version>
-	<configuration>
-	  <archive>
-	    <manifest>
-	      <addClasspath>true</addClasspath>
-	      <classpathPrefix>../lib/</classpathPrefix>
-	      <mainClass>de.ids_mannheim.korap.query.serialize.QuerySerializer</mainClass>
-	    </manifest>
-	  </archive>
-	</configuration>
-      </plugin>
-      <plugin>
-	<!-- This plugin will help to build the ANTLR4 grammar on the fly. The 
-	     recipe is based on http://stackoverflow.com/questions/15310628/ customize-maven-to-automatically-create-antlr4-grammar-java-files-on-build -->
-	<groupId>org.antlr</groupId>
-	<artifactId>antlr4-maven-plugin</artifactId>
-	<version>4.2</version>
-	<executions>
-	  <execution>
-	    <id>poliqarpplus</id>
-	    <goals>
-	      <goal>antlr4</goal>
-	    </goals>
-	    <configuration>
-	      <sourceDirectory>${basedir}/src/main/antlr/poliqarpplus</sourceDirectory>
-	      <outputDirectory>${basedir}/src/main/java/de/ids_mannheim/korap/query/parse/poliqarpplus</outputDirectory>
-	      <libDirectory>${basedir}/src/main/antlr/poliqarpplus</libDirectory>
-	    </configuration>
-	    <phase>generate-sources</phase>
-	  </execution>
-	  <execution>
-	    <id>annis</id>
-	    <goals>
-	      <goal>antlr4</goal>
-	    </goals>
-	    <configuration>
-	      <sourceDirectory>${basedir}/src/main/antlr/annis</sourceDirectory>
-	      <outputDirectory>${basedir}/src/main/java/de/ids_mannheim/korap/query/parse/annis</outputDirectory>
-	      <libDirectory>${basedir}/src/main/antlr/annis</libDirectory>
-	    </configuration>
-	    <phase>generate-sources</phase>
-	  </execution>
-	  <execution>
-	    <id>collection</id>
-	    <goals>
-	      <goal>antlr4</goal>
-	    </goals>
-	    <configuration>
-	      <sourceDirectory>${basedir}/src/main/antlr/collection</sourceDirectory>
-	      <outputDirectory>${basedir}/src/main/java/de/ids_mannheim/korap/query/parse/collection</outputDirectory>
-	      <libDirectory>${basedir}/src/main/antlr/collection</libDirectory>
-	    </configuration>
-	    <phase>generate-sources</phase>
-	  </execution>
-	</executions>
-      </plugin>
-      <plugin>
-	<!-- This plugin will help to build the ANTLR3 grammar on the fly. The 
-	     recipe is based on http://stackoverflow.com/questions/15310628/ customize-maven-to-automatically-create-antlr4-grammar-java-files-on-build -->
-	<groupId>org.antlr</groupId>
-	<artifactId>antlr3-maven-plugin</artifactId>
-	<version>3.5.1</version>
-	<configuration>
-	  <sourceDirectory>${basedir}/src/main/antlr/cosmas</sourceDirectory>
-	  <outputDirectory>${basedir}/src/main/java/de/ids_mannheim/korap/query/parse/cosmas</outputDirectory>
-	  <libDirectory>${basedir}/src/main/antlr</libDirectory>
-	</configuration>
-	<executions>
-	  <execution>
-	    <goals>
-	      <goal>antlr</goal>
-	    </goals>
-	    <phase>generate-sources</phase>
-	  </execution>
-	</executions>
-      </plugin>
-    </plugins>
-  </build>
+	<properties>
+		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>		
+	</properties>
+	
+	<repositories>
+		<repository>
+			<id>id-maven-repo</id>
+			<url>http://maven.indexdata.com</url>
+		</repository>
+		<repository>
+			<id>CLARIN</id>
+			<name>CLARIN Repository</name>
+			<url>https://nexus.clarin.eu/content/repositories/Clarin</url>
+			<snapshots>
+				<enabled>false</enabled>
+			</snapshots>
+		</repository>
+	</repositories>
+	<dependencies>
+		<!-- <dependency> <groupId>org.antlr</groupId> <artifactId>antlr4-runtime</artifactId> 
+			<version>4.2</version> </dependency> -->
+		<dependency>
+			<groupId>org.antlr</groupId>
+			<artifactId>antlr4-runtime</artifactId>
+			<version>4.5.1</version>
+		</dependency>
+		<dependency>
+			<groupId>org.antlr</groupId>
+			<artifactId>antlr4-maven-plugin</artifactId>
+			<version>4.2</version>
+		</dependency>
+		<dependency>
+			<groupId>org.antlr</groupId>
+			<artifactId>antlr-runtime</artifactId>
+			<version>3.5</version>
+			<scope>compile</scope>
+		</dependency>
+		<dependency>
+			<groupId>com.google.guava</groupId>
+			<artifactId>guava</artifactId>
+			<version>15.0</version>
+		</dependency>
+		<dependency>
+			<groupId>com.fasterxml.jackson.core</groupId>
+			<artifactId>jackson-core</artifactId>
+			<version>2.3.3</version>
+		</dependency>
+		<dependency>
+			<groupId>com.fasterxml.jackson.core</groupId>
+			<artifactId>jackson-annotations</artifactId>
+			<version>2.3.3</version>
+		</dependency>
+		<dependency>
+			<groupId>com.fasterxml.jackson.core</groupId>
+			<artifactId>jackson-databind</artifactId>
+			<version>2.3.3</version>
+		</dependency>
+		<dependency>
+			<groupId>junit</groupId>
+			<artifactId>junit</artifactId>
+			<version>4.11</version>
+			<scope>test</scope>
+		</dependency>
+		<dependency>
+			<groupId>commons-lang</groupId>
+			<artifactId>commons-lang</artifactId>
+			<version>2.6</version>
+		</dependency>
+		<dependency>
+			<groupId>org.z3950.zing</groupId>
+			<artifactId>cql-java</artifactId>
+			<version>1.12</version>
+		</dependency>
+		<dependency>
+			<groupId>log4j</groupId>
+			<artifactId>log4j</artifactId>
+			<version>1.2.17</version>
+		</dependency>
+		<dependency>
+			<groupId>log4j</groupId>
+			<artifactId>apache-log4j-extras</artifactId>
+			<version>1.2.17</version>
+		</dependency>
+		<dependency>
+			<groupId>org.slf4j</groupId>
+			<artifactId>slf4j-api</artifactId>
+			<version>1.7.5</version>
+		</dependency>
+		<dependency>
+			<groupId>org.slf4j</groupId>
+			<artifactId>slf4j-log4j12</artifactId>
+			<version>1.7.5</version>
+		</dependency>
+		<dependency>
+			<groupId>eu.clarin.sru.fcs</groupId>
+			<artifactId>fcs-simple-endpoint</artifactId>
+			<version>1.3.0</version>
+		</dependency>
+		<dependency>
+			<groupId>org.apache.lucene</groupId>
+			<artifactId>lucene-core</artifactId>
+			<version>5.2.1</version>
+		</dependency>
+		<dependency>
+			<groupId>org.apache.lucene</groupId>
+			<artifactId>lucene-analyzers-common</artifactId>
+			<version>5.2.1</version>
+		</dependency>
+		<dependency>
+			<groupId>org.apache.lucene</groupId>
+			<artifactId>lucene-queryparser</artifactId>
+			<version>5.2.1</version>
+		</dependency>
+	</dependencies>
+	<build>
+		<sourceDirectory>${basedir}/src/main/java</sourceDirectory>
+		<outputDirectory>${basedir}/target/classes</outputDirectory>
+		<plugins>
+			<plugin>
+				<groupId>org.apache.maven.plugins</groupId>
+				<artifactId>maven-compiler-plugin</artifactId>
+				<version>3.3</version>
+				<configuration>
+					<compilerVersion>1.7</compilerVersion>
+					<source>1.7</source>
+					<target>1.7</target>
+				</configuration>
+			</plugin>
+			<!-- <plugin>
+				<groupId>org.codehaus.mojo</groupId>
+				<artifactId>properties-maven-plugin</artifactId>
+				<version>1.0.0</version>
+				<executions>
+					<execution>
+						<goals>
+							<goal>set-system-properties</goal>
+						</goals>
+						<configuration>
+							<properties>
+								<property>
+									<name>https.protocols</name>
+									<value>TLSv1.2</value>
+								</property>
+							</properties>
+						</configuration>
+					</execution>
+				</executions>
+			</plugin> -->
+			<!-- <plugin>
+				<groupId>org.apache.maven.plugins</groupId>
+				<artifactId>maven-surefire-plugin</artifactId>
+				<version>2.19.1</version>
+				<configuration>
+					<systemProperties>
+			            <property>
+			              <name>https.protocols</name>
+			              <value>TLSv1.2</value>
+			            </property>
+			          </systemProperties>
+					<argLine>-Djava.https.protocols=TLSv1.2</argLine>
+				</configuration>
+			</plugin>
+			<plugin>
+		        <groupId>org.apache.maven.plugins</groupId>
+		        <artifactId>maven-failsafe-plugin</artifactId>
+		        <version>2.19.1</version>
+		        <configuration>
+		          <systemPropertyVariables>
+		            <https.protocols>TLSv1.2</https.protocols>
+		          </systemPropertyVariables>
+		        </configuration>
+	      </plugin> -->
+			<!-- Formatter plugin for Eclipse based coding conventions http://maven-java-formatter-plugin.googlecode.com/svn/site/0.4/usage.html -->
+			<plugin>
+				<groupId>com.googlecode.maven-java-formatter-plugin</groupId>
+				<artifactId>maven-java-formatter-plugin</artifactId>
+				<version>0.4</version>
+				<configuration>
+					<configFile>${project.basedir}/Format.xml</configFile>
+					<overrideConfigCompilerVersion>true</overrideConfigCompilerVersion>
+					<compilerSource>1.7</compilerSource>
+					<compilerCompliance>1.7</compilerCompliance>
+					<compilerTargetPlatform>1.7</compilerTargetPlatform>
+				</configuration>
+			</plugin>
+			<plugin>
+				<groupId>org.apache.maven.plugins</groupId>
+				<artifactId>maven-dependency-plugin</artifactId>
+				<executions>
+					<execution>
+						<phase>install</phase>
+						<goals>
+							<goal>copy-dependencies</goal>
+						</goals>
+						<configuration>
+							<outputDirectory>${project.build.directory}/../lib</outputDirectory>
+						</configuration>
+					</execution>
+				</executions>
+			</plugin>
+			<plugin>
+				<groupId>org.apache.maven.plugins</groupId>
+				<artifactId>maven-jar-plugin</artifactId>
+				<version>2.5</version>
+				<configuration>
+					<archive>
+						<manifest>
+							<addClasspath>true</addClasspath>
+							<classpathPrefix>../lib/</classpathPrefix>
+							<mainClass>de.ids_mannheim.korap.query.serialize.QuerySerializer</mainClass>
+						</manifest>
+					</archive>
+				</configuration>
+			</plugin>
+			<plugin>
+				<!-- This plugin will help to build the ANTLR4 grammar on the fly. The 
+					recipe is based on http://stackoverflow.com/questions/15310628/ customize-maven-to-automatically-create-antlr4-grammar-java-files-on-build -->
+				<groupId>org.antlr</groupId>
+				<artifactId>antlr4-maven-plugin</artifactId>
+				<version>4.2</version>
+				<executions>
+					<execution>
+						<id>poliqarpplus</id>
+						<goals>
+							<goal>antlr4</goal>
+						</goals>
+						<configuration>
+							<sourceDirectory>${basedir}/src/main/antlr/poliqarpplus</sourceDirectory>
+							<outputDirectory>${basedir}/src/main/java/de/ids_mannheim/korap/query/parse/poliqarpplus</outputDirectory>
+							<libDirectory>${basedir}/src/main/antlr/poliqarpplus</libDirectory>
+						</configuration>
+						<phase>generate-sources</phase>
+					</execution>
+					<execution>
+						<id>annis</id>
+						<goals>
+							<goal>antlr4</goal>
+						</goals>
+						<configuration>
+							<sourceDirectory>${basedir}/src/main/antlr/annis</sourceDirectory>
+							<outputDirectory>${basedir}/src/main/java/de/ids_mannheim/korap/query/parse/annis</outputDirectory>
+							<libDirectory>${basedir}/src/main/antlr/annis</libDirectory>
+						</configuration>
+						<phase>generate-sources</phase>
+					</execution>
+					<execution>
+						<id>collection</id>
+						<goals>
+							<goal>antlr4</goal>
+						</goals>
+						<configuration>
+							<sourceDirectory>${basedir}/src/main/antlr/collection</sourceDirectory>
+							<outputDirectory>${basedir}/src/main/java/de/ids_mannheim/korap/query/parse/collection</outputDirectory>
+							<libDirectory>${basedir}/src/main/antlr/collection</libDirectory>
+						</configuration>
+						<phase>generate-sources</phase>
+					</execution>
+				</executions>
+			</plugin>
+			<plugin>
+				<!-- This plugin will help to build the ANTLR3 grammar on the fly. The 
+					recipe is based on http://stackoverflow.com/questions/15310628/ customize-maven-to-automatically-create-antlr4-grammar-java-files-on-build -->
+				<groupId>org.antlr</groupId>
+				<artifactId>antlr3-maven-plugin</artifactId>
+				<version>3.5.1</version>
+				<configuration>
+					<sourceDirectory>${basedir}/src/main/antlr/cosmas</sourceDirectory>
+					<outputDirectory>${basedir}/src/main/java/de/ids_mannheim/korap/query/parse/cosmas</outputDirectory>
+					<libDirectory>${basedir}/src/main/antlr</libDirectory>
+				</configuration>
+				<executions>
+					<execution>
+						<goals>
+							<goal>antlr</goal>
+						</goals>
+						<phase>generate-sources</phase>
+					</execution>
+				</executions>
+			</plugin>
+		</plugins>
+	</build>
 </project>
diff --git a/src/main/antlr/poliqarpplus/PoliqarpPlusParser.g4 b/src/main/antlr/poliqarpplus/PoliqarpPlusParser.g4
index f1f9110..1907773 100644
--- a/src/main/antlr/poliqarpplus/PoliqarpPlusParser.g4
+++ b/src/main/antlr/poliqarpplus/PoliqarpPlusParser.g4
@@ -102,6 +102,7 @@
 
 termGroup
 : (term | LRPAREN termGroup RRPAREN) boolOp (term | LRPAREN termGroup RRPAREN | termGroup)
+| LRPAREN termGroup RRPAREN
 ;
 
 repetition
diff --git a/src/main/java/de/ids_mannheim/korap/query/object/KoralBoundary.java b/src/main/java/de/ids_mannheim/korap/query/object/KoralBoundary.java
new file mode 100644
index 0000000..0faee0e
--- /dev/null
+++ b/src/main/java/de/ids_mannheim/korap/query/object/KoralBoundary.java
@@ -0,0 +1,46 @@
+package de.ids_mannheim.korap.query.object;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+public class KoralBoundary implements KoralObject {
+
+    private static final KoralType type = KoralType.BOUNDARY;
+
+    private int min;
+    private int max;
+
+    public KoralBoundary (int min, int max) {
+        this.min = min;
+        this.max = max;
+    }
+
+    public int getMin() {
+        return min;
+    }
+
+    public void setMin(int min) {
+        this.min = min;
+    }
+
+    public int getMax() {
+        return max;
+    }
+
+    public void setMax(int max) {
+        this.max = max;
+    }
+
+    @Override
+    public Map<String, Object> buildMap() {
+        Map<String, Object> map = new LinkedHashMap<String, Object>();
+        map.put("@type", type.toString());
+        if (min > -1) {
+            map.put("min", getMin());
+        }
+        if (max > -1) {
+            map.put("max", getMax());
+        }
+        return map;
+    }
+}
diff --git a/src/main/java/de/ids_mannheim/korap/query/object/KoralDistance.java b/src/main/java/de/ids_mannheim/korap/query/object/KoralDistance.java
new file mode 100644
index 0000000..eb88f58
--- /dev/null
+++ b/src/main/java/de/ids_mannheim/korap/query/object/KoralDistance.java
@@ -0,0 +1,69 @@
+package de.ids_mannheim.korap.query.object;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+public class KoralDistance implements KoralObject {
+
+    private final KoralType type = KoralType.DISTANCE;
+    private String key = "w";
+    private String foundry;
+    private String layer;
+    private KoralBoundary boundary;
+
+    public KoralDistance (KoralBoundary boundary) {
+        this.boundary = boundary;
+    }
+    
+    public KoralDistance (String key, KoralBoundary boundary) {            
+        this(boundary);
+        this.key = key;
+    }
+
+    public String getKey() {
+        return key;
+    }
+
+    public void setKey(String key) {
+        this.key = key;
+    }
+
+    public String getFoundry() {
+        return foundry;
+    }
+
+    public void setFoundry(String foundry) {
+        this.foundry = foundry;
+    }
+
+    public String getLayer() {
+        return layer;
+    }
+
+    public void setLayer(String layer) {
+        this.layer = layer;
+    }
+
+    public KoralBoundary getBoundary() {
+        return boundary;
+    }
+
+    public void setBoundary(KoralBoundary boundary) {
+        this.boundary = boundary;
+    }
+
+    @Override
+    public Map<String, Object> buildMap() {
+        Map<String, Object> distanceMap = new LinkedHashMap<String, Object>();
+        distanceMap.put("@type", type.toString());
+        distanceMap.put("key", key);
+        if (foundry != null){
+            distanceMap.put("foundry", foundry);
+        }
+        if (layer!=null){
+            distanceMap.put("layer", layer);
+        }
+        distanceMap.put("boundary", boundary.buildMap());
+        return distanceMap;
+    }
+}
diff --git a/src/main/java/de/ids_mannheim/korap/query/object/KoralGroup.java b/src/main/java/de/ids_mannheim/korap/query/object/KoralGroup.java
index 090ecbc..b304f72 100644
--- a/src/main/java/de/ids_mannheim/korap/query/object/KoralGroup.java
+++ b/src/main/java/de/ids_mannheim/korap/query/object/KoralGroup.java
@@ -22,8 +22,9 @@
 
     private boolean inOrder = false;
     private List<KoralObject> operands;
-    private List<Distance> distances;
+    private List<KoralDistance> distances;
     private List<Frame> frames;
+    private KoralBoundary boundary;
 
     public KoralGroup (KoralOperation operation) {
         this.operation = operation;
@@ -45,11 +46,19 @@
 		this.operands = operands;
 	}
 
-    public List<Distance> getDistances() {
+    public KoralOperation getOperation() {
+        return operation;
+    }
+
+    public void setOperation(KoralOperation operation) {
+        this.operation = operation;
+    }
+
+    public List<KoralDistance> getDistances() {
         return distances;
     }
 
-    public void setDistances(List<Distance> distances) {
+    public void setDistances(List<KoralDistance> distances) {
         this.distances = distances;
     }
     
@@ -61,6 +70,14 @@
 		this.frames = frames;
 	}
 
+    public KoralBoundary getBoundary() {
+        return boundary;
+    }
+
+    public void setBoundary(KoralBoundary boundary) {
+        this.boundary = boundary;
+    }
+
     @Override
     public Map<String, Object> buildMap() {
         Map<String, Object> map = new LinkedHashMap<String, Object>();
@@ -70,17 +87,21 @@
         if (getDistances() != null) {
             map.put("inOrder", isInOrder());
             List<Map<String, Object>> distanceList = new ArrayList<Map<String, Object>>();
-            for (Distance d : getDistances()) {
+            for (KoralDistance d : distances) {
                 distanceList.add(d.buildMap());
             }
             map.put("distances", distanceList);
         }
 
         List<Map<String, Object>> operandList = new ArrayList<Map<String, Object>>();
-        for (Object o : getOperands()) {
+        for (Object o : operands) {
             operandList.add(MapBuilder.buildQueryMap(o));
         }
         map.put("operands", operandList);
+
+        if (boundary != null) {
+            map.put("boundary", boundary.buildMap());
+        }
         return map;
     }
 
@@ -100,54 +121,4 @@
 			return "frame:"+value;
 		}
 	}
-    
-    public class Distance implements KoralObject {
-
-        private final KoralType type = KoralType.DISTANCE;
-        private String key;
-        private String min;
-        private String max;
-
-        public Distance (String key, int min, int max) {
-            this.key = key;
-            this.min = String.valueOf(min);
-            this.max = String.valueOf(max);
-        }
-
-        public String getKey() {
-            return key;
-        }
-
-        public void setKey(String key) {
-            this.key = key;
-        }
-
-        public String getMin() {
-            return min;
-        }
-
-        public void setMin(String min) {
-            this.min = min;
-        }
-
-        public String getMax() {
-            return max;
-        }
-
-        public void setMax(String max) {
-            this.max = max;
-        }
-
-        @Override
-        public Map<String, Object> buildMap() {
-            Map<String, Object> distanceMap = new LinkedHashMap<String, Object>();
-            distanceMap.put("@type", type.toString());
-            distanceMap.put("key", getKey());
-            distanceMap.put("min", getMin());
-            distanceMap.put("max", getMax());
-            return distanceMap;
-
-        }
-
-    }
 }
diff --git a/src/main/java/de/ids_mannheim/korap/query/object/KoralToken.java b/src/main/java/de/ids_mannheim/korap/query/object/KoralToken.java
index 06a39ce..7798566 100644
--- a/src/main/java/de/ids_mannheim/korap/query/object/KoralToken.java
+++ b/src/main/java/de/ids_mannheim/korap/query/object/KoralToken.java
@@ -15,6 +15,8 @@
     private final static KoralType type = KoralType.TOKEN;
     private KoralObject wrappedObject;
 
+    public KoralToken () {}
+    
     public KoralToken (KoralObject wrappedObject) {
         this.wrappedObject = wrappedObject;
     }
@@ -30,7 +32,9 @@
     public Map<String, Object> buildMap() {
         Map<String, Object> map = new LinkedHashMap<String, Object>();
         map.put("@type", type.toString());
-        map.put("wrap", wrappedObject.buildMap());
+        if (wrappedObject != null){
+            map.put("wrap", wrappedObject.buildMap());
+        }
         return map;
     }
 }
diff --git a/src/main/java/de/ids_mannheim/korap/query/parse/fcsql/ExpressionParser.java b/src/main/java/de/ids_mannheim/korap/query/parse/fcsql/ExpressionParser.java
index 488b4c8..42f5f83 100644
--- a/src/main/java/de/ids_mannheim/korap/query/parse/fcsql/ExpressionParser.java
+++ b/src/main/java/de/ids_mannheim/korap/query/parse/fcsql/ExpressionParser.java
@@ -20,6 +20,7 @@
 import eu.clarin.sru.server.fcs.parser.ExpressionGroup;
 import eu.clarin.sru.server.fcs.parser.ExpressionNot;
 import eu.clarin.sru.server.fcs.parser.ExpressionOr;
+import eu.clarin.sru.server.fcs.parser.ExpressionWildcard;
 import eu.clarin.sru.server.fcs.parser.Operator;
 import eu.clarin.sru.server.fcs.parser.QueryNode;
 import eu.clarin.sru.server.fcs.parser.RegexFlag;
@@ -76,9 +77,9 @@
                 return parseBooleanExpression(operands, KoralRelation.OR);
             }
         }
-        // else if (queryNode instanceof ExpressionWildcard) {
-        // for distance query, using empty token
-        // }
+        else if (queryNode instanceof ExpressionWildcard) {
+            return new KoralToken();
+        }
         else {
             throw new KoralException(StatusCodes.QUERY_TOO_COMPLEX,
                     "FCS diagnostic 11: Query is too complex.");
diff --git a/src/main/java/de/ids_mannheim/korap/query/parse/fcsql/FCSSRUQueryParser.java b/src/main/java/de/ids_mannheim/korap/query/parse/fcsql/FCSSRUQueryParser.java
index 85be144..df1590f 100644
--- a/src/main/java/de/ids_mannheim/korap/query/parse/fcsql/FCSSRUQueryParser.java
+++ b/src/main/java/de/ids_mannheim/korap/query/parse/fcsql/FCSSRUQueryParser.java
@@ -7,12 +7,15 @@
 import de.ids_mannheim.korap.query.object.KoralContext;
 import de.ids_mannheim.korap.query.serialize.util.KoralException;
 import de.ids_mannheim.korap.query.serialize.util.StatusCodes;
+import de.ids_mannheim.korap.query.object.KoralBoundary;
 import de.ids_mannheim.korap.query.object.KoralGroup;
+import de.ids_mannheim.korap.query.object.KoralDistance;
 import de.ids_mannheim.korap.query.object.KoralObject;
 import de.ids_mannheim.korap.query.object.KoralOperation;
 import de.ids_mannheim.korap.query.object.KoralSpan;
 import de.ids_mannheim.korap.query.object.KoralTerm;
 import de.ids_mannheim.korap.query.object.KoralGroup.Frame;
+import eu.clarin.sru.server.fcs.parser.ExpressionWildcard;
 import eu.clarin.sru.server.fcs.parser.QueryDisjunction;
 import eu.clarin.sru.server.fcs.parser.QueryGroup;
 import eu.clarin.sru.server.fcs.parser.QueryNode;
@@ -34,7 +37,8 @@
         this.expressionParser = new ExpressionParser();
     }
 
-    public KoralObject parseQueryNode(QueryNode queryNode) throws KoralException {
+    public KoralObject parseQueryNode(QueryNode queryNode)
+            throws KoralException {
 
         if (queryNode instanceof QuerySegment) {
             return parseQuerySegment((QuerySegment) queryNode);
@@ -43,63 +47,85 @@
             return parseQueryNode(queryNode.getChild(0));
         }
         else if (queryNode instanceof QuerySequence) {
-            return parseGroupQuery(queryNode.getChildren(),
-                    KoralOperation.SEQUENCE);
+            return parseSequenceQuery(queryNode.getChildren());
         }
         else if (queryNode instanceof QueryDisjunction) {
             return parseGroupQuery(queryNode.getChildren(),
                     KoralOperation.DISJUNCTION);
         }
         else if (queryNode instanceof QueryWithWithin) {
-        	return parseWithinQuery((QueryWithWithin)queryNode);
+            return parseWithinQuery((QueryWithWithin) queryNode);
         }
         else if (queryNode instanceof SimpleWithin) {
-	    	SimpleWithin withinNode = (SimpleWithin) queryNode;
-	    	return parseWithinScope(withinNode.getScope());
-	    }
+            SimpleWithin withinNode = (SimpleWithin) queryNode;
+            return parseWithinScope(withinNode.getScope());
+        }
         else {
             throw new KoralException(StatusCodes.QUERY_TOO_COMPLEX,
                     "FCS diagnostic 11:" + queryNode.getNodeType().name()
                             + " is currently unsupported.");
         }
     }
-    private KoralObject parseWithinQuery(QueryWithWithin queryNode) throws KoralException {
-    	KoralGroup koralGroup = new KoralGroup(KoralOperation.POSITION);
-    	koralGroup.setFrames(Arrays.asList(Frame.IS_AROUND));
-    	
-    	List<KoralObject> operands = new ArrayList<KoralObject>();
-    	operands.add(parseQueryNode(queryNode.getWithin()));
-    	operands.add(parseQueryNode(queryNode.getQuery()));
-    	koralGroup.setOperands(operands);
-    	return koralGroup;
-	}
+    
+    private KoralObject parseQuerySegment(QuerySegment segment)
+            throws KoralException {
+        int minOccurs = segment.getMinOccurs();
+        int maxOccurs = segment.getMaxOccurs();
 
-    private KoralSpan parseWithinScope(Scope scope) throws KoralException{
-    	if (scope == null){
-    		throw new KoralException(StatusCodes.MALFORMED_QUERY,
-                    "FCS diagnostic 11: Within context is missing.");
-    	}
+        if ((minOccurs == 1) && (maxOccurs == 1)) {
+            return expressionParser.parseExpression(segment.getExpression());
+        }
+        else {
+            KoralBoundary boundary = new KoralBoundary(minOccurs, maxOccurs);
+            List<KoralObject> operand = new ArrayList<KoralObject>(1);
+            operand.add(expressionParser.parseExpression(segment
+                    .getExpression()));
 
-    	KoralContext contextSpan;
-    	if (scope == Scope.SENTENCE) {
-			contextSpan = KoralContext.SENTENCE;
-    	}
-    	else if (scope == Scope.PARAGRAPH){
-			contextSpan = KoralContext.PARAGRAPH;
-    	}
-    	else if (scope == Scope.TEXT){
-            contextSpan = KoralContext.TEXT;
-    	}
-    	else{
-    		throw new KoralException(StatusCodes.QUERY_TOO_COMPLEX,
-                    "FCS diagnostic 11: Within scope " + scope.toString()
-                            + " is currently unsupported.");
-    	}
-    	
-    	return new KoralSpan(new KoralTerm(contextSpan));
+            KoralGroup koralGroup = new KoralGroup(KoralOperation.REPETITION);
+            koralGroup.setBoundary(boundary);
+            koralGroup.setOperands(operand);
+            return koralGroup;
+        }
     }
     
-	private KoralGroup parseGroupQuery(List<QueryNode> children,
+    private KoralObject parseWithinQuery(QueryWithWithin queryNode)
+            throws KoralException {
+        KoralGroup koralGroup = new KoralGroup(KoralOperation.POSITION);
+        koralGroup.setFrames(Arrays.asList(Frame.IS_AROUND));
+
+        List<KoralObject> operands = new ArrayList<KoralObject>();
+        operands.add(parseQueryNode(queryNode.getWithin()));
+        operands.add(parseQueryNode(queryNode.getQuery()));
+        koralGroup.setOperands(operands);
+        return koralGroup;
+    }
+
+    private KoralSpan parseWithinScope(Scope scope) throws KoralException {
+        if (scope == null) {
+            throw new KoralException(StatusCodes.MALFORMED_QUERY,
+                    "FCS diagnostic 11: Within context is missing.");
+        }
+
+        KoralContext contextSpan;
+        if (scope == Scope.SENTENCE) {
+            contextSpan = KoralContext.SENTENCE;
+        }
+        else if (scope == Scope.PARAGRAPH) {
+            contextSpan = KoralContext.PARAGRAPH;
+        }
+        else if (scope == Scope.TEXT) {
+            contextSpan = KoralContext.TEXT;
+        }
+        else {
+            throw new KoralException(StatusCodes.QUERY_TOO_COMPLEX,
+                    "FCS diagnostic 11: Within scope " + scope.toString()
+                            + " is currently unsupported.");
+        }
+
+        return new KoralSpan(new KoralTerm(contextSpan));
+    }
+
+    private KoralGroup parseGroupQuery(List<QueryNode> children,
             KoralOperation operation) throws KoralException {
         KoralGroup koralGroup = new KoralGroup(operation);
         List<KoralObject> operands = new ArrayList<KoralObject>();
@@ -110,13 +136,104 @@
         return koralGroup;
     }
 
-    private KoralObject parseQuerySegment(QuerySegment segment) throws KoralException {
-        if ((segment.getMinOccurs() == 1) && (segment.getMaxOccurs() == 1)) {
-            return expressionParser.parseExpression(segment.getExpression());
+    private KoralGroup parseSequenceQuery(List<QueryNode> children)
+            throws KoralException {
+        KoralGroup koralGroup = new KoralGroup(KoralOperation.SEQUENCE);
+        List<KoralObject> operands = new ArrayList<KoralObject>();
+        KoralObject operand;
+
+        boolean isEmptyTokenFound = false;
+        boolean isLastTokenEmpty = false;
+        int size = children.size();
+
+        for (int i = 0; i < size; i++) {
+            QueryNode child = children.get(i);
+            if (i > 0 && i < size - 1 && findEmptyToken(child)) {
+                QuerySegment qs = (QuerySegment) child;
+                if (isLastTokenEmpty) {
+                    updateBoundary(operands.get(operands.size() - 1), qs);
+                }
+                else {
+                    operands.add(new KoralBoundary(qs.getMinOccurs(), qs
+                            .getMaxOccurs()));
+                    isLastTokenEmpty = true;
+                }
+                isEmptyTokenFound = true;
+                continue;
+            }
+            operand = parseQueryNode(child);
+            operands.add(operand);
+            isLastTokenEmpty = false;
         }
-        else {
-            throw new KoralException(StatusCodes.QUERY_TOO_COMPLEX,
-                    "FCS diagnostic 11: Query is too complex.");
+
+        if (isEmptyTokenFound) {
+            operands = createDistance(koralGroup,operands);
         }
+
+        koralGroup.setOperands(operands);
+        return koralGroup;
+    }
+
+    private boolean findEmptyToken(QueryNode child) {
+        if (child instanceof QuerySegment
+                && ((QuerySegment) child).getExpression() instanceof ExpressionWildcard) {
+            return true;
+        }
+        return false;
+    }
+
+    private void updateBoundary(KoralObject koralObject, QuerySegment qs) {
+        KoralBoundary boundary = (KoralBoundary) koralObject;
+        boundary.setMin(boundary.getMin() + qs.getMinOccurs());
+        boundary.setMax(boundary.getMax() + qs.getMaxOccurs());
+    }
+
+    private List<KoralObject> createDistance(KoralGroup koralGroup, List<KoralObject> operands){
+        boolean isSubGroupAdded = false;
+        List<KoralObject> newOperands = new ArrayList<KoralObject>(
+                operands.size());        
+        newOperands.add(operands.get(0));        
+        int operandSize = operands.size();
+        for (int i = 1; i < operandSize - 1; i++) {
+            KoralObject operand = operands.get(i);
+            if (operand instanceof KoralBoundary) {
+                List<KoralDistance> distances = new ArrayList<KoralDistance>();
+                distances.add(new KoralDistance ((KoralBoundary) operand));  
+                
+                if (koralGroup.getDistances() != null){
+                    KoralObject lastOperand = newOperands.get(newOperands.size()-1);
+                    KoralGroup subGroup = createSubGroup(distances, lastOperand, operands.get(i+1));
+                    newOperands.remove(lastOperand);
+                    newOperands.add(subGroup);
+                    isSubGroupAdded = true;
+                    continue;
+                }
+                else{                    
+                    koralGroup.setDistances(distances);
+                    koralGroup.setInOrder(true);
+                }
+            }
+            else{
+                newOperands.add(operand);                
+            }
+            isSubGroupAdded = false;
+        }
+        
+        if (!isSubGroupAdded){
+            newOperands.add(operands.get(operandSize-1));
+        }
+        return newOperands;
+    }
+    
+    private KoralGroup createSubGroup(List<KoralDistance> distances, 
+            KoralObject operand, KoralObject operand2) {
+        KoralGroup subGroup = new KoralGroup(KoralOperation.SEQUENCE);
+        subGroup.setDistances(distances);
+        subGroup.setInOrder(true);
+        List<KoralObject> operands = new ArrayList<KoralObject>();
+        operands.add(operand);
+        operands.add(operand2);
+        subGroup.setOperands(operands);
+        return subGroup;
     }
 }
diff --git a/src/main/java/de/ids_mannheim/korap/query/serialize/PoliqarpPlusQueryProcessor.java b/src/main/java/de/ids_mannheim/korap/query/serialize/PoliqarpPlusQueryProcessor.java
index 8eb859d..d92613a 100644
--- a/src/main/java/de/ids_mannheim/korap/query/serialize/PoliqarpPlusQueryProcessor.java
+++ b/src/main/java/de/ids_mannheim/korap/query/serialize/PoliqarpPlusQueryProcessor.java
@@ -864,6 +864,12 @@
             return term;
         }
         else if (nodeCat.equals("termGroup")) {
+
+            // TermGroup is defined recursive with non-necessary brackets
+            if (getNodeCat(node.getChild(0)).equals("(")) {
+                return parseTermOrTermGroup(node.getChild(1), negatedGlobal, mode);
+            };
+
             // For termGroups, establish a boolean relation between
             // operands and recursively call this function with
             // the term or termGroup operands
diff --git a/src/main/java/de/ids_mannheim/korap/query/serialize/QuerySerializer.java b/src/main/java/de/ids_mannheim/korap/query/serialize/QuerySerializer.java
index d4cb27e..28d371f 100644
--- a/src/main/java/de/ids_mannheim/korap/query/serialize/QuerySerializer.java
+++ b/src/main/java/de/ids_mannheim/korap/query/serialize/QuerySerializer.java
@@ -180,19 +180,29 @@
         return raw();
     }
 
-	private Map raw() {
+    private Map raw () {
         if (ast != null) {
-			Map<String, Object> requestMap = ast.getRequestMap();
+            Map<String, Object> requestMap = new HashMap<>(ast.getRequestMap());
             Map meta = (Map) requestMap.get("meta");
             Map collection = (Map) requestMap.get("collection");
             List errors = (List) requestMap.get("errors");
             List warnings = (List) requestMap.get("warnings");
             List messages = (List) requestMap.get("messages");
-			this.collection = mergeCollection(collection, this.collection);
-			requestMap.put("collection", this.collection);
+            collection = mergeCollection(collection, this.collection);
+            requestMap.put("collection", collection);
+            
+            if (meta == null)
+                meta = new HashMap();
+            if (errors == null)
+                errors = new LinkedList();
+            if (warnings == null)
+                warnings = new LinkedList();
+            if (messages == null)
+                messages = new LinkedList();
+
             if (this.meta != null) {
-				this.meta.putAll(meta);
-				requestMap.put("meta", this.meta);
+                meta.putAll(this.meta);
+                requestMap.put("meta", meta);
             }
             if (this.errors != null && !this.errors.isEmpty()) {
                 errors.addAll(this.errors);
@@ -206,37 +216,41 @@
                 messages.addAll(this.messages);
                 requestMap.put("messages", messages);
             }
-
             return cleanup(requestMap);
         }
         return new HashMap<>();
     }
 
-	private Map<String, Object> cleanup(Map<String, Object> requestMap) {
+    private Map<String, Object> cleanup (Map<String, Object> requestMap) {
         Iterator<Map.Entry<String, Object>> set = requestMap.entrySet()
                 .iterator();
         while (set.hasNext()) {
             Map.Entry<String, Object> entry = set.next();
-			if (entry.getValue() instanceof List
-					&& ((List) entry.getValue()).isEmpty())
+            if (entry.getValue() instanceof List
+                    && ((List) entry.getValue()).isEmpty())
                 set.remove();
-			else if (entry.getValue() instanceof Map
-					&& ((Map) entry.getValue()).isEmpty())
+            else if (entry.getValue() instanceof Map
+                    && ((Map) entry.getValue()).isEmpty())
                 set.remove();
-			else if (entry.getValue() instanceof String
-					&& ((String) entry.getValue()).isEmpty())
+            else if (entry.getValue() instanceof String
+                    && ((String) entry.getValue()).isEmpty())
                 set.remove();
         }
         return requestMap;
     }
 
-	private Map<String, Object> mergeCollection(
-			Map<String, Object> collection1, Map<String, Object> collection2) {
+	private Map<String, Object> mergeCollection (
+            Map<String, Object> collection1, Map<String, Object> collection2) {
         if (collection1 == null || collection1.isEmpty()) {
             return collection2;
-		} else if (collection2 == null || collection2.isEmpty()) {
+        }
+        else if (collection2 == null || collection2.isEmpty()) {
             return collection1;
-		} else {
+        }
+        else if (collection1.equals(collection2)) {
+            return collection1;
+        }
+        else {
             LinkedHashMap<String, Object> docGroup = KoralObjectGenerator
                     .makeDocGroup("and");
             ArrayList<Object> operands = (ArrayList<Object>) docGroup
diff --git a/src/test/java/de/ids_mannheim/korap/query/serialize/FCSQLComplexTest.java b/src/test/java/de/ids_mannheim/korap/query/serialize/FCSQLComplexTest.java
index 3973aea..47a174e 100644
--- a/src/test/java/de/ids_mannheim/korap/query/serialize/FCSQLComplexTest.java
+++ b/src/test/java/de/ids_mannheim/korap/query/serialize/FCSQLComplexTest.java
@@ -7,12 +7,18 @@
 
 import org.junit.Test;
 
+import com.fasterxml.jackson.core.JsonProcessingException;
+
 /**
  * @author margaretha
  * 
  */
 public class FCSQLComplexTest {
 
+    String query;
+    String jsonLd;
+    List<Object> error;
+
     // -------------------------------------------------------------------------
     // simple-query ::= '(' main_query ')' /* grouping */
     // | implicit-query
@@ -24,8 +30,8 @@
     // simple-query ::= '(' main_query ')' /* grouping */
     @Test
     public void testGroupQuery() throws IOException {
-        String query = "(\"blaue\"|\"grüne\")";
-        String jsonLd = "{@type:koral:group,"
+        query = "(\"blaue\"|\"grüne\")";
+        jsonLd = "{@type:koral:group,"
                 + "operation:operation:disjunction,"
                 + "operands:["
                 + "{@type:koral:token, wrap:{@type:koral:term,key:blaue,foundry:opennlp,layer:orth,type:type:regex,match:match:eq}},"
@@ -38,20 +44,6 @@
         FCSQLQueryProcessorTest
                 .validateNode(query, "/query/operands/1", jsonLd);
 
-        // sequence and disjunction
-        query = "([pos=\"NN\"]|[cnx:pos=\"N\"])[text=\"Mann\"]";
-        jsonLd = "{@type:koral:group,"
-                + "operation:operation:sequence,"
-                + "operands:["
-                + "{@type:koral:group,"
-                + "operation:operation:disjunction,"
-                + "operands:[{@type:koral:token,wrap:{@type:koral:term,key:NN,foundry:tt,layer:p,type:type:regex,match:match:eq}},"
-                + "{@type:koral:token,wrap:{@type:koral:term,key:N,foundry:cnx,layer:p,type:type:regex,match:match:eq}}"
-                + "]},"
-                + "{@type:koral:token,wrap:{@type:koral:term,key:Mann,foundry:opennlp,layer:orth,type:type:regex,match:match:eq}}"
-                + "]}";
-        FCSQLQueryProcessorTest.runAndValidate(query, jsonLd);
-
         // group and sequence
         query = "([text=\"blaue\"][pos=\"NN\"])";
         jsonLd = "{@type:koral:group,"
@@ -73,8 +65,8 @@
     // | simple-query "|" main-query /* or */
     @Test
     public void testOrQuery() throws IOException {
-        String query = "\"man\"|\"Mann\"";
-        String jsonLd = "{@type:koral:group,"
+        query = "\"man\"|\"Mann\"";
+        jsonLd = "{@type:koral:group,"
                 + "operation:operation:disjunction,"
                 + "operands:["
                 + "{@type:koral:token,wrap:{@type:koral:term,key:man,foundry:opennlp,layer:orth,type:type:regex,match:match:eq}},"
@@ -94,20 +86,13 @@
                 + "{@type:koral:token, wrap:{@type:koral:term,key:NN,foundry:tt,layer:p,type:type:regex,match:match:eq}},"
                 + "{@type:koral:token, wrap:{@type:koral:term,key:Mann,foundry:opennlp,layer:orth,type:type:regex,match:match:eq}}]}";
         FCSQLQueryProcessorTest.runAndValidate(query, jsonLd);
-
-        query = "[pos=\"NN\"]&[text=\"Mann\"]";
-        List<Object> error = FCSQLQueryProcessorTest
-                .getError(new FCSQLQueryProcessor(query, "2.0"));
-        assertEquals(399, error.get(0));
-        String msg = (String) error.get(1);
-        assertEquals(true, msg.startsWith("FCS diagnostic 10"));
     }
 
     // | simple-query main-query /* sequence */
     @Test
     public void testSequenceQuery() throws IOException {
-        String query = "\"blaue|grüne\" [pos = \"NN\"]";
-        String jsonLd = "{@type:koral:group, "
+        query = "\"blaue|grüne\" [pos = \"NN\"]";
+        jsonLd = "{@type:koral:group, "
                 + "operation:operation:sequence, "
                 + "operands:["
                 + "{@type:koral:token, wrap:{@type:koral:term, key:blaue|grüne, foundry:opennlp, layer:orth, type:type:regex, match:match:eq}},"
@@ -123,12 +108,148 @@
         FCSQLQueryProcessorTest
                 .validateNode(query, "/query/operands/1", jsonLd);
 
+        // sequence and disjunction
+        query = "([pos=\"NN\"]|[cnx:pos=\"N\"])[text=\"Mann\"]";
+        jsonLd = "{@type:koral:group,"
+                + "operation:operation:sequence,"
+                + "operands:["
+                + "{@type:koral:group,"
+                + "operation:operation:disjunction,"
+                + "operands:[{@type:koral:token,wrap:{@type:koral:term,key:NN,foundry:tt,layer:p,type:type:regex,match:match:eq}},"
+                + "{@type:koral:token,wrap:{@type:koral:term,key:N,foundry:cnx,layer:p,type:type:regex,match:match:eq}}"
+                + "]},"
+                + "{@type:koral:token,wrap:{@type:koral:term,key:Mann,foundry:opennlp,layer:orth,type:type:regex,match:match:eq}}"
+                + "]}";
+        FCSQLQueryProcessorTest.runAndValidate(query, jsonLd);
+
     }
 
     // | simple-query quantifier /* quatification */
     @Test
     public void testQueryWithQuantifier() throws IOException {
+        // repetition
+        query = "\"die\"{2}";
+        jsonLd = "{@type:koral:group,"
+                + "operation:operation:repetition,"
+                + "operands:["
+                + "{@type:koral:token,wrap:{@type:koral:term,key:die,foundry:opennlp,layer:orth,type:type:regex,match:match:eq}}],"
+                + "boundary:{@type:koral:boundary,min:2,max:2}}";
+        FCSQLQueryProcessorTest.runAndValidate(query, jsonLd);
 
+        query = "\"die\"{1,2}";
+        jsonLd = "{@type:koral:boundary,min:1,max:2}";
+        FCSQLQueryProcessorTest.validateNode(query, "/query/boundary", jsonLd);
+
+        query = "\"die\"{,2}";
+        jsonLd = "{@type:koral:boundary,min:0,max:2}";
+        FCSQLQueryProcessorTest.validateNode(query, "/query/boundary", jsonLd);
+
+        query = "\"die\"{2,}";
+        jsonLd = "{@type:koral:boundary,min:2}";
+        FCSQLQueryProcessorTest.validateNode(query, "/query/boundary", jsonLd);
+
+        query = "\"die\"+";
+        jsonLd = "{@type:koral:boundary,min:1}";
+        FCSQLQueryProcessorTest.validateNode(query, "/query/boundary", jsonLd);
+
+        query = "\"die\"?";
+        jsonLd = "{@type:koral:boundary,min:0, max:1}";
+        FCSQLQueryProcessorTest.validateNode(query, "/query/boundary", jsonLd);
+
+        query = "\"die\"*";
+        jsonLd = "{@type:koral:boundary,min:0}";
+        FCSQLQueryProcessorTest.validateNode(query, "/query/boundary", jsonLd);
+
+        query = "\"die\"{0}";
+        jsonLd = "{@type:koral:boundary,min:0, max:0}";
+        FCSQLQueryProcessorTest.validateNode(query, "/query/boundary", jsonLd);
+    }
+
+    // wildcards
+    @Test
+    public void testQueryWithEmptyToken() throws IOException {
+        // expansion query
+        query = "[]{2}\"Hund\"";
+        jsonLd = "{@type:koral:group, "
+                + "operation:operation:sequence, "
+                + "operands:["
+                + "{@type:koral:group,"
+                + "operation:operation:repetition,"
+                + "operands:["
+                + "{@type:koral:token}],"
+                + "boundary:{@type:koral:boundary,min:2,max:2}},"
+                + "{@type:koral:token, "
+                + "wrap:{@type:koral:term, key:Hund, foundry:opennlp, layer:orth, type:type:regex, match:match:eq}}"
+                + "]}";
+        FCSQLQueryProcessorTest.runAndValidate(query, jsonLd);
+
+        query = "\"Hund\"[]{2}";
+        jsonLd = "{@type:koral:group," + "operation:operation:repetition,"
+                + "operands:[" + "{@type:koral:token}],"
+                + "boundary:{@type:koral:boundary,min:2,max:2}}";
+        FCSQLQueryProcessorTest
+                .validateNode(query, "/query/operands/1", jsonLd);
+
+        // arbitrary tokens
+        query = "[]{2}";
+        FCSQLQueryProcessorTest.runAndValidate(query, jsonLd);
+
+        // sequence with extension
+        query = "[cnx:pos=\"A\"] \"Hund\"[]{2}";
+        jsonLd = "["
+                + "{@type:koral:token,wrap:{@type:koral:term,key:A,foundry:cnx,layer:p,type:type:regex,match:match:eq}},"
+                + "{@type:koral:token,wrap:{@type:koral:term,key:Hund,foundry:opennlp,layer:orth,type:type:regex,match:match:eq}},"
+                + "{@type:koral:group,operation:operation:repetition,operands:["
+                + "{@type:koral:token}],boundary:{@type:koral:boundary,min:2,max:2}}"
+                + "]";
+        FCSQLQueryProcessorTest.validateNode(query, "/query/operands", jsonLd);
+    }
+
+    @Test
+    public void testQueryWithDistance() throws IOException {
+        // distance query
+        query = "\"Katze\" []{3} \"Hund\"";
+        jsonLd = "{@type:koral:group,operation:operation:sequence,inOrder:true,"
+                + "distances:["
+                + "{@type:koral:distance,key:w,boundary:{@type:koral:boundary,min:3,max:3}}"
+                + "],"
+                + "operands:["
+                + "{@type:koral:token,wrap:{@type:koral:term,key:Katze,foundry:opennlp,layer:orth,type:type:regex,match:match:eq}},"
+                + "{@type:koral:token,wrap:{@type:koral:term,key:Hund,foundry:opennlp,layer:orth,type:type:regex,match:match:eq}}]}";
+        FCSQLQueryProcessorTest.runAndValidate(query, jsonLd);
+
+        // sequences of wildcards
+        query = "\"Katze\" []{3}[] \"Hund\"";
+        jsonLd = "{@type:koral:distance,key:w,boundary:{@type:koral:boundary,min:4,max:4}}";
+        FCSQLQueryProcessorTest.validateNode(query, "/query/distances/0",
+                jsonLd);
+
+        query = "\"Katze\" []{2}[]{3}[] \"Hund\"";
+        jsonLd = "{@type:koral:distance,key:w,boundary:{@type:koral:boundary,min:6,max:6}}";
+        FCSQLQueryProcessorTest.validateNode(query, "/query/distances/0",
+                jsonLd);
+
+        // multiple occurrences of wildcards
+        query = "\"Katze\" []{3} \"Hund\" []{1,2} [cnx:pos=\"V\"]";
+        jsonLd = "{@type:koral:group,"
+                + "operation:operation:sequence,"
+                + "inOrder:true,"
+                + "distances:["
+                + "{@type:koral:distance,key:w,boundary:{@type:koral:boundary,min:3,max:3}}"
+                + "],"
+                + "operands:["
+                + "{@type:koral:token,wrap:{@type:koral:term,key:Katze,foundry:opennlp,layer:orth,type:type:regex,match:match:eq}},"
+                + "{@type:koral:group,"
+                    + "operation:operation:sequence,"
+                    + "inOrder:true,"
+                    + "distances:["
+                    + "{@type:koral:distance,key:w,boundary:{@type:koral:boundary,min:1,max:2}}"
+                    + "],"
+                    + "operands:["
+                    + "{@type:koral:token,wrap:{@type:koral:term,key:Hund,foundry:opennlp,layer:orth,type:type:regex,match:match:eq}},"
+                    + "{@type:koral:token,wrap:{@type:koral:term,key:V,foundry:cnx,layer:p,type:type:regex,match:match:eq}}]}" 
+                +"]}";
+        FCSQLQueryProcessorTest.runAndValidate(query, jsonLd);
     }
 
     // -------------------------------------------------------------------------
@@ -139,8 +260,8 @@
 
     @Test
     public void testWithinQuery() throws IOException {
-        String query = "[cnx:pos=\"VVFIN\"] within s";
-        String jsonLd = "{@type:koral:group,"
+        query = "[cnx:pos=\"VVFIN\"] within s";
+        jsonLd = "{@type:koral:group,"
                 + "operation:operation:position,"
                 + "operands:["
                 + "{@type:koral:span,wrap:{@type:koral:term,key:s,foundry:base,layer:s}},"
@@ -162,12 +283,52 @@
                 .validateNode(query, "/query/operands/0", jsonLd);
 
         query = "[cnx:pos=\"VVFIN\"] within u";
-        List<Object> error = FCSQLQueryProcessorTest
-                .getError(new FCSQLQueryProcessor(query, "2.0"));
+        error = FCSQLQueryProcessorTest.getError(new FCSQLQueryProcessor(query,
+                "2.0"));
         assertEquals(310, error.get(0));
         assertEquals(
                 "FCS diagnostic 11: Within scope UTTERANCE is currently unsupported.",
                 (String) error.get(1));
     }
     
+    @Test
+    public void testWithinQueryWithEmptyTokens() throws IOException {        
+        query = "[] within s";
+        jsonLd = "{@type:koral:group,"
+                + "operation:operation:position,"
+                + "operands:["
+                + "{@type:koral:span,wrap:{@type:koral:term,key:s,foundry:base,layer:s}},"
+                + "{@type:koral:token}"
+                + "]}";
+        FCSQLQueryProcessorTest.runAndValidate(query, jsonLd);
+    }
+
+    @Test
+    public void testWrongQuery() throws IOException {
+        query = "!(mate:lemma=\"sein\" | mate:pos=\"PPOSS\")";
+        error = FCSQLQueryProcessorTest.getError(new FCSQLQueryProcessor(query,
+                "2.0"));
+        assertEquals(399, error.get(0));
+        assertEquals(true,
+                error.get(1).toString().startsWith("FCS diagnostic 10"));
+
+        query = "![mate:lemma=\"sein\" | mate:pos=\"PPOSS\"]";
+        error = FCSQLQueryProcessorTest.getError(new FCSQLQueryProcessor(query,
+                "2.0"));
+        assertEquals(true,
+                error.get(1).toString().startsWith("FCS diagnostic 10"));
+
+        query = "(\"blaue\"&\"grüne\")";
+        error = FCSQLQueryProcessorTest.getError(new FCSQLQueryProcessor(query,
+                "2.0"));
+        assertEquals(true,
+                error.get(1).toString().startsWith("FCS diagnostic 10"));
+
+        query = "[pos=\"NN\"]&[text=\"Mann\"]";
+        error = FCSQLQueryProcessorTest.getError(new FCSQLQueryProcessor(query,
+                "2.0"));
+        assertEquals(399, error.get(0));
+        String msg = (String) error.get(1);
+        assertEquals(true, msg.startsWith("FCS diagnostic 10"));
+    }
 }
diff --git a/src/test/java/de/ids_mannheim/korap/query/serialize/FCSQLQueryProcessorTest.java b/src/test/java/de/ids_mannheim/korap/query/serialize/FCSQLQueryProcessorTest.java
index 7fa90d0..9c030de 100644
--- a/src/test/java/de/ids_mannheim/korap/query/serialize/FCSQLQueryProcessorTest.java
+++ b/src/test/java/de/ids_mannheim/korap/query/serialize/FCSQLQueryProcessorTest.java
@@ -20,13 +20,16 @@
     static QuerySerializer qs = new QuerySerializer();
     static ObjectMapper mapper = new ObjectMapper();
     static JsonNode node;
+    String query;
+    String jsonLd;
+    List<Object> error;
 
-    public static void runAndValidate(String query, String jsonLD)
+    public static void runAndValidate(String query, String jsonLd)
             throws JsonProcessingException {
         FCSQLQueryProcessor processor = new FCSQLQueryProcessor(query, "2.0");
         String serializedQuery = mapper.writeValueAsString(processor
                 .getRequestMap().get("query"));
-        assertEquals(jsonLD.replace(" ", ""), serializedQuery.replace("\"", ""));
+        assertEquals(jsonLd.replace(" ", ""), serializedQuery.replace("\"", ""));
     }
 
     public static void validateNode(String query, String path, String jsonLd)
@@ -44,7 +47,7 @@
 
     @Test
     public void testVersion() throws JsonProcessingException {
-        List<Object> error = getError(new FCSQLQueryProcessor("\"Sonne\"",
+        error = getError(new FCSQLQueryProcessor("\"Sonne\"",
                 "1.0"));
         assertEquals(309, error.get(0));
         assertEquals("SRU diagnostic 5: Only supports SRU version 2.0.",
@@ -59,16 +62,16 @@
     // regexp ::= quoted-string
     @Test
     public void testTermQuery() throws JsonProcessingException {
-        String query = "\"Sonne\"";
-        String jsonLd = "{@type:koral:token, wrap:{@type:koral:term, key:Sonne, "
+        query = "\"Sonne\"";
+        jsonLd = "{@type:koral:token, wrap:{@type:koral:term, key:Sonne, "
                 + "foundry:opennlp, layer:orth, type:type:regex, match:match:eq}}";
         runAndValidate(query, jsonLd);
     }
 
     @Test
     public void testRegex() throws JsonProcessingException {
-        String query = "[text=\"M(a|ä)nn(er)?\"]";
-        String jsonLd = "{@type:koral:token,wrap:{@type:koral:term,"
+        query = "[text=\"M(a|ä)nn(er)?\"]";
+        jsonLd = "{@type:koral:token,wrap:{@type:koral:term,"
                 + "key:M(a|ä)nn(er)?,foundry:opennlp,layer:orth,type:type:regex,match:match:eq}}";
         runAndValidate(query, jsonLd);
 
@@ -95,8 +98,8 @@
     // | regexp "/" regexp-flag+
     @Test
     public void testTermQueryWithRegexFlag() throws IOException {
-        String query = "\"Fliegen\" /c";
-        String jsonLd = "{@type:koral:token, wrap:{@type:koral:term, caseInsensitive:true, "
+        query = "\"Fliegen\" /c";
+        jsonLd = "{@type:koral:token, wrap:{@type:koral:term, caseInsensitive:true, "
                 + "key:Fliegen, foundry:opennlp, layer:orth, type:type:regex, match:match:eq}}";
         FCSQLQueryProcessorTest.runAndValidate(query, jsonLd);
 
@@ -111,7 +114,7 @@
         FCSQLQueryProcessorTest.validateNode(query, "/query/wrap", jsonLd);
 
         query = "\"Fliegen\" /l";
-        List<Object> error = FCSQLQueryProcessorTest
+        error = FCSQLQueryProcessorTest
                 .getError(new FCSQLQueryProcessor(query, "2.0"));
         assertEquals(306, error.get(0));
         String msg = (String) error.get(1);
@@ -130,8 +133,8 @@
     // | "!=" /* non-equals */
     @Test
     public void testOperator() throws IOException {
-        String query = "[cnx:pos != \"N\"]";
-        String jsonLd = "{@type:koral:token, wrap:{@type:koral:term, key:N, "
+        query = "[cnx:pos != \"N\"]";
+        jsonLd = "{@type:koral:token, wrap:{@type:koral:term, key:N, "
                 + "foundry:cnx, layer:p, type:type:regex, match:match:ne}}";
         runAndValidate(query, jsonLd);
     }
@@ -145,8 +148,8 @@
     // simple-attribute ::= identifier
     @Test
     public void testTermQueryWithSpecificLayer() throws JsonProcessingException {
-        String query = "[text = \"Sonne\"]";
-        String jsonLd = "{@type:koral:token, wrap:{@type:koral:term, key:Sonne, "
+        query = "[text = \"Sonne\"]";
+        jsonLd = "{@type:koral:token, wrap:{@type:koral:term, key:Sonne, "
                 + "foundry:opennlp, layer:orth, type:type:regex, match:match:eq}}";
         FCSQLQueryProcessorTest.runAndValidate(query, jsonLd);
 
@@ -164,8 +167,8 @@
     // qualified-attribute ::= identifier ":" identifier
     @Test
     public void testTermQueryWithQualifier() throws JsonProcessingException {
-        String query = "[mate:lemma = \"sein\"]";
-        String jsonLd = "{@type:koral:token, wrap:{@type:koral:term, key:sein, "
+        query = "[mate:lemma = \"sein\"]";
+        jsonLd = "{@type:koral:token, wrap:{@type:koral:term, key:sein, "
                 + "foundry:mate, layer:l, type:type:regex, match:match:eq}}";
         runAndValidate(query, jsonLd);
 
@@ -175,28 +178,6 @@
         runAndValidate(query, jsonLd);
     }
 
-    @Test
-    public void testTermQueryException() throws JsonProcessingException {
-        String query = "[opennlp:lemma = \"sein\"]";
-        List<Object> error = getError(new FCSQLQueryProcessor(query, "2.0"));
-        assertEquals(306, error.get(0));
-        assertEquals(
-                "SRU diagnostic 48: Layer lemma with qualifier opennlp is unsupported.",
-                error.get(1));
-
-        query = "[malt:lemma = \"sein\"]";
-        error = getError(new FCSQLQueryProcessor(query, "2.0"));
-        assertEquals(306, error.get(0));
-        assertEquals("SRU diagnostic 48: Qualifier malt is unsupported.",
-                error.get(1));
-
-        query = "[cnx:morph = \"heit\"]";
-        error = getError(new FCSQLQueryProcessor(query, "2.0"));
-        assertEquals(306, error.get(0));
-        assertEquals("SRU diagnostic 48: Layer morph is unsupported.",
-                error.get(1));
-
-    }
 
     // segment-query ::= "[" expression? "]"
     // -------------------------------------------------------------------------
@@ -208,8 +189,8 @@
     // | expression "|" expression /* or */
     @Test
     public void testExpressionOr() throws IOException {
-        String query = "[mate:lemma=\"sein\" | mate:pos=\"PPOSS\"]";
-        String jsonLd = "{@type: koral:token,"
+        query = "[mate:lemma=\"sein\" | mate:pos=\"PPOSS\"]";
+        jsonLd = "{@type: koral:token,"
                 + " wrap: { @type: koral:termGroup,"
                 + "relation: relation:or,"
                 + " operands:["
@@ -227,8 +208,8 @@
     // | expression "&" expression /* and */
     @Test
     public void testExpressionAnd() throws IOException {
-        String query = "[mate:lemma=\"sein\" & mate:pos=\"PPOSS\"]";
-        String jsonLd = "{@type: koral:token,"
+        query = "[mate:lemma=\"sein\" & mate:pos=\"PPOSS\"]";
+        jsonLd = "{@type: koral:token,"
                 + " wrap: { @type: koral:termGroup,"
                 + "relation: relation:and,"
                 + " operands:["
@@ -247,8 +228,8 @@
 
     @Test
     public void testExpressionGroup() throws JsonProcessingException {
-        String query = "[(text=\"blau\"|pos=\"ADJ\")]";
-        String jsonLd = "{@type: koral:token,"
+        query = "[(text=\"blau\"|pos=\"ADJ\")]";
+        jsonLd = "{@type: koral:token,"
                 + "wrap: {@type: koral:termGroup,"
                 + "relation: relation:or,"
                 + "operands: ["
@@ -260,9 +241,9 @@
     // "!" expression /* not */
     @Test
     public void testExpressionNot() throws IOException {
-        String jsonLd = "{@type:koral:token, wrap:{@type:koral:term, key:NN, "
+        jsonLd = "{@type:koral:token, wrap:{@type:koral:term, key:NN, "
                 + "foundry:tt, layer:p, type:type:regex, match:match:eq}}";
-        String query = "[!pos != \"NN\"]";
+        query = "[!pos != \"NN\"]";
         FCSQLQueryProcessorTest.runAndValidate(query, jsonLd);
         query = "[!!pos = \"NN\"]";
         FCSQLQueryProcessorTest.runAndValidate(query, jsonLd);
@@ -280,24 +261,42 @@
         FCSQLQueryProcessorTest.runAndValidate(query, jsonLd);
     }
 
-
     @Test
-    public void testWrongQuery() throws IOException {
-        String query = "!(mate:lemma=\"sein\" | mate:pos=\"PPOSS\")";
-        List<Object> error = getError(new FCSQLQueryProcessor(query, "2.0"));
-        assertEquals(399, error.get(0));
-        assertEquals(true,
-                error.get(1).toString().startsWith("FCS diagnostic 10"));
-
-        query = "![mate:lemma=\"sein\" | mate:pos=\"PPOSS\"]";
+    public void testExceptions() throws JsonProcessingException {
+        // unsupported lemma und qualifier
+        query = "[opennlp:lemma = \"sein\"]";
         error = getError(new FCSQLQueryProcessor(query, "2.0"));
-        assertEquals(true,
-                error.get(1).toString().startsWith("FCS diagnostic 10"));
+        assertEquals(306, error.get(0));
+        assertEquals(
+                "SRU diagnostic 48: Layer lemma with qualifier opennlp is unsupported.",
+                error.get(1));
 
-        query = "(\"blaue\"&\"grüne\")";
+        query = "[tt:morph = \"sein\"]";
         error = getError(new FCSQLQueryProcessor(query, "2.0"));
-        assertEquals(true,
-                error.get(1).toString().startsWith("FCS diagnostic 10"));
+        assertEquals(306, error.get(0));
+        assertEquals(
+                "SRU diagnostic 48: Layer morph is unsupported.",
+                error.get(1));
+        
+        // unsupported qualifier
+        query = "[malt:lemma = \"sein\"]";
+        error = getError(new FCSQLQueryProcessor(query, "2.0"));
+        assertEquals(306, error.get(0));
+        assertEquals("SRU diagnostic 48: Qualifier malt is unsupported.",
+                error.get(1));
+
+        // unsupported layer
+        query = "[cnx:morph = \"heit\"]";
+        error = getError(new FCSQLQueryProcessor(query, "2.0"));
+        assertEquals(306, error.get(0));
+        assertEquals("SRU diagnostic 48: Layer morph is unsupported.",
+                error.get(1));
+
+        // missing layer
+        query = "[cnx=\"V\"]";
+        error = getError(new FCSQLQueryProcessor(query, "2.0"));
+        assertEquals(306, error.get(0));
+        assertEquals("SRU diagnostic 48: Layer cnx is unsupported.",
+                error.get(1));
     }
-
 }
diff --git a/src/test/java/de/ids_mannheim/korap/query/serialize/PoliqarpPlusQueryProcessorTest.java b/src/test/java/de/ids_mannheim/korap/query/serialize/PoliqarpPlusQueryProcessorTest.java
index d36376e..2cb60e3 100644
--- a/src/test/java/de/ids_mannheim/korap/query/serialize/PoliqarpPlusQueryProcessorTest.java
+++ b/src/test/java/de/ids_mannheim/korap/query/serialize/PoliqarpPlusQueryProcessorTest.java
@@ -658,7 +658,13 @@
         res = mapper.readTree(qs.toJSON());
         assertEquals("koral:token", res.at("/query/@type").asText());
         assertEquals(true, res.at("/query/key").isMissingNode());
-
+        
+        query = "[]{3}";
+        qs.setQuery(query, "poliqarpplus");
+        res = mapper.readTree(qs.toJSON());
+        assertEquals("{@type:koral:boundary,min:3,max:3}", 
+                res.at("/query/boundary").asText());
+        
         query = "contains(<s>, [])";
         qs.setQuery(query, "poliqarpplus");
         res = mapper.readTree(qs.toJSON());
@@ -726,6 +732,24 @@
         assertEquals("koral:token", operands.get(0).at("/@type").asText());
         assertEquals(true, operands.get(0).at("/key").isMissingNode());
 
+        query = "[base=Mann][]";
+        qs.setQuery(query, "poliqarpplus");
+        res = mapper.readTree(qs.toJSON());
+        operands = Lists.newArrayList(res.at("/query/operands").elements());
+        assertEquals("koral:token", operands.get(1).at("/@type").asText());
+        assertEquals(true, operands.get(1).at("/key").isMissingNode());
+
+        query = "[base=Mann][]{3}";
+        qs.setQuery(query, "poliqarpplus");
+        res = mapper.readTree(qs.toJSON());
+        operands = Lists.newArrayList(res.at("/query/operands").elements());
+        res = operands.get(1);
+        assertEquals("koral:group", res.at("/@type").asText());
+        assertEquals(true, res.at("/key").isMissingNode());
+        assertEquals("operation:repetition", res.at("/operation").asText());
+        assertEquals(3, res.at("/boundary/min").asInt());
+        assertEquals(3, res.at("/boundary/max").asInt());
+
         query = "startswith(<s>, [][base=Mann])";
         qs.setQuery(query, "poliqarpplus");
         res = mapper.readTree(qs.toJSON());
@@ -995,6 +1019,59 @@
         assertEquals("lemma", res.at("/query/wrap/layer").asText());
         assertEquals("match:eq", res.at("/query/wrap/match").asText());
 
+        query = "[(base=Mann&cas=N)]";
+        qs.setQuery(query, "poliqarpplus");
+        res = mapper.readTree(qs.toJSON());
+        assertEquals("koral:token", res.at("/query/@type").asText());
+        assertEquals("koral:termGroup", res.at("/query/wrap/@type")
+                .asText());
+        assertEquals("relation:and", res.at("/query/wrap/relation")
+                     .asText());
+        assertEquals("Mann", res.at("/query/wrap/operands/0/key")
+                     .asText());
+        assertEquals("lemma", res.at("/query/wrap/operands/0/layer")
+                     .asText());
+        assertEquals("N", res.at("/query/wrap/operands/1/key")
+                     .asText());
+        assertEquals("cas", res.at("/query/wrap/operands/1/layer")
+                     .asText());
+
+
+        query = "[(((base=Mann&cas=N)))]";
+        qs.setQuery(query, "poliqarpplus");
+        res = mapper.readTree(qs.toJSON());
+        assertEquals("koral:token", res.at("/query/@type").asText());
+        assertEquals("koral:termGroup", res.at("/query/wrap/@type")
+                .asText());
+        assertEquals("relation:and", res.at("/query/wrap/relation")
+                     .asText());
+        assertEquals("Mann", res.at("/query/wrap/operands/0/key")
+                     .asText());
+        assertEquals("lemma", res.at("/query/wrap/operands/0/layer")
+                     .asText());
+        assertEquals("N", res.at("/query/wrap/operands/1/key")
+                     .asText());
+        assertEquals("cas", res.at("/query/wrap/operands/1/layer")
+                     .asText());
+
+
+        query = "[(((base=Mann&((cas=N)))))]";
+        qs.setQuery(query, "poliqarpplus");
+        res = mapper.readTree(qs.toJSON());
+        assertEquals("koral:token", res.at("/query/@type").asText());
+        assertEquals("koral:termGroup", res.at("/query/wrap/@type")
+                .asText());
+        assertEquals("relation:and", res.at("/query/wrap/relation")
+                     .asText());
+        assertEquals("Mann", res.at("/query/wrap/operands/0/key")
+                     .asText());
+        assertEquals("lemma", res.at("/query/wrap/operands/0/layer")
+                     .asText());
+        assertEquals("N", res.at("/query/wrap/operands/1/key")
+                     .asText());
+        assertEquals("cas", res.at("/query/wrap/operands/1/layer")
+                     .asText());
+
     };
 
     @Test