diff --git a/.classpath b/.classpath
index 7e287b782af15b0e0956b6db746bff13e0505b10..eec61a3dd8967a34b840d241b6ab13df648ca4e9 100644
--- a/.classpath
+++ b/.classpath
@@ -26,6 +26,7 @@
 	</classpathentry>
 	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-11">
 		<attributes>
+			<attribute name="module" value="true"/>
 			<attribute name="maven.pomderived" value="true"/>
 		</attributes>
 	</classpathentry>
@@ -36,18 +37,23 @@
 	</classpathentry>
 	<classpathentry kind="src" path="target/generated-sources/annotations">
 		<attributes>
-			<attribute name="ignore_optional_problems" value="true"/>
 			<attribute name="optional" value="true"/>
-			<attribute name="maven.pomderived" value="true"/>
-			<attribute name="m2e-apt" value="true"/>
 		</attributes>
 	</classpathentry>
 	<classpathentry kind="src" output="target/test-classes" path="target/generated-test-sources/test-annotations">
 		<attributes>
 			<attribute name="optional" value="true"/>
-			<attribute name="maven.pomderived" value="true"/>
-			<attribute name="ignore_optional_problems" value="true"/>
-			<attribute name="m2e-apt" value="true"/>
+			<attribute name="test" value="true"/>
+		</attributes>
+	</classpathentry>
+	<classpathentry kind="src" path=".apt_generated">
+		<attributes>
+			<attribute name="optional" value="true"/>
+		</attributes>
+	</classpathentry>
+	<classpathentry kind="src" output="target/test-classes" path=".apt_generated_tests">
+		<attributes>
+			<attribute name="optional" value="true"/>
 			<attribute name="test" value="true"/>
 		</attributes>
 	</classpathentry>
diff --git a/.gitignore b/.gitignore
index 08525cb6919cf50aa6d5ea8d48e0ec74f997a19b..e13c6c735aaadd5b20eb9150d3c7f494b605f4c3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -85,6 +85,7 @@ out/
 ######################
 /log/
 /target/
+/target\\*
 
 ######################
 # Gradle
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index c067424c3db31ce05c9d056fd039fd340d641a27..4cf5e4174731f5457b6e5e8c7f62a0021e983c3a 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -122,7 +122,7 @@ sonar-analyze:
     - frontend-test
   script:
     - ./mvnw -ntp org.jacoco:jacoco-maven-plugin:prepare-agent initialize sonar:sonar -Dsonar.organization=codeAbility -Dsonar.host.url=https://qe-sonarqube.uibk.ac.at/ -Dsonar.login=${SONAR_TOKEN_QE} -Dmaven.repo.local=$MAVEN_USER_HOME
-    - ./mvnw -ntp org.jacoco:jacoco-maven-plugin:prepare-agent initialize sonar:sonar -Dsonar.organization=codeAbility -Dsonar.host.url=https://server.arctis.at/sonar/ -Dsonar.login=${SONAR_TOKEN} -Dmaven.repo.local=$MAVEN_USER_HOME
+  #    - ./mvnw -ntp org.jacoco:jacoco-maven-plugin:prepare-agent initialize sonar:sonar -Dsonar.organization=codeAbility -Dsonar.host.url=https://server.arctis.at/sonar/ -Dsonar.login=${SONAR_TOKEN} -Dmaven.repo.local=$MAVEN_USER_HOME
   allow_failure: true
 
 maven-package:
diff --git a/.pmd b/.pmd
new file mode 100644
index 0000000000000000000000000000000000000000..ecf1e36d70d5164fe0dca82399cc4943243de006
--- /dev/null
+++ b/.pmd
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<pmd>
+    <useProjectRuleSet>true</useProjectRuleSet>
+    <ruleSetFile>C:\Users\Micha\git\gitsearch\pmd_rules.xml</ruleSetFile>
+    <includeDerivedFiles>false</includeDerivedFiles>
+    <violationsAsErrors>true</violationsAsErrors>
+    <fullBuildEnabled>true</fullBuildEnabled>
+</pmd>
diff --git a/.prettierrc b/.prettierrc
index 6d25fbaf569d588f789b50234d8c7d28aae09db0..0364c31fcaaa21044a08f16cce73cd1ab809bd69 100644
--- a/.prettierrc
+++ b/.prettierrc
@@ -13,6 +13,6 @@ bracketSameLine: false
 
 # java rules:
 overrides:
-  - files: "*.java"
+  - files: '*.java'
     options:
       tabWidth: 4
diff --git a/.project b/.project
index ce0c43f19ba6e9645ac164f0273b518305aa4f89..31dfbfe855f403921d662c1fe76a4ce091ec585d 100644
--- a/.project
+++ b/.project
@@ -30,10 +30,16 @@
 			<arguments>
 			</arguments>
 		</buildCommand>
+		<buildCommand>
+			<name>net.sourceforge.pmd.eclipse.plugin.pmdBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
 	</buildSpec>
 	<natures>
 		<nature>org.eclipse.jdt.core.javanature</nature>
 		<nature>org.eclipse.m2e.core.maven2Nature</nature>
+		<nature>net.sourceforge.pmd.eclipse.plugin.pmdNature</nature>
 	</natures>
 	<filteredResources>
 		<filter>
