diff --git a/convert.py b/convert.py
deleted file mode 100755
index 62b10f89a6858dfa7658e99c238a35f3b8c22f90..0000000000000000000000000000000000000000
--- a/convert.py
+++ /dev/null
@@ -1,141 +0,0 @@
-#!/usr/local/bin/python3
-""" a simple script that converts ilias exam output to readable json
-
-The json output will look like this:
-{
-    "max.mustermann": { <<--- OR all uppercase letter of the name + username/matrikel_no
-        "matrikel_no": "12345678",
-        "name": "Mustermann, Max",
-        "task_list": {
-            "[task_id_1]": "print Hello World!",
-            ....,
-            "[task_id_n]": "#include <stdio.h> etc."
-        }
-    },
-    ... ans so on
-}
-
-usage: convert.py [-h] [-n NUMBER_OF_TASKS] INFILE OUTFILE
-
-positional arguments:
-  INFILE                Ilias exam data
-  OUTFILE               Where to write the final file
-
-optional arguments:
-  -h, --help            show this help message and exit
-  -n NUMBER_OF_TASKS, --NUMBER_OF_TASKS NUMBER_OF_TASKS
-                        Where to write the final file
-
-
-Author: Jan Maximilian Michal
-Date: 30 March 2017
-"""
-
-import json
-import os
-import re
-import argparse
-import urllib.parse
-from collections import namedtuple, defaultdict
-
-from xlrd import open_workbook
-
-parser = argparse.ArgumentParser()
-parser.add_argument('INFILE', help='Ilias exam data')
-parser.add_argument('OUTFILE', help='Where to write the final file')
-parser.add_argument('-u', '--usernames', help='a json dict matno -> email')
-parser.add_argument(
-    '-n', '--NUMBER_OF_TASKS',
-    default=0, # don't check
-    metavar='NUMBER_OF_TASKS',
-    type=int,
-    help='Where to write the final file')
-args = parser.parse_args()
-
-# meta sheet contains ilias evaluation names usernames etc - data contains code
-meta, *data = open_workbook(args.INFILE, open(os.devnull, 'w')).sheets()
-
-# one user has one submission (code) per task
-# yes, I know it is possible to name match groups via (?P<name>) but
-# I like this solution better since it gets the job done nicely
-user_head = namedtuple('user_head', 'kohorte, name')
-user_head_re = re.compile(r'^Ergebnisse von Testdurchlauf (?P<kohorte>\d+) für (?P<name>[\w\s\.,-]+)$')
-
-# one task has a title and id and hpfly code
-task_head_re = re.compile(r'^Quellcode Frage(?P<title>.*) \d{8}$')
-
-# nor parsing the weird mat no
-matno_re = re.compile(r'^(?P<matrikel_no>\d{8})-(\d{3})-(\d{3})$')
-
-# Modify these iterators in order to change extraction behaviour
-
-
-def sheet_iter_meta(sheet):
-    """ yield first and second col entry as tuple of (name, matnr) """
-    for row in (sheet.row(i) for i in range(1, sheet.nrows)):
-        m = re.search(matno_re, row[1].value)
-        yield row[0].value, m.group('matrikel_no') if m else row[1].value
-
-
-def sheet_iter_data(sheet):
-    """ yields all rows that are not of empty type as one string """
-    for row in (sheet.row(i) for i in range(sheet.nrows)):
-        if any(map(lambda c: c.ctype, row)):
-            yield ''.join(c.value for c in row)
-
-# nice!
-name2mat = dict(sheet_iter_meta(meta))
-
-# from xls to lists and namedtuples
-# [ [user0, task0_h, code0, ..., taskn, coden ], ..., [...] ]
-root = []
-for sheet in data:
-    for row in sheet_iter_data(sheet):
-        user = re.search(user_head_re, row)
-        task = re.search(task_head_re, row)
-        if user:
-            root.append([user_head(*user.groups())])
-        elif task:
-            root[-1].append(task.group('title'))
-        else: # should be code
-            root[-1].append(urllib.parse.unquote(row).strip())
-
-if args.NUMBER_OF_TASKS:
-    for (user, *task_list) in sorted(root, key=lambda u: u[0].name):
-        assert len(task_list) == args.NUMBER_OF_TASKS * 2
-
-mat_to_email = defaultdict(str)
-if args.usernames:
-    with open(args.usernames) as data:
-        mat_to_email.update(json.JSONDecoder().decode(data.read()))
-
-def get_username(user):
-    if name2mat[user.name] in mat_to_email:
-        return mat_to_email[name2mat[user.name]].split('@')[0]
-    return ''.join(filter(str.isupper, user.name)) + name2mat[user.name]
-
-usernames = {user.name : get_username(user) for (user, *_) in root}
-
-# form list to json_like via comprehension
-# the format {userinitials + matrikel_no : {name:, matrikel_no:, tasklist: {id:, ..., id:}}}
-json_dict = {
-    usernames[user.name] : {
-        'name' : name2mat[user.name],
-        'email' : mat_to_email[name2mat[user.name]],
-        'matrikel_no' : name2mat[user.name],
-        'submissions' : [
-            {
-                "type" : task,
-                "code" : code,
-                "label" : [],
-                "annotations": {}
-            } for task, code in zip(task_list[::2], task_list[1::2])
-        ]
-    } for (user, *task_list) in sorted(root, key=lambda u: u[0].name)
-}
-
-# just encode python style
-with open(args.OUTFILE, "w") as out:
-    out.write(json.JSONEncoder().encode(json_dict))
-
-print(f"Wrote data to {args.OUTFILE}. Done.")
diff --git a/scripts/convert.py b/scripts/convert.py
index 62b10f89a6858dfa7658e99c238a35f3b8c22f90..638fc16f8504f48d6f55488d20e6973b56f06f51 100755
--- a/scripts/convert.py
+++ b/scripts/convert.py
@@ -15,7 +15,7 @@ The json output will look like this:
     ... ans so on
 }
 
