diff --git a/jar-exclude-corpus-services.xml b/jar-exclude-corpus-services.xml
new file mode 100644
index 0000000000000000000000000000000000000000..6e805119460cb8147405d528495871c3572fbdc0
--- /dev/null
+++ b/jar-exclude-corpus-services.xml
@@ -0,0 +1,27 @@
+ <?xml version="1.0" encoding="UTF-8"?>
+    <assembly xmlns="http://maven.apache.org/ASSEMBLY/2.0.0"
+      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+      xsi:schemaLocation="http://maven.apache.org/ASSEMBLY/2.0.0 http://maven.apache.org/xsd/assembly-2.0.0.xsd">
+        <id>bundle</id>
+        <formats>
+          <format>jar</format>
+        </formats>
+        <includeBaseDirectory>false</includeBaseDirectory>
+        <dependencySets>
+          <dependencySet>
+            <outputDirectory>/</outputDirectory>
+            <useProjectArtifact>false</useProjectArtifact>
+            <unpack>true</unpack>
+            <scope>runtime</scope>
+            <excludes>
+              <exclude>de.uni_hamburg.corpora:corpus-services</exclude>
+            </excludes>
+           </dependencySet>
+        </dependencySets>
+        <fileSets>
+          <fileSet>
+            <outputDirectory>/</outputDirectory>
+            <directory>${project.build.outputDirectory}</directory>
+          </fileSet>
+        </fileSets>
+      </assembly>
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000000000000000000000000000000000000..fe8f5387dac7ca86181dbdcede871564c8ae8840
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,153 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+
+  <groupId>de.uni_hamburg.corpora</groupId>
+  <artifactId>corpus-service-gui</artifactId>
+  <version>1.0-SNAPSHOT</version>
+
+  <name>corpus-service-gui</name>
+  <!-- FIXME change it to the project's website -->
+  <url>http://www.example.com</url>
+
+  <properties>
+    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+    <maven.compiler.source>11</maven.compiler.source>
+    <maven.compiler.target>11</maven.compiler.target>
+    <mainClass>de.uni_hamburg.corpora.gui.GUIApp</mainClass>
+  </properties>
+
+  <dependencies>
+    <dependency>
+      <groupId>de.uni_hamburg.corpora</groupId>
+      <artifactId>corpus-services</artifactId>
+      <version>1.0</version>
+      <type>jar</type>
+    </dependency>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <version>4.11</version>
+      <scope>test</scope>
+    </dependency>
+    <!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.dataformat/jackson-dataformat-yaml -->
+    <dependency>
+      <groupId>com.fasterxml.jackson.dataformat</groupId>
+      <artifactId>jackson-dataformat-yaml</artifactId>
+      <version>2.13.3</version>
+    </dependency>
+    <!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
+    <dependency>
+      <groupId>com.fasterxml.jackson.core</groupId>
+      <artifactId>jackson-databind</artifactId>
+      <version>2.13.3</version>
+    </dependency>
+    <dependency>
+      <groupId>com.google.guava</groupId>
+      <artifactId>guava</artifactId>
+      <version>31.0.1-jre</version>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
+      <plugins>
+        <!-- clean lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#clean_Lifecycle -->
+        <plugin>
+          <artifactId>maven-clean-plugin</artifactId>
+          <version>3.1.0</version>
+        </plugin>
+        <!-- default lifecycle, jar packaging: see https://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_jar_packaging -->
+        <plugin>
+          <artifactId>maven-resources-plugin</artifactId>
+          <version>3.0.2</version>
+        </plugin>
+        <plugin>
+          <artifactId>maven-compiler-plugin</artifactId>
+          <version>3.8.0</version>
+        </plugin>
+        <plugin>
+          <artifactId>maven-surefire-plugin</artifactId>
+          <version>2.22.1</version>
+        </plugin>
+        <plugin>
+          <artifactId>maven-jar-plugin</artifactId>
+          <version>3.0.2</version>
+          <configuration>
+          <!-- archive>
+            <manifestEntries>
+              <Class-Path>corpus-services.jar</Class-Path>
+              <Main-Class>${mainClass}</Main-Class>
+            </manifestEntries>
+          </archive -->
+          </configuration>
+        </plugin>
+        <plugin>
+          <artifactId>maven-install-plugin</artifactId>
+          <version>2.5.2</version>
+        </plugin>
+        <plugin>
+          <artifactId>maven-deploy-plugin</artifactId>
+          <version>2.8.2</version>
+        </plugin>
+        <!-- site lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#site_Lifecycle -->
+        <plugin>
+          <artifactId>maven-site-plugin</artifactId>
+          <version>3.7.1</version>
+        </plugin>
+        <plugin>
+          <artifactId>maven-project-info-reports-plugin</artifactId>
+          <version>3.0.0</version>
+        </plugin>
+        <plugin>
+          <groupId>org.codehaus.mojo</groupId>
+          <artifactId>exec-maven-plugin</artifactId>
+          <version>1.2.1</version>
+          <executions>
+            <execution>
+              <goals>
+                <goal>java</goal>
+              </goals>
+            </execution>
+          </executions>
+          <configuration>
+            <mainClass>${mainClass}</mainClass>
+          </configuration>
+        </plugin>
+        <plugin>
+          <artifactId>maven-assembly-plugin</artifactId>
+          <configuration>
+            <archive>
+              <manifest>
+                <addClasspath>true</addClasspath>
+                <mainClass>${mainClass}</mainClass>
+              </manifest>
+              <!-- manifestEntries>
+                <Class-Path>corpus-services.jar</Class-Path>
+              </manifestEntries -->
+            </archive>
+            <descriptors>
+              <descriptor>jar-exclude-corpus-services.xml</descriptor>
+            </descriptors>
+            <!-- descriptorRefs>
+              <descriptorRef>jar-with-dependencies</descriptorRef>
+            </descriptorRefs -->
+            <appendAssemblyId>true</appendAssemblyId>
+          </configuration>
+        </plugin>
+      </plugins>
+    </pluginManagement>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-compiler-plugin</artifactId>
+        <configuration>
+          <source>11</source>
+          <target>11</target>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+</project>
diff --git a/run-linux.sh b/run-linux.sh
new file mode 100644
index 0000000000000000000000000000000000000000..361784bc810ca1463f8834c8d593e23edd37fb2e
--- /dev/null
+++ b/run-linux.sh
@@ -0,0 +1,2 @@
+#!/bin/bash
+java -cp corpus-services.jar:target/corpus-service-gui-1.0-SNAPSHOT-jar-with-dependencies.jar de.uni_hamburg.corpora.gui.GUIApp
diff --git a/src/main/java/de/uni_hamburg/corpora/gui/Config.java b/src/main/java/de/uni_hamburg/corpora/gui/Config.java
new file mode 100644
index 0000000000000000000000000000000000000000..814c37bba09beb67c986d204d1574705e0818665
--- /dev/null
+++ b/src/main/java/de/uni_hamburg/corpora/gui/Config.java
@@ -0,0 +1,101 @@
+package de.uni_hamburg.corpora.gui;
+
+import com.fasterxml.jackson.annotation.JsonAnyGetter;
+import com.fasterxml.jackson.annotation.JsonAnySetter;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.DeserializationFeature;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.dataformat.yaml.YAMLGenerator;
+import com.fasterxml.jackson.dataformat.yaml.YAMLMapper;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ * Class representing the YAML config created by the web interface
+ */
+public class Config {
+    @JsonProperty("corpus")
+    String name;
+    @JsonProperty("checker")
+    List<String> functions = new ArrayList<>();
+    // Properties parameters = new Properties();
+    @JsonProperty("parameters")
+    Map<String,String> parameters = new HashMap<>();
+
+    public Config() {
+    }
+
+    /**
+     * Reads a config file
+     * @param fileName the config file
+     * @return the configuration
+     * @throws IOException if reading fails
+     */
+    public static Config read(String fileName) throws IOException {
+        // Instantiating a new ObjectMapper as a YAMLFactory
+        ObjectMapper om = new YAMLMapper()
+                // Don't expect quotes around strings when not necessary
+                .configure(YAMLGenerator.Feature.MINIMIZE_QUOTES,true)
+                // Don't fail if more information than expected
+                .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
+                .findAndRegisterModules();
+        return om.readValue(new File(fileName), Config.class);
+    }
+
+    /**
+     * Writes a configuration back as a YAML string
+     * @return the resulting YAML
+     * @throws JsonProcessingException if conversion fails
+     */
+    public String write() throws JsonProcessingException {
+        ObjectMapper om = new YAMLMapper()
+                .configure(YAMLGenerator.Feature.MINIMIZE_QUOTES,true);
+        return om.writeValueAsString(this);
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+
+    public List<String> getFunctions() {
+        return functions;
+    }
+
+    public void setFunctions(List<String> functions) {
+        this.functions = functions;
+    }
+
+    @JsonAnyGetter
+    public Map<String,String> getParameters() {
+        return parameters;
+    }
+
+    @JsonAnySetter
+    public void setParameters(Map<String,String> parameters) {
+        this.parameters = parameters;
+    }
+
+    public Properties getParametersAsProperties() {
+        Properties props = new Properties();
+        props.putAll(this.parameters);
+        return props;
+    }
+
+    @Override
+    public String toString() {
+        return "Config{" +
+                "name='" + name + '\'' +
+                ", functions=" + String.join(",", functions) +
+                ", params=" + parameters +
+                '}';
+    }
+}
diff --git a/src/main/java/de/uni_hamburg/corpora/gui/CorpusServices.java b/src/main/java/de/uni_hamburg/corpora/gui/CorpusServices.java
new file mode 100644
index 0000000000000000000000000000000000000000..12c657d0c7de2c2de3a5b108b639cb0f089977d4
--- /dev/null
+++ b/src/main/java/de/uni_hamburg/corpora/gui/CorpusServices.java
@@ -0,0 +1,65 @@
+package de.uni_hamburg.corpora.gui;
+
+import de.uni_hamburg.corpora.CorpusData;
+import de.uni_hamburg.corpora.CorpusFunction;
+import de.uni_hamburg.corpora.Report;
+import de.uni_hamburg.corpora.ReportItem;
+import org.reflections.Reflections;
+
+import java.lang.reflect.Modifier;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+/**
+ * @author bba1792 Dr. Herbert Lange
+ * @version 20220404
+ * Class encapsulating some corpus services functionality
+ */
+public class CorpusServices {
+    /**
+     * Gets the names of all corpus functions, ie all classes implementing CorpusFunction, defined in de.uni_hamburg.corpora.
+     *
+     * @return the list of corpus functions
+     */
+    public static Set<String> getCorpusFunctions() {
+        // Get all classes implementing the interface via reflections
+        Reflections reflections = new Reflections("de.uni_hamburg.corpora");
+        Set<Class<? extends CorpusFunction>> classes = reflections.getSubTypesOf(CorpusFunction.class);
+        // Convert classes to class names
+        return classes.stream()
+                .filter((c) -> Modifier.isPublic(c.getModifiers()) && !Modifier.isAbstract(c.getModifiers()))
+                .map(Class::getCanonicalName)
+                .collect(Collectors.toSet());
+    }
+
+    /**
+     * Gets the class names of all corpus types, ie all classes derived from CorpusData, defined in de.uni_hamburg.corpora.
+     *
+     * @return the list of corpus types
+     */
+    public static Set<String> getCorpusTypes () {
+        Reflections reflections = new Reflections("de.uni_hamburg.corpora");
+        HashSet<String> classNames = new HashSet<>();
+        Set<Class<? extends CorpusData>> classes = reflections.getSubTypesOf(CorpusData.class);
+        for (Class<? extends CorpusData> c : classes) {
+            classNames.add(c.getCanonicalName());
+        }
+        return classNames ;
+    }
+
+    /**
+     * Generate the summary of a report returning the count of items for each severity level.
+     *
+     * @param report the report
+     * @return the hash map
+     */
+    public static HashMap<ReportItem.Severity,Integer> generateSummary(Report report) {
+        HashMap<ReportItem.Severity,Integer> results = new HashMap<>();
+        for (ReportItem item : report.getRawStatistics()) {
+            results.compute(item.getSeverity(),(k,v) -> (v==null) ? 1 : v + 1) ;
+        }
+        return results;
+    }
+}
diff --git a/src/main/java/de/uni_hamburg/corpora/gui/CorpusThread.java b/src/main/java/de/uni_hamburg/corpora/gui/CorpusThread.java
new file mode 100644
index 0000000000000000000000000000000000000000..7237305c5921ac32e1ef153bfbad38a255b3d248
--- /dev/null
+++ b/src/main/java/de/uni_hamburg/corpora/gui/CorpusThread.java
@@ -0,0 +1,143 @@
+package de.uni_hamburg.corpora.gui;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import de.uni_hamburg.corpora.*;
+import org.exmaralda.partitureditor.jexmaralda.JexmaraldaException;
+import org.xml.sax.SAXException;
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.*;
+import java.util.function.Function;
+import java.util.logging.Logger;
+
+class CorpusThread extends Thread {
+
+    private final Logger logger = Logger.getLogger(this.getClass().getName());
+
+    de.uni_hamburg.corpora.Report report = new de.uni_hamburg.corpora.Report();
+    String corpusName;
+    String inFile ;
+    List<String> functionNames;
+    String outFile;
+    Properties props; // The properties for the function calls
+    Function<String,Void> callbackFunction;
+
+    CorpusThread(String name, String infile, String outfile, List<String> functions, Properties properties,
+                 Function<String, Void> callback) {
+        this.corpusName=name;
+        if (infile.equals("tmp"))
+            this.inFile = System.getProperty("java.io.tmpdir") + "/corpus-files";
+        else
+            this.inFile = infile;
+        this.functionNames = functions ;
+        this.props = properties;
+        if (outfile.equals("tmp")) {
+            File tmpDir = new File(System.getProperty("java.io.tmpdir") + "/" + corpusName);
+            // Create parent directory if it is missing
+            if (!tmpDir.exists())
+                tmpDir.mkdirs();
+            this.outFile = tmpDir + "/checker-report.html";
+        }
+        else
+            this.outFile = outfile;
+        callbackFunction = callback;
+        logger.info("Input: " + this.inFile + " output: " + this.outFile + " functions: " + functions + " params: " +
+                this.props);
+    }
+
+    public void run() {
+        Set<String> allFunctions = CorpusServices.getCorpusFunctions() ;
+        CorpusIO cio = new CorpusIO();
+        report.addNote("CorpusWebServices","Starting run at " +
+                DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss").format(LocalDateTime.now()));
+        try {
+            // Create corpus from given input file/folder
+            Corpus corpus;
+            if (corpusName != null && !corpusName.isEmpty()) {
+                URL baseUrl = new File(inFile).toURI().toURL();
+                corpus = new Corpus(corpusName,baseUrl,cio.read(baseUrl,report)) ;
+            }
+            else
+                corpus = new Corpus(cio.read(new File(inFile).toURI().toURL(),report)) ;
+            logger.info("Loaded " + corpus.getCorpusData().size() + " corpus files");
+            logger.info("Got report: " + report.getFullReports());
+            // For all functions to be applied, get their canonical name and create an object for them
+            Set<CorpusFunction> functions = new HashSet<>() ;
+            for (String function : functionNames) {
+                // Indicator if we encountered the function
+                boolean found = false ;
+                for (String canonical : allFunctions) {
+                    if (canonical.toLowerCase(Locale.ROOT).endsWith("." + function.toLowerCase(Locale.ROOT))) {
+                        // Create an object from canonical name. calls the constructor with thr constructor setting hasfixingoption to false
+                        try {
+                            functions.add((CorpusFunction) Class.forName(canonical).getDeclaredConstructor(Properties.class).newInstance(props));
+                            found = true ;
+                        }
+                        catch (IllegalArgumentException | NoSuchMethodException | InstantiationException | InvocationTargetException | IllegalAccessException e) {
+                            logger.severe(String.format("Error creating %s", canonical));
+                            report.addWarning("CorpusWebServices", "Test " + function + " cannot be created");
+//                            e.printStackTrace();
+                        }
+                    }
+                }
+                if (!found) {
+                    // Warn if we could not find the function
+                    report.addWarning("CorpusWebServices", "Test " + function + " is not available");
+                    logger.severe(String.format("Function %s is not available in corpus services", function));
+
+                }
+            }
+            for (CorpusFunction f : functions) {
+                logger.severe(String.format("Running function %s", f.getFunction()));
+                report.addNote("CorpusWebServices", "Run test " + f.getFunction());
+                de.uni_hamburg.corpora.Report result = f.execute(corpus);
+                report.merge(result);
+                report.addNote("CorpusWebServices", "Finish test " + f.getFunction());
+                logger.severe(String.format("Done with function %s", f.getFunction()));
+            }
+        } catch (URISyntaxException | ClassNotFoundException | IOException | SAXException | JexmaraldaException e) {
+            e.printStackTrace();
+        }
+
+        logger.info("Done with all functions");
+        report.addNote("CorpusWebServices","Finished all tests at " +
+                DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss").format(LocalDateTime.now()));
+        logger.info("Creating report");
+        // Get summary
+        HashMap<ReportItem.Severity,Integer> summary = CorpusServices.generateSummary(report);
+        // try to convert to JSON
+        String jsonSummary = "{}";
+        try {
+            jsonSummary = new ObjectMapper().writeValueAsString(summary);
+        } catch (JsonProcessingException e) {
+            e.printStackTrace();
+        }
+        // Generate HTML report
+        Collection<ReportItem> rawStatistics = report.getRawStatistics();
+        String reportOutput = ReportItem.generateDataTableHTML(new ArrayList<>(rawStatistics),
+                report.getSummaryLines());
+        // Alternative: Generate XML
+        //XStream xstream = new XStream();
+        //String reportOutput = xstream.toXML(rawStatistics);
+
+        logger.info("Writing report to " + outFile);
+        try {
+            BufferedWriter out = new BufferedWriter(new FileWriter(outFile));
+            out.write(reportOutput);
+            out.close();
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+        logger.info("Done with report");
+        callbackFunction.apply(outFile);
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/de/uni_hamburg/corpora/gui/GUI.java b/src/main/java/de/uni_hamburg/corpora/gui/GUI.java
new file mode 100644
index 0000000000000000000000000000000000000000..cafc5dea16f3b0b4aba8d18bebd16bd5c893a2f1
--- /dev/null
+++ b/src/main/java/de/uni_hamburg/corpora/gui/GUI.java
@@ -0,0 +1,171 @@
+package de.uni_hamburg.corpora.gui;
+
+import javax.swing.*;
+import javax.swing.filechooser.FileNameExtensionFilter;
+import java.awt.*;
+import java.io.*;
+import java.net.URL;
+import java.util.function.Function;
+
+/**
+ * The definition of the GUI
+ * @author bba1792, Dr. Herbert Lange
+ * @version 20220802
+ */
+public class GUI {
+
+    // Information on how to download the corpus-services
+    private final String BRANCH = "develop-quest";
+    private final String FILE_URL = "https://gitlab.rrz.uni-hamburg.de/corpus-services/corpus-services/-/jobs/artifacts/" +
+            BRANCH + "/raw/target/corpus-services-1.0.jar?job=compile_withmaven";
+    // The main window
+    JFrame window;
+    // The path to the report created by the checkers
+    String reportFile;
+
+    /**
+     * Constructor setting up the GUI
+     */
+    public GUI() {
+        window = new JFrame("Corpus-Services GUI");
+        window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+        JPanel mainPanel = new JPanel(new GridLayout(5,1));
+        JPanel corpusFiles = new JPanel(new GridLayout(1,3));
+        mainPanel.add(new JLabel("Corpus directory"));
+        final JTextField corpusPath = new JTextField();
+        corpusFiles.add(corpusPath);
+        final JButton corpusButton = new JButton("Select");
+        corpusButton.addActionListener(actionEvent -> {
+            JFileChooser chooser = new JFileChooser();
+            chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
+            int result = chooser.showOpenDialog(corpusButton);
+            if (result == JFileChooser.APPROVE_OPTION)
+                corpusPath.setText(chooser.getSelectedFile().toString());
+        });
+        corpusFiles.add(corpusButton);
+        mainPanel.add(corpusFiles);
+        mainPanel.add(new JLabel("Configuration file"));
+        JPanel configFile = new JPanel(new GridLayout(1,3));
+        final JTextField configPath = new JTextField();
+        configFile.add(configPath);
+        final JButton configButton = new JButton("Select");
+        configButton.addActionListener(actionEvent -> {
+            JFileChooser chooser = new JFileChooser();
+            chooser.setFileFilter(new FileNameExtensionFilter(
+                    "YAML configurations", "yaml", "yml"));
+            int result = chooser.showOpenDialog(configButton);
+            if (result == JFileChooser.APPROVE_OPTION)
+                configPath.setText(chooser.getSelectedFile().toString());
+        });
+        configFile.add(configButton);
+        mainPanel.add(configFile);
+        JPanel buttonPanel = new JPanel(new GridLayout(1,4));
+        JButton checkButton = new JButton("Check corpus");
+        buttonPanel.add(checkButton);
+        JButton reportButton = new JButton("Show report");
+        reportButton.setEnabled(false);
+        buttonPanel.add(reportButton);
+        JButton updateButton = new JButton("Update corpus services");
+        buttonPanel.add(updateButton);
+        JButton exitButton = new JButton("Exit");
+        buttonPanel.add(exitButton);
+        // Handle check
+        // Create callback for after the check
+        Function<String, Void> callback =
+                (outFile) -> {
+            reportFile = outFile;
+            reportButton.setEnabled(true);
+            JOptionPane.showMessageDialog(window,
+                            "Checks executed successfully. You can now check the report.",
+                            "Success",
+                            JOptionPane.INFORMATION_MESSAGE);
+            checkButton.setEnabled(true);
+            updateButton.setEnabled(true);
+            return null ;
+        };
+        checkButton.addActionListener(actionEvent -> {
+            checkButton.setEnabled(false);
+            updateButton.setEnabled(false);
+            // Do the checking
+            try {
+                Config config = Config.read(configPath.getText());
+                JOptionPane.showMessageDialog(window,
+                        "Starting checks now. Depending on the corpus and the checks selected this can take" +
+                                "a while",
+                        "Info",
+                        JOptionPane.INFORMATION_MESSAGE);
+                CorpusThread worker = new CorpusThread(
+                        config.getName()
+                        , corpusPath.getText()
+                        , "tmp" // write report to tmp
+                        , config.getFunctions()
+                        , config.getParametersAsProperties()
+                        , callback);
+                worker.start();
+            } catch (IOException e) {
+                JOptionPane.showMessageDialog(window,
+                        "Problem loading configuration file",
+                        "Error",
+                        JOptionPane.ERROR_MESSAGE);
+                e.printStackTrace();
+                checkButton.setEnabled(true);
+                updateButton.setEnabled(true);
+            }
+        });
+        // Handle update
+        updateButton.addActionListener(actionEvent -> {
+            checkButton.setEnabled(false);
+            updateButton.setEnabled(false);
+            exitButton.setEnabled(false);
+            JOptionPane.showMessageDialog(window,
+                    "Download started. Depending on the internet connection this can take a few minutes",
+                    "Info",
+                    JOptionPane.INFORMATION_MESSAGE);
+            try {
+                BufferedInputStream in = new BufferedInputStream(new URL(FILE_URL).openStream());
+                BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream("corpus-services.jar"));
+                in.transferTo(out);
+                in.close();
+                out.close();
+                JOptionPane.showMessageDialog(window,
+                        "Download successful. You now have to restart the application.",
+                        "Success",
+                        JOptionPane.INFORMATION_MESSAGE);
+            } catch (IOException e) {
+                //custom title, error icon
+                JOptionPane.showMessageDialog(window,
+                        "Error downloading file.",
+                        "Error",
+                        JOptionPane.ERROR_MESSAGE);
+            }
+            checkButton.setEnabled(true);
+            updateButton.setEnabled(true);
+            exitButton.setEnabled(true);
+        });
+        reportButton.addActionListener(actionEvent -> {
+            Desktop dt = Desktop.getDesktop();
+            try {
+                dt.open(new File(reportFile));
+            } catch (Exception e) {
+                JOptionPane.showMessageDialog(window,
+                        "Error opening report file " + reportFile + ".",
+                        "Error",
+                        JOptionPane.ERROR_MESSAGE);
+            }
+        });
+        // Handle exit
+        exitButton.addActionListener(actionEvent -> {
+            // Close window
+            window.dispose();
+        });
+        mainPanel.add(buttonPanel);
+        window.getContentPane().add(mainPanel);
+    }
+
+    /**
+     * Shows the window
+     */
+    public void show() {
+        window.setVisible(true);
+    }
+}
diff --git a/src/main/java/de/uni_hamburg/corpora/gui/GUIApp.java b/src/main/java/de/uni_hamburg/corpora/gui/GUIApp.java
new file mode 100644
index 0000000000000000000000000000000000000000..b7ca134f2a3aa44b479bd93b796fcb6ec09c72fd
--- /dev/null
+++ b/src/main/java/de/uni_hamburg/corpora/gui/GUIApp.java
@@ -0,0 +1,18 @@
+package de.uni_hamburg.corpora.gui;
+
+/**
+ * Simple GUI for the corpus services
+ * @author bba1792, Dr. Herbert Lange
+ * @version 20220802
+ */
+public class GUIApp
+{
+    public static void main( String[] args )
+    {
+        // Create window
+        GUI gui = new GUI();
+        // Show window
+        gui.show();
+        // This app will continue running until the window is closed
+    }
+}
diff --git a/src/test/java/de/uni_hamburg/corpora/AppTest.java b/src/test/java/de/uni_hamburg/corpora/AppTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..883599a4af48727af47bc974b4f30c574ac2bbd4
--- /dev/null
+++ b/src/test/java/de/uni_hamburg/corpora/AppTest.java
@@ -0,0 +1,20 @@
+package de.uni_hamburg.corpora;
+
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+
+/**
+ * Unit test for simple App.
+ */
+public class AppTest 
+{
+    /**
+     * Rigorous Test :-)
+     */
+    @Test
+    public void shouldAnswerWithTrue()
+    {
+        assertTrue( true );
+    }
+}