diff --git a/.ruleset b/.ruleset
new file mode 100644
index 0000000000000000000000000000000000000000..39103d7b3012809ad10d0e9063d07043b53073f6
--- /dev/null
+++ b/.ruleset
@@ -0,0 +1,455 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ruleset xmlns="http://pmd.sourceforge.net/ruleset/2.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         name="pmd-eclipse"
+         xsi:schemaLocation="http://pmd.sourceforge.net/ruleset/2.0.0 https://pmd.sourceforge.io/ruleset_2_0_0.xsd">
+   <description>PMD Plugin preferences rule set</description>
+   <rule ref="category/java/bestpractices.xml/AbstractClassWithoutAbstractMethod"/>
+   <rule ref="category/java/bestpractices.xml/AccessorClassGeneration"/>
+   <rule ref="category/java/bestpractices.xml/AccessorMethodGeneration"/>
+   <rule ref="category/apex/bestpractices.xml/ApexAssertionsShouldIncludeMessage"/>
+   <rule ref="category/apex/bestpractices.xml/ApexUnitTestClassShouldHaveAsserts"/>
+   <rule ref="category/apex/bestpractices.xml/ApexUnitTestMethodShouldHaveIsTestAnnotation"/>
+   <rule ref="category/apex/bestpractices.xml/ApexUnitTestShouldNotUseSeeAllDataTrue"/>
+   <rule ref="category/java/bestpractices.xml/ArrayIsStoredDirectly"/>
+   <rule ref="category/apex/bestpractices.xml/AvoidGlobalModifier"/>
+   <rule ref="category/apex/bestpractices.xml/AvoidLogicInTrigger"/>
+   <rule ref="category/java/bestpractices.xml/AvoidMessageDigestField"/>
+   <rule ref="category/java/bestpractices.xml/AvoidPrintStackTrace"/>
+   <rule ref="category/java/bestpractices.xml/AvoidReassigningCatchVariables"/>
+   <rule ref="category/java/bestpractices.xml/AvoidReassigningLoopVariables"/>
+   <rule ref="category/java/bestpractices.xml/AvoidReassigningParameters"/>
+   <rule ref="category/vm/bestpractices.xml/AvoidReassigningParameters"/>
+   <rule ref="category/java/bestpractices.xml/AvoidStringBufferField"/>
+   <rule ref="category/java/bestpractices.xml/AvoidUsingHardCodedIP"/>
+   <rule ref="category/ecmascript/bestpractices.xml/AvoidWithStatement"/>
+   <rule ref="category/java/bestpractices.xml/CheckResultSet"/>
+   <rule ref="category/ecmascript/bestpractices.xml/ConsistentReturn"/>
+   <rule ref="category/java/bestpractices.xml/ConstantsInInterface"/>
+   <rule ref="category/apex/bestpractices.xml/DebugsShouldUseLoggingLevel"/>
+   <rule ref="category/java/bestpractices.xml/DefaultLabelNotLastInSwitchStmt"/>
+   <rule ref="category/jsp/bestpractices.xml/DontNestJsfInJstlIteration"/>
+   <rule ref="category/java/bestpractices.xml/DoubleBraceInitialization"/>
+   <rule ref="category/java/bestpractices.xml/ForLoopCanBeForeach"/>
+   <rule ref="category/java/bestpractices.xml/ForLoopVariableCount"/>
+   <rule ref="category/ecmascript/bestpractices.xml/GlobalVariable"/>
+   <rule ref="category/java/bestpractices.xml/GuardLogStatement"/>
+   <rule ref="category/java/bestpractices.xml/JUnit4SuitesShouldUseSuiteAnnotation"/>
+   <rule ref="category/java/bestpractices.xml/JUnit4TestShouldUseAfterAnnotation"/>
+   <rule ref="category/java/bestpractices.xml/JUnit4TestShouldUseBeforeAnnotation"/>
+   <rule ref="category/java/bestpractices.xml/JUnit4TestShouldUseTestAnnotation"/>
+   <rule ref="category/java/bestpractices.xml/JUnit5TestShouldBePackagePrivate"/>
+   <rule ref="category/java/bestpractices.xml/JUnitAssertionsShouldIncludeMessage"/>
+   <rule ref="category/java/bestpractices.xml/JUnitTestContainsTooManyAsserts"/>
+   <rule ref="category/java/bestpractices.xml/JUnitTestsShouldIncludeAssert"/>
+   <rule ref="category/java/bestpractices.xml/JUnitUseExpected"/>
+   <rule ref="category/java/bestpractices.xml/LiteralsFirstInComparisons"/>
+   <rule ref="category/java/bestpractices.xml/LooseCoupling"/>
+   <rule ref="category/java/bestpractices.xml/MethodReturnsInternalArray"/>
+   <rule ref="category/java/bestpractices.xml/MissingOverride"/>
+   <rule ref="category/jsp/bestpractices.xml/NoClassAttribute"/>
+   <rule ref="category/jsp/bestpractices.xml/NoHtmlComments"/>
+   <rule ref="category/jsp/bestpractices.xml/NoJspForward"/>
+   <rule ref="category/java/bestpractices.xml/OneDeclarationPerLine"/>
+   <rule ref="category/java/bestpractices.xml/PositionLiteralsFirstInCaseInsensitiveComparisons"/>
+   <rule ref="category/java/bestpractices.xml/PositionLiteralsFirstInComparisons"/>
+   <rule ref="category/java/bestpractices.xml/PreserveStackTrace"/>
+   <rule ref="category/java/bestpractices.xml/PrimitiveWrapperInstantiation"/>
+   <rule ref="category/java/bestpractices.xml/ReplaceEnumerationWithIterator"/>
+   <rule ref="category/java/bestpractices.xml/ReplaceHashtableWithMap"/>
+   <rule ref="category/java/bestpractices.xml/ReplaceVectorWithList"/>
+   <rule ref="category/ecmascript/bestpractices.xml/ScopeForInVariable"/>
+   <rule ref="category/java/bestpractices.xml/SimplifiableTestAssertion"/>
+   <rule ref="category/java/bestpractices.xml/SwitchStmtsShouldHaveDefault"/>
+   <rule ref="category/java/bestpractices.xml/SystemPrintln"/>
+   <rule ref="category/plsql/bestpractices.xml/TomKytesDespair"/>
+   <rule ref="category/java/bestpractices.xml/UnusedAssignment"/>
+   <rule ref="category/java/bestpractices.xml/UnusedFormalParameter"/>
+   <rule ref="category/java/bestpractices.xml/UnusedImports"/>
+   <rule ref="category/apex/bestpractices.xml/UnusedLocalVariable"/>
+   <rule ref="category/java/bestpractices.xml/UnusedLocalVariable"/>
+   <rule ref="category/vm/bestpractices.xml/UnusedMacroParameter"/>
+   <rule ref="category/java/bestpractices.xml/UnusedPrivateField"/>
+   <rule ref="category/java/bestpractices.xml/UnusedPrivateMethod"/>
+   <rule ref="category/java/bestpractices.xml/UseAssertEqualsInsteadOfAssertTrue"/>
+   <rule ref="category/java/bestpractices.xml/UseAssertNullInsteadOfAssertTrue"/>
+   <rule ref="category/java/bestpractices.xml/UseAssertSameInsteadOfAssertTrue"/>
+   <rule ref="category/java/bestpractices.xml/UseAssertTrueInsteadOfAssertEquals"/>
+   <rule ref="category/ecmascript/bestpractices.xml/UseBaseWithParseInt"/>
+   <rule ref="category/java/bestpractices.xml/UseCollectionIsEmpty"/>
+   <rule ref="category/java/bestpractices.xml/UseStandardCharsets"/>
+   <rule ref="category/java/bestpractices.xml/UseTryWithResources"/>
+   <rule ref="category/java/bestpractices.xml/UseVarargs"/>
+   <rule ref="category/java/bestpractices.xml/WhileLoopWithLiteralBoolean"/>
+   <rule ref="category/java/codestyle.xml/AbstractNaming"/>
+   <rule ref="category/ecmascript/codestyle.xml/AssignmentInOperand"/>
+   <rule ref="category/java/codestyle.xml/AtLeastOneConstructor"/>
+   <rule ref="category/java/codestyle.xml/AvoidDollarSigns"/>
+   <rule ref="category/java/codestyle.xml/AvoidFinalLocalVariable"/>
+   <rule ref="category/java/codestyle.xml/AvoidPrefixingMethodParameters"/>
+   <rule ref="category/java/codestyle.xml/AvoidProtectedFieldInFinalClass"/>
+   <rule ref="category/java/codestyle.xml/AvoidProtectedMethodInFinalClassNotExtending"/>
+   <rule ref="category/plsql/codestyle.xml/AvoidTabCharacter"/>
+   <rule ref="category/java/codestyle.xml/AvoidUsingNativeCode"/>
+   <rule ref="category/java/codestyle.xml/BooleanGetMethodName"/>
+   <rule ref="category/java/codestyle.xml/CallSuperInConstructor"/>
+   <rule ref="category/apex/codestyle.xml/ClassNamingConventions"/>
+   <rule ref="category/java/codestyle.xml/ClassNamingConventions"/>
+   <rule ref="category/plsql/codestyle.xml/CodeFormat"/>
+   <rule ref="category/java/codestyle.xml/CommentDefaultAccessModifier"/>
+   <rule ref="category/java/codestyle.xml/ConfusingTernary"/>
+   <rule ref="category/java/codestyle.xml/ControlStatementBraces"/>
+   <rule ref="category/java/codestyle.xml/DefaultPackage"/>
+   <rule ref="category/java/codestyle.xml/DontImportJavaLang"/>
+   <rule ref="category/java/codestyle.xml/DuplicateImports"/>
+   <rule ref="category/jsp/codestyle.xml/DuplicateJspImports"/>
+   <rule ref="category/java/codestyle.xml/EmptyMethodInAbstractClassShouldBeAbstract"/>
+   <rule ref="category/java/codestyle.xml/ExtendsObject"/>
+   <rule ref="category/apex/codestyle.xml/FieldDeclarationsShouldBeAtStart"/>
+   <rule ref="category/java/codestyle.xml/FieldDeclarationsShouldBeAtStartOfClass"/>
+   <rule ref="category/apex/codestyle.xml/FieldNamingConventions"/>
+   <rule ref="category/java/codestyle.xml/FieldNamingConventions"/>
+   <rule ref="category/java/codestyle.xml/FinalParameterInAbstractMethod"/>
+   <rule ref="category/plsql/codestyle.xml/ForLoopNaming"/>
+   <rule ref="category/java/codestyle.xml/ForLoopShouldBeWhileLoop"/>
+   <rule ref="category/apex/codestyle.xml/ForLoopsMustUseBraces"/>
+   <rule ref="category/ecmascript/codestyle.xml/ForLoopsMustUseBraces"/>
+   <rule ref="category/java/codestyle.xml/ForLoopsMustUseBraces"/>
+   <rule ref="category/apex/codestyle.xml/FormalParameterNamingConventions"/>
+   <rule ref="category/java/codestyle.xml/FormalParameterNamingConventions"/>
+   <rule ref="category/java/codestyle.xml/GenericsNaming"/>
+   <rule ref="category/java/codestyle.xml/IdenticalCatchBranches"/>
+   <rule ref="category/apex/codestyle.xml/IfElseStmtsMustUseBraces"/>
+   <rule ref="category/ecmascript/codestyle.xml/IfElseStmtsMustUseBraces"/>
+   <rule ref="category/java/codestyle.xml/IfElseStmtsMustUseBraces"/>
+   <rule ref="category/apex/codestyle.xml/IfStmtsMustUseBraces"/>
+   <rule ref="category/ecmascript/codestyle.xml/IfStmtsMustUseBraces"/>
+   <rule ref="category/java/codestyle.xml/IfStmtsMustUseBraces"/>
+   <rule ref="category/plsql/codestyle.xml/LineLength"/>
+   <rule ref="category/java/codestyle.xml/LinguisticNaming"/>
+   <rule ref="category/java/codestyle.xml/LocalHomeNamingConvention"/>
+   <rule ref="category/java/codestyle.xml/LocalInterfaceSessionNamingConvention"/>
+   <rule ref="category/java/codestyle.xml/LocalVariableCouldBeFinal"/>
+   <rule ref="category/apex/codestyle.xml/LocalVariableNamingConventions"/>
+   <rule ref="category/java/codestyle.xml/LocalVariableNamingConventions"/>
+   <rule ref="category/java/codestyle.xml/LongVariable"/>
+   <rule ref="category/java/codestyle.xml/MDBAndSessionBeanNamingConvention"/>
+   <rule ref="category/java/codestyle.xml/MethodArgumentCouldBeFinal"/>
+   <rule ref="category/apex/codestyle.xml/MethodNamingConventions"/>
+   <rule ref="category/java/codestyle.xml/MethodNamingConventions"/>
+   <rule ref="category/java/codestyle.xml/MIsLeadingVariableName"/>
+   <rule ref="category/plsql/codestyle.xml/MisplacedPragma"/>
+   <rule ref="category/ecmascript/codestyle.xml/NoElseReturn"/>
+   <rule ref="category/java/codestyle.xml/NoPackage"/>
+   <rule ref="category/apex/codestyle.xml/OneDeclarationPerLine"/>
+   <rule ref="category/java/codestyle.xml/OnlyOneReturn"/>
+   <rule ref="category/java/codestyle.xml/PackageCase"/>
+   <rule ref="category/java/codestyle.xml/PrematureDeclaration"/>
+   <rule ref="category/apex/codestyle.xml/PropertyNamingConventions"/>
+   <rule ref="category/java/codestyle.xml/RemoteInterfaceNamingConvention"/>
+   <rule ref="category/java/codestyle.xml/RemoteSessionInterfaceNamingConvention"/>
+   <rule ref="category/java/codestyle.xml/ShortClassName"/>
+   <rule ref="category/java/codestyle.xml/ShortMethodName"/>
+   <rule ref="category/java/codestyle.xml/ShortVariable"/>
+   <rule ref="category/java/codestyle.xml/SuspiciousConstantFieldName"/>
+   <rule ref="category/java/codestyle.xml/TooManyStaticImports"/>
+   <rule ref="category/java/codestyle.xml/UnnecessaryAnnotationValueElement"/>
+   <rule ref="category/ecmascript/codestyle.xml/UnnecessaryBlock"/>
+   <rule ref="category/java/codestyle.xml/UnnecessaryCast"/>
+   <rule ref="category/java/codestyle.xml/UnnecessaryConstructor"/>
+   <rule ref="category/java/codestyle.xml/UnnecessaryFullyQualifiedName"/>
+   <rule ref="category/java/codestyle.xml/UnnecessaryImport"/>
+   <rule ref="category/java/codestyle.xml/UnnecessaryLocalBeforeReturn"/>
+   <rule ref="category/java/codestyle.xml/UnnecessaryModifier"/>
+   <rule ref="category/ecmascript/codestyle.xml/UnnecessaryParentheses"/>
+   <rule ref="category/java/codestyle.xml/UnnecessaryReturn"/>
+   <rule ref="category/ecmascript/codestyle.xml/UnreachableCode"/>
+   <rule ref="category/xsl/codestyle.xml/UseConcatOnce"/>
+   <rule ref="category/java/codestyle.xml/UseDiamondOperator"/>
+   <rule ref="category/java/codestyle.xml/UselessParentheses"/>
+   <rule ref="category/java/codestyle.xml/UselessQualifiedThis"/>
+   <rule ref="category/java/codestyle.xml/UseShortArrayInitializer"/>
+   <rule ref="category/java/codestyle.xml/UseUnderscoresInNumericLiterals"/>
+   <rule ref="category/apex/codestyle.xml/VariableNamingConventions"/>
+   <rule ref="category/java/codestyle.xml/VariableNamingConventions"/>
+   <rule ref="category/apex/codestyle.xml/WhileLoopsMustUseBraces"/>
+   <rule ref="category/ecmascript/codestyle.xml/WhileLoopsMustUseBraces"/>
+   <rule ref="category/java/codestyle.xml/WhileLoopsMustUseBraces"/>
+   <rule ref="category/java/design.xml/AbstractClassWithoutAnyMethod"/>
+   <rule ref="category/java/design.xml/AvoidCatchingGenericException"/>
+   <rule ref="category/apex/design.xml/AvoidDeeplyNestedIfStmts"/>
+   <rule ref="category/java/design.xml/AvoidDeeplyNestedIfStmts"/>
+   <rule ref="category/vm/design.xml/AvoidDeeplyNestedIfStmts"/>
+   <rule ref="category/java/design.xml/AvoidRethrowingException"/>
+   <rule ref="category/java/design.xml/AvoidThrowingNewInstanceOfSameException"/>
+   <rule ref="category/java/design.xml/AvoidThrowingNullPointerException"/>
+   <rule ref="category/java/design.xml/AvoidThrowingRawExceptionTypes"/>
+   <rule ref="category/java/design.xml/AvoidUncheckedExceptionsInSignatures"/>
+   <rule ref="category/java/design.xml/ClassWithOnlyPrivateConstructorsShouldBeFinal"/>
+   <rule ref="category/apex/design.xml/CognitiveComplexity"/>
+   <rule ref="category/java/design.xml/CognitiveComplexity"/>
+   <rule ref="category/java/design.xml/CollapsibleIfStatements"/>
+   <rule ref="category/vm/design.xml/CollapsibleIfStatements"/>
+   <rule ref="category/java/design.xml/CouplingBetweenObjects"/>
+   <rule ref="category/apex/design.xml/CyclomaticComplexity"/>
+   <rule ref="category/java/design.xml/CyclomaticComplexity"/>
+   <rule ref="category/plsql/design.xml/CyclomaticComplexity"/>
+   <rule ref="category/java/design.xml/DataClass"/>
+   <rule ref="category/java/design.xml/DoNotExtendJavaLangError"/>
+   <rule ref="category/java/design.xml/ExceptionAsFlowControl"/>
+   <rule ref="category/apex/design.xml/ExcessiveClassLength"/>
+   <rule ref="category/java/design.xml/ExcessiveClassLength"/>
+   <rule ref="category/java/design.xml/ExcessiveImports"/>
+   <rule ref="category/java/design.xml/ExcessiveMethodLength"/>
+   <rule ref="category/plsql/design.xml/ExcessiveMethodLength"/>
+   <rule ref="category/plsql/design.xml/ExcessiveObjectLength"/>
+   <rule ref="category/plsql/design.xml/ExcessivePackageBodyLength"/>
+   <rule ref="category/plsql/design.xml/ExcessivePackageSpecificationLength"/>
+   <rule ref="category/apex/design.xml/ExcessiveParameterList"/>
+   <rule ref="category/java/design.xml/ExcessiveParameterList"/>
+   <rule ref="category/plsql/design.xml/ExcessiveParameterList"/>
+   <rule ref="category/apex/design.xml/ExcessivePublicCount"/>
+   <rule ref="category/java/design.xml/ExcessivePublicCount"/>
+   <rule ref="category/vm/design.xml/ExcessiveTemplateLength"/>
+   <rule ref="category/plsql/design.xml/ExcessiveTypeLength"/>
+   <rule ref="category/java/design.xml/FinalFieldCouldBeStatic"/>
+   <rule ref="category/java/design.xml/GodClass"/>
+   <rule ref="category/java/design.xml/ImmutableField"/>
+   <rule ref="category/java/design.xml/LawOfDemeter"/>
+   <rule ref="category/java/design.xml/LogicInversion"/>
+   <rule ref="category/java/design.xml/LoosePackageCoupling"/>
+   <rule ref="category/java/design.xml/ModifiedCyclomaticComplexity"/>
+   <rule ref="category/java/design.xml/MutableStaticState"/>
+   <rule ref="category/apex/design.xml/NcssConstructorCount"/>
+   <rule ref="category/java/design.xml/NcssConstructorCount"/>
+   <rule ref="category/java/design.xml/NcssCount"/>
+   <rule ref="category/apex/design.xml/NcssMethodCount"/>
+   <rule ref="category/java/design.xml/NcssMethodCount"/>
+   <rule ref="category/plsql/design.xml/NcssMethodCount"/>
+   <rule ref="category/plsql/design.xml/NcssObjectCount"/>
+   <rule ref="category/apex/design.xml/NcssTypeCount"/>
+   <rule ref="category/java/design.xml/NcssTypeCount"/>
+   <rule ref="category/vm/design.xml/NoInlineJavaScript"/>
+   <rule ref="category/jsp/design.xml/NoInlineScript"/>
+   <rule ref="category/jsp/design.xml/NoInlineStyleInformation"/>
+   <rule ref="category/vm/design.xml/NoInlineStyles"/>
+   <rule ref="category/jsp/design.xml/NoLongScripts"/>
+   <rule ref="category/jsp/design.xml/NoScriptlets"/>
+   <rule ref="category/java/design.xml/NPathComplexity"/>
+   <rule ref="category/plsql/design.xml/NPathComplexity"/>
+   <rule ref="category/java/design.xml/SignatureDeclareThrowsException"/>
+   <rule ref="category/java/design.xml/SimplifiedTernary"/>
+   <rule ref="category/java/design.xml/SimplifyBooleanAssertion"/>
+   <rule ref="category/java/design.xml/SimplifyBooleanExpressions"/>
+   <rule ref="category/java/design.xml/SimplifyBooleanReturns"/>
+   <rule ref="category/java/design.xml/SimplifyConditional"/>
+   <rule ref="category/java/design.xml/SingularField"/>
+   <rule ref="category/apex/design.xml/StdCyclomaticComplexity"/>
+   <rule ref="category/java/design.xml/StdCyclomaticComplexity"/>
+   <rule ref="category/java/design.xml/SwitchDensity"/>
+   <rule ref="category/apex/design.xml/TooManyFields"/>
+   <rule ref="category/java/design.xml/TooManyFields"/>
+   <rule ref="category/plsql/design.xml/TooManyFields"/>
+   <rule ref="category/java/design.xml/TooManyMethods"/>
+   <rule ref="category/plsql/design.xml/TooManyMethods"/>
+   <rule ref="category/java/design.xml/UselessOverridingMethod"/>
+   <rule ref="category/java/design.xml/UseObjectForClearerAPI"/>
+   <rule ref="category/java/design.xml/UseUtilityClass"/>
+   <rule ref="category/apex/documentation.xml/ApexDoc"/>
+   <rule ref="category/java/documentation.xml/CommentContent"/>
+   <rule ref="category/java/documentation.xml/CommentRequired"/>
+   <rule ref="category/java/documentation.xml/CommentSize"/>
+   <rule ref="category/java/documentation.xml/UncommentedEmptyConstructor"/>
+   <rule ref="category/java/documentation.xml/UncommentedEmptyMethodBody"/>
+   <rule ref="category/apex/errorprone.xml/ApexCSRF"/>
+   <rule ref="category/java/errorprone.xml/AssignmentInOperand"/>
+   <rule ref="category/java/errorprone.xml/AssignmentToNonFinalStatic"/>
+   <rule ref="category/java/errorprone.xml/AvoidAccessibilityAlteration"/>
+   <rule ref="category/java/errorprone.xml/AvoidAssertAsIdentifier"/>
+   <rule ref="category/java/errorprone.xml/AvoidBranchingStatementAsLastInLoop"/>
+   <rule ref="category/java/errorprone.xml/AvoidCallingFinalize"/>
+   <rule ref="category/java/errorprone.xml/AvoidCatchingNPE"/>
+   <rule ref="category/java/errorprone.xml/AvoidCatchingThrowable"/>
+   <rule ref="category/java/errorprone.xml/AvoidDecimalLiteralsInBigDecimalConstructor"/>
+   <rule ref="category/apex/errorprone.xml/AvoidDirectAccessTriggerMap"/>
+   <rule ref="category/java/errorprone.xml/AvoidDuplicateLiterals"/>
+   <rule ref="category/java/errorprone.xml/AvoidEnumAsIdentifier"/>
+   <rule ref="category/java/errorprone.xml/AvoidFieldNameMatchingMethodName"/>
+   <rule ref="category/java/errorprone.xml/AvoidFieldNameMatchingTypeName"/>
+   <rule ref="category/apex/errorprone.xml/AvoidHardcodingId"/>
+   <rule ref="category/java/errorprone.xml/AvoidInstanceofChecksInCatchClause"/>
+   <rule ref="category/java/errorprone.xml/AvoidLiteralsInIfCondition"/>
+   <rule ref="category/java/errorprone.xml/AvoidLosingExceptionInformation"/>
+   <rule ref="category/java/errorprone.xml/AvoidMultipleUnaryOperators"/>
+   <rule ref="category/apex/errorprone.xml/AvoidNonExistentAnnotations"/>
+   <rule ref="category/ecmascript/errorprone.xml/AvoidTrailingComma"/>
+   <rule ref="category/java/errorprone.xml/AvoidUsingOctalValues"/>
+   <rule ref="category/java/errorprone.xml/BeanMembersShouldSerialize"/>
+   <rule ref="category/java/errorprone.xml/BrokenNullCheck"/>
+   <rule ref="category/java/errorprone.xml/CallSuperFirst"/>
+   <rule ref="category/java/errorprone.xml/CallSuperLast"/>
+   <rule ref="category/java/errorprone.xml/CheckSkipResult"/>
+   <rule ref="category/java/errorprone.xml/ClassCastExceptionWithToArray"/>
+   <rule ref="category/java/errorprone.xml/CloneMethodMustBePublic"/>
+   <rule ref="category/java/errorprone.xml/CloneMethodMustImplementCloneable"/>
+   <rule ref="category/java/errorprone.xml/CloneMethodReturnTypeMustMatchClassName"/>
+   <rule ref="category/java/errorprone.xml/CloneThrowsCloneNotSupportedException"/>
+   <rule ref="category/java/errorprone.xml/CloseResource"/>
+   <rule ref="category/java/errorprone.xml/CompareObjectsWithEquals"/>
+   <rule ref="category/java/errorprone.xml/ComparisonWithNaN"/>
+   <rule ref="category/java/errorprone.xml/ConstructorCallsOverridableMethod"/>
+   <rule ref="category/java/errorprone.xml/DataflowAnomalyAnalysis"/>
+   <rule ref="category/java/errorprone.xml/DetachedTestCase"/>
+   <rule ref="category/java/errorprone.xml/DoNotCallGarbageCollectionExplicitly"/>
+   <rule ref="category/java/errorprone.xml/DoNotExtendJavaLangThrowable"/>
+   <rule ref="category/java/errorprone.xml/DoNotHardCodeSDCard"/>
+   <rule ref="category/java/errorprone.xml/DoNotTerminateVM"/>
+   <rule ref="category/java/errorprone.xml/DoNotThrowExceptionInFinally"/>
+   <rule ref="category/java/errorprone.xml/DontImportSun"/>
+   <rule ref="category/java/errorprone.xml/DontUseFloatTypeForLoopIndices"/>
+   <rule ref="category/apex/errorprone.xml/EmptyCatchBlock"/>
+   <rule ref="category/java/errorprone.xml/EmptyCatchBlock"/>
+   <rule ref="category/java/errorprone.xml/EmptyFinalizer"/>
+   <rule ref="category/java/errorprone.xml/EmptyFinallyBlock"/>
+   <rule ref="category/vm/errorprone.xml/EmptyForeachStmt"/>
+   <rule ref="category/apex/errorprone.xml/EmptyIfStmt"/>
+   <rule ref="category/java/errorprone.xml/EmptyIfStmt"/>
+   <rule ref="category/vm/errorprone.xml/EmptyIfStmt"/>
+   <rule ref="category/java/errorprone.xml/EmptyInitializer"/>
+   <rule ref="category/apex/errorprone.xml/EmptyStatementBlock"/>
+   <rule ref="category/java/errorprone.xml/EmptyStatementBlock"/>
+   <rule ref="category/java/errorprone.xml/EmptyStatementNotInLoop"/>
+   <rule ref="category/java/errorprone.xml/EmptySwitchStatements"/>
+   <rule ref="category/java/errorprone.xml/EmptySynchronizedBlock"/>
+   <rule ref="category/java/errorprone.xml/EmptyTryBlock"/>
+   <rule ref="category/apex/errorprone.xml/EmptyTryOrFinallyBlock"/>
+   <rule ref="category/apex/errorprone.xml/EmptyWhileStmt"/>
+   <rule ref="category/java/errorprone.xml/EmptyWhileStmt"/>
+   <rule ref="category/ecmascript/errorprone.xml/EqualComparison"/>
+   <rule ref="category/java/errorprone.xml/EqualsNull"/>
+   <rule ref="category/java/errorprone.xml/FinalizeDoesNotCallSuperFinalize"/>
+   <rule ref="category/java/errorprone.xml/FinalizeOnlyCallsSuperFinalize"/>
+   <rule ref="category/java/errorprone.xml/FinalizeOverloaded"/>
+   <rule ref="category/java/errorprone.xml/FinalizeShouldBeProtected"/>
+   <rule ref="category/java/errorprone.xml/IdempotentOperations"/>
+   <rule ref="category/java/errorprone.xml/ImplicitSwitchFallThrough"/>
+   <rule ref="category/java/errorprone.xml/ImportFromSamePackage"/>
+   <rule ref="category/apex/errorprone.xml/InaccessibleAuraEnabledGetter"/>
+   <rule ref="category/ecmascript/errorprone.xml/InnaccurateNumericLiteral"/>
+   <rule ref="category/java/errorprone.xml/InstantiationToGetClass"/>
+   <rule ref="category/pom/errorprone.xml/InvalidDependencyTypes"/>
+   <rule ref="category/java/errorprone.xml/InvalidLogMessageFormat"/>
+   <rule ref="category/jsp/errorprone.xml/JspEncoding"/>
+   <rule ref="category/java/errorprone.xml/JumbledIncrementer"/>
+   <rule ref="category/java/errorprone.xml/JUnitSpelling"/>
+   <rule ref="category/java/errorprone.xml/JUnitStaticSuite"/>
+   <rule ref="category/java/errorprone.xml/LoggerIsNotStaticFinal"/>
+   <rule ref="category/apex/errorprone.xml/MethodWithSameNameAsEnclosingClass"/>
+   <rule ref="category/java/errorprone.xml/MethodWithSameNameAsEnclosingClass"/>
+   <rule ref="category/java/errorprone.xml/MisplacedNullCheck"/>
+   <rule ref="category/java/errorprone.xml/MissingSerialVersionUID"/>
+   <rule ref="category/java/errorprone.xml/MissingStaticMethodInNonInstantiatableClass"/>
+   <rule ref="category/xml/errorprone.xml/MistypedCDATASection"/>
+   <rule ref="category/java/errorprone.xml/MoreThanOneLogger"/>
+   <rule ref="category/java/errorprone.xml/NonCaseLabelInSwitchStatement"/>
+   <rule ref="category/java/errorprone.xml/NonStaticInitializer"/>
+   <rule ref="category/java/errorprone.xml/NullAssignment"/>
+   <rule ref="category/apex/errorprone.xml/OverrideBothEqualsAndHashcode"/>
+   <rule ref="category/java/errorprone.xml/OverrideBothEqualsAndHashcode"/>
+   <rule ref="category/pom/errorprone.xml/ProjectVersionAsDependencyVersion"/>
+   <rule ref="category/java/errorprone.xml/ProperCloneImplementation"/>
+   <rule ref="category/java/errorprone.xml/ProperLogger"/>
+   <rule ref="category/java/errorprone.xml/ReturnEmptyArrayRatherThanNull"/>
+   <rule ref="category/java/errorprone.xml/ReturnEmptyCollectionRatherThanNull"/>
+   <rule ref="category/java/errorprone.xml/ReturnFromFinallyBlock"/>
+   <rule ref="category/java/errorprone.xml/SimpleDateFormatNeedsLocale"/>
+   <rule ref="category/java/errorprone.xml/SingleMethodSingleton"/>
+   <rule ref="category/java/errorprone.xml/SingletonClassReturningNewInstance"/>
+   <rule ref="category/java/errorprone.xml/StaticEJBFieldShouldBeFinal"/>
+   <rule ref="category/java/errorprone.xml/StringBufferInstantiationWithChar"/>
+   <rule ref="category/java/errorprone.xml/SuspiciousEqualsMethodName"/>
+   <rule ref="category/java/errorprone.xml/SuspiciousHashcodeMethodName"/>
+   <rule ref="category/java/errorprone.xml/SuspiciousOctalEscape"/>
+   <rule ref="category/java/errorprone.xml/TestClassWithoutTestCases"/>
+   <rule ref="category/apex/errorprone.xml/TestMethodsMustBeInTestClasses"/>
+   <rule ref="category/plsql/errorprone.xml/TO_DATEWithoutDateFormat"/>
+   <rule ref="category/plsql/errorprone.xml/TO_DATE_TO_CHAR"/>
+   <rule ref="category/plsql/errorprone.xml/TO_TIMESTAMPWithoutDateFormat"/>
+   <rule ref="category/java/errorprone.xml/UnconditionalIfStatement"/>
+   <rule ref="category/java/errorprone.xml/UnnecessaryBooleanAssertion"/>
+   <rule ref="category/java/errorprone.xml/UnnecessaryCaseChange"/>
+   <rule ref="category/java/errorprone.xml/UnnecessaryConversionTemporary"/>
+   <rule ref="category/java/errorprone.xml/UnusedNullCheckInEquals"/>
+   <rule ref="category/java/errorprone.xml/UseCorrectExceptionLogging"/>
+   <rule ref="category/java/errorprone.xml/UseEqualsToCompareStrings"/>
+   <rule ref="category/java/errorprone.xml/UselessOperationOnImmutable"/>
+   <rule ref="category/java/errorprone.xml/UseLocaleWithCaseConversions"/>
+   <rule ref="category/java/errorprone.xml/UseProperClassLoader"/>
+   <rule ref="category/java/multithreading.xml/AvoidSynchronizedAtMethodLevel"/>
+   <rule ref="category/java/multithreading.xml/AvoidThreadGroup"/>
+   <rule ref="category/java/multithreading.xml/AvoidUsingVolatile"/>
+   <rule ref="category/java/multithreading.xml/DoNotUseThreads"/>
+   <rule ref="category/java/multithreading.xml/DontCallThreadRun"/>
+   <rule ref="category/java/multithreading.xml/DoubleCheckedLocking"/>
+   <rule ref="category/java/multithreading.xml/NonThreadSafeSingleton"/>
+   <rule ref="category/java/multithreading.xml/UnsynchronizedStaticDateFormatter"/>
+   <rule ref="category/java/multithreading.xml/UnsynchronizedStaticFormatter"/>
+   <rule ref="category/java/multithreading.xml/UseConcurrentHashMap"/>
+   <rule ref="category/java/multithreading.xml/UseNotifyAllInsteadOfNotify"/>
+   <rule ref="category/java/performance.xml/AddEmptyString"/>
+   <rule ref="category/java/performance.xml/AppendCharacterWithChar"/>
+   <rule ref="category/java/performance.xml/AvoidArrayLoops"/>
+   <rule ref="category/xsl/performance.xml/AvoidAxisNavigation"/>
+   <rule ref="category/java/performance.xml/AvoidCalendarDateCreation"/>
+   <rule ref="category/apex/performance.xml/AvoidDebugStatements"/>
+   <rule ref="category/apex/performance.xml/AvoidDmlStatementsInLoops"/>
+   <rule ref="category/java/performance.xml/AvoidFileStream"/>
+   <rule ref="category/java/performance.xml/AvoidInstantiatingObjectsInLoops"/>
+   <rule ref="category/apex/performance.xml/AvoidSoqlInLoops"/>
+   <rule ref="category/apex/performance.xml/AvoidSoslInLoops"/>
+   <rule ref="category/java/performance.xml/AvoidUsingShortType"/>
+   <rule ref="category/java/performance.xml/BigIntegerInstantiation"/>
+   <rule ref="category/java/performance.xml/BooleanInstantiation"/>
+   <rule ref="category/java/performance.xml/ByteInstantiation"/>
+   <rule ref="category/java/performance.xml/ConsecutiveAppendsShouldReuse"/>
+   <rule ref="category/java/performance.xml/ConsecutiveLiteralAppends"/>
+   <rule ref="category/apex/performance.xml/EagerlyLoadedDescribeSObjectResult"/>
+   <rule ref="category/java/performance.xml/InefficientEmptyStringCheck"/>
+   <rule ref="category/java/performance.xml/InefficientStringBuffering"/>
+   <rule ref="category/java/performance.xml/InsufficientStringBufferDeclaration"/>
+   <rule ref="category/java/performance.xml/IntegerInstantiation"/>
+   <rule ref="category/java/performance.xml/LongInstantiation"/>
+   <rule ref="category/apex/performance.xml/OperationWithLimitsInLoop"/>
+   <rule ref="category/java/performance.xml/OptimizableToArrayCall"/>
+   <rule ref="category/java/performance.xml/RedundantFieldInitializer"/>
+   <rule ref="category/java/performance.xml/ShortInstantiation"/>
+   <rule ref="category/java/performance.xml/SimplifyStartsWith"/>
+   <rule ref="category/java/performance.xml/StringInstantiation"/>
+   <rule ref="category/java/performance.xml/StringToString"/>
+   <rule ref="category/java/performance.xml/TooFewBranchesForASwitchStatement"/>
+   <rule ref="category/java/performance.xml/UnnecessaryWrapperObjectCreation"/>
+   <rule ref="category/java/performance.xml/UseArrayListInsteadOfVector"/>
+   <rule ref="category/java/performance.xml/UseArraysAsList"/>
+   <rule ref="category/java/performance.xml/UseIndexOfChar"/>
+   <rule ref="category/java/performance.xml/UseIOStreamsWithApacheCommonsFileItem"/>
+   <rule ref="category/java/performance.xml/UselessStringValueOf"/>
+   <rule ref="category/java/performance.xml/UseStringBufferForStringAppends"/>
+   <rule ref="category/java/performance.xml/UseStringBufferLength"/>
+   <rule ref="category/apex/security.xml/ApexBadCrypto"/>
+   <rule ref="category/apex/security.xml/ApexCRUDViolation"/>
+   <rule ref="category/apex/security.xml/ApexDangerousMethods"/>
+   <rule ref="category/apex/security.xml/ApexInsecureEndpoint"/>
+   <rule ref="category/apex/security.xml/ApexOpenRedirect"/>
+   <rule ref="category/apex/security.xml/ApexSharingViolations"/>
+   <rule ref="category/apex/security.xml/ApexSOQLInjection"/>
+   <rule ref="category/apex/security.xml/ApexSuggestUsingNamedCred"/>
+   <rule ref="category/apex/security.xml/ApexXSSFromEscapeFalse"/>
+   <rule ref="category/apex/security.xml/ApexXSSFromURLParam"/>
+   <rule ref="category/java/security.xml/HardCodedCryptoKey"/>
+   <rule ref="category/jsp/security.xml/IframeMissingSrcAttribute"/>
+   <rule ref="category/java/security.xml/InsecureCryptoIv"/>
+   <rule ref="category/jsp/security.xml/NoUnsanitizedJSPExpression"/>
+   <rule ref="category/vf/security.xml/VfCsrf"/>
+   <rule ref="category/vf/security.xml/VfHtmlStyleTagXss"/>
+   <rule ref="category/vf/security.xml/VfUnescapeEl"/>
+</ruleset>
\ No newline at end of file
diff --git a/.settings/org.eclipse.m2e.core.prefs b/.settings/org.eclipse.m2e.core.prefs
index 7677864654019633090c7d833785377e923d1947..6fbcdc76f91eaa8e3bd3a50e58bb052bdd5652b0 100644
--- a/.settings/org.eclipse.m2e.core.prefs
+++ b/.settings/org.eclipse.m2e.core.prefs
@@ -1,4 +1,4 @@
-activeProfiles=dev,test
+activeProfiles=dev, eclipse
 eclipse.preferences.version=1
 resolveWorkspaceProjects=true
 version=1