-usage: convert.py [-h] [-n NUMBER_OF_TASKS] INFILE OUTFILE
+usage: convert.py [-h] [-u USERNAMES] [-n NUMBER_OF_TASKS] INFILE OUTFILE
 
 positional arguments:
   INFILE                Ilias exam data
@@ -23,6 +23,8 @@ positional arguments:
 
 optional arguments:
   -h, --help            show this help message and exit
+  -u USERNAMES, --usernames USERNAMES
+                        a json dict matno -> email
   -n NUMBER_OF_TASKS, --NUMBER_OF_TASKS NUMBER_OF_TASKS
                         Where to write the final file
 
@@ -120,15 +122,14 @@ usernames = {user.name : get_username(user) for (user, *_) in root}
 # the format {userinitials + matrikel_no : {name:, matrikel_no:, tasklist: {id:, ..., id:}}}
 json_dict = {
     usernames[user.name] : {
-        'name' : name2mat[user.name],
+        'name' : user.name,
         'email' : mat_to_email[name2mat[user.name]],
         'matrikel_no' : name2mat[user.name],
         'submissions' : [
             {
                 "type" : task,
                 "code" : code,
-                "label" : [],
-                "annotations": {}
+                "tests" : {},
             } for task, code in zip(task_list[::2], task_list[1::2])
         ]
     } for (user, *task_list) in sorted(root, key=lambda u: u[0].name)
diff --git a/util/processing.py b/util/processing.py
index 997cf1b86f70c1b55fe3b7303234512fee8d345b..bf0b60baa78d7bcdbe2f587c0a1086546e2d2f19 100644
--- a/util/processing.py
+++ b/util/processing.py
@@ -1,86 +1,46 @@
 import abc
 import hashlib
-import json
 import tempfile
 import os
+import re
+import json
 import shutil
 import subprocess
 
-before = {
-    "username": {
-        "name": "87654321",
-        "email": "username@example.org",
-        "matrikel_no": "87654321",
-        "submissions": [
-            {
-                "type": "[a01] Zeichen und Strings",
-                "code": "#include <ctype.h>\nint umschalt(char *s)\n\n{\n\t if (s == 0) return 0;int i = 0, count = 0;\n\twhile(s[i] != '\\0')\n\t{\n\t\tif(islower(s[i]) != 0)\n\t\t{\n\t\t\ts[i] = toupper(s[i]);\n\t\t} else if(isupper(s[i]) != 0)\n\t\t{\n\t\t\ts[i] = tolower(s[i]);\n\t\t} else\n\t\t{\n\t\t\tcount++;\n\t\t}\n\t\ti++;\n\t}\n\treturn count;\n}",
-                "tests" : {}
-            },
-            {
-                "type": "[a02] Iteration",
-                "code": "#include <stdlib.h>\nlong iteP(unsigned int k)\n{\n\tif(k == 0)\n\t{\n\t\treturn 3;\n\t}\n\tif( k == 1)\n\t{\n\t\treturn 0;\n\t}\n\tif( k == 3)\n\t{\n\t\treturn 2;\n\t}\n\tint *p = malloc(k * sizeof(int));\n\tp[0] = 3;\n\tp[1] = 0;\n\tp[2] = 2;\n\tfor(int i = 3; i < k; i++)\n\t{\n\t\tp[i] = p[i-2] + p[i - 3];\n\t}\n\n\treturn p[k];\n}",
-                "tests" : {}
-            }
-        ]
-    }
-}
-
-after = {
-    "username": {
-        "name": "87654321",
-        "email": "username@example.org",
-        "matrikel_no": "87654321",
-        "submissions": [
-            {
-                "type": "[a01] Zeichen und Strings",
-                "code": "#include <ctype.h>\nint umschalt(char *s)\n\n{\n\tint i = 0, count = 0;\n\twhile(s[i] != '\\0')\n\t{\n\t\tif(islower(s[i]) != 0)\n\t\t{\n\t\t\ts[i] = toupper(s[i]);\n\t\t} else if(isupper(s[i]) != 0)\n\t\t{\n\t\t\ts[i] = tolower(s[i]);\n\t\t} else\n\t\t{\n\t\t\tcount++;\n\t\t}\n\t\ti++;\n\t}\n\treturn count;\n}",
-                "tests": {
-                    "EmptyTest": {
-                        "name": "EmptyTest",
-                        "annotation": "",
-                        "label": "NOT_EMPTY"
-                    }
-                }
-            },
-            {
-                "type": "[a02] Iteration",
-                "code": "#include <stdlib.h>\nlong iteP(unsigned int k)\n{\n\tif(k == 0)\n\t{\n\t\treturn 3;\n\t}\n\tif( k == 1)\n\t{\n\t\treturn 0;\n\t}\n\tif( k == 3)\n\t{\n\t\treturn 2;\n\t}\n\tint *p = malloc(k * sizeof(int));\n\tp[0] = 3;\n\tp[1] = 0;\n\tp[2] = 2;\n\tfor(int i = 3; i < k; i++)\n\t{\n\t\tp[i] = p[i-2] + p[i - 3];\n\t}\n\n\treturn p[k];\n}",
-                "tests": {}
-            }
-        ]
-    }
-}
-
-
-def sha(s):
-    return hashlib.sha1(s.encode()).hexdigest()
-
-
-def run_cmd(cmd, stdin=None):
+import testcases
+
+DESCFILE    = '../data/descfile.txt'
+BINARIES    = '../data/klausur20170627/bin'
+OBJECTS     = '../data/klausur20170627/objects'
+SUBMISSIONS = '../data/ok.json'
+HEADER      = '../data/klausur20170627/code-testing'
+
+def run_cmd(cmd, stdin=None, check=False):
     return subprocess.run(
-        cmd,
+        'ulimit -v 1024;' + cmd,
         stderr=subprocess.PIPE,
         stdout=subprocess.PIPE,
         input=stdin,
         shell=True,
+        check=check,
         encoding='utf-8',
         timeout=0.5
     )
 
+'submission'
 
 def testcase(i, args, stdout):
     try:
-        ret = run_cmd("./code %s" % args)
+        ret = run_cmd("./code %s" % args, check=True)
         assert ret.stdout == stdout
     except AssertionError:
-        return f"Case #{i}: [ASSERT FAILED] ./umschalt {args} WAS '{ret.stdout}' SHOULD '{stdout}'"
+        return f"Case #{i}: [ASSERT FAILED] ./program {args} WAS '{ret.stdout}' SHOULD '{stdout}'"
     except subprocess.CalledProcessError:
-        return f"Case #{i}: [FAILED] ./umschalt {args}"
+        return f"Case #{i}: [FAILED] ./program {args}"
     except subprocess.TimeoutExpired:
-        return f"Case #{i}: [TIMEOUT] ./umschalt {args}"
+        return f"Case #{i}: [TIMEOUT] ./program {args}"
     else:
-        return f"Case #{i}: [SUCCESS] ./umschalt {args}"
+        return f"Case #{i}: [SUCCESS] ./program {args}"
 
 
 def all_subclasses(cls):
@@ -108,16 +68,15 @@ class Test(metaclass=abc.ABCMeta):
     def __init__(self, submission_obj, **kwargs):
 
         if not self.dependencies_satisfied(submission_obj):
-            self.result     = self.label_failure
+            self.result     = False
             self.annotation = "TEST DEPENDENCY NOT MET"
-            return
+            self.serialize(submission_obj)
 
         elif str(self) in submission_obj['tests']:
             self.deserialize(submission_obj['tests'][str(self)])
 
         else:
-            self.result, self.annotation = self.run_test(
-                submission_obj, **kwargs)
+            self.result, self.annotation = self.run_test(submission_obj, **kwargs)
             self.serialize(submission_obj)
 
     def __bool__(self):
@@ -170,11 +129,7 @@ class CompileTest(Test):
 
     def run_test(self, submission_obj):
 
-        try:
-            ret = run_cmd("gcc-7 -c -xc -o code.o -", submission_obj['code'])
-        except subprocess.CalledProcessError as err:
-            print('[FATAL] The compiler failed.')
-
+        ret = run_cmd("gcc-7 -c -xc -Icode-testing -o code.o -", submission_obj['code'])
         return not ret.returncode, ret.stderr
 
 
@@ -186,7 +141,10 @@ class LinkTest(Test):
 
     def run_test(self, submission_obj):
 
-        ret = run_cmd("gcc-7 -o code a01-testing.o code.o")
+        t = submission_obj['type']
+        m = re.search(r'(a0\d)', t)
+
+        ret = run_cmd(f"gcc-7 -o code objects/{m.group(0)}-testing.o code.o")
         return not ret.returncode, ret.stderr
 
 
@@ -199,26 +157,37 @@ class UnitTestTest(Test):
 
     def run_test(self, submission_obj):
 
-        test_cases = (
-            ('', 'umschalt(NULL)\n== 0\n'),
-            ('...',  'input : "..."\numschalt("...")\n== 3\nresult: "..."\n'),
-            ('anV',  'input : "anV"\numschalt("anV")\n== 0\nresult: "ANv"\n'),
-        )
+        task = testcases_dict[submission_obj['type']]
+
+        return 1, '\n'.join(testcase(i, case, run_cmd(f"{task['cmd']} {case}").stdout) for i, case in enumerate(task['cases']))
+
+
+def main():
+
+    with open(SUBMISSIONS) as submission_file:
+        submissions = json.JSONDecoder().decode(submission_file.read())
 
-        return 1, '\n'.join(testcase(i, *test) for i, test in enumerate(test_cases))
+    # Get something disposable
+    path = tempfile.mkdtemp()
+    run_cmd(f'cp -r {OBJECTS}  {path}')
+    run_cmd(f'cp -r {BINARIES} {path}')
+    run_cmd(f'cp -r {HEADER} {path}')
+    os.chdir(path)
 
+    for username, data in submissions.items():
+        for submission_obj in data['submissions']:
+            UnitTestTest(submission_obj)
+            run_cmd('rm code*')
 
-path = tempfile.mkdtemp()
-run_cmd(f'cp ../data/testing_facility/klausur_tag_02/objects/* {path}')
-os.chdir(path)
+    print(json.dumps(submissions, sort_keys=True, indent=4))
 
-d = UnitTestTest(before["username"]['submissions'][0])
+if __name__ == '__main__':
+    testcases_dict = testcases.testcases(DESCFILE)
 
-# shutil.rmtree(path)
+    from pprint import pprint
+    main()
 
-print(path)
-print(d.annotation)
 
+# x = "#include \"a06-testing.h\"\n#include <stdio.h>\nvoid main() {\nchar *a;\nint *b;\nint i=0;\nint j=0;\nint k=0;\nwhile (scanf(\"%s\", &a)) {\nb[i]=ahoi(a);\ni++;\n}\nwhile(i-j) {\nprintf(\"%i\", b[j++]);\n}\nint c=1;\nint *t=b+i;\nint recSort(b, t, c)\nwhile (i-k) {\nprintf(\"%i\", b[k++]);\n}"
 
-with open("/dev/stdout", "w") as out:
-    out.write(json.JSONEncoder().encode(before))
+# print(x)
diff --git a/util/testcases.py b/util/testcases.py
index 87e24ed44e7cef2ea4f45315d21d2fcf230dfec2..e96efc26b21a1bfa131125bea0711468bae8ddd1 100644
--- a/util/testcases.py
+++ b/util/testcases.py
@@ -1,60 +1,53 @@
-r = '''-- [a01] Zeichen und Strings
-USAGE: ./bin/a01 <string> <character>
--- [a02] Iteration
-USAGE: ./bin/a02 <unsigned integer>
--- [a03] Rekursion
-USAGE: ./bin/a03 <integer> <integer> <integer> <integer>
--- [a04] Strukturen I
-USAGE: ./bin/a04 <integer> <integer> ... <integer> <integer>
--- [a05] Strukturen II
-NO EXECUTABLE
--- [a06] Speicher auf dem Heap
-USAGE: ./bin/a06 <integer> <integer> ... <integer> <integer>
-'''
-
 import re
+import json
 import random
 from string import ascii_letters, digits
 
 types = ('integer', 'unsigned_integer', 'character', 'string')
 list_sep = '...'
 
+re_task = re.compile(
+    r'^-- (?P<title>.*)\n(USAGE: (?P<cmd>[\./\w]+) (?P<syntax>.*)|NO EXECUTABLE)', re.MULTILINE)
+re_args = re.compile(rf"<({'|'.join(types)}|{'|'.join(t + '_list' for t in types)})>")
+
+
 def call_function(name: str, *args, **kwargs):
     return globals()[name](*args, **kwargs)
 
+
 def integer(bounds=1000):
     return random.randint(-bounds, bounds)
 
-def unsigned_integer(bounds=1000):
-    return random.randint(0, bounds)
+
+def unsigned_integer(upper=1000):
+    return random.randint(0, upper)
+
 
 def character():
     return random.choice(5*ascii_letters + 2*digits + '%*+,-./:?@[]^_{}~')
 
+
 def string(lenght=31):
-    return ''.join(character() for i in range(unsigned_integer(lenght)))
+    return ''.join(character() for i in range(2, 2 + unsigned_integer(lenght)))
+
 
 def type_list(_type):
     def generic_list():
         return ' '.join(str(call_function(_type)) for i in range(unsigned_integer(30)))
     return generic_list
 
-def rubbish():
-    return ' '.join(string(4))
-
-for t in types:
-    globals()[t + '_list'] = type_list(t) # I fucking love it
 
-
-task = re.compile(r'^-- (?P<title>.*)\n(USAGE: (?P<cmd>[\./\w]+) (?P<syntax>.*)|NO EXECUTABLE)', re.MULTILINE)
-args = re.compile(rf"<({'|'.join(types)}|{'|'.join(t + '_list' for t in types)})>")
+def rubbish():
+    return str(call_function(random.choice(tuple(t + '_list' for t in types) + types)))
 
 
 def argument_generator(syntax):
-    syntax, _ = re.subn(r'<([\w\s]+)> <\1> \.\.\. <\1> <\1>', r'<\1_list>', syntax)
+    syntax, _ = re.subn(
+        r'<([\w\s]+)> <\1> \.\.\. <\1> <\1>', r'<\1_list>', syntax)
     syntax, _ = re.subn(r'<(\w+)\s(\w+)>', r'<\1_\2>', syntax)
 
-    return ' '.join(str(call_function(arg)) for arg in re.findall(args, syntax))
+    return ' '.join(str(call_function(arg)) for arg in re.findall(re_args, syntax))
+
 
 def testcases_generator(task, n=10):
     syntax = task.group('syntax')
@@ -63,16 +56,29 @@ def testcases_generator(task, n=10):
         return
 
     yield ''
-    yield 0
+    yield '0'
 
-    for i in range(n//3):
+    for i in range(n//2):
         yield rubbish()
 
     for i in range(n):
         yield argument_generator(syntax)
 
-for task in re.finditer(task, r):
-    for t in testcases_generator(task):
-        print(t)
+
+def testcases(description_path):
+    for t in types:
+        globals()[t + '_list'] = type_list(t) # I fucking love it
+
+    with open(description_path) as description_file:
+        description = description_file.read()
+
+    return {
+        task['title'] : {
+            'cmd' : task['cmd'],
+            'cases' : [t for t in testcases_generator(task)]
+        } for task in re.finditer(re_task, description)
+    }
 
 
+if __name__ == '__main__':
+    print(json.JSONEncoder().encode(testcases()))