diff --git a/.vscode/launch.json b/.vscode/launch.json
index d5cb3489fe784f32a0c0422347a33c0a199314e7..17cab4c4520df72a47343dd0484b023bef37fb1c 100644
--- a/.vscode/launch.json
+++ b/.vscode/launch.json
@@ -1,25 +1,21 @@
 {
-    // Use IntelliSense to learn about possible attributes.
-    // Hover to view descriptions of existing attributes.
-    // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
-    "version": "0.2.0",
-    "configurations": [
-        
-
-    
-        
-        {
-            "type": "java",
-            "name": "Launch Current File",
-            "request": "launch",
-            "mainClass": "${file}"
-        },
-        {
-            "type": "java",
-            "name": "Launch GitsearchApp",
-            "request": "launch",
-            "mainClass": "at.ac.uibk.gitsearch.GitsearchApp",
-            "projectName": "gitsearch"
-        }
-    ]
-}
\ No newline at end of file
+  // Use IntelliSense to learn about possible attributes.
+  // Hover to view descriptions of existing attributes.
+  // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
+  "version": "0.2.0",
+  "configurations": [
+    {
+      "type": "java",
+      "name": "Launch Current File",
+      "request": "launch",
+      "mainClass": "${file}"
+    },
+    {
+      "type": "java",
+      "name": "Launch GitsearchApp",
+      "request": "launch",
+      "mainClass": "at.ac.uibk.gitsearch.GitsearchApp",
+      "projectName": "gitsearch"
+    }
+  ]
+}
diff --git a/.vscode/settings.json b/.vscode/settings.json
index ded95bb3e516109e5b9064cbf74b4ce2b0c0f45f..8fe4be9e00ac79c97d61f56cf24caa3aed07ce5c 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -1,5 +1,5 @@
 {
-    "java.configuration.updateBuildConfiguration": "automatic",
-    "jestrunner.jestCommand": "npm run test --",
-    "run-protractor.protractorConfiguration": "src/test/javascript/protractor.conf.js",
-}
\ No newline at end of file
+  "java.configuration.updateBuildConfiguration": "automatic",
+  "jestrunner.jestCommand": "npm run test --",
+  "run-protractor.protractorConfiguration": "src/test/javascript/protractor.conf.js"
+}
diff --git a/.vscode/tasks.json b/.vscode/tasks.json
index 7603801885149c0b1b6ead443e353bb7b14be015..0bdbac0eb905e3e0e18d32fd67a75f048d26f0d8 100644
--- a/.vscode/tasks.json
+++ b/.vscode/tasks.json
@@ -1,16 +1,16 @@
 {
-    "version": "2.0.0",
-    "tasks": [
-        {
-            "type": "npm",
-            "script": "start",
-            "problemMatcher": [],
-            "label": "npm: start",
-            "detail": "npm run webpack:dev",
-            "group": {
-                "kind": "build",
-                "isDefault": true
-            }
-        },
-    ]
-}
\ No newline at end of file
+  "version": "2.0.0",
+  "tasks": [
+    {
+      "type": "npm",
+      "script": "start",
+      "problemMatcher": [],
+      "label": "npm: start",
+      "detail": "npm run webpack:dev",
+      "group": {
+        "kind": "build",
+        "isDefault": true
+      }
+    }
+  ]
+}
diff --git a/pom.xml b/pom.xml
index b03778890e343b38c3975b0858e15007306b95dd..4c4643826b12e4d0b17a4382d95ec5c1c7679762 100644
--- a/pom.xml
+++ b/pom.xml
@@ -155,7 +155,7 @@
         <dependency>
 		    <groupId>org.codeability.sharing</groupId>
 		    <artifactId>SharingPluginPlatformAPI</artifactId>
-		    <version>0.2.1</version>
+		    <version>0.3.1</version>
 		</dependency>
         <dependency>
             <groupId>org.springdoc</groupId>
diff --git a/src/main/java/at/ac/uibk/gitsearch/aop/logging/LoggingAspect.java b/src/main/java/at/ac/uibk/gitsearch/aop/logging/LoggingAspect.java
index 194412f5b553ca0e52083e1a7f2329908a83e6e0..2b2834e1a6aa69f2a7ff87fd8cc963f9d0366c01 100644
--- a/src/main/java/at/ac/uibk/gitsearch/aop/logging/LoggingAspect.java
+++ b/src/main/java/at/ac/uibk/gitsearch/aop/logging/LoggingAspect.java
@@ -74,7 +74,7 @@ public class LoggingAspect {
                 .error(
                     "Exception in {}() with cause = '{}' and exception = '{}'",
                     joinPoint.getSignature().getName(),
-                    e.getCause() != null ? e.getCause() : "NULL",
+                    e.getCause() == null ? "NULL" : e.getCause(),
                     e.getMessage(),
                     e
                 );
@@ -83,7 +83,7 @@ public class LoggingAspect {
                 .error(
                     "Exception in {}() with cause = {}",
                     joinPoint.getSignature().getName(),
-                    e.getCause() != null ? e.getCause() : "NULL"
+                    e.getCause() == null ? "NULL" : e.getCause()
                 );
         }
     }
diff --git a/src/main/java/at/ac/uibk/gitsearch/config/CacheConfiguration.java b/src/main/java/at/ac/uibk/gitsearch/config/CacheConfiguration.java
index 00391af91ae4d2193b5a7bfeef14bc9f8a0e68db..99026cf68ee1bb742ef98db0260e4ff800247d1f 100644
--- a/src/main/java/at/ac/uibk/gitsearch/config/CacheConfiguration.java
+++ b/src/main/java/at/ac/uibk/gitsearch/config/CacheConfiguration.java
@@ -64,10 +64,10 @@ public class CacheConfiguration {
 
     private void createCache(javax.cache.CacheManager cm, String cacheName) {
         javax.cache.Cache<Object, Object> cache = cm.getCache(cacheName);
-        if (cache != null) {
-            cache.clear();
-        } else {
+        if (cache == null) {
             cm.createCache(cacheName, jcacheConfiguration);
+        } else {
+            cache.clear();
         }
     }
 
diff --git a/src/main/java/at/ac/uibk/gitsearch/config/LoggingConfiguration.java b/src/main/java/at/ac/uibk/gitsearch/config/LoggingConfiguration.java
index 0542ac98da13763dd4b763b9848e4f74791b25b4..858d9c9b5620b0e87865e77019275c6d1c6d7a55 100644
--- a/src/main/java/at/ac/uibk/gitsearch/config/LoggingConfiguration.java
+++ b/src/main/java/at/ac/uibk/gitsearch/config/LoggingConfiguration.java
@@ -1,12 +1,14 @@
 package at.ac.uibk.gitsearch.config;
 
-import static tech.jhipster.config.logging.LoggingUtils.*;
+import static tech.jhipster.config.logging.LoggingUtils.addContextListener;
+import static tech.jhipster.config.logging.LoggingUtils.addJsonConsoleAppender;
+import static tech.jhipster.config.logging.LoggingUtils.addLogstashTcpSocketAppender;
 
 import ch.qos.logback.classic.LoggerContext;
 import com.fasterxml.jackson.core.JsonProcessingException;
 import com.fasterxml.jackson.databind.ObjectMapper;
-import java.util.HashMap;
 import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.context.annotation.Configuration;
@@ -26,7 +28,7 @@ public class LoggingConfiguration {
     ) throws JsonProcessingException {
         LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory();
 
-        Map<String, String> map = new HashMap<>();
+        Map<String, String> map = new ConcurrentHashMap<>();
         map.put("app_name", appName);
         map.put("app_port", serverPort);
         String customFields = mapper.writeValueAsString(map);
diff --git a/src/main/java/at/ac/uibk/gitsearch/config/SecurityConfiguration.java b/src/main/java/at/ac/uibk/gitsearch/config/SecurityConfiguration.java
index c60c13b1bd9791b221a3ae71680870334a5f0d09..e9e030c2d29992b906d5517486d7efde784dd68e 100644
--- a/src/main/java/at/ac/uibk/gitsearch/config/SecurityConfiguration.java
+++ b/src/main/java/at/ac/uibk/gitsearch/config/SecurityConfiguration.java
@@ -13,11 +13,11 @@ import at.ac.uibk.gitsearch.service.dto.AdminUserDTO;
 import at.ac.uibk.gitsearch.service.mapper.UserMapper;
 import java.net.URI;
 import java.util.Collections;
-import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Map;
 import java.util.Optional;
 import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
 import javax.servlet.DispatcherType;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.boot.web.servlet.FilterRegistrationBean;
@@ -89,7 +89,7 @@ public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
 
     private final CorsFilter corsFilter;
     private final SecurityProblemSupport problemSupport;
-    private UserDetailsFetcher userDetailsFetcher;
+    private final UserDetailsFetcher userDetailsFetcher;
 
     public SecurityConfiguration(
         TokenProvider tokenProvider,
@@ -97,6 +97,7 @@ public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
         UserDetailsFetcher userDetailsFetcher,
         SecurityProblemSupport problemSupport
     ) {
+        super();
         this.tokenProvider = tokenProvider;
         this.corsFilter = corsFilter;
         this.problemSupport = problemSupport;
@@ -143,7 +144,8 @@ public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
         .and()
             .referrerPolicy(ReferrerPolicyHeaderWriter.ReferrerPolicy.STRICT_ORIGIN_WHEN_CROSS_ORIGIN)
         .and()
-            .featurePolicy("geolocation 'none'; midi 'none'; sync-xhr 'none'; microphone 'none'; camera 'none'; magnetometer 'none'; gyroscope 'none'; speaker 'none'; fullscreen 'self'; payment 'none'")
+        	.permissionsPolicy(permissions -> permissions
+					.policy("geolocation 'none'; midi 'none'; sync-xhr 'none'; microphone 'none'; camera 'none'; magnetometer 'none'; gyroscope 'none'; speaker 'none'; fullscreen 'self'; payment 'none'"))
         .and()
             .frameOptions()
             .deny()
@@ -296,8 +298,8 @@ public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
             return new RequestEntity<>(formParameters, headers, HttpMethod.POST, uri);
         }
 
-        static org.springframework.http.HttpHeaders getTokenRequestHeaders(ClientRegistration clientRegistration) {
-            org.springframework.http.HttpHeaders headers = new org.springframework.http.HttpHeaders();
+        static HttpHeaders getTokenRequestHeaders(ClientRegistration clientRegistration) {
+            HttpHeaders headers = new HttpHeaders();
             headers.addAll(getDefaultTokenRequestHeaders());
             //    		if (ClientAuthenticationMethod.BASIC.equals(clientRegistration.getClientAuthenticationMethod())) {
             //    			headers.setBasicAuth(clientRegistration.getClientId(), clientRegistration.getClientSecret());
@@ -305,7 +307,7 @@ public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
             return headers;
         }
 
-        private static org.springframework.http.HttpHeaders getDefaultTokenRequestHeaders() {
+        private static HttpHeaders getDefaultTokenRequestHeaders() {
             HttpHeaders headers = new HttpHeaders();
             headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));
             final MediaType contentType = MediaType.valueOf(APPLICATION_FORM_URLENCODED_VALUE + ";charset=UTF-8");
@@ -384,7 +386,9 @@ public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
                     userRequest.getAccessToken(),
                     userRequest.getClientRegistration()
                 );
-                if (hasChanged) userService.updateUser(adminUserDto);
+                if (hasChanged) {
+                    userService.updateUser(adminUserDto);
+                }
 
                 userO
                     .get()
@@ -421,7 +425,7 @@ public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
                 userService.createUser(u);
             }
 
-            Map<String, Object> claims = new HashMap<>(oidcUser.getUserInfo().getClaims());
+            Map<String, Object> claims = new ConcurrentHashMap<>(oidcUser.getUserInfo().getClaims());
             claims.put(TokenProvider.GITLAB_ACCESS_TOKEN, userRequest.getAccessToken().getTokenValue());
             claims.put(TokenProvider.GITLAB_ACCESS_ISSUER, userRequest.getClientRegistration().getRegistrationId());
             OidcUserInfo userInfo = new OidcUserInfo(claims);
diff --git a/src/main/java/at/ac/uibk/gitsearch/config/StaticResourcesWebConfiguration.java b/src/main/java/at/ac/uibk/gitsearch/config/StaticResourcesWebConfiguration.java
index 714d24f58a3edcdc49ab7a167795364673061232..89e619bbde3a12e2b5725e9a851a78aa0ba2c4ec 100644
--- a/src/main/java/at/ac/uibk/gitsearch/config/StaticResourcesWebConfiguration.java
+++ b/src/main/java/at/ac/uibk/gitsearch/config/StaticResourcesWebConfiguration.java
@@ -14,20 +14,8 @@ import tech.jhipster.config.JHipsterProperties;
 @Profile({ JHipsterConstants.SPRING_PROFILE_PRODUCTION })
 public class StaticResourcesWebConfiguration implements WebMvcConfigurer {
 
-    protected static final String[] RESOURCE_LOCATIONS = new String[] {
-        "classpath:/static/",
-        "classpath:/static/content/",
-        "classpath:/static/i18n/",
-    };
-    protected static final String[] RESOURCE_PATHS = new String[] {
-        "/*.js",
-        "/*.css",
-        "/*.svg",
-        "/*.png",
-        "*.ico",
-        "/content/**",
-        "/i18n/*",
-    };
+    protected static final String[] RESOURCE_LOCATIONS = { "classpath:/static/", "classpath:/static/content/", "classpath:/static/i18n/" };
+    protected static final String[] RESOURCE_PATHS = { "/*.js", "/*.css", "/*.svg", "/*.png", "*.ico", "/content/**", "/i18n/*" };
 
     private final JHipsterProperties jhipsterProperties;
 
diff --git a/src/main/java/at/ac/uibk/gitsearch/domain/Authority.java b/src/main/java/at/ac/uibk/gitsearch/domain/Authority.java
index 0911e6c5e88d1839597fbd5727def283c9f60631..733248a44824e1c43cdb6d2dd57fafac2d0bd3e3 100644
--- a/src/main/java/at/ac/uibk/gitsearch/domain/Authority.java
+++ b/src/main/java/at/ac/uibk/gitsearch/domain/Authority.java
@@ -21,6 +21,12 @@ public class Authority implements Serializable {
 
     private static final long serialVersionUID = 1L;
 
+    @NotNull
+    @Size(max = 50)
+    @Id
+    @Column(length = 50)
+    private String name;
+
     public Authority(@NotNull @Size(max = 50) String name) {
         super();
         this.name = name;
@@ -30,12 +36,6 @@ public class Authority implements Serializable {
         // For JPA
     }
 
-    @NotNull
-    @Size(max = 50)
-    @Id
-    @Column(length = 50)
-    private String name;
-
     public String getName() {
         return name;
     }
diff --git a/src/main/java/at/ac/uibk/gitsearch/domain/PersistentAuditEvent.java b/src/main/java/at/ac/uibk/gitsearch/domain/PersistentAuditEvent.java
index 790c72560f48f9e6f0fa6b345575f21fb2cf6c1f..2728c81222b563789f1bffbd2d76d797921a9244 100644
--- a/src/main/java/at/ac/uibk/gitsearch/domain/PersistentAuditEvent.java
+++ b/src/main/java/at/ac/uibk/gitsearch/domain/PersistentAuditEvent.java
@@ -2,9 +2,18 @@ package at.ac.uibk.gitsearch.domain;
 
 import java.io.Serializable;
 import java.time.Instant;
-import java.util.HashMap;
 import java.util.Map;
-import javax.persistence.*;
+import java.util.concurrent.ConcurrentHashMap;
+import javax.persistence.CollectionTable;
+import javax.persistence.Column;
+import javax.persistence.ElementCollection;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.MapKeyColumn;
+import javax.persistence.Table;
 import javax.validation.constraints.NotNull;
 
 /**
@@ -37,7 +46,7 @@ public class PersistentAuditEvent implements Serializable {
     @MapKeyColumn(name = "name")
     @Column(name = "value")
     @CollectionTable(name = "jhi_persistent_audit_evt_data", joinColumns = @JoinColumn(name = "event_id"))
-    private Map<String, String> data = new HashMap<>();
+    private Map<String, String> data = new ConcurrentHashMap<>();
 
     public Long getId() {
         return id;
diff --git a/src/main/java/at/ac/uibk/gitsearch/repository/search/GitFilesRepositoryImpl.java b/src/main/java/at/ac/uibk/gitsearch/repository/search/GitFilesRepositoryImpl.java
index 7521977ffbba3154dd7cdcea2401dda743e22dba..b7d7c7175ebad94b4173a02cf5e16249b7738622 100644
--- a/src/main/java/at/ac/uibk/gitsearch/repository/search/GitFilesRepositoryImpl.java
+++ b/src/main/java/at/ac/uibk/gitsearch/repository/search/GitFilesRepositoryImpl.java
@@ -10,6 +10,7 @@ import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.List;
 import org.codeability.sharing.plugins.api.search.SearchInputDTO;
 import org.elasticsearch.action.search.SearchRequest;
@@ -144,7 +145,7 @@ public class GitFilesRepositoryImpl implements GitFilesRepository {
 
     private Collection<String> searchProjectsIDsMetadata(SearchInputDTO searchInputDTO) throws IOException {
         if (!searchInputDTO.hasMetadataInput()) {
-            return null;
+            return Collections.emptyList();
         }
         SearchRequest searchRequest = new SearchRequest(SearchRepositoryConstants.INDEX_METADATA);
         BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
diff --git a/src/main/java/at/ac/uibk/gitsearch/repository/search/MetaDataRepository.java b/src/main/java/at/ac/uibk/gitsearch/repository/search/MetaDataRepository.java
index 479e9f2d1888a6cb13bec1c72a45a47258d5d3c4..26a08c71ed8f64cfccd38433bdbf7470d24de83b 100644
--- a/src/main/java/at/ac/uibk/gitsearch/repository/search/MetaDataRepository.java
+++ b/src/main/java/at/ac/uibk/gitsearch/repository/search/MetaDataRepository.java
@@ -21,7 +21,10 @@ import java.util.StringTokenizer;
 import java.util.Timer;
 import java.util.TimerTask;
 import java.util.TreeMap;
+import java.util.concurrent.CancellationException;
 import java.util.function.Consumer;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 import javax.annotation.PostConstruct;
@@ -219,7 +222,7 @@ public class MetaDataRepository {
                 public void run() {
                     try {
                         updateAutocompletionCache();
-                    } catch (IOException e) {
+                    } catch (IOException | RuntimeException e) {
                         LOGGER.warn("Cannot refresh Autocompletion Cache", e);
                     }
                 }
@@ -448,8 +451,34 @@ public class MetaDataRepository {
         );
         if (formatBuilder.hasClauses()) queryBuilder.must(formatBuilder);
 
-        if (!StringUtils.isEmpty(searchInputDTO.getMetadata().getParentId())) {
-            queryBuilder.must(QueryBuilders.termQuery(SearchRepositoryConstants.FILE_PARENTID, searchInputDTO.getMetadata().getParentId()));
+        String parentId = searchInputDTO.getMetadata().getParentId();
+        SearchResultDTO parentExercise = null;
+        if (!StringUtils.isEmpty(parentId)) {
+            try {
+                parentExercise = getExerciseById(parentId, user);
+            } catch (NotFoundException e) {
+                String stripped = convertToPreviousId(parentId);
+                if (stripped.equals(parentId)) try {
+                    parentExercise = getExerciseById(stripped, user);
+                } catch (NotFoundException e1) {
+                    LOGGER.warn("Cannot find exercise for: {}", parentId);
+                }
+            }
+            if (parentExercise == null || parentExercise.getFile().getChildren() == null) {
+                // just a very lazy workaround
+                return null;
+            } else {
+                String[] childrenIds = parentExercise.getFile().getChildren();
+                BoolQueryBuilder collectionBuilder = QueryBuilders.boolQuery();
+                for (int i = 0; i < childrenIds.length; i++) {
+                    collectionBuilder.should(QueryBuilders.termQuery(SearchRepositoryConstants.EXERCISE_ID, childrenIds[i]));
+                    String previousId = convertToPreviousId(childrenIds[i]);
+                    if (!previousId.equals(childrenIds[i])) collectionBuilder.should(
+                        QueryBuilders.termQuery(SearchRepositoryConstants.EXERCISE_ID, previousId)
+                    );
+                }
+                queryBuilder.must(collectionBuilder);
+            }
         }
 
         BoolQueryBuilder authorBuilder = QueryBuilders.boolQuery();
@@ -511,6 +540,22 @@ public class MetaDataRepository {
         return parseSearchResponse(searchResponse);
     }
 
+    /**
+     * strips brackets from exercise Id. Just for temporary use. Will not be necessary, when we change to bracketed ids in general.
+     * @param exerciseId
+     * @return
+     */
+    public String convertToPreviousId(String exerciseId) {
+        Pattern newParser = Pattern.compile("^\\[(\\d+)\\](.*)$");
+        Matcher matcher = newParser.matcher(exerciseId.trim());
+        if (matcher.matches()) {
+            String projectId = matcher.group(1);
+            String path = matcher.group(2);
+            if (StringUtils.isEmpty(path)) return projectId; else return projectId + ":" + path;
+        }
+        return exerciseId;
+    }
+
     /**
      * this adds extra authorization requirements.
      * It currently supports directly the group membership in the hierarchy
@@ -712,6 +757,12 @@ public class MetaDataRepository {
         } catch (IOException e) {
             throw new NotFoundException("Query for exercise with id " + exerciseId + " went wrong?", e);
         }
-        throw new NotFoundException(" Exercise with id " + exerciseId + " not found?");
+        // temporary for backward compatibility!
+        String oldExerciseId = convertToPreviousId(exerciseId);
+        if (oldExerciseId.equals(exerciseId)) {
+            throw new NotFoundException(" Exercise with id " + exerciseId + " not found?");
+        } else {
+            return getExerciseById(oldExerciseId, user);
+        }
     }
 }
diff --git a/src/main/java/at/ac/uibk/gitsearch/service/GitlabService.java b/src/main/java/at/ac/uibk/gitsearch/service/GitlabService.java
index 38bb1d4bbb4064e1b96791f4144ac9c8683a4142..da99c211f6e33ad7afec049f45532a44239a5f16 100644
--- a/src/main/java/at/ac/uibk/gitsearch/service/GitlabService.java
+++ b/src/main/java/at/ac/uibk/gitsearch/service/GitlabService.java
@@ -177,7 +177,7 @@ public class GitlabService {
      * @throws IOException
      */
     public InputStream getRepositoryFile(ExerciseId exerciseId, String filePath) throws GitLabApiException, IOException {
-        final SearchResultDTO exercise = metaDataRepository.getExerciseById(exerciseId, tokenProvider.getCurrentPrincipal());
+        final SearchResultDTO exercise = metaDataRepository.getExerciseById(exerciseId.toString(), tokenProvider.getCurrentPrincipal());
         if (exercise == null) throw new IOException("Exercise with id " + exerciseId + " not found!");
 
         final GitLabApi gitLabApi = gitLabRepository.getGitLabApi(tokenProvider.getGitLabAccessInfo());
diff --git a/src/main/java/at/ac/uibk/gitsearch/service/SavedSearchesService.java b/src/main/java/at/ac/uibk/gitsearch/service/SavedSearchesService.java
index 6b53550f99dc835e5cc3c42b9def8bb6f7054e39..471445ed0841f41fa0bdf0239adece53ea8a87e4 100644
--- a/src/main/java/at/ac/uibk/gitsearch/service/SavedSearchesService.java
+++ b/src/main/java/at/ac/uibk/gitsearch/service/SavedSearchesService.java
@@ -1,7 +1,5 @@
 package at.ac.uibk.gitsearch.service;
 
-import static org.elasticsearch.index.query.QueryBuilders.*;
-
 import at.ac.uibk.gitsearch.domain.SavedSearches;
 import at.ac.uibk.gitsearch.repository.SavedSearchesRepository;
 import at.ac.uibk.gitsearch.repository.search.SavedSearchesSearchRepository;
diff --git a/src/main/java/at/ac/uibk/gitsearch/service/SearchService.java b/src/main/java/at/ac/uibk/gitsearch/service/SearchService.java
index a0649cde259917df3b1fea913aebd54d64706fda..243bc2a30d3fff91cd3b90098d92b371530db74e 100644
--- a/src/main/java/at/ac/uibk/gitsearch/service/SearchService.java
+++ b/src/main/java/at/ac/uibk/gitsearch/service/SearchService.java
@@ -7,18 +7,27 @@ import at.ac.uibk.gitsearch.security.jwt.TokenProvider;
 import at.ac.uibk.gitsearch.security.jwt.TokenProvider.GitLabAccessInfo;
 import at.ac.uibk.gitsearch.service.dto.AutoCompleteEntry;
 import java.io.File;
+import java.io.FileInputStream;
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
+import java.io.PipedInputStream;
+import java.io.PipedOutputStream;
 import java.net.URI;
 import java.net.URISyntaxException;
+import java.nio.file.attribute.FileTime;
 import java.text.ParseException;
 import java.util.Arrays;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Optional;
+import java.util.Set;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
+import java.util.zip.ZipEntry;
 import java.util.zip.ZipInputStream;
+import java.util.zip.ZipOutputStream;
+import org.apache.commons.lang3.StringUtils;
 import org.codeability.sharing.plugins.api.search.SearchInputDTO;
 import org.codeability.sharing.plugins.api.search.SearchResultDTO;
 import org.codeability.sharing.plugins.api.search.SearchResultsDTO;
@@ -271,13 +280,31 @@ public class SearchService {
     }
 
     public File exportExercise(String exerciseId) throws IOException, ParseException {
-        return exportExercise(ExerciseId.fromString(exerciseId));
+        return exportExercise(ExerciseId.fromString(exerciseId), ExtractionDepth.JUST_PROJECT);
     }
 
-    public File exportExercise(ExerciseId exerciseId) throws IOException {
+    public enum ExtractionDepth {
+        JUST_PROJECT,
+        WITH_CHILDREN,
+        WITH_DESCENDANTS,
+    }
+
+    public File exportExercise(ExerciseId exerciseId, ExtractionDepth recursive) throws IOException {
+        ZipInputStream inputFile = getZippedExercise(exerciseId, tokenProvider.getCurrentPrincipal(), recursive, new HashSet<>());
+        if (inputFile == null) return null;
+        File file = File.createTempFile("exercise" + exerciseId.getProjectId(), ".zip");
+
+        return copyInputStreamToFile(inputFile, file);
+    }
+
+    private ZipInputStream getZippedExercise(
+        ExerciseId exerciseId,
+        Optional<User> user,
+        ExtractionDepth recursive,
+        Set<ExerciseId> alreadyTreatedExerciseIds
+    ) throws IOException {
         try {
-            final Optional<User> currentPrincipal = tokenProvider.getCurrentPrincipal();
-            final SearchResultDTO exercise = metaDataRepository.getExerciseById(exerciseId, currentPrincipal);
+            final SearchResultDTO exercise = metaDataRepository.getExerciseById(exerciseId.toString(), user);
             final GitLabApi gitLabApi = gitLabRepository.getGitLabApi(tokenProvider.getGitLabAccessInfo());
             // first we try with user credentials!
             InputStream repositoryArchive = null;
@@ -302,21 +329,123 @@ public class SearchService {
                     throw e;
                 }
             }
-            InputStream inputFile = shoppingBasketService.rePackageGitLabProjectZip(
+            ZipInputStream project = shoppingBasketService.rePackageGitLabProjectZip(
                 new ZipInputStream(repositoryArchive),
                 "from project " + exerciseId.getProjectId(),
                 filter,
                 exerciseId.getPath()
             );
-            File file = new File("exercise" + exerciseId.getProjectId() + ".zip");
-
-            return copyInputStreamToFile(inputFile, file);
+            if (recursive == ExtractionDepth.JUST_PROJECT) return project; else {
+                alreadyTreatedExerciseIds.add(exerciseId); // Side effects are always dangerous :-(
+                return extendZipByChildren(exerciseId, project, user, recursive, alreadyTreatedExerciseIds);
+            }
         } catch (GitLabApiException exception) {
             log.error(exception.getMessage());
             return null;
         }
     }
 
+    @SuppressWarnings("unused")
+    private InputStream copyInBackground(InputStream in) throws IOException {
+        PipedInputStream pis = new PipedInputStream();
+        PipedOutputStream pos = new PipedOutputStream(pis);
+
+        Runnable copy = () -> {
+            byte[] buffer = new byte[10240];
+            int i = 0;
+            try {
+                while ((i = in.read(buffer)) > 0) {
+                    pos.write(buffer, 0, i);
+                }
+                pos.close();
+            } catch (IOException e) {
+                log.error("Cannot copy inputstream?", e);
+            }
+        };
+
+        Thread t = new Thread(copy, "StreamCopyThread");
+        t.start();
+        return pis;
+    }
+
+    /**
+     *
+     * @param exerciseId the exercise id
+     * @param existingZip a zip input stream that should be amended by children, may be null
+     * @param user the user to check for permissions
+     * @param recursive the recursion type
+     * @param alreadyTreatedExerciseIds list of already treated Exercise Ids (in order to avoid endless recursions)
+     * @return an zipped output stream containing also children
+     * @throws IOException
+     */
+    private ZipInputStream extendZipByChildren(
+        ExerciseId exerciseId,
+        ZipInputStream existingZip,
+        Optional<User> user,
+        ExtractionDepth recursive,
+        Set<ExerciseId> alreadyTreatedExerciseIds
+    ) throws IOException {
+        if (recursive == ExtractionDepth.JUST_PROJECT) {
+            return existingZip;
+        }
+
+        SearchResultDTO exerciseMD = metaDataRepository.getExerciseById(exerciseId, user);
+        ExtractionDepth childRecursion = (recursive == ExtractionDepth.WITH_CHILDREN)
+            ? ExtractionDepth.JUST_PROJECT
+            : ExtractionDepth.WITH_DESCENDANTS;
+        if (exerciseMD != null && exerciseMD.getFile().getChildren() != null) {
+            File file = File.createTempFile("exercise" + exerciseId.getProjectId() + "recursive", "zip");
+            ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(file));
+            if (existingZip != null) copyZip(existingZip, zos, null);
+
+            for (String child : exerciseMD.getFile().getChildren()) {
+                try {
+                    ExerciseId childExerciseId = ExerciseId.fromString(child);
+                    if (!childExerciseId.isDescendantOf(exerciseId)) {
+                        ZipInputStream zis = getZippedExercise(childExerciseId, user, childRecursion, alreadyTreatedExerciseIds);
+                        copyZip(zis, zos, child);
+                    } else {
+                        ZipInputStream zis = extendZipByChildren(childExerciseId, null, user, childRecursion, alreadyTreatedExerciseIds);
+                        copyZip(zis, zos, child);
+                    }
+                } catch (IOException | ParseException e) {
+                    log.error("Cannot extract children {}", child);
+                }
+            }
+            zos.close();
+            return new ZipInputStream(new FileInputStream(file));
+        }
+        // nothing copied
+        return existingZip;
+    }
+
+    /**
+     * copies a zipped input stream into the existing zipped output stream.
+     * @param zis
+     * @param zos
+     * @param parent
+     * @throws IOException
+     */
+    private void copyZip(ZipInputStream zis, ZipOutputStream zos, String parent) throws IOException {
+        for (ZipEntry ze = zis.getNextEntry(); ze != null; ze = zis.getNextEntry()) {
+            String newName = StringUtils.isEmpty(parent) ? ze.getName() : parent + "/" + ze.getName();
+            ZipEntry newZE = new ZipEntry(newName);
+            newZE.setComment(ze.getComment());
+            FileTime creationTime = ze.getCreationTime();
+            if (creationTime != null) newZE.setCreationTime(creationTime);
+
+            zos.putNextEntry(newZE);
+            byte[] buffer = new byte[1024];
+            for (int read = zis.read(buffer); read != -1; read = zis.read(buffer)) {
+                zos.write(buffer, 0, read);
+            }
+            zos.closeEntry();
+        }
+
+        zis.close();
+    }
+
+    @SuppressWarnings("unused")
     private File copyInputStreamToFile(InputStream inputStream, File file) throws IOException {
         // append = false
         try (FileOutputStream outputStream = new FileOutputStream(file, false)) {
@@ -329,6 +458,14 @@ public class SearchService {
         }
     }
 
+    private File copyInputStreamToFile(ZipInputStream inputStream, File file) throws IOException {
+        // append = false
+        try (ZipOutputStream outputStream = new ZipOutputStream(new FileOutputStream(file, false))) {
+            copyZip(inputStream, outputStream, null);
+            return file;
+        }
+    }
+
     public Boolean hasAccessToExerciseId(String exerciseId) {
         if (tokenProvider.getCurrentPrincipal().isEmpty()) {
             log.warn("Cannot find a principal for for exercise {}", exerciseId);
@@ -346,9 +483,9 @@ public class SearchService {
         return true;
     }
 
-    public Optional<SearchResultDTO> findExerciseById(ExerciseId exerciseId) {
+    public Optional<SearchResultDTO> findExerciseById(String exerciseId) {
         try {
-            SearchResultDTO result = metaDataRepository.getExerciseById(exerciseId.toString(), tokenProvider.getCurrentPrincipal());
+            SearchResultDTO result = metaDataRepository.getExerciseById(exerciseId, tokenProvider.getCurrentPrincipal());
             return Optional.ofNullable(result);
         } catch (javax.ws.rs.NotFoundException e) {
             log.error("exercise with id {} not found?", exerciseId, e);
diff --git a/src/main/java/at/ac/uibk/gitsearch/service/ShoppingBasketService.java b/src/main/java/at/ac/uibk/gitsearch/service/ShoppingBasketService.java
index 548310318a338d52cffe4cfa29e96ba2674ff40e..3eadb3fe1aee07e1ebf690ef950deff6225056d3 100644
--- a/src/main/java/at/ac/uibk/gitsearch/service/ShoppingBasketService.java
+++ b/src/main/java/at/ac/uibk/gitsearch/service/ShoppingBasketService.java
@@ -319,7 +319,7 @@ public class ShoppingBasketService {
      * @return
      * @throws IOException
      */
-    protected InputStream rePackageGitLabProjectZip(
+    protected ZipInputStream rePackageGitLabProjectZip(
         ZipInputStream zipIn,
         String originalLocation,
         String[] filterOut,
@@ -359,6 +359,7 @@ public class ShoppingBasketService {
                     zipInEntry = zipIn.getNextEntry();
                 }
                 zipIn.close();
+                zipOut.close();
             } catch (IOException e) {
                 log.error("Cannot rezip file from {}", originalLocation);
             }
@@ -366,7 +367,7 @@ public class ShoppingBasketService {
 
         new Thread(rePackage).start();
 
-        return pis;
+        return new ZipInputStream(pis);
     }
 
     public String getExerciseFolderPath(String exercisesPath) {
diff --git a/src/main/java/at/ac/uibk/gitsearch/service/dto/SavedSearchesDTO.java b/src/main/java/at/ac/uibk/gitsearch/service/dto/SavedSearchesDTO.java
index 9a54aef4fd148cbd5d35878a2b7fda240e7733ec..4761f81a2307a49b85e426924f7e5e79afbed08b 100644
--- a/src/main/java/at/ac/uibk/gitsearch/service/dto/SavedSearchesDTO.java
+++ b/src/main/java/at/ac/uibk/gitsearch/service/dto/SavedSearchesDTO.java
@@ -9,6 +9,11 @@ import javax.validation.constraints.*;
  */
 public class SavedSearchesDTO implements Serializable {
 
+    /**
+     *
+     */
+    private static final long serialVersionUID = -873007677104911565L;
+
     private Long id;
 
     @NotNull
diff --git a/src/main/java/at/ac/uibk/gitsearch/web/rest/ExerciseResource.java b/src/main/java/at/ac/uibk/gitsearch/web/rest/ExerciseResource.java
index 9ba53e1e923b61ae770a4d9ac48ed85876afa192..c0da94a831eb5e3285df3390c80525ef58078ac9 100644
--- a/src/main/java/at/ac/uibk/gitsearch/web/rest/ExerciseResource.java
+++ b/src/main/java/at/ac/uibk/gitsearch/web/rest/ExerciseResource.java
@@ -6,8 +6,10 @@ import at.ac.uibk.gitsearch.service.ArtemisImportError;
 import at.ac.uibk.gitsearch.service.ExerciseService;
 import at.ac.uibk.gitsearch.service.GitlabService;
 import at.ac.uibk.gitsearch.service.SearchService;
+import at.ac.uibk.gitsearch.service.SearchService.ExtractionDepth;
 import at.ac.uibk.gitsearch.service.StatisticsService;
 import at.ac.uibk.gitsearch.service.dto.StatisticsDTO;
+import at.ac.uibk.gitsearch.web.rest.utils.RestUtils;
 import at.ac.uibk.gitsearch.web.util.HeaderUtil;
 import java.io.File;
 import java.io.FileInputStream;
@@ -23,6 +25,7 @@ import java.text.ParseException;
 import java.util.Optional;
 import javax.servlet.http.HttpServletRequest;
 import javax.ws.rs.core.Response;
+import org.apache.commons.lang3.StringUtils;
 import org.codeability.sharing.plugins.api.search.SearchResultDTO;
 import org.codeability.sharing.plugins.api.search.util.ExerciseId;
 import org.eclipse.jgit.api.errors.GitAPIException;
@@ -92,7 +95,7 @@ public class ExerciseResource {
         throws IOException {
         String pattern = (String) request.getAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE);
 
-        String exerciseId = new AntPathMatcher().extractPathWithinPattern(pattern, request.getRequestURI());
+        String exerciseId = RestUtils.decodeURL(request, pattern);
 
         ExerciseId parsedId;
         try {
@@ -146,7 +149,7 @@ public class ExerciseResource {
     public ResponseEntity<SearchResultDTO> getExerciseById(HttpServletRequest request) throws IOException {
         String pattern = (String) request.getAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE);
 
-        String exerciseId = new AntPathMatcher().extractPathWithinPattern(pattern, request.getRequestURI());
+        String exerciseId = RestUtils.decodeURL(request, pattern);
 
         ExerciseId parsedId;
         try {
@@ -166,7 +169,7 @@ public class ExerciseResource {
                 .build();
         }
 
-        final Optional<SearchResultDTO> result = searchService.findExerciseById(parsedId);
+        final Optional<SearchResultDTO> result = searchService.findExerciseById(parsedId.getProjectId());
 
         if (result.isPresent()) {
             return ResponseEntity.ok().contentType(MediaType.APPLICATION_JSON).body(result.get());
@@ -191,14 +194,24 @@ public class ExerciseResource {
      * However excepted files/folders are omitted, if exercise is publicVisibility
      *
      * @param exerciseId the id of the exercise to get the repos from
+     * @param recursion the recursion depth for the children
      * ResponseEntity with status
      * @throws IOException if something during the zip process went wrong
      */
     @PostMapping("/exerciseFiles/**")
     public ResponseEntity<Resource> exportProgrammingExercise(HttpServletRequest request) throws IOException {
         String pattern = (String) request.getAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE);
-
-        String exerciseId = new AntPathMatcher().extractPathWithinPattern(pattern, request.getRequestURI());
+        String recursionParam = request.getParameter("recursion");
+        ExtractionDepth recursion = ExtractionDepth.JUST_PROJECT;
+        if (!StringUtils.isEmpty(recursionParam)) {
+            try {
+                recursion = ExtractionDepth.valueOf(recursionParam);
+            } catch (IllegalArgumentException e) {
+                log.warn("Cannog parse {}", recursionParam);
+                recursion = ExtractionDepth.JUST_PROJECT;
+            }
+        }
+        String exerciseId = RestUtils.decodeURL(request, pattern);
 
         ExerciseId parsedId;
         try {
@@ -218,7 +231,7 @@ public class ExerciseResource {
                 .build();
         }
 
-        File zipFile = searchService.exportExercise(parsedId);
+        File zipFile = searchService.exportExercise(parsedId, recursion);
         if (zipFile == null) {
             return ResponseEntity
                 .badRequest()
@@ -280,7 +293,7 @@ public class ExerciseResource {
             .ok()
             .contentLength(zipFile.length())
             .contentType(MediaType.APPLICATION_OCTET_STREAM)
-            .header("filename", zipFile.getName())
+            .header("filename", "exercise" + exerciseId, ".zip")
             .body(resource);
     }
 
diff --git a/src/main/java/at/ac/uibk/gitsearch/web/rest/LikesResource.java b/src/main/java/at/ac/uibk/gitsearch/web/rest/LikesResource.java
index 347c57aa4fa0cd5d3b89224d1b31c0c2a76de194..bfb1bf2afd882f02746928d9484250e714f24950 100644
--- a/src/main/java/at/ac/uibk/gitsearch/web/rest/LikesResource.java
+++ b/src/main/java/at/ac/uibk/gitsearch/web/rest/LikesResource.java
@@ -7,6 +7,7 @@ import at.ac.uibk.gitsearch.service.SearchService;
 import at.ac.uibk.gitsearch.service.UserService;
 import at.ac.uibk.gitsearch.service.dto.LikesCriteria;
 import at.ac.uibk.gitsearch.web.rest.errors.BadRequestAlertException;
+import at.ac.uibk.gitsearch.web.rest.utils.RestUtils;
 import java.net.URI;
 import java.net.URISyntaxException;
 import java.time.LocalDate;
@@ -145,7 +146,7 @@ public class LikesResource {
     public ResponseEntity<Void> deleteLikeWithexerciseID(HttpServletRequest request) {
         String pattern = (String) request.getAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE);
 
-        String exerciseID = new AntPathMatcher().extractPathWithinPattern(pattern, request.getRequestURI());
+        String exerciseID = RestUtils.decodeURL(request, pattern);
 
         log.debug("REST request to delete Likes for project : {}", exerciseID);
         likesService.deleteByUserIDandExerciseID(userService.getUserWithAuthorities().get().getId().intValue(), exerciseID);
@@ -159,7 +160,7 @@ public class LikesResource {
     public ResponseEntity<Integer> getNumberOfLikesForExerciseID(HttpServletRequest request) {
         String pattern = (String) request.getAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE);
 
-        String exerciseID = new AntPathMatcher().extractPathWithinPattern(pattern, request.getRequestURI());
+        String exerciseID = RestUtils.decodeURL(request, pattern);
 
         log.debug("REST request to get number of likes for project {}", exerciseID);
         Integer n = likesService.findNumberOfLikesByExerciseID(exerciseID);
@@ -170,7 +171,7 @@ public class LikesResource {
     public ResponseEntity<Boolean> hasLikedProject(HttpServletRequest request) {
         String pattern = (String) request.getAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE);
 
-        String exerciseID = new AntPathMatcher().extractPathWithinPattern(pattern, request.getRequestURI());
+        String exerciseID = RestUtils.decodeURL(request, pattern);
 
         log.debug("REST request to see if user has liked project {}", exerciseID);
         Boolean bool = false;
diff --git a/src/main/java/at/ac/uibk/gitsearch/web/rest/PublicUserResource.java b/src/main/java/at/ac/uibk/gitsearch/web/rest/PublicUserResource.java
index 6ffd9228e81c3a9c1491881067433714574a2371..57514c50f890c7b467769c396e4b1a6fff5c4eef 100644
--- a/src/main/java/at/ac/uibk/gitsearch/web/rest/PublicUserResource.java
+++ b/src/main/java/at/ac/uibk/gitsearch/web/rest/PublicUserResource.java
@@ -1,6 +1,5 @@
 package at.ac.uibk.gitsearch.web.rest;
 
-import at.ac.uibk.gitsearch.config.Constants;
 import at.ac.uibk.gitsearch.repository.search.UserSearchRepository;
 import at.ac.uibk.gitsearch.service.UserService;
 import at.ac.uibk.gitsearch.service.dto.UserDTO;
@@ -9,13 +8,9 @@ import java.util.Collections;
 import java.util.List;
 import java.util.stream.Collectors;
 import java.util.stream.StreamSupport;
-import javax.validation.constraints.NotBlank;
-import javax.validation.constraints.Pattern;
-import javax.validation.constraints.Size;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.data.domain.Page;
-import org.springframework.data.domain.PageImpl;
 import org.springframework.data.domain.Pageable;
 import org.springframework.data.domain.Sort;
 import org.springframework.http.HttpHeaders;
diff --git a/src/main/java/at/ac/uibk/gitsearch/web/rest/SavedSearchesResource.java b/src/main/java/at/ac/uibk/gitsearch/web/rest/SavedSearchesResource.java
index d73c75854a620a52e6b513b635dbfe1980d9829c..3171f4c15669187a663563f069abbbf91b11603c 100644
--- a/src/main/java/at/ac/uibk/gitsearch/web/rest/SavedSearchesResource.java
+++ b/src/main/java/at/ac/uibk/gitsearch/web/rest/SavedSearchesResource.java
@@ -1,7 +1,5 @@
 package at.ac.uibk.gitsearch.web.rest;
 
-import static org.elasticsearch.index.query.QueryBuilders.*;
-
 import at.ac.uibk.gitsearch.repository.SavedSearchesRepository;
 import at.ac.uibk.gitsearch.service.SavedSearchesService;
 import at.ac.uibk.gitsearch.service.dto.SavedSearchesDTO;
@@ -11,7 +9,6 @@ import java.net.URISyntaxException;
 import java.util.List;
 import java.util.Objects;
 import java.util.Optional;
-import java.util.stream.StreamSupport;
 import javax.validation.Valid;
 import javax.validation.constraints.NotNull;
 import org.slf4j.Logger;
@@ -20,9 +17,17 @@ import org.springframework.beans.factory.annotation.Value;
 import org.springframework.data.domain.Page;
 import org.springframework.data.domain.Pageable;
 import org.springframework.http.HttpHeaders;
-import org.springframework.http.HttpStatus;
 import org.springframework.http.ResponseEntity;
-import org.springframework.web.bind.annotation.*;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PatchMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
 import org.springframework.web.servlet.support.ServletUriComponentsBuilder;
 import tech.jhipster.web.util.HeaderUtil;
 import tech.jhipster.web.util.PaginationUtil;
diff --git a/src/main/java/at/ac/uibk/gitsearch/web/rest/StatisticsResource.java b/src/main/java/at/ac/uibk/gitsearch/web/rest/StatisticsResource.java
index 650707ca96ceedb27d635eae2d0bcad5946b0fa4..3ae5411b7118f70555ec998c0a6668ace000cf17 100644
--- a/src/main/java/at/ac/uibk/gitsearch/web/rest/StatisticsResource.java
+++ b/src/main/java/at/ac/uibk/gitsearch/web/rest/StatisticsResource.java
@@ -5,15 +5,14 @@ import at.ac.uibk.gitsearch.service.SearchService;
 import at.ac.uibk.gitsearch.service.StatisticsService;
 import at.ac.uibk.gitsearch.service.dto.StatisticsDTO;
 import at.ac.uibk.gitsearch.web.rest.errors.BadRequestAlertException;
+import at.ac.uibk.gitsearch.web.rest.utils.RestUtils;
 import java.net.URI;
 import java.net.URISyntaxException;
-import java.text.ParseException;
+import java.nio.charset.Charset;
 import java.util.List;
 import java.util.Optional;
-import java.util.regex.Pattern;
 import javax.servlet.http.HttpServletRequest;
 import javax.validation.Valid;
-import org.codeability.sharing.plugins.api.search.util.ExerciseId;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -44,7 +43,7 @@ import tech.jhipster.web.util.ResponseUtil;
 @RequestMapping("/api")
 public class StatisticsResource {
 
-    private final Logger log = LoggerFactory.getLogger(StatisticsResource.class);
+    private static final Logger log = LoggerFactory.getLogger(StatisticsResource.class);
 
     private static final String ENTITY_NAME = "statistics";
 
@@ -143,8 +142,6 @@ public class StatisticsResource {
         return ResponseUtil.wrapOrNotFound(statisticsDTO);
     }
 
-    protected static final Pattern ExerciseIdPattern = Pattern.compile("(\\d+):(.*)");
-
     /*
     getStatisticsByExerciseId is used to match the exerciseId of a Gitlab project with the database object for the statistics
     If a rest request for an exerciseId comes from the client and there is no object with a fitting exerciseId in the DB the server will create a new db entry with number of views
@@ -155,9 +152,10 @@ public class StatisticsResource {
     public ResponseEntity<StatisticsDTO> getStatisticsByExerciseId(HttpServletRequest request) {
         String pattern = (String) request.getAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE);
 
-        String exerciseId = new AntPathMatcher().extractPathWithinPattern(pattern, request.getRequestURI());
+        String exerciseId = RestUtils.decodeURL(request, pattern);
+
+        log.debug("REST request to get exercise Statistics for ExerciseID : {}", exerciseId);
 
-        log.debug("REST request to get Statistics for ExerciseID : {}", exerciseId);
         Optional<StatisticsDTO> statisticsDTO = statisticsService.findOneByExerciseID(exerciseId);
 
         if (statisticsDTO.isPresent()) {
@@ -167,14 +165,9 @@ public class StatisticsResource {
             return ResponseUtil.wrapOrNotFound(Optional.of(newStats));
         }
 
-        ExerciseId parsedId;
-        try {
-            parsedId = ExerciseId.fromString(exerciseId);
-        } catch (ParseException e) {
-            return ResponseUtil.wrapOrNotFound(statisticsDTO);
-        }
-
-        if (searchService.findExerciseById(parsedId).isPresent()) {
+        // TODO there is a race condition, if serveral parallel requests do not find an entry.
+        if (searchService.findExerciseById(exerciseId).isPresent()) {
+        	// the exercise exists in the meta data search index
             StatisticsDTO newStats = new StatisticsDTO();
             newStats.setDownloads(0);
             newStats.setViews(1);
@@ -226,10 +219,10 @@ public class StatisticsResource {
     public ResponseEntity<Integer> getNumberOfWatchListEntriesForExerciseID(HttpServletRequest request) {
         String pattern = (String) request.getAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE);
 
-        String exerciseID = new AntPathMatcher().extractPathWithinPattern(pattern, request.getRequestURI());
+        String exerciseId = RestUtils.decodeURL(request, pattern);
 
-        log.debug("REST request to get number of watchlists for project {}", exerciseID);
-        Integer n = statisticsRepository.findNumberOfWatchListEntriesByExerciseID(exerciseID);
+        log.debug("REST request to get number of watchlists for project {}", exerciseId);
+        Integer n = statisticsRepository.findNumberOfWatchListEntriesByExerciseID(exerciseId);
         return ResponseEntity.ok().body(n);
     }
 }
diff --git a/src/main/java/at/ac/uibk/gitsearch/web/rest/utils/RestUtils.java b/src/main/java/at/ac/uibk/gitsearch/web/rest/utils/RestUtils.java
new file mode 100644
index 0000000000000000000000000000000000000000..ef2ce53c29a50d792a9e050ee870aada0dc45fb7
--- /dev/null
+++ b/src/main/java/at/ac/uibk/gitsearch/web/rest/utils/RestUtils.java
@@ -0,0 +1,26 @@
+package at.ac.uibk.gitsearch.web.rest.utils;
+
+import java.nio.charset.Charset;
+import javax.servlet.http.HttpServletRequest;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.util.AntPathMatcher;
+
+public class RestUtils {
+
+    private static final Logger log = LoggerFactory.getLogger(RestUtils.class);
+
+    private static final Charset UTF_8_CHARSET = Charset.forName("UTF-8");
+
+    public static String decodeURL(HttpServletRequest request, String pattern) {
+        String resultString = new AntPathMatcher().extractPathWithinPattern(pattern, request.getRequestURI());
+
+        // special handling for URL-encoded ids!
+        // better: always encode the string correctly, then the following should be the default
+        if (resultString.contains("%5B")) { // check for encode "["
+            log.debug("we need to decode resultString : {}", resultString);
+            resultString = java.net.URLDecoder.decode(resultString, UTF_8_CHARSET);
+        }
+        return resultString;
+    }
+}
diff --git a/src/main/resources/.h2.server.properties b/src/main/resources/.h2.server.properties
index a13568c06a9ae1a0523b4e9b9c4d83dfdb92f99d..7376460d93a68b25b8f2bab404250e970d30f9aa 100644
--- a/src/main/resources/.h2.server.properties
+++ b/src/main/resources/.h2.server.properties
@@ -1,5 +1,5 @@
 #H2 Server Properties
-#Mon Feb 21 15:53:48 CET 2022
+#Sun Mar 20 17:12:15 CET 2022
 0=JHipster H2 (Disk)|org.h2.Driver|jdbc\:h2\:file\:./target/h2db/db/gitsearch|gitsearch
 webSSL=false
 webAllowOthers=true
diff --git a/src/main/webapp/app/core/auth/account.service.ts b/src/main/webapp/app/core/auth/account.service.ts
index d07388d73a68afad2de85de11d0f32301383e634..bfc65e9712feeb8c1f6d33cf8fa6a6d62f5d48cd 100644
--- a/src/main/webapp/app/core/auth/account.service.ts
+++ b/src/main/webapp/app/core/auth/account.service.ts
@@ -80,6 +80,10 @@ export class AccountService {
     return this.userIdentity && this.userIdentity.imageUrl ? this.userIdentity.imageUrl : '';
   }
 
+  getUserEMail(): string {
+    return this.userIdentity && this.userIdentity.email ? this.userIdentity.email : '';
+  }
+
   private fetch(): Observable<Account> {
     return this.http.get<Account>(this.applicationConfigService.getEndpointFor('api/account'));
   }
diff --git a/src/main/webapp/app/entities/likes/likes.service.ts b/src/main/webapp/app/entities/likes/likes.service.ts
index a630fc4230692360a053b75c9be9b5cb926ec01e..4c26d8591b9d498db8076bf43cf8c74f65922498 100644
--- a/src/main/webapp/app/entities/likes/likes.service.ts
+++ b/src/main/webapp/app/entities/likes/likes.service.ts
@@ -36,7 +36,7 @@ export class LikesService {
 
   find(id: number): Observable<EntityResponseType> {
     return this.http
-      .get<ILikes>(`${this.resourceUrl}/${id}`, { observe: 'response' })
+      .get<ILikes>(`${this.resourceUrl}/${encodeURIComponent(id)}`, { observe: 'response' })
       .pipe(map((res: EntityResponseType) => this.convertDateFromServer(res)));
   }
 
@@ -65,15 +65,15 @@ export class LikesService {
   }
 
   unlikeExercise(exerciseID: string): Observable<HttpResponse<{}>> {
-    return this.http.delete(SERVER_API_URL + 'api/likes/unlikeExercise/' + exerciseID, { observe: 'response' });
+    return this.http.delete(SERVER_API_URL + 'api/likes/unlikeExercise/' + encodeURIComponent(exerciseID), { observe: 'response' });
   }
 
   getLikesForexerciseID(exerciseID: string): Observable<number> {
-    return this.http.get<number>(SERVER_API_URL + 'api/likes/numberOfLikes/' + exerciseID);
+    return this.http.get<number>(SERVER_API_URL + 'api/likes/numberOfLikes/' + encodeURIComponent(exerciseID));
   }
 
   hasLiked(exerciseID: string): Observable<boolean> {
-    return this.http.get<boolean>(SERVER_API_URL + 'api/likes/hasLiked/' + exerciseID);
+    return this.http.get<boolean>(SERVER_API_URL + 'api/likes/hasLiked/' + encodeURIComponent(exerciseID));
   }
 
   protected convertDateFromClient(likes: ILikes): ILikes {
diff --git a/src/main/webapp/app/entities/statistics/statistics.service.ts b/src/main/webapp/app/entities/statistics/statistics.service.ts
index dded10df8a7577d1385060a6aecb2a3195989500..7c5e719da0303282fbc1ae322aa130c0812982a5 100644
--- a/src/main/webapp/app/entities/statistics/statistics.service.ts
+++ b/src/main/webapp/app/entities/statistics/statistics.service.ts
@@ -25,7 +25,7 @@ export class StatisticsService {
   }
 
   find(id: number): Observable<EntityResponseType> {
-    return this.http.get<IStatistics>(`${this.resourceUrl}/${id}`, { observe: 'response' });
+    return this.http.get<IStatistics>(`${this.resourceUrl}/${encodeURIComponent(id)}`, { observe: 'response' });
   }
 
   query(req?: any): Observable<EntityArrayResponseType> {
@@ -34,7 +34,7 @@ export class StatisticsService {
   }
 
   delete(id: number): Observable<HttpResponse<{}>> {
-    return this.http.delete(`${this.resourceUrl}/${id}`, { observe: 'response' });
+    return this.http.delete(`${this.resourceUrl}/${encodeURIComponent(id)}`, { observe: 'response' });
   }
 
   search(req: Search): Observable<EntityArrayResponseType> {
@@ -43,6 +43,6 @@ export class StatisticsService {
   }
 
   getNumberOfWatchListEntriesForExerciseID(exerciseID: string): Observable<number> {
-    return this.http.get<number>(SERVER_API_URL + 'api/statistics/numberOfWatchlistEntries/' + exerciseID);
+    return this.http.get<number>(SERVER_API_URL + 'api/statistics/numberOfWatchlistEntries/' + encodeURIComponent(exerciseID));
   }
 }
diff --git a/src/main/webapp/app/exercise/exercise-details/exercise-details.component.html b/src/main/webapp/app/exercise/exercise-details/exercise-details.component.html
index fb7129d696a4cd00665d85166e2807ba9efbc8ba..fac0ca9a644cd8e6da4da0dbaa57c23035d33bca 100644
--- a/src/main/webapp/app/exercise/exercise-details/exercise-details.component.html
+++ b/src/main/webapp/app/exercise/exercise-details/exercise-details.component.html
@@ -200,6 +200,31 @@
               <div class="col-12">
                 <p style="text-align: left; margin-top: 20px"><strong jhiTranslate="exercise.export.export"></strong></p>
                 <hr />
+                <table>
+                  <tr>
+                    <td>
+                      <a
+                        class="btn btn-outline-secondary"
+                        role="button"
+                        aria-pressed="true"
+                        style="float: left; margin-right: 5px; margin-top: 5px"
+                        (click)="download()"
+                        jhiTranslate="exercise.export.download"
+                      ></a>
+                    </td>
+                    <td style="vertical-align: middle">
+                      <input
+                        type="checkbox"
+                        [checked]="downloadWithChildren"
+                        (change)="toggleWithChildren()"
+                        value=""
+                        value=""
+                        id="withChildren"
+                      />
+                      <label class="form-check-label" for="withChildren" jhiTranslate="exercise.details.withChildren"></label>
+                    </td>
+                  </tr>
+                </table>
                 <a
                   *ngFor="let action of exercise.originalResult.supportedActions"
                   class="btn btn-outline-secondary positionAction"
@@ -218,14 +243,6 @@
                     disabled
                   ></button>
                 </div>
-
-                <a
-                  class="btn btn-outline-secondary positionAction"
-                  role="button"
-                  aria-pressed="true"
-                  (click)="download()"
-                  jhiTranslate="exercise.export.download"
-                ></a>
               </div>
             </div>
           </div>
diff --git a/src/main/webapp/app/exercise/exercise-details/exercise-details.component.ts b/src/main/webapp/app/exercise/exercise-details/exercise-details.component.ts
index f8a29a1e718e329de864504836345e0e95f937b3..a4e59e2b69824ac22f197eb483b4a3bf9592bc1f 100644
--- a/src/main/webapp/app/exercise/exercise-details/exercise-details.component.ts
+++ b/src/main/webapp/app/exercise/exercise-details/exercise-details.component.ts
@@ -9,11 +9,13 @@ import { ExerciseService } from 'app/exercise/service/exercise.service';
 import { SearchService } from 'app/search/service/search-service';
 import { ShoppingBasketInfo, ShoppingBasketRedirectInfoDTO } from 'app/shared/model/basket/shopping-basket-info.model';
 import { Exercise, searchResultToExercise } from 'app/shared/model/exercise.model';
+import { Person } from 'app/shared/model/person.model';
 import { PluginActionInfo } from 'app/shared/model/search/search-result-dto.model';
 import { PluginService } from 'app/shared/service/plugin-service';
 import { WatchlistManager } from 'app/shared/watchlist/watchlist-manager';
 import { AlertService } from 'app/core/util/alert.service';
 import { Subscription } from 'rxjs';
+import { ApplicationInfoService } from 'app/core/application/applicationInfo.service';
 
 @Component({
   selector: 'jhi-exercise-details',
@@ -31,7 +33,10 @@ export class ExerciseDetailsComponent implements OnInit, OnDestroy {
   hasLiked: Boolean | null = null;
   likeSubscription?: Subscription;
   authenticated = false;
+  downloadWithChildren = false;
   treeIcon = faFolder;
+  oerLink?: String;
+  oerExerciseMatch = new RegExp('/([a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12})$');
 
   constructor(
     private accountService: AccountService,
@@ -41,11 +46,20 @@ export class ExerciseDetailsComponent implements OnInit, OnDestroy {
     private jhiAlertService: AlertService,
     private watchlistManager: WatchlistManager,
     private exerciseService: ExerciseService,
+    private applicationInfoService: ApplicationInfoService,
     private router: Router
   ) {}
 
   ngOnInit(): void {
     this.authSubscription = this.accountService.getAuthenticationState().subscribe(account => (this.account = account));
+    this.applicationInfoService.loadOerLink().subscribe(
+      (res: string) => {
+        this.oerLink = res;
+      },
+      error =>
+        // eslint-disable-next-line no-console
+        console.error(error)
+    );
   }
 
   public isAuthenticated(): boolean {
@@ -81,12 +95,50 @@ export class ExerciseDetailsComponent implements OnInit, OnDestroy {
     );
   }
 
+  public isEditable(): boolean {
+    if (!this.exercise) return false;
+    if (!this.exercise.gitlabURL) return false;
+    const matchGroups = this.exercise.gitlabURL.match(this.oerExerciseMatch);
+    if (!matchGroups) return false;
+
+    // Just for Testing: allow every edit
+    if (this.oerLink) return true;
+
+    const email = this.accountService.getUserEMail();
+    if (!email || email == '') return false;
+
+    // test all: creator, publisher
+    let potentialEditors: Person[] = [];
+
+    // potentialEditors.concat(this.exercise.contributor);
+    potentialEditors = potentialEditors.concat(this.exercise.creator);
+    potentialEditors = potentialEditors.concat(this.exercise.publisher);
+
+    for (let i = 0; i < potentialEditors.length; i++) {
+      if (potentialEditors[i].email.localeCompare(email, undefined, { sensitivity: 'base' }) === 0) return true;
+    }
+    return false;
+  }
+
+  public getOEResourceLink(): string {
+    if (this.oerLink) {
+      const matchGroups = this.exercise!.gitlabURL.match(this.oerExerciseMatch);
+      if (!matchGroups) return '';
+
+      const guid = matchGroups[1];
+
+      return this.oerLink.toString() + '/en/update/1/' + guid;
+    }
+    return '';
+  }
+
   public download(): void {
     this.exportProject(this.exercise!.originalResult.exerciseId);
   }
 
   exportProject(exerciseId: string) {
-    return this.searchService.exportProject(exerciseId).subscribe(
+    const recursion = this.downloadWithChildren ? 'WITH_DESCENDANTS' : 'JUST_PROJECT';
+    return this.searchService.exportProject(exerciseId, recursion).subscribe(
       (response: HttpResponse<Blob>) => {
         this.jhiAlertService.addAlert({ type: 'success', translationKey: 'artemisApp.programmingExercise.export.successMessage' });
         // success('artemisApp.programmingExercise.export.successMessage');
@@ -182,6 +234,9 @@ export class ExerciseDetailsComponent implements OnInit, OnDestroy {
     console.log(`Reloaded number of likes is ${this.exercise!.numberOfLikes}`);
   }
 
+  toggleWithChildren() {
+    this.downloadWithChildren = !this.downloadWithChildren;
+  }
   selectREADME(): void {
     this.markDownExercise = this.exercise;
   }
diff --git a/src/main/webapp/app/exercise/exercise-details/exercise-metadata/exercise-metadata.component.html b/src/main/webapp/app/exercise/exercise-details/exercise-metadata/exercise-metadata.component.html
index 7bfc4827280eee0b9275b4d0bac765935aab0f8e..aa9bfabedb90fed3b1d8fa3aca98622436930992 100644
--- a/src/main/webapp/app/exercise/exercise-details/exercise-metadata/exercise-metadata.component.html
+++ b/src/main/webapp/app/exercise/exercise-details/exercise-metadata/exercise-metadata.component.html
@@ -113,6 +113,8 @@
   </jhi-exercise-metadata-item>
 
   <jhi-exercise-metadata-item [description]="'exercise.metadata.identifier'" [value]="exercise.identifier"> </jhi-exercise-metadata-item>
+  <jhi-exercise-metadata-item [description]="'exercise.metadata.internalIdentifier'" [value]="exercise.originalResult.exerciseId">
+  </jhi-exercise-metadata-item>
 
   <jhi-exercise-metadata-item [description]="'exercise.metadata.interactivityType'" [value]="exercise.interactivityType">
   </jhi-exercise-metadata-item>
diff --git a/src/main/webapp/app/exercise/service/exercise.service.ts b/src/main/webapp/app/exercise/service/exercise.service.ts
index 52afc9e7c675ee4ec4938b3a57d38533eb4e3a73..5d0e70ff3555d583f5dc5eddd1119f2e1cb93c9f 100644
--- a/src/main/webapp/app/exercise/service/exercise.service.ts
+++ b/src/main/webapp/app/exercise/service/exercise.service.ts
@@ -28,7 +28,7 @@ export class ExerciseService {
     const options: HttpParams = new HttpParams();
     options.append('filePath', filePath);
 
-    return this.http.get<string>(this.resourceUrl + exerciseId, {
+    return this.http.get<string>(this.resourceUrl + encodeURIComponent(exerciseId), {
       headers,
       params: new HttpParams().set('filePath', filePath),
       responseType: 'text' as 'json',
@@ -36,7 +36,7 @@ export class ExerciseService {
   }
 
   public loadExercise(exerciseId: string): Observable<SearchResultDTO> {
-    return this.http.get<SearchResultDTO>(this.exerciseUrl + exerciseId);
+    return this.http.get<SearchResultDTO>(this.exerciseUrl + encodeURIComponent(exerciseId));
   }
 
   populateExerciseWithData(exercise: Exercise): Exercise {
@@ -82,7 +82,9 @@ export class ExerciseService {
    * @param exerciseUrl
    */
   public importExerciseInfoFromArtemis(exerciseToken: string): Observable<ArtemisExerciseInfo> {
-    return this.http.get<ArtemisExerciseInfo>(`${this.exerciseUrl}imported-exercise-info/${exerciseToken}`);
+    return this.http.get<ArtemisExerciseInfo>(
+      `${encodeURIComponent(this.exerciseUrl)}imported-exercise-info/${encodeURIComponent(exerciseToken)}`
+    );
   }
 
   /**
diff --git a/src/main/webapp/app/layouts/main/main.component.spec.ts b/src/main/webapp/app/layouts/main/main.component.spec.ts
index a57d3aa928a7afbf4e7024fac89edced574e6960..c8a59a4929261ac0c6b83d435e550766a443f1f0 100644
--- a/src/main/webapp/app/layouts/main/main.component.spec.ts
+++ b/src/main/webapp/app/layouts/main/main.component.spec.ts
@@ -49,6 +49,7 @@ describe('MainComponent', () => {
     comp = fixture.componentInstance;
     titleService = TestBed.inject(Title);
     translateService = TestBed.inject(TranslateService);
+    // eslint-disable-next-line @typescript-eslint/no-unused-vars
     authService = TestBed.inject(AuthServerProvider);
     mockAccountService = TestBed.inject(AccountService);
     mockAccountService.identity = jest.fn(() => of(null));
diff --git a/src/main/webapp/app/layouts/navbar/navbar.component.scss b/src/main/webapp/app/layouts/navbar/navbar.component.scss
index 28170730b241fee9eb35507c0e21b52410bd54a5..ab6a9283336fe830a04be7e442b726092f0d8d20 100644
--- a/src/main/webapp/app/layouts/navbar/navbar.component.scss
+++ b/src/main/webapp/app/layouts/navbar/navbar.component.scss
@@ -7,3 +7,8 @@
     justify-content: flex-start;
   }
 }
+
+.profile-image {
+  height: 1.75em;
+  width: 1.75em;
+}
diff --git a/src/main/webapp/app/search/service/search-service.ts b/src/main/webapp/app/search/service/search-service.ts
index 61e58a16b97d9c1c46317753b76b84167e30ceec..73963beb3a36e8e7304742dfba5bb4bd82320e9d 100644
--- a/src/main/webapp/app/search/service/search-service.ts
+++ b/src/main/webapp/app/search/service/search-service.ts
@@ -30,7 +30,7 @@ export class SearchService {
   }
 
   getStatisticsForExercise(exerciseID: string): Observable<Statistics> {
-    return this.http.get<Statistics>(this.resourceSearchUrlStatisticsForExercise + exerciseID);
+    return this.http.get<Statistics>(this.resourceSearchUrlStatisticsForExercise + encodeURIComponent(exerciseID));
   }
 
   getStatisticsForUser(): Observable<Statistics> {
@@ -42,11 +42,17 @@ export class SearchService {
    * The file will contain all files as well as the exercise text and further metadata, except for protected files/forlder
    * @param exerciseId
    */
-  exportProject(exerciseId: string): Observable<HttpResponse<Blob>> {
-    return this.http.post(this.applicationConfigService.getEndpointFor('/api/exerciseFiles/') + `${exerciseId}`, '', {
-      observe: 'response',
-      responseType: 'blob',
-    });
+  exportProject(exerciseId: string, recursion: string): Observable<HttpResponse<Blob>> {
+    const parameters = new HttpParams().set('recursion', recursion);
+    return this.http.post(
+      this.applicationConfigService.getEndpointFor('/api/exerciseFiles/') + encodeURIComponent(exerciseId) + '?recursion=' + recursion,
+      '',
+      {
+        params: parameters,
+        observe: 'response',
+        responseType: 'blob',
+      }
+    );
   }
 
   /** 
diff --git a/src/main/webapp/app/teaserContent/teaserContent.component.scss b/src/main/webapp/app/teaserContent/teaserContent.component.scss
index a2acaf768f93c56a9b6574c9259127a0ab7c1b08..9139e2763f25451073d648becdb8465752215a01 100644
--- a/src/main/webapp/app/teaserContent/teaserContent.component.scss
+++ b/src/main/webapp/app/teaserContent/teaserContent.component.scss
@@ -1,12 +1,12 @@
-angular-tag-cloud span {
+angular-tag-cloud.teaserCloud span {
   cursor: pointer;
 }
 
 /* fonts */
 
-div.ng-tag-cloud {
+angular-tag-cloud.teaserCloud {
   font-family: 'Helvetica', 'Arial', sans-serif;
-  font-size: 10px;
+  font-size: 35%;
   line-height: normal;
 }
 
diff --git a/src/main/webapp/content/scss/navbar.scss b/src/main/webapp/content/scss/navbar.scss
index b053644124ccb8c6014e28ae30465a15a0f5a6b3..42d860326c9294e64f8612a6ffd73f0e2468b339 100644
--- a/src/main/webapp/content/scss/navbar.scss
+++ b/src/main/webapp/content/scss/navbar.scss
@@ -1,6 +1,5 @@
 * {
   box-sizing: border-box;
-  font-family: Open Sans;
 }
 
 .pagewrapper {
@@ -177,7 +176,7 @@ svg {
 }
 
 .nav-item {
-  padding-right: 50px;
+  padding-right: 25px;
 }
 
 .logo-footer {
diff --git a/src/main/webapp/i18n/de/exercise.json b/src/main/webapp/i18n/de/exercise.json
index fe457c895fb0ced92b3c7d47d01bd21ef29785f5..7f2372a934896e3a62bf496ee09b0bd26d38bb37 100644
--- a/src/main/webapp/i18n/de/exercise.json
+++ b/src/main/webapp/i18n/de/exercise.json
@@ -5,9 +5,11 @@
       "details": "Details",
       "rating": "Trefferqualität",
       "bookmark": "Merken",
+      "withChildren": "mit Unteraufgaben",
       "hitDetails": "Suchergebnis Details",
       "allExercises": "Alle Aufgaben für diesen Kurs anzeigen",
       "git": "In GitLab öffnen",
+      "editOEResource": "In OEResource bearbeiten",
       "views": "Anzahl der Aufrufe",
       "downloads": "Anzahl der Downloads",
       "readmeNotFound": "# Keine README.md Datei (oder Alternative) gefunden!",
@@ -105,8 +107,7 @@
       "OTHER": "Andere",
       "structure": "Struktur",
       "atomic": "Atomar",
-      "learningResourceType": "Lernressourcen Typ",
-      "identifier": "Identifikator",
+      "internalIdentifier": "interner Schlüssel",
       "source": "Quelle",
       "networked": "Vernetzt",
       "hierarchical": "Hierarchisch",
diff --git a/src/main/webapp/i18n/en/exercise.json b/src/main/webapp/i18n/en/exercise.json
index 450a800c8764dc7495b16f61f5b0623b4b6468d0..d9d77b3dc5e13c780d23cdcad92c9d3c2fa9f9da 100644
--- a/src/main/webapp/i18n/en/exercise.json
+++ b/src/main/webapp/i18n/en/exercise.json
@@ -5,9 +5,11 @@
       "details": "Details",
       "rating": "Hit quality",
       "bookmark": "Bookmark",
+      "withChildren": "with children",
       "hitDetails": "Show hit details",
       "allExercises": "Show all exercises for this course",
       "git": "Open in GitLab",
+      "editOEResource": "Edit in OEResource",
       "views": "Number of views",
       "downloads": "Number of downloads",
       "readmeNotFound": "# No README.md (or alternatives) found!",
@@ -105,8 +107,7 @@
       "OTHER": "Other",
       "structure": "Structure",
       "atomic": "Atomic",
-      "learningResourceType": "Learning Resource Type",
-      "identifier": "Identifier",
+      "internalIdentifier": "internal Identifier",
       "source": "Source",
       "networked": "Networked",
       "hierarchical": "Hierarchical",
diff --git a/src/test/java/at/ac/uibk/gitsearch/domain/ExerciseIdTest.java b/src/test/java/at/ac/uibk/gitsearch/domain/ExerciseIdTest.java
deleted file mode 100644
index ebba2facadd6bcc620e14b919f443798dfb1f5ed..0000000000000000000000000000000000000000
--- a/src/test/java/at/ac/uibk/gitsearch/domain/ExerciseIdTest.java
+++ /dev/null
@@ -1,32 +0,0 @@
-package at.ac.uibk.gitsearch.domain;
-
-import java.text.ParseException;
-import org.codeability.sharing.plugins.api.search.util.ExerciseId;
-import org.junit.Assert;
-import org.junit.jupiter.api.Assertions;
-import org.junit.jupiter.api.Test;
-import org.junit.jupiter.params.ParameterizedTest;
-import org.junit.jupiter.params.provider.ValueSource;
-
-public class ExerciseIdTest {
-
-    @ParameterizedTest
-    @ValueSource(strings = { "3", "3:path", "3:path1/path2" })
-    public void parseVariousIds(String externalRepresentation) throws ParseException {
-        Assert.assertEquals(externalRepresentation, ExerciseId.fromString(externalRepresentation).toString());
-    }
-
-    @Test
-    public void parseIdsWithTrailingSlashes() throws ParseException {
-        Assert.assertEquals("30:abc", ExerciseId.fromString("30:/abc").toString());
-        Assert.assertEquals("30:abc", ExerciseId.fromString("30://abc").toString());
-        Assert.assertEquals("30", ExerciseId.fromString("30://").toString());
-        Assert.assertEquals("30:abc/def", ExerciseId.fromString("30:/abc/def").toString());
-    }
-
-    @ParameterizedTest
-    @ValueSource(strings = { "=", ":path", "3x2", "3x2:/asd", "asdf=asd:30" })
-    public void parseCorruptIds(String corruptIds) throws ParseException {
-        Assertions.assertThrows(ParseException.class, () -> ExerciseId.fromString(corruptIds));
-    }
-}
diff --git a/src/test/java/at/ac/uibk/gitsearch/repository/gitlab/testProject1/metadata.yaml b/src/test/java/at/ac/uibk/gitsearch/repository/gitlab/testProject1/metadata.yaml
index 5dca0ff03b4b00068aeef2fb2210417e219a7db5..68c7253bbd544633580a675d4911ed2760dbf076 100644
--- a/src/test/java/at/ac/uibk/gitsearch/repository/gitlab/testProject1/metadata.yaml
+++ b/src/test/java/at/ac/uibk/gitsearch/repository/gitlab/testProject1/metadata.yaml
@@ -1,21 +1,21 @@
-metadataVersion: "0.4"
-learningResourceType: "exercise"
+metadataVersion: '0.4'
+learningResourceType: 'exercise'
 language: [de]
 identifier: BlackBoxTexting
 structure: atomic # one from atomic, networked, hierarchical, linear
-version: "1.0.0" # just a version tag
-title: "Metatest ${title}" 
-format: 
- - pdf
-description: "Die Studierenden sollen für eine textuell beschriebene Lagerverwaltung Testfälle anhand der Grenzwertanalyse entwickeln."
+version: '1.0.0' # just a version tag
+title: 'Metatest ${title}'
+format:
+  - pdf
+description: 'Die Studierenden sollen für eine textuell beschriebene Lagerverwaltung Testfälle anhand der Grenzwertanalyse entwickeln.'
 status: final # one fo draft, final, revised, unavalable
-keyword: ["MetaTest", "Testen", "Black Box Testing", "{keyword}"]
+keyword: ['MetaTest', 'Testen', 'Black Box Testing', '{keyword}']
 license: CC-SA-BY 4.0
-creator: 
- - {name: "Ruth Breu", affiliation: "Universität Innsbruck", email: "ruth.breu@uibk.ac.at"}
+creator:
+  - { name: 'Ruth Breu', affiliation: 'Universität Innsbruck', email: 'ruth.breu@uibk.ac.at' }
 publisher:
- - {name: "Michael Breu", affiliation: "Universität Innsbruck", email: "michael.breu@uibk.ac.at"}
-audience: "Anfänger"
+  - { name: 'Michael Breu', affiliation: 'Universität Innsbruck', email: 'michael.breu@uibk.ac.at' }
+audience: 'Anfänger'
 difficulty: medium
 requires: [UML]
 image: UMLModelling.png
diff --git a/src/test/java/at/ac/uibk/gitsearch/repository/search/MetaDataRepositoryIT.java b/src/test/java/at/ac/uibk/gitsearch/repository/search/MetaDataRepositoryIT.java
index 9958cb5f81300cb22f8338dc127b684960ba707b..2cbc980aeb2eeadb54d2dbb399d790e2a10dbe7c 100644
--- a/src/test/java/at/ac/uibk/gitsearch/repository/search/MetaDataRepositoryIT.java
+++ b/src/test/java/at/ac/uibk/gitsearch/repository/search/MetaDataRepositoryIT.java
@@ -82,6 +82,7 @@ public class MetaDataRepositoryIT {
     @Test
     public void testContributorAutocompletion() throws IOException {
         final List<AutoCompleteEntry> contributorAutoComplete = metaDataRepository.getContributorAutoComplete("Bast", 10);
+        LOGGER.debug(contributorAutoComplete.toString());
         MatcherAssert.assertThat(contributorAutoComplete, contains(hasProperty("target", is("Daniel Bastta"))));
     }
 
diff --git a/src/test/java/at/ac/uibk/gitsearch/service/mapper/SavedSearchesMapperTest.java b/src/test/java/at/ac/uibk/gitsearch/service/mapper/SavedSearchesMapperTest.java
index 6f8feb9b35b71ff17eefd782fc64a54773ec3a0a..76b689d580d4685c8492233e12f6d393a9e89342 100644
--- a/src/test/java/at/ac/uibk/gitsearch/service/mapper/SavedSearchesMapperTest.java
+++ b/src/test/java/at/ac/uibk/gitsearch/service/mapper/SavedSearchesMapperTest.java
@@ -1,12 +1,10 @@
 package at.ac.uibk.gitsearch.service.mapper;
 
-import static org.assertj.core.api.Assertions.assertThat;
-
 import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
 
 class SavedSearchesMapperTest {
 
+    @SuppressWarnings("unused")
     private SavedSearchesMapper savedSearchesMapper;
 
     @BeforeEach
diff --git a/src/test/java/at/ac/uibk/gitsearch/web/rest/LikesResourceIT.java b/src/test/java/at/ac/uibk/gitsearch/web/rest/LikesResourceIT.java
index 29c7a488661799b6a11cdfcdddaa5493e2d1094c..d0f36619dd1a3a108b377bce3713ed356af62fc6 100644
--- a/src/test/java/at/ac/uibk/gitsearch/web/rest/LikesResourceIT.java
+++ b/src/test/java/at/ac/uibk/gitsearch/web/rest/LikesResourceIT.java
@@ -282,6 +282,7 @@ public class LikesResourceIT {
     @Test
     @Transactional
     public void testLikeWorkflowWithAuthorities() throws Exception {
+        @SuppressWarnings("unused")
         List<User> userList = userRepo.findAll();
         // Initialize the database
         likesRepository.saveAndFlush(likes);
diff --git a/src/test/javascript/e2e/entities/saved-searches/saved-searches.spec.ts b/src/test/javascript/e2e/entities/saved-searches/saved-searches.spec.ts
index 6ba2a7579663662ecd02583f6d0a88ec983c5526..e597296df4a9b7667471b313f08386a788aa7a43 100644
--- a/src/test/javascript/e2e/entities/saved-searches/saved-searches.spec.ts
+++ b/src/test/javascript/e2e/entities/saved-searches/saved-searches.spec.ts
@@ -15,7 +15,9 @@ describe('SavedSearches e2e test', () => {
   let savedSearchesComponentsPage: SavedSearchesComponentsPage;
   let savedSearchesUpdatePage: SavedSearchesUpdatePage;
   /* let savedSearchesDeleteDialog: SavedSearchesDeleteDialog; */
+  // eslint-disable-next-line @typescript-eslint/no-unused-vars
   const username = process.env.E2E_USERNAME ?? 'admin';
+  // eslint-disable-next-line @typescript-eslint/no-unused-vars
   const password = process.env.E2E_PASSWORD ?? 'admin';
 
   before(async () => {
diff --git a/src/test/javascript/e2e/page-objects/jhi-page-objects.ts b/src/test/javascript/e2e/page-objects/jhi-page-objects.ts
index 27b384727a9efc92cb76a187049ba6450a878d4f..49440378226e817a4d3be1983e9aab965c94e76d 100644
--- a/src/test/javascript/e2e/page-objects/jhi-page-objects.ts
+++ b/src/test/javascript/e2e/page-objects/jhi-page-objects.ts
@@ -1,3 +1,4 @@
+// eslint-disable-next-line @typescript-eslint/no-unused-vars
 import { element, by, ElementFinder, browser } from 'protractor';
 /* eslint @typescript-eslint/no-use-before-define: 0 */
 export class NavBarPage {
diff --git a/src/test/javascript/e2e/search/search.spec.ts b/src/test/javascript/e2e/search/search.spec.ts
index e68efc68c912903f37c1a146b58c89d05f59e4c9..7e8c57b25e220c272a6b92cff33809cc93047fcd 100644
--- a/src/test/javascript/e2e/search/search.spec.ts
+++ b/src/test/javascript/e2e/search/search.spec.ts
@@ -1,5 +1,6 @@
 import { browser, element, by, ExpectedConditions as ec } from 'protractor';
 
+// eslint-disable-next-line @typescript-eslint/no-unused-vars
 import { NavBarPage, SignInPage, PasswordPage, SettingsPage } from '../page-objects/jhi-page-objects';
 
 const expect = chai.expect;
diff --git a/src/test/resources/at/ac/uibk/gitsearch/service/testData/metaData/1/metaData.yaml b/src/test/resources/at/ac/uibk/gitsearch/service/testData/metaData/1/metaData.yaml
index 3963136edc269f99bedadfe18c3357fd360e9315..35b448540145fd0344ecb4729c9c7c03a4eeff44 100644
--- a/src/test/resources/at/ac/uibk/gitsearch/service/testData/metaData/1/metaData.yaml
+++ b/src/test/resources/at/ac/uibk/gitsearch/service/testData/metaData/1/metaData.yaml
@@ -3,7 +3,7 @@ learningResourceType: programming exercise
 # format (not used here)
 identifier: collection1
 structure: atomic # one from atomic, networked, hierarchical, linear
-version: "1.0" # just a version tag
+version: '1.0' # just a version tag
 status: final # one fo draft, final, revised, unavailable
 title: Simple IO Test
 description: This is a programming exercise to demonstrate a simple IO testing framework.
@@ -13,12 +13,12 @@ language: [de]
 timeRequired: 0:05:00 # [hh:mm:ss]
 keyword: [Java, IOTest, artemis]
 license: CC-SA-BY 4.0 # mandatory
-creator: 
-  - {name: "Breu Michael", affiliation: "University of Innsbruck", email: "c703257@uibk.ac.at"}
+creator:
+  - { name: 'Breu Michael', affiliation: 'University of Innsbruck', email: 'c703257@uibk.ac.at' }
 publisher:
-  - {name: "Breu Michael", affiliation: "University of Innsbruck", email: "c703257@uibk.ac.at"}
+  - { name: 'Breu Michael', affiliation: 'University of Innsbruck', email: 'c703257@uibk.ac.at' }
 difficulty: simple
 contributor:
-  - {name: "Manuel Seywald", affiliation: "University of Klagenfurt", email: "maseywald@edu.aau.at"}
-requires: []  # empty, t.b.d. later
+  - { name: 'Manuel Seywald', affiliation: 'University of Klagenfurt', email: 'maseywald@edu.aau.at' }
+requires: [] # empty, t.b.d. later
 image: 'https://sharing-codeability.uibk.ac.at/static/CodeAbility%20Austria-Dateien/Partner_UIBK.png'
diff --git a/src/test/resources/at/ac/uibk/gitsearch/service/testData/metaData/1/project.yaml b/src/test/resources/at/ac/uibk/gitsearch/service/testData/metaData/1/project.yaml
index 8868a74f21a113a04efd9cc605cf7d88f5577462..ea1d730c89e72766ee42cba2b1de3d619c211320 100644
--- a/src/test/resources/at/ac/uibk/gitsearch/service/testData/metaData/1/project.yaml
+++ b/src/test/resources/at/ac/uibk/gitsearch/service/testData/metaData/1/project.yaml
@@ -3,13 +3,8 @@ project_name: es test
 namespace: sharing/vienna-universityof-technology/latex
 main_group: sharing
 sub_group: vienna-universityof-technology
-groups: [
-              "sharing/health-check-tests/collection_tests",
-              "sharing/health-check-tests",
-              "teacher",
-              "teacher/unauthenticatedteachers",
-              "sharing"
-            ]
+groups:
+  ['sharing/health-check-tests/collection_tests', 'sharing/health-check-tests', 'teacher', 'teacher/unauthenticatedteachers', 'sharing']
 url: https://sharing.codeability-austria.uibk.ac.at/sharing/vienna-universityof-technology/latex
 visibility: public
 archived: false
@@ -17,4 +12,4 @@ star_count: 0
 open_issues_count: 0
 forks_count: 1
 last_activity_at: 2021-02-17T15:13:27.123Z
-description: 
+description:
diff --git a/src/test/resources/at/ac/uibk/gitsearch/service/testData/metaData/143/metaData.yaml b/src/test/resources/at/ac/uibk/gitsearch/service/testData/metaData/143/metaData.yaml
index 31a0c6b1422dfe80e1a8cff6099db0a1159a57ef..474e3b2e366560868a4ea08b5e2d7d8fa6b769fb 100644
--- a/src/test/resources/at/ac/uibk/gitsearch/service/testData/metaData/143/metaData.yaml
+++ b/src/test/resources/at/ac/uibk/gitsearch/service/testData/metaData/143/metaData.yaml
@@ -1,30 +1,30 @@
-metadataVersion: "0.4"
+metadataVersion: '0.4'
 learningResourceType: collection
-collectionContent: 
+collectionContent:
   - src/if-001/if-001.yml
   - src/if-002/if-002.yml
   - src/if-003/if-003.yml
 identifier: javaCourseTUWienTest
 structure: hierarchical # one from atomic, networked, hierarchical, linear
-version: "1.0" # just a version tag
+version: '1.0' # just a version tag
 status: final # one fo draft, final, revised, unavalable
 title: Meta Test Data 76
-description: "Dies sind Teile des Einführungskurses an der TU Wien. 
-   Momentan hier genutzt zum Testen der Metadateninfrastruktur. Version 1.xxx
-   3. Zeile"
-programmingLanguage: 
+description: 'Dies sind Teile des Einführungskurses an der TU Wien.
+  Momentan hier genutzt zum Testen der Metadateninfrastruktur. Version 1.xxx
+  3. Zeile'
+programmingLanguage:
   - JAVA
 language: [de]
 keyword: [Java, IOTest, latex, testing76]
 license: MIT # mandatory
-creator: 
-  - {name: "Stefan Podlipnig", affiliation: "TU Wien", email: "stefan.podlipnig@tuwien.ac.at"}
+creator:
+  - { name: 'Stefan Podlipnig', affiliation: 'TU Wien', email: 'stefan.podlipnig@tuwien.ac.at' }
 contributor:
-  - {name: "Daniel Bastta", affiliation: "TU Wien", email: "daniel.bastta@tuwien.ac.at"}
-  - {name: "Andreas Merckel", affiliation: "TU Wien", email: "andreas.merkel@tuwien.ac.at"}
-  - {name: "Kerstin Limbeck", affiliation: "TU Wien", email: "kerstin.limbeck@tuwien.ac.at"}
+  - { name: 'Daniel Bastta', affiliation: 'TU Wien', email: 'daniel.bastta@tuwien.ac.at' }
+  - { name: 'Andreas Merckel', affiliation: 'TU Wien', email: 'andreas.merkel@tuwien.ac.at' }
+  - { name: 'Kerstin Limbeck', affiliation: 'TU Wien', email: 'kerstin.limbeck@tuwien.ac.at' }
 publisher:
-  - {name: "Andreas Merckel", affiliation: "TU Wien", email: "andreas.merkel@tuwien.ac.at"}
+  - { name: 'Andreas Merckel', affiliation: 'TU Wien', email: 'andreas.merkel@tuwien.ac.at' }
 
 format: [latex]
 difficulty: simple
diff --git a/src/test/resources/at/ac/uibk/gitsearch/service/testData/metaData/143/project.yaml b/src/test/resources/at/ac/uibk/gitsearch/service/testData/metaData/143/project.yaml
index c575ad1d5cd884e469c87fe5dca949ae43101b98..8e6d3e1fe58c8b0385929eacb4f612a05f957cbf 100644
--- a/src/test/resources/at/ac/uibk/gitsearch/service/testData/metaData/143/project.yaml
+++ b/src/test/resources/at/ac/uibk/gitsearch/service/testData/metaData/143/project.yaml
@@ -3,13 +3,8 @@ project_name: apiTest_76_1613574806194
 namespace: sharing/health-check-tests/apiTest_76_1613574806194
 main_group: sharing
 sub_group: health-check-tests
-groups: [
-              "sharing/health-check-tests/collection_tests",
-              "sharing/health-check-tests",
-              "teacher",
-              "teacher/unauthenticatedteachers",
-              "sharing"
-            ]
+groups:
+  ['sharing/health-check-tests/collection_tests', 'sharing/health-check-tests', 'teacher', 'teacher/unauthenticatedteachers', 'sharing']
 url: https://sharing.codeability-austria.uibk.ac.at/sharing/health-check-tests/apitest_76_1613574806194/
 visibility: public
 archived: false
diff --git a/src/test/resources/at/ac/uibk/gitsearch/service/testData/metaData/2/metaData.yaml b/src/test/resources/at/ac/uibk/gitsearch/service/testData/metaData/2/metaData.yaml
index 768180a878028e9280f7faf7b2bd574ac6670cf7..e8102f2695e41333835ef5baaf5d3595e4c1ab1e 100644
--- a/src/test/resources/at/ac/uibk/gitsearch/service/testData/metaData/2/metaData.yaml
+++ b/src/test/resources/at/ac/uibk/gitsearch/service/testData/metaData/2/metaData.yaml
@@ -1,24 +1,24 @@
-metadataVersion: "0.4"
+metadataVersion: '0.4'
 learningResourceType: collection
 identifier: javaCourseTUWienTest
 structure: hierarchical # one from atomic, networked, hierarchical, linear
-version: "1.0" # just a version tag
+version: '1.0' # just a version tag
 status: final # one fo draft, final, revised, unavalable
 title: Java Einführungskurs der TU Wien (Test)
 description: Dies sind Teile des Einfhrungskurses an der TU Wien. Momentan hier genutzt zum Testen der Metadateninfrastruktur.
-programmingLanguage: 
+programmingLanguage:
   - JAVA
 language: [de]
 keyword: [Java, IOTest, latex]
 license: MIT # mandatory
-creator: 
-  - {name: "Stefan Podlipnig", affiliation: "TU Wien", email: "stefan.podlipnig@tuwien.ac.at"}
+creator:
+  - { name: 'Stefan Podlipnig', affiliation: 'TU Wien', email: 'stefan.podlipnig@tuwien.ac.at' }
 contributor:
-  - {name: "Daniel Bastta", affiliation: "TU Wien", email: "daniel.bastta@tuwien.ac.at"}
-  - {name: "Andreas Merckel", affiliation: "TU Wien", email: "andreas.merkel@tuwien.ac.at"}
-  - {name: "Kerstin Limbeck", affiliation: "TU Wien", email: "kerstin.limbeck@tuwien.ac.at"}
+  - { name: 'Daniel Bastta', affiliation: 'TU Wien', email: 'daniel.bastta@tuwien.ac.at' }
+  - { name: 'Andreas Merckel', affiliation: 'TU Wien', email: 'andreas.merkel@tuwien.ac.at' }
+  - { name: 'Kerstin Limbeck', affiliation: 'TU Wien', email: 'kerstin.limbeck@tuwien.ac.at' }
 publisher:
-  - {name: "Andreas Merckel", affiliation: "TU Wien", email: "andreas.merkel@tuwien.ac.at"}
+  - { name: 'Andreas Merckel', affiliation: 'TU Wien', email: 'andreas.merkel@tuwien.ac.at' }
 
 format: [latex]
 difficulty: EASY
diff --git a/src/test/resources/at/ac/uibk/gitsearch/service/testData/metaData/2/project.yaml b/src/test/resources/at/ac/uibk/gitsearch/service/testData/metaData/2/project.yaml
index fba3fa7ae093e8829cfb096bac91fe83d2e1fdc4..c4c63330fb72acc19b936f36106653eef87909bd 100644
--- a/src/test/resources/at/ac/uibk/gitsearch/service/testData/metaData/2/project.yaml
+++ b/src/test/resources/at/ac/uibk/gitsearch/service/testData/metaData/2/project.yaml
@@ -3,13 +3,8 @@ project_name: latex
 namespace: sharing/vienna-universityof-technology/latex
 main_group: sharing
 sub_group: vienna-universityof-technology
-groups: [
-              "sharing/health-check-tests/collection_tests",
-              "sharing/health-check-tests",
-              "teacher",
-              "teacher/unauthenticatedteachers",
-              "sharing"
-            ]
+groups:
+  ['sharing/health-check-tests/collection_tests', 'sharing/health-check-tests', 'teacher', 'teacher/unauthenticatedteachers', 'sharing']
 url: https://sharing.codeability-austria.uibk.ac.at/sharing/vienna-universityof-technology/latex
 visibility: private
 archived: false
@@ -17,4 +12,4 @@ star_count: 0
 open_issues_count: 0
 forks_count: 1
 last_activity_at: 2021-02-17T15:13:27.123Z
-description: 
+description:
diff --git a/src/test/resources/at/ac/uibk/gitsearch/service/testData/metaData/272/metaData.yaml b/src/test/resources/at/ac/uibk/gitsearch/service/testData/metaData/272/metaData.yaml
index a24635dd84539291f7c38115e966e33086115478..42754ffa93be5550c4a4b4c63b121a3e09001a60 100644
--- a/src/test/resources/at/ac/uibk/gitsearch/service/testData/metaData/272/metaData.yaml
+++ b/src/test/resources/at/ac/uibk/gitsearch/service/testData/metaData/272/metaData.yaml
@@ -1,20 +1,20 @@
-metadataVersion: "0.4"
-learningResourceType: "programming exercise"
+metadataVersion: '0.4'
+learningResourceType: 'programming exercise'
 programmingLanguage: [java]
 language: [de]
 identifier: artemisOriginalCourseAndTitle
 structure: atomic # one from atomic, networked, hierarchical, linear
-version: "0.1.6" # just a version tag
+version: '0.1.6' # just a version tag
 title: JUnit Quality Tests Exercise2 (cloned)
-format: 
-    - Artemis
-description: "Dies ist ein Beispiel, wie Tests die JUnit Test Coverage testen."
+format:
+  - Artemis
+description: 'Dies ist ein Beispiel, wie Tests die JUnit Test Coverage testen.'
 status: final # one fo draft, final, revised, unavalable
-keyword: ["Example", "JUnit Tests", "JUnit", "Test Coverage Tests"]
+keyword: ['Example', 'JUnit Tests', 'JUnit', 'Test Coverage Tests']
 license: CC-SA-BY 4.0
-creator: 
- - {name: "Michael Breu", affiliation: "Universität Innsbruck", email: "admin@localhost"}
+creator:
+  - { name: 'Michael Breu', affiliation: 'Universität Innsbruck', email: 'admin@localhost' }
 publisher:
- - {name: "Michael Breu", affiliation: "Universität Innsbruck", email: "michael.breu@uibk.ac.at"}
+  - { name: 'Michael Breu', affiliation: 'Universität Innsbruck', email: 'michael.breu@uibk.ac.at' }
 difficulty: medium
 requires: [Java8, JUnit]
diff --git a/src/test/resources/at/ac/uibk/gitsearch/service/testData/metaData/272/project.yaml b/src/test/resources/at/ac/uibk/gitsearch/service/testData/metaData/272/project.yaml
index 92fc5267896bf80338c476539532143927a33db7..e289b4c262a2cc06a1dd1b185ba3a816b6b52998 100644
--- a/src/test/resources/at/ac/uibk/gitsearch/service/testData/metaData/272/project.yaml
+++ b/src/test/resources/at/ac/uibk/gitsearch/service/testData/metaData/272/project.yaml
@@ -1,12 +1,7 @@
 project_id: 272
 project_name: junit-quality-tests-exercise2
-groups: [
-              "sharing/health-check-tests/collection_tests",
-              "sharing/health-check-tests",
-              "teacher",
-              "teacher/unauthenticatedteachers",
-              "sharing"
-            ]
+groups:
+  ['sharing/health-check-tests/collection_tests', 'sharing/health-check-tests', 'teacher', 'teacher/unauthenticatedteachers', 'sharing']
 namespace: sharing/university-innsbruck/java/junit-quality-tests-exercise2
 main_group: sharing
 sub_group: university-innsbruck
diff --git a/src/test/resources/at/ac/uibk/gitsearch/service/testData/metaData/272/solution/src/at/metaData.yaml b/src/test/resources/at/ac/uibk/gitsearch/service/testData/metaData/272/solution/src/at/metaData.yaml
index 8a341ea81ba2e23290b3324f3ad2414262dd7232..7147830a0e70126dc84520bc69e69701bdb41d3b 100644
--- a/src/test/resources/at/ac/uibk/gitsearch/service/testData/metaData/272/solution/src/at/metaData.yaml
+++ b/src/test/resources/at/ac/uibk/gitsearch/service/testData/metaData/272/solution/src/at/metaData.yaml
@@ -1,9 +1,9 @@
 metadataVersion: 0.4
-learningResourceType: "programming exercise"
+learningResourceType: 'programming exercise'
 # format (not used here)
 identifier: simpleIO
 structure: atomic # one from atomic, networked, hierarchical, linear
-version: "1.0" # just a version tag
+version: '1.0' # just a version tag
 status: final # one fo draft, final, revised, unavailable
 title: Just another sub exercise Demo
 description: Not a really good structured example.
@@ -13,12 +13,12 @@ language: [de]
 timeRequired: 0:05:00 # [hh:mm:ss]
 keyword: [Java, IOTest, artemis]
 license: CC-SA-BY 4.0 # mandatory
-creator: 
-  - {name: "Breu Michael", affiliation: "University of Innsbruck", email: "c703257@uibk.ac.at"}
+creator:
+  - { name: 'Breu Michael', affiliation: 'University of Innsbruck', email: 'c703257@uibk.ac.at' }
 publisher:
-  - {name: "Breu Michael", affiliation: "University of Innsbruck", email: "c703257@uibk.ac.at"}
+  - { name: 'Breu Michael', affiliation: 'University of Innsbruck', email: 'c703257@uibk.ac.at' }
 difficulty: simple
 contributor:
-  - {name: "Manuel Seywald", affiliation: "University of Klagenfurt", email: "maseywald@edu.aau.at"}
-requires: []  # empty, t.b.d. later
+  - { name: 'Manuel Seywald', affiliation: 'University of Klagenfurt', email: 'maseywald@edu.aau.at' }
+requires: [] # empty, t.b.d. later
 image: 'https://sharing-codeability.uibk.ac.at/static/CodeAbility%20Austria-Dateien/Partner_UIBK.png'
diff --git a/src/test/resources/at/ac/uibk/gitsearch/service/testData/metaData/3/metaData.yaml b/src/test/resources/at/ac/uibk/gitsearch/service/testData/metaData/3/metaData.yaml
index f5946f89d9d2ce1e86a9d979c97ed4b72fc36a94..f788442da6dfa875d5263a9c907d22bc5a48ab5d 100644
--- a/src/test/resources/at/ac/uibk/gitsearch/service/testData/metaData/3/metaData.yaml
+++ b/src/test/resources/at/ac/uibk/gitsearch/service/testData/metaData/3/metaData.yaml
@@ -2,10 +2,9 @@
 learningResourceType: collection
 # format (not used here)
 identifier: simpleIO
-collectionContent:
-  "solution/src/at/metaData.yaml"
+collectionContent: 'solution/src/at/metaData.yaml'
 structure: hierarchical # one from atomic, networked, hierarchical, linear
-version: "1.0" # just a version tag
+version: '1.0' # just a version tag
 status: final # one fo draft, final, revised, unavailable
 title: Simple IO Test
 description: This is a programming exercise to demonstrate a simple IO testing framework.
@@ -14,12 +13,12 @@ language: [de]
 timeRequired: 0:05:00 # [hh:mm:ss]
 keyword: [Java, IOTest, artemis]
 license: CC-SA-BY 4.0 # mandatory
-creator: 
-  - {name: "Breu Michael", affiliation: "University of Innsbruck", email: "c703257@uibk.ac.at"}
+creator:
+  - { name: 'Breu Michael', affiliation: 'University of Innsbruck', email: 'c703257@uibk.ac.at' }
 publisher:
-  - {name: "Breu Michael", affiliation: "University of Innsbruck", email: "c703257@uibk.ac.at"}
+  - { name: 'Breu Michael', affiliation: 'University of Innsbruck', email: 'c703257@uibk.ac.at' }
 difficulty: simple
 contributor:
-  - {name: "Manuel Seywald", affiliation: "University of Klagenfurt", email: "maseywald@edu.aau.at"}
-requires: []  # empty, t.b.d. later
+  - { name: 'Manuel Seywald', affiliation: 'University of Klagenfurt', email: 'maseywald@edu.aau.at' }
+requires: [] # empty, t.b.d. later
 image: 'https://sharing-codeability.uibk.ac.at/static/CodeAbility%20Austria-Dateien/Partner_UIBK.png'
diff --git a/src/test/resources/at/ac/uibk/gitsearch/service/testData/metaData/3/project.yaml b/src/test/resources/at/ac/uibk/gitsearch/service/testData/metaData/3/project.yaml
index 0cafced363d6ce18de0b9a19ef0a15f75494db01..ab56c4d27021850d03126658351afef0c38b465c 100644
--- a/src/test/resources/at/ac/uibk/gitsearch/service/testData/metaData/3/project.yaml
+++ b/src/test/resources/at/ac/uibk/gitsearch/service/testData/metaData/3/project.yaml
@@ -3,13 +3,8 @@ project_name: latex
 namespace: sharing/vienna-universityof-technology/latex
 main_group: sharing
 sub_group: vienna-universityof-technology
-groups: [
-              "sharing/health-check-tests/collection_tests",
-              "sharing/health-check-tests",
-              "teacher",
-              "teacher/unauthenticatedteachers",
-              "sharing"
-            ]
+groups:
+  ['sharing/health-check-tests/collection_tests', 'sharing/health-check-tests', 'teacher', 'teacher/unauthenticatedteachers', 'sharing']
 url: https://sharing.codeability-austria.uibk.ac.at/sharing/vienna-universityof-technology/latex
 visibility: private
 archived: false
@@ -17,4 +12,4 @@ star_count: 0
 open_issues_count: 0
 forks_count: 1
 last_activity_at: 2021-02-17T15:13:27.123Z
-description: 
+description:
diff --git a/src/test/resources/at/ac/uibk/gitsearch/service/testData/metaData/3/solution/src/at/metaData.yaml b/src/test/resources/at/ac/uibk/gitsearch/service/testData/metaData/3/solution/src/at/metaData.yaml
index 29b6b92a2706da18ee3f5f700001f6754cd517e7..c9a2c36c00ea9ace2f7dd421f9c92263d947dea3 100644
--- a/src/test/resources/at/ac/uibk/gitsearch/service/testData/metaData/3/solution/src/at/metaData.yaml
+++ b/src/test/resources/at/ac/uibk/gitsearch/service/testData/metaData/3/solution/src/at/metaData.yaml
@@ -3,7 +3,7 @@ learningResourceType: programming exercise
 # format (not used here)
 identifier: simpleIO
 structure: atomic # one from atomic, networked, hierarchical, linear
-version: "1.0" # just a version tag
+version: '1.0' # just a version tag
 status: final # one fo draft, final, revised, unavailable
 title: Simple IO Test (inside collection)
 description: This is a programming exercise to demonstrate a simple IO testing framework.
@@ -13,12 +13,12 @@ language: [de]
 timeRequired: 0:05:00 # [hh:mm:ss]
 keyword: [Java, IOTest, artemis]
 license: CC-SA-BY 4.0 # mandatory
-creator: 
-  - {name: "Breu Michael", affiliation: "University of Innsbruck", email: "c703257@uibk.ac.at"}
+creator:
+  - { name: 'Breu Michael', affiliation: 'University of Innsbruck', email: 'c703257@uibk.ac.at' }
 publisher:
-  - {name: "Breu Michael", affiliation: "University of Innsbruck", email: "c703257@uibk.ac.at"}
+  - { name: 'Breu Michael', affiliation: 'University of Innsbruck', email: 'c703257@uibk.ac.at' }
 difficulty: simple
 contributor:
-  - {name: "Manuel Seywald", affiliation: "University of Klagenfurt", email: "maseywald@edu.aau.at"}
-requires: []  # empty, t.b.d. later
+  - { name: 'Manuel Seywald', affiliation: 'University of Klagenfurt', email: 'maseywald@edu.aau.at' }
+requires: [] # empty, t.b.d. later
 image: 'https://sharing-codeability.uibk.ac.at/static/CodeAbility%20Austria-Dateien/Partner_UIBK.png'
diff --git a/src/test/resources/at/ac/uibk/gitsearch/service/testData/metaData/318/metaData.yaml b/src/test/resources/at/ac/uibk/gitsearch/service/testData/metaData/318/metaData.yaml
index a24635dd84539291f7c38115e966e33086115478..42754ffa93be5550c4a4b4c63b121a3e09001a60 100644
--- a/src/test/resources/at/ac/uibk/gitsearch/service/testData/metaData/318/metaData.yaml
+++ b/src/test/resources/at/ac/uibk/gitsearch/service/testData/metaData/318/metaData.yaml
@@ -1,20 +1,20 @@
-metadataVersion: "0.4"
-learningResourceType: "programming exercise"
+metadataVersion: '0.4'
+learningResourceType: 'programming exercise'
 programmingLanguage: [java]
 language: [de]
 identifier: artemisOriginalCourseAndTitle
 structure: atomic # one from atomic, networked, hierarchical, linear
-version: "0.1.6" # just a version tag
+version: '0.1.6' # just a version tag
 title: JUnit Quality Tests Exercise2 (cloned)
-format: 
-    - Artemis
-description: "Dies ist ein Beispiel, wie Tests die JUnit Test Coverage testen."
+format:
+  - Artemis
+description: 'Dies ist ein Beispiel, wie Tests die JUnit Test Coverage testen.'
 status: final # one fo draft, final, revised, unavalable
-keyword: ["Example", "JUnit Tests", "JUnit", "Test Coverage Tests"]
+keyword: ['Example', 'JUnit Tests', 'JUnit', 'Test Coverage Tests']
 license: CC-SA-BY 4.0
-creator: 
- - {name: "Michael Breu", affiliation: "Universität Innsbruck", email: "admin@localhost"}
+creator:
+  - { name: 'Michael Breu', affiliation: 'Universität Innsbruck', email: 'admin@localhost' }
 publisher:
- - {name: "Michael Breu", affiliation: "Universität Innsbruck", email: "michael.breu@uibk.ac.at"}
+  - { name: 'Michael Breu', affiliation: 'Universität Innsbruck', email: 'michael.breu@uibk.ac.at' }
 difficulty: medium
 requires: [Java8, JUnit]
diff --git a/src/test/resources/at/ac/uibk/gitsearch/service/testData/metaData/318/project.yaml b/src/test/resources/at/ac/uibk/gitsearch/service/testData/metaData/318/project.yaml
index ba987bebd913cf03dcbb367f3fc142710c936451..5da8d64813a0804368344081f437a50763916baa 100644
--- a/src/test/resources/at/ac/uibk/gitsearch/service/testData/metaData/318/project.yaml
+++ b/src/test/resources/at/ac/uibk/gitsearch/service/testData/metaData/318/project.yaml
@@ -3,13 +3,8 @@ project_name: junit-quality-tests-exercise2
 namespace: sharing/university-innsbruck/java/junit-quality-tests-exercise2
 main_group: sharing
 sub_group: university-innsbruck
-groups: [
-              "sharing/health-check-tests/collection_tests",
-              "sharing/health-check-tests",
-              "teacher",
-              "teacher/unauthenticatedteachers",
-              "sharing"
-            ]
+groups:
+  ['sharing/health-check-tests/collection_tests', 'sharing/health-check-tests', 'teacher', 'teacher/unauthenticatedteachers', 'sharing']
 url: https://sharing.codeability-austria.uibk.ac.at/sharing/university-innsbruck/java/junit-quality-tests-exercise2/
 visibility: public
 archived: false
diff --git a/src/test/resources/at/ac/uibk/gitsearch/service/testData/metaData/318/solution/src/at/metaData.yaml b/src/test/resources/at/ac/uibk/gitsearch/service/testData/metaData/318/solution/src/at/metaData.yaml
index 8a341ea81ba2e23290b3324f3ad2414262dd7232..7147830a0e70126dc84520bc69e69701bdb41d3b 100644
--- a/src/test/resources/at/ac/uibk/gitsearch/service/testData/metaData/318/solution/src/at/metaData.yaml
+++ b/src/test/resources/at/ac/uibk/gitsearch/service/testData/metaData/318/solution/src/at/metaData.yaml
@@ -1,9 +1,9 @@
 metadataVersion: 0.4
-learningResourceType: "programming exercise"
+learningResourceType: 'programming exercise'
 # format (not used here)
 identifier: simpleIO
 structure: atomic # one from atomic, networked, hierarchical, linear
-version: "1.0" # just a version tag
+version: '1.0' # just a version tag
 status: final # one fo draft, final, revised, unavailable
 title: Just another sub exercise Demo
 description: Not a really good structured example.
@@ -13,12 +13,12 @@ language: [de]
 timeRequired: 0:05:00 # [hh:mm:ss]
 keyword: [Java, IOTest, artemis]
 license: CC-SA-BY 4.0 # mandatory
-creator: 
-  - {name: "Breu Michael", affiliation: "University of Innsbruck", email: "c703257@uibk.ac.at"}
+creator:
+  - { name: 'Breu Michael', affiliation: 'University of Innsbruck', email: 'c703257@uibk.ac.at' }
 publisher:
-  - {name: "Breu Michael", affiliation: "University of Innsbruck", email: "c703257@uibk.ac.at"}
+  - { name: 'Breu Michael', affiliation: 'University of Innsbruck', email: 'c703257@uibk.ac.at' }
 difficulty: simple
 contributor:
-  - {name: "Manuel Seywald", affiliation: "University of Klagenfurt", email: "maseywald@edu.aau.at"}
-requires: []  # empty, t.b.d. later
+  - { name: 'Manuel Seywald', affiliation: 'University of Klagenfurt', email: 'maseywald@edu.aau.at' }
+requires: [] # empty, t.b.d. later
 image: 'https://sharing-codeability.uibk.ac.at/static/CodeAbility%20Austria-Dateien/Partner_UIBK.png'
diff --git a/src/test/resources/at/ac/uibk/gitsearch/service/testData/metaData/333/metaData.yaml b/src/test/resources/at/ac/uibk/gitsearch/service/testData/metaData/333/metaData.yaml
index 8a838d6af4ec21bfa926549c5e177e8a23d48e23..81df5dc59430784bd35ae900fe0b09aa6dddc77c 100644
--- a/src/test/resources/at/ac/uibk/gitsearch/service/testData/metaData/333/metaData.yaml
+++ b/src/test/resources/at/ac/uibk/gitsearch/service/testData/metaData/333/metaData.yaml
@@ -1,24 +1,23 @@
-metadataVersion: "0.4"
-learningResourceType: "programming exercise"
+metadataVersion: '0.4'
+learningResourceType: 'programming exercise'
 programmingLanguage: [java]
 language: [de]
 identifier: artemisOriginalCourseAndTitle
 structure: atomic # one from atomic, networked, hierarchical, linear
-version: "0.1.6" # just a version tag
+version: '0.1.6' # just a version tag
 title: Exercise with publicVisibility except solution
 format:
-    - artemis
-description: "Dies ist ein Beispiel, wie Tests die JUnit Test Coverage testen."
+  - artemis
+description: 'Dies ist ein Beispiel, wie Tests die JUnit Test Coverage testen.'
 status: final # one fo draft, final, revised, unavalable
-keyword: ["Example", "JUnit Tests", "JUnit", "Test Coverage Tests"]
+keyword: ['Example', 'JUnit Tests', 'JUnit', 'Test Coverage Tests']
 license: CC-SA-BY 4.0
 creator:
- - {name: "Michael Breu", affiliation: "Universität Innsbruck", email: "admin@localhost"}
+  - { name: 'Michael Breu', affiliation: 'Universität Innsbruck', email: 'admin@localhost' }
 publisher:
- - {name: "Michael Breu", affiliation: "Universität Innsbruck", email: "michael.breu@uibk.ac.at"}
+  - { name: 'Michael Breu', affiliation: 'Universität Innsbruck', email: 'michael.breu@uibk.ac.at' }
 difficulty: medium
 requires: [Java8, JUnit]
 publicVisibility:
-    except:
-        - "solution"
-
+  except:
+    - 'solution'
diff --git a/src/test/resources/at/ac/uibk/gitsearch/service/testData/metaData/333/project.yaml b/src/test/resources/at/ac/uibk/gitsearch/service/testData/metaData/333/project.yaml
index 6d645427def4a00c484e6f00238a7b63c1dc8f69..2e1508644f2f849c4a7ee4ef0d01f95f43d8d9f0 100644
--- a/src/test/resources/at/ac/uibk/gitsearch/service/testData/metaData/333/project.yaml
+++ b/src/test/resources/at/ac/uibk/gitsearch/service/testData/metaData/333/project.yaml
@@ -3,13 +3,8 @@ project_name: Exercise with publicVisibility except solution
 namespace: sharing/university-innsbruck/java/exercise-with-publicvisibility-except-solution
 main_group: sharing
 sub_group: university-innsbruck
-groups: [
-              "sharing/health-check-tests/collection_tests",
-              "sharing/health-check-tests",
-              "teacher",
-              "teacher/unauthenticatedteachers",
-              "sharing"
-            ]
+groups:
+  ['sharing/health-check-tests/collection_tests', 'sharing/health-check-tests', 'teacher', 'teacher/unauthenticatedteachers', 'sharing']
 url: https://sharing.codeability-austria.uibk.ac.at/sharing/university-innsbruck/java/exercise-with-publicvisibility-except-solution/
 visibility: private
 archived: false
diff --git a/src/test/resources/at/ac/uibk/gitsearch/service/testData/metaData/333/solution/src/at/metaData.yaml b/src/test/resources/at/ac/uibk/gitsearch/service/testData/metaData/333/solution/src/at/metaData.yaml
index 8a341ea81ba2e23290b3324f3ad2414262dd7232..7147830a0e70126dc84520bc69e69701bdb41d3b 100644
--- a/src/test/resources/at/ac/uibk/gitsearch/service/testData/metaData/333/solution/src/at/metaData.yaml
+++ b/src/test/resources/at/ac/uibk/gitsearch/service/testData/metaData/333/solution/src/at/metaData.yaml
@@ -1,9 +1,9 @@
 metadataVersion: 0.4
-learningResourceType: "programming exercise"
+learningResourceType: 'programming exercise'
 # format (not used here)
 identifier: simpleIO
 structure: atomic # one from atomic, networked, hierarchical, linear
-version: "1.0" # just a version tag
+version: '1.0' # just a version tag
 status: final # one fo draft, final, revised, unavailable
 title: Just another sub exercise Demo
 description: Not a really good structured example.
@@ -13,12 +13,12 @@ language: [de]
 timeRequired: 0:05:00 # [hh:mm:ss]
 keyword: [Java, IOTest, artemis]
 license: CC-SA-BY 4.0 # mandatory
-creator: 
-  - {name: "Breu Michael", affiliation: "University of Innsbruck", email: "c703257@uibk.ac.at"}
+creator:
+  - { name: 'Breu Michael', affiliation: 'University of Innsbruck', email: 'c703257@uibk.ac.at' }
 publisher:
-  - {name: "Breu Michael", affiliation: "University of Innsbruck", email: "c703257@uibk.ac.at"}
+  - { name: 'Breu Michael', affiliation: 'University of Innsbruck', email: 'c703257@uibk.ac.at' }
 difficulty: simple
 contributor:
-  - {name: "Manuel Seywald", affiliation: "University of Klagenfurt", email: "maseywald@edu.aau.at"}
-requires: []  # empty, t.b.d. later
+  - { name: 'Manuel Seywald', affiliation: 'University of Klagenfurt', email: 'maseywald@edu.aau.at' }
+requires: [] # empty, t.b.d. later
 image: 'https://sharing-codeability.uibk.ac.at/static/CodeAbility%20Austria-Dateien/Partner_UIBK.png'