diff --git a/.gitignore b/.gitignore
index 7bd1165a32fb31075471368e925f415581b1d296..0c8dd6311b0c94b655c76c98c8fc75e6d004799f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,6 +4,7 @@ __pycache__/
 *$py.class
 
 output/*
+hallgrim.egg-info/*
 notes.html
 README.html
 .DS_Store
diff --git a/config.sample.ini b/config.sample.ini
deleted file mode 100644
index cfe9d5401aa5ad856a600c28388889c1df047167..0000000000000000000000000000000000000000
--- a/config.sample.ini
+++ /dev/null
@@ -1,9 +0,0 @@
-[META]
-author = your name
-
-
-[UPLAODER]
-user = root
-pass = homer
-host = http://localhost:8000/
-rtoken = c13456ec3d71dc657e19fb826750f676
diff --git a/deprecated_scripts/01_basics.py b/deprecated_scripts/01_basics.py
deleted file mode 100644
index d733ff197797d9888dd425b848a5073c7cf5f966..0000000000000000000000000000000000000000
--- a/deprecated_scripts/01_basics.py
+++ /dev/null
@@ -1,53 +0,0 @@
-import re
-
-
-def gap(content, points):
-    return "[gap({points}P)]{gap}[/gap]".format(points=points, gap=content)
-
-def p(content):
-    return '<p>{}</p>\n'.format(content)
-
-def li(content):
-    return '<li>{}</li>\n'.format(content)
-
-def tex(content):
-    return ('<span class="latex">' + content + '</span>').replace('\\', '\\\\')
-
-def generate_ilias():
-    aufgabe = p('Berechnen Sie:')
-
-    aufgabe += li(tex(r'\{a,b\} \cdot \{\varepsilon, cd\} = \{') + gap('a, acd, b, bcd', 0.5) + tex('\}'))
-    aufgabe += li(tex(r'\{\varepsilon, cd\} \cdot \{a, b\} = \{') + gap('a, b, cda, cdb', 0.5) + tex('\}'))
-    aufgabe += li(tex(r'\{\varepsilon, a, ab\}^2 = \{') + gap('eps, a, aa, aab, aba, abab', 0.5) + tex('\}'))
-    aufgabe += li(tex(r'\{\varepsilon\} \cdot \{\varepsilon\} = \{') + gap('eps', 0.5) + tex('\}'))
-    aufgabe += li(tex(r'\{\varepsilon\} \cdot \emptyset = ') + gap('{}', 0.5))
-    aufgabe += li(tex(r'\{\varepsilon\} \cdot \emptyset = ') + gap('{}', 0.5))
-    aufgabe += li(tex(r'\emptyset^2 = ') + gap('{}', 0.5))
-    aufgabe += li(tex(r'\emptyset^* = \{') + gap('eps', 0.5) + tex('\}'))
-    aufgabe += li(tex(r'\{\varepsilon\}^* = \{') + gap('eps', 0.5) + tex('\}'))
-    aufgabe += li(tex(r'\{\varepsilon, a\}^+ = \{') + gap('a*', 0.5) + tex('\}'))
-
-    aufgabe += ''' Verwenden Sie <code>eps</code> für {eps} und
-    <code>{{}}</code> für {empty}. Geben Sie alle Elemente der neuen Menge in
-    lexikographischer Reihenfolge an und verwenden Sie Leerzeichen nach einem
-    Komma. (Z.B. eps, a, ab, acd, ba)'''.format(eps=tex(r'\varepsilon'), empty=tex(r'\emptyset'))
-
-
-    return aufgabe.replace(r'"', r'\"')
-
-def generate_solution():
-        solution = "<h3>Musterloesung</h3><br>"
-        solution += re.sub(r'\[gap\(\d+P\)\](.+)\[\/gap\]',
-                           r'\1', generate_ilias())
-        return solution
-
-
-### END OF SCRIPT ########################################################
-meta = {
-    "type": "GAP",
-    "title": "Grundlagen",
-    "author": "Jan Maximilian Michal",
-    "gapLength": 10,
-    "question": generate_ilias(),
-    "solution": generate_solution(),
-}
diff --git a/deprecated_scripts/02_chomsky_grammar.py b/deprecated_scripts/02_chomsky_grammar.py
deleted file mode 100644
index 092f63d0f496c865dbc8731912f1c16274149cf7..0000000000000000000000000000000000000000
--- a/deprecated_scripts/02_chomsky_grammar.py
+++ /dev/null
@@ -1,89 +0,0 @@
-from itertools import product
-
-
-delta = """
-    S := AB | ABA
-    A := aA | a
-    B := Bb | eps
-"""
-
-class rule:
-    __slots__ = ['left', 'right']
-    def __init__(self, left, right, sep=""):
-        self.left = left
-        self.right = [c for c in right] if right != "eps" else []
-
-    def __str__(self):
-        return self.left + " := " + ''.join(self.right)
-
-    def __hash__(self):
-        return hash(str(self))
-
-    def __eq__(self, other):
-        return self.left == other.left and self.right == other.right
-
-
-def parse(grammer):
-    grammer   = grammer.strip()
-    terminals = set()
-    non_terms = set()
-    rules     = set()
-
-    for line in grammer.split("\n"):
-        N, rule_list = line.split(":=")
-        rules |= {rule(N.strip(), right.strip()) for right in rule_list.split("|")}
-        non_terms |= {N}
-
-    for r in rules:
-        if r.right != 'eps':
-            terminals |= {T for T in r.right if T.islower()}
-
-    return rules, terminals, non_terms
-
-P, T, N = parse(delta)
-
-# print(('\n'.join(map(str, P))))
-# print()
-
-letters_to_kill = {p.left for p in P if not p.right}
-new_P = set() | P
-for p in P:
-    for l in letters_to_kill:
-        n = p.right.count(l)
-        r = ''.join(p.right).replace(l, "{}")
-
-        # 0 is a placeholder for empty string
-        for prod in product(l + "0", repeat=n):
-            new_P |= {rule(p.left, r.format(*prod).replace("0", ""))}
-
-P = {p for p in new_P if p.right}
-# print(('\n'.join(map(str, P))))
-# print()
-
-for t in T:
-    P |= {rule("T_" + t, t)}
-
-# print(T)
-
-new_P = set() | P
-for p in P:
-    p.right = ["T_" + p if p in T else p for p in p.right]
-
-P = new_P
-# print(('\n'.join(map(str, P))))
-# print()
-
-new_P = set() | P
-for p in P:
-    if len(p.right) > 2:
-        pass
-
-### END OF SCRIPT ##############################################################
-meta = {
-    "type"      : "GAP",
-    "title"     : "Grammatik in Chomsky Normalform umwandeln",
-    "author"    : "Jan Maximilian Michal",
-    "gapLength" : 10,
-    "question"  : "Empty",
-    "solution"  : "TODO",
-}
\ No newline at end of file
diff --git a/deprecated_scripts/04_minimize_dea.py b/deprecated_scripts/04_minimize_dea.py
deleted file mode 100644
index 3c2fa64a42007b21a029e34d23500b768d53aedc..0000000000000000000000000000000000000000
--- a/deprecated_scripts/04_minimize_dea.py
+++ /dev/null
@@ -1,173 +0,0 @@
-import re
-
-from itertools import product
-from graphviz import Digraph
-
-# relative imports
-
-def gap(content, points):
-    return "[gap({points}P)]{gap}[/gap]".format(points=points, gap=content)
-
-def tex(content):
-    return ('<span class="latex">' + content + '</span>').replace('\\', '\\\\')
-
-
-class Automaton:
-
-    """docstring for Automaton"""
-    __slots__ = ['states', 'sigma', 'delta', 'q0', 'F']
-
-    def __init__(self, states, sigma, delta, q0, F):
-        self.states = states
-        self.sigma = set(sigma)
-        self.delta = delta
-        self.q0 = q0
-        self.F = set(F)
-
-    def state_pairs(self):
-        return filter(lambda p: p[0] != p[1], product(self.states[:-1], self.states[1:]))
-
-    def bisimilar(self, k, z1, z2):
-        if k == 0:
-            return (z1 in self.F) == (z2 in self.F)
-
-        return self.bisimilar(k-1, z1, z2) and \
-            all(self.bisimilar(k-1, self.delta(z1, a), self.delta(z2, a))
-                for a in self.sigma)
-
-    def minimize(self):
-        # Initialize
-        k = 0
-        change = True
-        marker = {
-            pair: 0 for pair in self.state_pairs() if not self.bisimilar(0, *pair)}
-
-        # Iterate
-        while change:
-            change = False
-            for z1, z2 in (pair for pair in self.state_pairs() if pair not in marker):
-                if any(not self.bisimilar(k, self.delta(z1, a), self.delta(z2, a)) for a in self.sigma):
-                    marker[(z1, z2)] = k+1
-                    change = True
-            k += 1
-
-        # Finalize TODO
-        return marker
-
-    def generate_form(self):
-        marker = self.minimize()
-
-        form = '\n\n<p><table  border-collapse: collapse; border-style: hidden;  rules=\"all\">\n'
-        form += '<tr>\n\t<td> </td>\n\t<td>' + \
-            '</td>\n\t<td>'.join(self.states[1:]) + '</td></tr>\n'
-        for i, z1 in enumerate(self.states[:-1]):
-            form += '<tr>\n\t<td>{}</td>\n'.format(z1)
-            for j, z2 in enumerate(self.states[1:]):
-                content = '\t<td>{}</td>\n'
-                if j < i:
-                    content = content.format(' ')
-                elif (z1, z2) not in marker:
-                    content = content.format(gap('X', 1))
-                else:
-                    content = content.format(gap(marker[(z1, z2)], 1))
-                form += content
-            form += '</tr>\n'
-        form += '</table></p>'
-
-        return form
-
-    def generate_task(self):
-
-        aufgabe = '''Minimieren Sie den folgenden deterministischen Automaten
-{[tex]M = \\{\\{%s\\},\\{%s\\},\\\\delta,\\{%s\\},\\{%s\\}\\}[/tex]} oder zeigen Sie, dass der Automat
-bereits minimal ist. Geben Sie die Tabelle mit den Zustandspaaren an, sowie den
-minimierten Graphen.<br>\n\n''' % (', '.join(self.states), ', '.join(self.sigma),
-                                   str(self.q0), ', '.join(self.F))
-
-        aufgabe += '<p>' + self.graph_output() + '</p>'
-
-        aufgabe += self.generate_form()
-
-        return aufgabe.replace(r'"', r'\"')
-
-    def graph_output(self, file_format='svg'):
-        f = Digraph('finite_state_machine', format=file_format, engine='dot')
-        f.body.extend(['rankdir=LR', 'size="8,5"'])
-
-        f.attr('node', shape='doublecircle')
-        for node in self.F:
-            f.node(node)
-
-        f.attr('node', shape='circle')
-        f.node('', style='invis')
-        f.edge('', self.q0)
-        for state in self.states:
-            for a in self.sigma:
-                f.edge(state, self.delta(state, a), label=a)
-
-        return str(f.pipe(), encoding='utf-8')
-
-    def generate_solution(self):
-        solution = "<h3>Musterloesung</h3><br>"
-        solution += re.sub(r'\[gap\(\d+P\)\](.+)\[\/gap\]',
-                           r'\1', self.generate_form())
-        return solution.replace(r'"', r'\"')
-
-
-def delta(state, char):
-    return {
-        ('s0', 'a'): 's3',
-        ('s0', 'b'): 's1',
-        ('s1', 'a'): 's2',
-        ('s1', 'b'): 's4',
-        ('s2', 'a'): 's2',
-        ('s2', 'b'): 's4',
-        ('s3', 'a'): 's3',
-        ('s3', 'b'): 's1',
-        ('s4', 'a'): 's4',
-        ('s4', 'b'): 's4'
-    }[(state, char)]
-
-
-def delta2(state, char):
-    return {
-        ('s0', 'a'): 's2',
-        ('s0', 'b'): 's2',
-
-        ('s1', 'a'): 's0',
-        ('s1', 'b'): 's3',
-
-        ('s2', 'a'): 's1',
-        ('s2', 'b'): 's4',
-
-        ('s3', 'a'): 's4',
-        ('s3', 'b'): 's3',
-
-        ('s4', 'a'): 's5',
-        ('s4', 'b'): 's4',
-
-        ('s5', 'a'): 's3',
-        ('s5', 'b'): 's6',
-
-        ('s6', 'a'): 's6',
-        ('s6', 'b'): 's6',
-    }[(state, char)]
-
-states = ["s{}".format(i) for i in range(5)]
-states2 = ["s{}".format(i) for i in range(7)]
-
-F = ["s2"]
-F2 = ["s0", "s3", "s4", "s6"]
-
-A = Automaton(states, "ab", delta, "s0", F)
-
-
-### END OF SCRIPT ########################################################
-meta = {
-    "type": "GAP",
-    "title": "Minimieren eines deterministischen Automaten small",
-    "author": "Jan Maximilian Michal",
-    "gapLength": 10,
-    "question": A.generate_task(),
-    "solution": A.generate_solution(),
-}
diff --git a/deprecated_scripts/05_nea_to_dea.py b/deprecated_scripts/05_nea_to_dea.py
deleted file mode 100644
index 6d67db55f167f544ead725f9e44c8100d2ad1424..0000000000000000000000000000000000000000
--- a/deprecated_scripts/05_nea_to_dea.py
+++ /dev/null
@@ -1,133 +0,0 @@
-from collections import deque
-from functools import reduce
-from graphviz import Digraph
-
-import re
-
-
-def gap(content, points):
-    return "[gap({points}P)]{gap}[/gap]".format(points=points, gap=content)
-
-def p(content):
-    return '<p>{}</p>\n'.format(content)
-
-def tex(content):
-    return ('<span class="latex">' + content + '</span>').replace('\\', '\\\\')
-
-
-class NEA:
-
-    """docstring for NEA"""
-    __slots__ = ['states', 'sigma', 'delta', 'q0', 'F']
-
-    def __init__(self, states, sigma, delta, q0, F):
-        self.states = states
-        self.sigma = sigma
-        self.delta = delta
-        self.q0 = q0
-        self.F = set(F)
-
-    def to_dea(self):
-        done = []
-        new_steps = deque([{self.q0}])
-        table = []
-
-        while new_steps:
-            cur = new_steps.popleft()
-            table.append([cur])
-            for a in self.sigma:
-                next = reduce(lambda a, b: a | b, (self.delta(s, a) for s in cur))
-                table[-1].append(next)
-                if next not in done:
-                    new_steps.append(next)
-                    done.append(next)
-
-        return table
-
-    def graph_output(self, file_format='svg'):
-        f = Digraph('finite_state_machine', format=file_format, engine='dot')
-        f.body.extend(['rankdir=LR', 'size="8,5"'])
-
-        f.attr('node', shape='doublecircle')
-        for node in self.F:
-            f.node(node)
-
-        f.attr('node', shape='circle')
-        f.node('', style='invis')
-        f.edge('', self.q0)
-        for state in self.states:
-            for a in self.sigma:
-                for next in self.delta(state, a):
-                    f.edge(str(state), next, label=a)
-
-        return str(f.pipe(), encoding='utf-8')
-
-    def generate_form(self):
-        table = self.to_dea()
-        tr = '<tr>\n{}</tr>\n'
-        td = '\t<td>{}</td>\n'
-
-        aufgabe = '<table  border-collapse: collapse; border-style: hidden;  rules=\"all\">\n'
-        aufgabe += tr.format(''.join(td.format(s)
-                                     for s in [tex(r'\delta'), "a", "b"]))
-        for row in table:
-            first, second, third = map(', '.join, (sorted(s) for s in row))
-            aufgabe += tr.format(td.format(first) +
-                                 td.format(gap(second, 1)) +
-                                 td.format(gap(third, 1)))
-        aufgabe += '</table>'
-
-        return aufgabe
-
-    def generate_ilias(self):
-        aufgabe = '''Wandeln Sie M in einen DEA M' um, indem Sie die
-            Potenzmenge der Zustände aus M in M' als neue Zustände einfügen
-            (Eine Anleitung befindet sich im Skript von Dr. Müller S. 25).\n\n'''
-
-        aufgabe += p(self.graph_output())
-        aufgabe += p('''Füllen Sie diese Tabelle nach dem Vorbild im Müller
-            Skript aus. Achten Sie dabei darauf alle Zustände in lexikographischer
-            Reihenfolge aufzulisten (Zum Beispiel: s1, s2, s4) und alle Zustände
-            müssen mit Komma und Leerzeichen getrennt werden.''')
-        aufgabe += p(self.generate_form())
-
-        return aufgabe.replace('"', r'\"')
-
-    def generate_solution(self):
-        solution = "<h3>Musterloesung</h3><br>"
-        solution += re.sub(r'\[gap\(\d+P\)\](.+)\[\/gap\]',
-                           r'\1', self.generate_form())
-        return solution.replace(r'"', r'\"')
-
-
-# Define one Automaton
-def delta(state, char):
-    return {
-        ('s0', 'a'): {'s0', 's1'},
-        ('s0', 'b'): {'s0', 's2'},
-
-        ('s1', 'a'): {'s1', 's3'},
-        ('s1', 'b'): {'s1'},
-
-        ('s2', 'a'): {'s2'},
-        ('s2', 'b'): {'s2', 's3'},
-
-        ('s3', 'a'): set(),
-        ('s3', 'b'): set(),
-    }[(state, char)]
-
-states = ["s{}".format(i) for i in range(4)]
-F = ["s3"]
-
-# create
-N = NEA(states, "ab", delta, 's0', F)
-
-### END OF SCRIPT ########################################################
-meta = {
-    "type": "GAP",
-    "title": "NEA in DEA umwandeln",
-    "author": "Jan Maximilian Michal",
-    "gapLength": 10,
-    "question": N.generate_ilias(),
-    "solution": N.generate_solution(),
-}
diff --git a/deprecated_scripts/README.md b/deprecated_scripts/README.md
deleted file mode 100644
index 5f9441fe252f8656772cf2ee2751c4febc613293..0000000000000000000000000000000000000000
--- a/deprecated_scripts/README.md
+++ /dev/null
@@ -1,3 +0,0 @@
-These scripts can no longer function with Hallgrim, since they rely on autoilias
-which will become obsolete once hallgrim is feature complete. They are kept here
-so their logic can be translated into proper scripts.
diff --git a/deprecated_scripts/__init__.py b/deprecated_scripts/__init__.py
deleted file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000
diff --git a/deprecated_scripts/util.py b/deprecated_scripts/util.py
deleted file mode 100644
index 85341592c3fb6a55076f30e9889afd94e87a409e..0000000000000000000000000000000000000000
--- a/deprecated_scripts/util.py
+++ /dev/null
@@ -1,4 +0,0 @@
-
-def gap(content, points):
-    return "[gap({points}P)]{gap}[/gap]".format(points=points, gap=content)
-
diff --git a/hallgrim/IliasXMLCreator/gap.py b/hallgrim/IliasXMLCreator/gap.py
index 936c66a3dc9af1ca595b4b3e15018195719f2f12..523f5e9875ad085689ee55b088da253652ac7e38 100644
--- a/hallgrim/IliasXMLCreator/gap.py
+++ b/hallgrim/IliasXMLCreator/gap.py
@@ -1,6 +1,6 @@
 import xml.etree.ElementTree as et
 
-from hallgrim.IliasXMLCreator.xmlBuildingBlocks import *
+from .xmlBuildingBlocks import *
 
 def xml_print(element, **kwargs):
     import xml.dom.minidom
diff --git a/hallgrim/IliasXMLCreator/multi.py b/hallgrim/IliasXMLCreator/multi.py
index b7a4d2c2d3afcfbc650550c7a8d085b80dd4c088..fa62314065ad94c673dbeca03949ad36763a521b 100644
--- a/hallgrim/IliasXMLCreator/multi.py
+++ b/hallgrim/IliasXMLCreator/multi.py
@@ -1,6 +1,6 @@
 import xml.etree.ElementTree as et
 
-from hallgrim.IliasXMLCreator.xmlBuildingBlocks import *
+from .xmlBuildingBlocks import *
 
 
 class MultipleChoiceQuestion:
diff --git a/hallgrim/IliasXMLCreator/packer.py b/hallgrim/IliasXMLCreator/packer.py
index f3cccb6cc47a1f726aa2c4c511fca37a121c9ceb..f82504c7a6cb3ae46b6067c7dfee6c182edaf820 100644
--- a/hallgrim/IliasXMLCreator/packer.py
+++ b/hallgrim/IliasXMLCreator/packer.py
@@ -1,6 +1,6 @@
 import xml.etree.ElementTree as et
 
-from hallgrim.IliasXMLCreator import multi, single, gap
+from . import multi, single, gap
 
 def create_xml_tree(item_list):
     root = et.Element('questestinterop')
diff --git a/hallgrim/IliasXMLCreator/single.py b/hallgrim/IliasXMLCreator/single.py
index 747fd686649447e6308582db15b13e9f743569d1..38c65230682d65bdf270cfec063a38f7a418c7f7 100644
--- a/hallgrim/IliasXMLCreator/single.py
+++ b/hallgrim/IliasXMLCreator/single.py
@@ -1,6 +1,6 @@
 import xml.etree.ElementTree as et
 
-from hallgrim.IliasXMLCreator.multi import *
+from .multi import *
 
 
 class SingleChoiceQuestion(MultipleChoiceQuestion):
diff --git a/hallgrim/IliasXMLCreator/xmlBuildingBlocks.py b/hallgrim/IliasXMLCreator/xmlBuildingBlocks.py
index 238591e5a922720e5197250f9ec50acf8f03a69c..dd9a9a28c868bb013b0272e544c905f8c97a7aa0 100644
--- a/hallgrim/IliasXMLCreator/xmlBuildingBlocks.py
+++ b/hallgrim/IliasXMLCreator/xmlBuildingBlocks.py
@@ -150,7 +150,3 @@ def response_num(ident, columns, _min, _max, numtype='Decimal'):
     render_fib = et.Element('render_fib', attrib={'columns': str(columns), 'fibtype': numtype, 'maxnumber': _max, 'minnumber': _min, 'prompt': "Box"})
     response_num.append(render_fib)
     return response_num
-
-
-# xml_print(response_choice(2, ['a', 'b', 'c']))
-
diff --git a/hallgrim/__init__.py b/hallgrim/__init__.py
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..803f7ff936f5b32b02922092e27c905556058dc5 100644
--- a/hallgrim/__init__.py
+++ b/hallgrim/__init__.py
@@ -0,0 +1,9 @@
+
+__title__ = 'hallgrim'
+__version__ = '0.1'
+__author__ = 'Jan Maximilian Michal'
+__license__ = 'MIT'
+__copyright__ = 'Copyright 2016 Jan Maximilian Michal'
+
+# for the executable
+from .hallgrim import parseme
diff --git a/hallgrim/bin/hallgrim b/hallgrim/bin/hallgrim
new file mode 100644
index 0000000000000000000000000000000000000000..7de9d220eb6af00968d4beafef945064b63cea28
--- /dev/null
+++ b/hallgrim/bin/hallgrim
@@ -0,0 +1,4 @@
+import hallgrim
+
+if __name__ == '__main__':
+    hallgrim.parseme()
\ No newline at end of file
diff --git a/grim.py b/hallgrim/hallgrim.py
similarity index 94%
rename from grim.py
rename to hallgrim/hallgrim.py
index 516c26160bbd02903270e697d26baed11b86f421..0eabbe00c3f1a0817e3a5d386b11cef61265287f 100755
--- a/grim.py
+++ b/hallgrim/hallgrim.py
@@ -1,4 +1,4 @@
-#!/usr/local/bin/python3
+#!/usr/bin/env python3
 
 ##########################################################################
 #
@@ -17,18 +17,22 @@
 #
 ##########################################################################
 
-import importlib
+import importlib.util
 import argparse
 import os
 import sys
 import configparser
 
 # local import
-from hallgrim.IliasXMLCreator import packer
-from hallgrim.custom_markdown import get_markdown
-from hallgrim.messages import *
-from hallgrim.parser import *
-from hallgrim.uploader import send_script
+from .IliasXMLCreator import packer
+from .custom_markdown import get_markdown
+from .messages import *
+from .parser import choice_parser, gap_parser
+from .uploader import send_script
+from .templates import scaffolding
+
+# set markdown
+markdown = get_markdown()
 
 
 def get_config():
@@ -38,7 +42,7 @@ def get_config():
         error('Could not find config file.')
         error('Please edit config.sample.ini and move it to config.ini')
         error('Continue with default values. Script might fail.')
-        config.read('config.sample.ini')
+        config['META'] = {'author' : '__default__'}
     return config
 
 def file_to_module(name):
@@ -158,7 +162,10 @@ def delegator(output, script_list, instances):
         instances {int}    -- number of instances that should be generated
     """
     for script_name in filter(lambda a: a.endswith('.py'), script_list):
-        script = importlib.import_module(file_to_module(script_name))
+        module_name = os.path.basename(script_name)
+        spec   = importlib.util.spec_from_file_location(module_name, script_name)
+        script = importlib.util.module_from_spec(spec)
+        spec.loader.exec_module(script)
         handler = {
             'gap': handle_gap_questions,
             'single': handle_choice_questions,
@@ -245,8 +252,6 @@ def handle_new_script(name, qtype, author, points):
         author {str}   -- the author of the script
         points {float} -- number of points for the task
     """
-    from hallgrim.templates import scaffolding
-
     with open('scripts/' + name + '.py', 'w') as new_script:
         choice = ''
         if qtype in ['multiple choice', 'single choice']:
@@ -277,7 +282,3 @@ def handle_upload(script_path, config):
     )
     info("Uploaded %s. Status code looks %s." %
          (script_path, "good" if r else "bad"))
-
-if __name__ == '__main__':
-    markdown = get_markdown()
-    parseme()
diff --git a/hallgrim/parser.py b/hallgrim/parser.py
index 70d7e5002abaf92f1bb7b9d560c396442360e363..3ccb74119f2ef3d11c0925f06eeef972eb69cdd7 100644
--- a/hallgrim/parser.py
+++ b/hallgrim/parser.py
@@ -1,8 +1,7 @@
 import re
+import collections
 
-from hallgrim.custom_markdown import get_markdown
-from collections import deque
-from pprint import pprint
+from .custom_markdown import get_markdown
 
 
 def choice_parser(raw_choices, points):
@@ -23,28 +22,31 @@ def choice_parser(raw_choices, points):
         markdown(text),
         True if mark != ' ' else False,
         float(mark) if mark not in ' X' else points)
-    for mark, _, text in parse]
+        for mark, _, text in parse]
     return final
 
+
 def gap_parser(task):
     markdown = get_markdown()
 
     # '\[gap\]([\w\W]+?)\[\/gap\]'
     # '\[select\]([\w\W]+?)\[\/select\]'
     # '\[numeric\]([\w\W]+?)\[\/numeric\]'
-    # We match against one big regex that consists of three smaller ones (see above)
+    # We match against one big regex that consists of three smaller ones (see
+    # above)
     _all = re.compile('(\[numeric\((([0-9]*[.])?[0-9]+)P\)\]([\w\W]+?)(\[\/numeric\])|(\[select\])([\w\W]+?)\[\/select\]|\[gap\((([0-9]*[.])?[0-9]+)P\)\]([\w\W]+?)(\[\/gap\]))', re.MULTILINE)
     for m in re.finditer(_all, task):
         ('[gap]' in m.groups())
 
-    gaps = deque()
+    gaps = collections.deque()
     for m in re.finditer(_all, task):
         if '[select]' in m.groups():
             match = m.group(7)
             lines = match.strip().split('\n')
             regex = re.compile('\[(([0-9]*[.])?[0-9]+| )\]\s?([\w\W]+)', re.MULTILINE)
             parse = [re.search(regex, line).groups() for line in lines]
-            gaps.append(([(text, float(points) if not points == ' ' else 0) for points, _, text in parse], 999))
+            gaps.append(([(text, float(points) if not points == ' ' else 0)
+                          for points, _, text in parse], 999))
 
         if '[/gap]' in m.groups():
             match = m.group(10)
@@ -63,9 +65,9 @@ def gap_parser(task):
 
     source = re.sub(_all, 'AISBLAKJSD', task)
     source = markdown(source)
-    texts = deque(source.split('AISBLAKJSD'))
+    texts = collections.deque(source.split('AISBLAKJSD'))
 
-    final = deque()
+    final = collections.deque()
     for _ in range(min(len(texts), len(gaps))):
         text = texts.popleft()
         if text != "":
diff --git a/hallgrim/ilias_templates/gap/1478024104__9310__qpl_82996.xml b/hallgrim/res/ilias_templates/gap/1478024104__9310__qpl_82996.xml
similarity index 100%
rename from hallgrim/ilias_templates/gap/1478024104__9310__qpl_82996.xml
rename to hallgrim/res/ilias_templates/gap/1478024104__9310__qpl_82996.xml
diff --git a/hallgrim/ilias_templates/gap/1478024104__9310__qti_82996.xml b/hallgrim/res/ilias_templates/gap/1478024104__9310__qti_82996.xml
similarity index 100%
rename from hallgrim/ilias_templates/gap/1478024104__9310__qti_82996.xml
rename to hallgrim/res/ilias_templates/gap/1478024104__9310__qti_82996.xml
diff --git a/hallgrim/ilias_templates/multiple choice/1478003900__9310__qpl_82996.xml b/hallgrim/res/ilias_templates/multiple choice/1478003900__9310__qpl_82996.xml
similarity index 100%
rename from hallgrim/ilias_templates/multiple choice/1478003900__9310__qpl_82996.xml
rename to hallgrim/res/ilias_templates/multiple choice/1478003900__9310__qpl_82996.xml
diff --git a/hallgrim/ilias_templates/multiple choice/1478003900__9310__qti_82996.xml b/hallgrim/res/ilias_templates/multiple choice/1478003900__9310__qti_82996.xml
similarity index 100%
rename from hallgrim/ilias_templates/multiple choice/1478003900__9310__qti_82996.xml
rename to hallgrim/res/ilias_templates/multiple choice/1478003900__9310__qti_82996.xml
diff --git a/hallgrim/ilias_templates/single choice/1478020233__9310__qpl_82996.xml b/hallgrim/res/ilias_templates/single choice/1478020233__9310__qpl_82996.xml
similarity index 100%
rename from hallgrim/ilias_templates/single choice/1478020233__9310__qpl_82996.xml
rename to hallgrim/res/ilias_templates/single choice/1478020233__9310__qpl_82996.xml
diff --git a/hallgrim/ilias_templates/single choice/1478020233__9310__qti_82996.xml b/hallgrim/res/ilias_templates/single choice/1478020233__9310__qti_82996.xml
similarity index 100%
rename from hallgrim/ilias_templates/single choice/1478020233__9310__qti_82996.xml
rename to hallgrim/res/ilias_templates/single choice/1478020233__9310__qti_82996.xml
diff --git a/hallgrim/test.py b/hallgrim/test.py
deleted file mode 100644
index 289453af3e27f95dd95b1e66c47d7cc834316fbb..0000000000000000000000000000000000000000
--- a/hallgrim/test.py
+++ /dev/null
@@ -1,84 +0,0 @@
-# -*- coding: utf-8 -*-
-
-from custom_markdown import get_markdown
-from collections import deque
-from pprint import pprint
-
-
-task = """[gap]LALAL2[/gap] KJAakjsfdaskdjfnalksdf
-
-
-```java
-[select]
-    [3] `int n_ze = m.length;`
-    [ ] `int n_ze = m[0].length;`
-    [ ] `int n_ze = m.length();`
-    [ ] `int n_ze = m[0].length();`
-[/select]
-
-[gap]LALAL1[/gap][gap]LALAL2[/gap]
-
-public static void main {
-    System.out.println("TATAT");
-}
-[numeric]3.4,-1, 34.7[/numeric][numeric]4,+5,6[/numeric][numeric]4[/numeric]
-```
-
-
-HALLO WO BIN ICH
-
-[select]
-    [4] `int n_ze = m.length;`
-    [ ] `asdlkjasld;`
-[/select]
-
-END"""
-
-import re
-
-markdown = get_markdown()
-
-
-# '\[gap\]([\w\W]+?)\[\/gap\]'
-# '\[select\]([\w\W]+?)\[\/select\]'
-# '\[numeric\]([\w\W]+?)\[\/numeric\]'
-# We match against one big regex that consists of three smaller ones (see above)
-_all = re.compile('(\[numeric\]([\w\W]+?)(\[\/numeric\])|(\[select\])([\w\W]+?)\[\/select\]|\[gap\]([\w\W]+?)(\[\/gap\]))', re.MULTILINE)
-for m in re.finditer(_all, task):
-    ('[gap]' in m.groups())
-
-gaps = deque()
-for m in re.finditer(_all, task):
-    if '[select]' in m.groups():
-        match = m.group(5)
-        lines = match.strip().split('\n')
-        regex = re.compile('\[(([0-9]*[.])?[0-9]+| )\]\s?([\w\W]+)', re.MULTILINE)
-        parse = [re.search(regex, line).groups() for line in lines]
-        gaps.append([(text, float(points) if not points == ' ' else 0) for points, _, text in parse])
-
-    if '[/gap]' in m.groups():
-        match = m.group(6).strip('\n\t ')
-        gaps.append((match, 4)) ## ADD POINTS !!
-
-    if '[/numeric]' in m.groups():
-        match = m.group(2)
-        regex = re.compile('[-+]?\d*\.\d+|\d+')
-        parse = re.findall(regex, match)
-        if len(parse) == 1:
-            gaps.append(((parse[0], parse[0], parse[0]), 4))
-        elif len(parse) == 3:
-            gaps.append((tuple(parse), 4))
-        else:
-            raise Exception("Numeric gap takes either exactly one value or (value, min, max).")
-
-n = re.sub(_all, 'GAPGAP', task)
-n = markdown(n)
-t = deque(n.split('GAPGAP'))
-
-final = deque()
-while text or gaps:
-    if text[0] != "":
-        final.append(text.popleft())
-    final.append(gap.popleft())
-
-return final
\ No newline at end of file
diff --git a/scripts/Eine Methode (I1-ID: 75li4j91gdg0).py b/scripts/Eine Methode (I1-ID: 75li4j91gdg0).py
deleted file mode 100644
index 1ab1b5c639c9a5d907c1c90ad848a62393638d21..0000000000000000000000000000000000000000
--- a/scripts/Eine Methode (I1-ID: 75li4j91gdg0).py	
+++ /dev/null
@@ -1,51 +0,0 @@
-meta = {
-    'author': 'ILIAS Author',
-    'title': 'Eine Methode (I1-ID: 75li4j91gdg0)',
-    'type': 'gap',
-    'points': 5.0,
-}
-
-gap1 = "[select][0.0]final\n [0.5]static\n [0]void\n [0]private\n [/select]"
-gap2 = "[select][0]string\n [0]int\n [0.5]boolean\n [0]class\n [/select]"
-gap3 = "[select][1]return\n [0]system.out.println\n [0]=\n [0]set\n [/select]"
-gap4 = "[select][0]j % 4\n [0]j : 4\n [0.5]j % 4 == 0\n [0]j : 4 == 0\n [/select]"
-gap5 = "[select][0.5]&&\n [0.5]||\n [0.5]&\n [0]^\n [/select]"
-gap6 = "[select][0]j : 100 != 0 || j : 400 == 0\n [0]j % 100 != 0 || j % 400 = 0\n [0]j : 100 != 0 || j : 400 = 0\n [1]j % 100 != 0 || j % 400 == 0\n [/select]"
-
-task = """
-
-Ein Jahr ist ein Schaltjahr, wenn es durch 4 aber nicht durch 100 teilbar ist
-oder aber, wenn es durch 400 teilbar ist. Ergänzen Sie den folgenden Quelltext
-so, dass die Methode genau dann den Wert true liefert, wenn Jahr j ein
-Schaltjahr ist.
-
-```java
-class Schaltjahr {
-    public static void main(String[] args) {
-        int jahr = Integer.parseInt(args[0]);
-        System.out.println(schaltjahr(jahr));
-    }
-    public %s %s schaltjahr (int j) {
-        %s (%s %s %s);
-    }
-}
-```
-
-""" % (gap1, gap2, gap3, gap4, gap5, gap6)
-
-
-feedback = """
-Der vollständige Code:
-
-```java_copy
-class Schaltjahr {
-    public static void main(String[] args) {
-        int jahr = Integer.parseInt(args[0]);
-        System.out.println(schaltjahr(jahr));
-    }
-    public static boolean schaltjahr (int j) {
-        return (j % 4 == 0 && j % 100 != 0 || j % 400 == 0);
-    }
-}
-```
-"""
diff --git a/scripts/Polynome (I1-ID: 177d1ez05pg0).py b/scripts/Polynome (I1-ID: 177d1ez05pg0).py
deleted file mode 100644
index a7d5646617e9ef135756f3391a4aceb5489708b2..0000000000000000000000000000000000000000
--- a/scripts/Polynome (I1-ID: 177d1ez05pg0).py	
+++ /dev/null
@@ -1,75 +0,0 @@
-meta = {
-    'author': 'Jan Maximilian Michal',
-    'title': 'Polynome (I1-ID: 177d1ez05pg0)',
-    'type': 'gap',
-    'points': 0.0,
-}
-
-task = """
-Vervollständigen Sie die folgende Klasse:
-
-```java
-public class Polynom {
-    // diese Klasse dient dazu, Polynome (also Funktionen der Gestalt
-    // a(x) = a0 + a1*x + a2*x^2 + ... + ad*x^d) als statische
-    // Java-Funktionen bereitzustellen
-
-    /* Argumente: double-Feld (fuer Koeffizienten a0, a1, .., ad) und Zahl x
-       Ergebniswert: Wert des Polynoms an der Stelle x (Typ double)*/
-    public static double p([gap(0.5P)]double[] a[/gap], double x) {
-        // Sonderfall: das Nullpolynom
-        int d = [gap(0.5P)]a.length - 1[/gap]; // Polynomgrad
-        if ( d == -1)
-            return 0;
-        // ansonsten: berechne gesuchten Wert nach dem Horner-Schema:
-        double v = 0;
-        for (int i = d; i [gap(0.5P)]>=[/gap] 0; i--) {
-            v [gap(0.5P)]*=[/gap] x;
-            v += a[i];
-        }
-        return v;
-    }
-
-    public static void main(String[] args) {     /* Unit-Test */
-        [gap(0.5P)]double[][/gap] a = {2,1,-1,3};
-        System.out.println(p([gap(0.5P)]a[/gap], 10));
-    }
-}
-```
-
-Welcher Wert wird bei dem Unit-Test ausgegeben? [gap(1P)]2912[/gap]
-"""
-
-feedback = """
-Der vollständige Quelltext
-
-```java
-public class Polynom {
-    // diese Klasse dient dazu, Polynome (also Funktionen der Gestalt
-    // a(x) = a0 + a1*x + a2*x^2 + ... + ad*x^d) als statische
-    // Java-Funktionen bereitzustellen
-
-    /* Argumente: double-Feld (fuer Koeffizienten a0, a1, .., ad) und Zahl x
-       Ergebniswert: Wert des Polynoms an der Stelle x (Typ double)*/
-    public static double p(double[] a, double x) {
-        // Sonderfall: das Nullpolynom
-        int d = a.length - 1; // Polynomgrad
-        if ( d == -1)
-            return 0;
-        // ansonsten: berechne gesuchten Wert nach dem Horner-Schema:
-        double v = 0;
-        for (int i = d; i >= 0; i--) {
-            v *= x;
-            v += a[i];
-        }
-        return v;
-    }
-
-    public static void main(String[] args) {     /* Unit-Test */
-        double[] a = {2,1,-1,3};
-        System.out.println(p(a, 10));
-    }
-}
-```
-
- """
diff --git a/scripts/Rekursion (I1-ID: vi02mcw0lfh0).py b/scripts/Rekursion (I1-ID: vi02mcw0lfh0).py
deleted file mode 100644
index cd6e0301cb6d8c14358b6f102ac119acfac6336e..0000000000000000000000000000000000000000
--- a/scripts/Rekursion (I1-ID: vi02mcw0lfh0).py	
+++ /dev/null
@@ -1,35 +0,0 @@
-meta = {
-    'author': 'ILIAS Author',
-    'title': 'Rekursion (I1-ID: vi02mcw0lfh0)',
-    'type': 'gap',
-    'points': 4,
-}
-
-task = """
-Welchen String liefert der Aufruf exB(5)?
-
-```java_copy
-public static String exB(int n) {
-    if (n <= 0)
-        return "";
-    return exB(n-2) + (n+1) + exB(n-1);
-}
-```
-
-Geben Sie die Ziffern hintereinander an, d.h. ohne Leerzeichen o.ä.: [gap(4P)]243263252432[/gap]
-"""
-
-feedback = """
-
-Der Rekursionsbaum stellt die Aufrufe durch Knoten dar, die jeweils mit dem
-Aufrufargument markiert sind. Die äußeren Knoten (ganz unten) entsprechen
-Basisfällen, sie tragen nicht zum Ergebnisstring bei (denn sie liefern nur das
-leere Wort). Die anderen (inneren) Knoten tragen bei, und zwar in unserem Fall
-je eine Ziffer.
-
-glw4u2g0xfg0.png
-
-Traversiert man den Baum in Inorder-Reihenfolge, so ist die Reihenfolge der
-Aufrufargumente genau `1, 3, 2, 1, 5, 2, 1, 4, 1, 3, 2, 1`. Die entsprechenden
-Ziffern sind immer um 1 höher, also lautet der Ergebnisstring: 243263252432
-"""
diff --git a/scripts/Vermischtes aus Kapitel 3 (I1-ID: uo93wey0oog0).py b/scripts/Vermischtes aus Kapitel 3 (I1-ID: uo93wey0oog0).py
deleted file mode 100644
index 68cd72145e3e60b07a5a054c069fc2436362995a..0000000000000000000000000000000000000000
--- a/scripts/Vermischtes aus Kapitel 3 (I1-ID: uo93wey0oog0).py	
+++ /dev/null
@@ -1,32 +0,0 @@
-meta = {
-    'author': 'Jan Maximilian Michal',
-    'title': 'Vermischtes aus Kapitel 3 (I1-ID: uo93wey0oog0)',
-    'type': 'multiple choice',
-    'points': 0.5,
-}
-
-task = """ Kreuzen Sie alles an, was im weitesten Sinne wahr ist (wahre Aussagen, korrekte Formulierungen, Ausdrücke mit Wert true): """
-
-choices = """
-[X] Formalparameter sind lokale Variablen.
-[X] Die JVM interpretiert Java-Bytecode.
-[X] (false ? true : false) == (true ? false : true)
-[ ] Das rekursive Grundschema lautet: Rekurriere - Finalisiere (falls trivial)
-[ ] Die Java-Laufzeitumgebung beinhaltet Compiler, Klassenbibliotheken und die (JVM) Java Virtual Machine.
-[ ] An Ausdrücke dürfen keine Zuweisungen erfolgen.
-[ ] Methoden mit Signatur int (int) werden mit call-by-reference aufgerufen.
-[ ] (false ? false : true) == (false ? true : false)
-"""
-
-feedback = """
-| Aussage                                                                                                 |  Wert   |   Begründung                                                                                                                                                                                                                                                                                                         |
-|---------------------------------------------------------------------------------------------------------|---------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-| Formalparameter sind lokale Variablen.                                                                  | TRUE    |  Die im Methodenkopf definierten Parameter heißen auch Formalparameter und werden innerhalb der Methode als Variable gebraucht. Tatsächliche Parameter sind die im Programmablauf übergebenen Werte oder Referenzen.                                                                                                |
-| Die JVM interpretiert Java-Bytecode.                                                                    | TRUE    |  Java-Bytecode ist das Instruction-Set der Java-Virtual-Machine                                                                                                                                                                                                                                                      |
-| (false ? true : false) == (true ? false : true)                                                         | TRUE    |  (false ? true : false) == (true ? false : true) -> false == false -> true                                                                                                                                                                                                                                           |
-| Das rekursive Grundschema lautet: Rekurriere - Finalisiere (falls trivial)                              | FALSE   |  Das rekursive Grundschema lautet: Finalisiere (falls trivial) - Rekurriere                                                                                                                                                                                                                                          |
-| Die Java-Laufzeitumgebung beinhaltet Compiler, Klassenbibliotheken und die (JVM) Java Virtual Machine.  | FALSE   |  Wikipedia: "Allgemein besteht die Laufzeitumgebung aus der Java Virtual Machine (Java VM), die für die Ausführung der Java-Anwendungen verantwortlich ist, einer Programmierschnittstelle (API, für Application and Programming Interface) und weiteren Programmbibliotheken." Ein Compiler gehört nicht dazu.      |
-| An Ausdrücke dürfen keine Zuweisungen erfolgen.                                                         | FALSE   |  Da zum Beispiel x[0] = 1                                                                                                                                                                                                                                                                                            |
-| Methoden mit Signatur int (int) werden mit call-by-reference aufgerufen.                                | FALSE   |  Sämtliche Java Methoden werden mit call-by-value aufgerufen. Eine gute Erklärung zu den Unterschieden finden Sie hier.                                                                                                                                                                                            |
-| (false ? false : true) == (false ? true : false)                                                        | FALSE   |  (false ? false : true) == (false ? true : false) -> true == false -> false                                                                                                                                                                                                                                          |
-"""
diff --git a/scripts/examples/feldarbeit_param.py b/scripts/examples/feldarbeit_param.py
deleted file mode 100644
index b803eca2aba19ae4754050cd78f4a31cbdb7c8b5..0000000000000000000000000000000000000000
--- a/scripts/examples/feldarbeit_param.py
+++ /dev/null
@@ -1,63 +0,0 @@
-# -*- coding: utf-8 -*-
-
-from random import shuffle, sample
-
-meta = {
-    'author': 'Jan Maximilian Michal',
-    'title': 'Feldarbeit (I1-ID: p0kaixs0lyg0)',
-    'type': 'single choice',
-    'points': 1,  # per correct choice
-}
-
-
-def list_to_str(lst):
-    return str(lst).strip('[]')
-
-
-N = 8
-a = sample(range(20), N)
-o = list(a)
-for i in range(N):
-    a[i] = a[(i + 1) % N]
-
-c = a[:-1] + [o[0]]
-
-task = """
-Welche Ausgabe erzeugt folgender Code:
-
-```java
-public class Feldarbeit {
-    public static void main(String[] args) {
-        int[] a = { %s };
-        int N = a.length;
-        for (int i = 0; i < N; i++) {
-            a[i] = a[(i+1) %% N];
-        }
-        for (int i = 0; i < N; i++)
-            System.out.print(a[i] + " ");
-        System.out.println();
-    }
-}
-```
-""" % list_to_str(o)
-
-choices = """
-[4] `%s`
-[2] `%s`
-[ ] `1 1 1 1 1 1 1 1`
-[ ] `%s`
-""" % (list_to_str(a), list_to_str(c), list_to_str(shuffle(o)))
-
-feedback = """
-
-Betrachten Sie die folgenden Zeilen:
-```java
-for (int i = 0; i < N; i++) {
-    a[i] = a[(i+1) %% N];
-}
-```
-
-Der Inhalt jeder Zelle des Arrays jeweils durch den linken Nachbarn ersetzt,
-wobei an den Rändern zyklisch verfahren wird. Dadurch, dass *in-place* verfahren
-wird, also keine Kopie erstellt wird, wird der neue Inhalt der 0. Zelle in die
-letzte geschrieben, daher enthält das neue Array keine %d mehr.""" % o[0]
diff --git a/scripts/examples/multi_proto.py b/scripts/examples/multi_proto.py
deleted file mode 100644
index 266816ad7c5dea64f5101f6a81266aff3f35c3aa..0000000000000000000000000000000000000000
--- a/scripts/examples/multi_proto.py
+++ /dev/null
@@ -1,40 +0,0 @@
-meta = {
-    'author': 'Jan Maximilian Michal',
-    'title': 'Sortieren nach Punkten (I1-ID: nipe84411eh0)',
-    'type': 'multiple choice',
-    'points': 0.5, # per correct choice
-}
-
-task = """
-Hier der Anfang der Datei `punkte.csv`, die Komma-getrennte Angaben
-zu erreichten Übungspunkten enthält [[Example Formula \\sum_{i=0}^n i]]:
-
-```
-21600001,Herr,Bollman,Fritze-Peter,15
-21600002,Frau,Bollwoman,Franzi,19
-21600003,Herr,Lindemann,Erwin,17
-21600004,Frau,Lindefrau,Edelgard Martha,12
-21600005,Herr,Machtnix,Mike,2
-.....
-```
-
-Welches Shell-Kommando ist geeignet, die Zeilen nach fallender Punktzahl
-sortiert auszugeben (also erst große, dann kleinere Punktzahlen)? """
-
-choices = """
-[ ] `sort --reverse --k 5 --numeric-sort punkte.csv`
-[ ] `sort --r --field-separator=, -k 5 --n punkte.csv`
-[ ] `sort -r -t="," -k 5 --n punkte.csv`
-[X] `sort --reverse -t "," -k 5 -n punkte.csv`
-[ ] `sort -r --field-separator "," -k 4 -numeric punkte.csv`
-[ ] `sort -r --field-separator "," -k 4 punkte.csv`
-"""
-
-feedback = """
-* [ ] `sort --reverse --k 5 --numeric-sort punkte.csv` falsch (u.a.: ungültiges Argument --k)
-* [ ] `sort --r --field-separator=, -k 5 --n punkte.csv` falsch (u.a.: bei kurzem Argument -k darf kein = stehen)
-* [ ] `sort -r -t="," -k 5 --n punkte.csv` falsch (siehe oben)
-* [X] `sort --reverse -t "," -k 5 -n punkte.csv` richtig
-* [ ] `sort -r --field-separator "," -k 4 -numeric punkte.csv` falsch (u.a.: Punkte stehen in Spalte 5)
-* [ ] `sort -r --field-separator "," -k 4 punkte.csv` falsch (u.a.: keine numerische Sortierung)
-"""
\ No newline at end of file
diff --git a/scripts/examples/param_example.py b/scripts/examples/param_example.py
deleted file mode 100644
index ef47ec2f2d366cef13a75bf4ba7d0772a0b2096c..0000000000000000000000000000000000000000
--- a/scripts/examples/param_example.py
+++ /dev/null
@@ -1,24 +0,0 @@
-from random import randint, sample
-
-meta = {
-    'author': 'Jan Maximilian Michal',
-    'title': 'Parameter example',
-    'type': 'single choice',
-    'points': 4,  # for correct answer
-}
-
-a = randint(-50, 49)
-b = randint(-50, 49)
-
-
-def get_answers(right, count=4):
-    possible = sample(range(-100, a+b), count//2) + \
-        sample(range(a+b+1, 100), count//2-1) + [a+b]
-    return [('X' if answer == right else ' ', answer) for answer in possible]
-
-
-task = """ What is the answer to the question {} + {}?""".format(a, b)
-
-choices = '\n'.join('[%s] a + b = %d' % c for c in get_answers(a+b))
-
-feedback = "[[a + b = {}]]".format(a + b)
diff --git a/scripts/examples/select.py b/scripts/examples/select.py
deleted file mode 100644
index 6eac93ef553bc176a8e903e1d7aa39d4d81563e8..0000000000000000000000000000000000000000
--- a/scripts/examples/select.py
+++ /dev/null
@@ -1,94 +0,0 @@
-meta = {
-    'author': 'Jan Maximilian Michal',
-    'title': 'Zeilen sind anders, Spalten auch (I1-ID: lhu27691fzg0)',
-    'type': 'gap',
-}
-
-
-gap_1 = """[select]
-[1] int n_ze = m.length;
-[ ] int n_ze = m[0].length;
-[ ] int n_ze = m.length();
-[ ] int n_ze = m[0].length();
-[/select]"""
-
-gap_2 = """[select]
-[ ] int n_sp = m.length();
-[ ] int n_sp = m[0].length();
-[ ] int n_sp = m.length;
-[1] int n_sp = m[0].length;
-[/select]"""
-
-gap_3 = """[select]
-[ ] for (int i = 1; i <= n_ze; i++)
-[1] for (int i = 0; i < n_ze; i++)
-[ ] for (int i = 1; i <= n_sp; i++)
-[ ] for (int i = 0; i < n_sp; i++)
-[/select]"""
-
-gap_4 = """[select]
-[ ] ms[i] = ms[i] + m[j][i]*s[i];
-[ ] ms[i] = ms[i] + m[i][j]*s[i];
-[ ] ms[i] = ms[i] + m[j][i]*s[j];
-[1] ms[i] = ms[i] + m[i][j]*s[j];
-[/select]"""
-
-
-task = """ Folgendes Codefragment soll die Multiplikation eines Zeilenvektors mit einer Matrix sowie einer Matrix mit einem Spaltenvektor realisieren. Wählen Sie die fehlenden Zeilen unten entsprechend aus:
-
-```java
-01: int[][] m = {{ 0, 1, 2, 3},   // Matrix
-02:              { 4, 5, 6, 7},
-03:              {8, 9, 10, 11}};
-04: int[] z = { 12, 13, 14};      // Zeile
-05: int[] s = {15, 16, 17, 18};   // Spalte
-06:
-07: %s     // Zeilenanzahl der Matrix
-08: %s     // Spaltenanzahl der Matrix
-09:
-10: /* 1: Zeile mal Matrix */
-11: int[] zm = new int[n_sp];
-12: for (int j = 0; j < n_sp; j++) {
-13:     zm[j] = 0;
-14:     %s
-15:         zm[j] = zm[j] + z[i]*m[i][j];
-16: }
-17: /* 2: Matrix mal Spalte */
-18: int[] ms = new int[n_ze];
-19: for (int i = 0; i < n_ze; i++) {
-20:     ms[i] = 0;
-21:     for (int j = 0; j < n_sp; j++)
-22:         %s
-23:
-```
-""" % (gap_1, gap_2, gap_3, gap_4)
-
-feedback = """
-
-Der vollständige Code:
-
-```java
-int[][] m = {{ 0, 1, 2, 3},   // Matrix
-             { 4, 5, 6, 7},
-             {8, 9, 10, 11}};
-int[] z = { 12, 13, 14};      // Zeile
-int[] s = {15, 16, 17, 18};   // Spalte
-
-int n_ze = m.length;        // Zeilenanzahl der Matrix
-int n_sp = m[0].length;     // Spaltenanzahl der Matrix
-
-/* 1: Zeile mal Matrix */011: int[] zm = new int[n_sp];
-for (int j = 0; j < n_sp; j++) {
-    zm[j] = 0;
-    for (int i = 0; i < n_ze; i++)
-        zm[j] = zm[j] + z[i]*m[i][j];
-}
-/* 2: Matrix mal Spalte */
-int[] ms = new int[n_ze];
-for (int i = 0; i < n_ze; i++) {
-    ms[i] = 0;
-    for (int j = 0; j < n_sp; j++)
-        ms[i] = ms[i] + m[i][j]*s[j];
-
-```
-"""
\ No newline at end of file
diff --git a/scripts/examples/single_proto.py b/scripts/examples/single_proto.py
deleted file mode 100644
index f96e4de18c1f8aa642f8bcc5bbc96c9ba083a22c..0000000000000000000000000000000000000000
--- a/scripts/examples/single_proto.py
+++ /dev/null
@@ -1,41 +0,0 @@
-meta = {
-    'author': 'Jan Maximilian Michal',
-    'title': 'Sortieren nach Punkten (I1-ID: nipe84411eh0)',
-    'type': 'single choice',
-    'points': 4,  # for correct answer
-}
-
-task = """ Hier der Anfang der Datei `punkte.csv`, die Komma-getrennte Angaben
-zu erreichten Übungspunkten enthält:
-
-```
-21600001,Herr,Bollman,Fritze-Peter,15
-21600002,Frau,Bollwoman,Franzi,19
-21600003,Herr,Lindemann,Erwin,17
-21600004,Frau,Lindefrau,Edelgard Martha,12
-21600005,Herr,Machtnix,Mike,2
-.....
-```
-
-Welches Shell-Kommando ist geeignet, die Zeilen nach fallender Punktzahl
-sortiert auszugeben (also erst große, dann kleinere Punktzahlen)? """
-
-choices = """
-[ ] `sort --reverse --k 5 --numeric-sort punkte.csv`
-[2] `sort --r --field-separator=, -k 5 --n punkte.csv`
-[ ] `sort -r -t="," -k 5 --n punkte.csv`
-[4] `sort --reverse -t "," -k 5 -n punkte.csv`
-[ ] `sort -r --field-separator "," -k 4 -numeric punkte.csv`
-[ ] `sort -r --field-separator "," -k 4 punkte.csv`
-"""
-
-feedback = """
-```
-[ ] sort --reverse --k 5 --numeric-sort punkte.csv falsch (u.a.: ungültiges Argument --k)
-[ ] sort --r --field-separator=, -k 5 --n punkte.csv falsch (u.a.: bei kurzem Argument -k darf kein = stehen)
-[ ] sort -r -t="," -k 5 --n punkte.csv falsch (siehe oben)
-[X] sort --reverse -t "," -k 5 -n punkte.csv richtig
-[ ] sort -r --field-separator "," -k 4 -numeric punkte.csv falsch (u.a.: Punkte stehen in Spalte 5)
-[ ] sort -r --field-separator "," -k 4 punkte.csv falsch (u.a.: keine numerische Sortierung)
-```
-"""
diff --git a/scripts/feld_umgraben.py b/scripts/feld_umgraben.py
deleted file mode 100644
index abb0542eebf050ba0c18a95d26e136212120a5d9..0000000000000000000000000000000000000000
--- a/scripts/feld_umgraben.py
+++ /dev/null
@@ -1,60 +0,0 @@
-# -*- coding: utf-8 -*-
-
-meta = {
-    'author': 'Jan Maximilian Michal',
-    'title': 'Feld umgraben (I1-ID: xu71ubs0lyg0)',
-    'type': 'single choice',
-    'shuffle' : False,
-    'points': 1, # per correct choice
-}
-
-task = """Die Reihenfolge der Elemente im Feld `a` der Länge **N** soll umgekehrt werden. Wählen
-Sie den Code aus, der diese Aufgabe am besten löst:"""
-
-choices = [
-"""[4]
-```
-for (int i = 0; i < N/2; i++) {
-    int tmp = a[i];
-    a[i] = a[N-i-1];
-    a[N-i-1] = tmp;
-}
-```
-""",
-
-"""[ ]
-```
-int[] b = new int[N];
-for (int i = 0; i < N; i++)
-    b[i] = a[N-i-1];
-a = b;
-```
-""",
-
-"""[ ]
-```
-for (int i = 0; i < N; i++) {
-    int tmp = a[i];
-    a[i] = a[N-i-1];
-    a[N-i-1] = tmp;
-}```
-""",
-
-"""[ ]
-```
-for (int i = 0; i < N/2; i++) {
-    int tmp = a[i];
-    a[i] = a[N-i];
-    a[N-i] = tmp;
-}```
-"""
-
-
-]
-
-feedback = """
-1. löst die Aufgabe, indem alle Elemente "um die Mitte herum rotiert" werden. Das sind maximal n/2 Operationen.
-2. löst die Aufgabe NICHT, denn nach n/2 Tauschoperationen wird nochmal zurückgetauscht und alles steht am alten Platz.
-3. löst die Aufgabe, verbraucht aber doppelt soviel Speicher wie nötig.
-4. löst die Aufgabe NICHT: bei der ersten Iteration wird auf das nicht existente Element a[N] zugegriffen.
-"""
\ No newline at end of file
diff --git a/scripts/feldarbeit.py b/scripts/feldarbeit.py
deleted file mode 100644
index 8e11ad59d47a18ee81990b6d7928a43e323c1e72..0000000000000000000000000000000000000000
--- a/scripts/feldarbeit.py
+++ /dev/null
@@ -1,47 +0,0 @@
-meta = {
-    'author': 'Jan Maximilian Michal',
-    'title': 'Feldarbeit (I1-ID: p0kaixs0lyg0)',
-    'type': 'single choice',
-    'points': 1, # per correct choice
-}
-
-task = """
-Welche Ausgabe erzeugt folgender Code:
-
-```java
-public class Feldarbeit {
-    public static void main(String[] args) {
-        int[] a = { 0, 1, 2, 3, 4, 5, 6, 7};
-        int N = a.length;
-        for (int i = 0; i < N; i++) {
-            a[i] = a[(i+1) % N];
-        }
-        for (int i = 0; i < N; i++)
-            System.out.print(a[i] + " ");
-        System.out.println();
-    }
-}
-```
-"""
-
-choices = """
-[4] `1 2 3 4 5 6 7 1`
-[2] `1 2 3 4 5 6 7 0`
-[ ] `1 1 1 1 1 1 1 1`
-[ ] `7 0 1 2 3 4 5 6`
-"""
-
-feedback = """
-Betrachten Sie die folgenden Zeilen:
-```java
-for (int i = 0; i < N; i++) {
-    a[i] = a[(i+1) % N];
-}
-```
-
-Der Inhalt jeder Zelle des Arrays jeweils durch den linken Nachbarn ersetzt,
-wobei an den Rändern zyklisch verfahren wird. Dadurch, dass *in-place* verfahren
-wird, also keine Kopie erstellt wird, wird der neue Inhalt der 0. Zelle in die
-letzte geschrieben, daher enthält das neue Array keine 0 mehr. """
-
-
diff --git a/scripts/info1_02_klausur.py b/scripts/info1_02_klausur.py
deleted file mode 100644
index 3ebc25c119a6a4ea2cb440ebb1f34397a9c525d8..0000000000000000000000000000000000000000
--- a/scripts/info1_02_klausur.py
+++ /dev/null
@@ -1,30 +0,0 @@
-meta = {
-    'author': 'Carsten Damm',
-    'title': 'Vermischtes zu elementaren Daten (I1-ID: e638zfi0qtg0)',
-    'type': 'multiple choice',
-    'points': 0.5, # per correct choice
-}
-
-task = """ Markieren Sie alle zutreffenden Aussagen: """
-
-choices = """
-[ ] `int x = Integer.MAX_VALUE; x++;` verursacht eine OverflowException.
-[ ] Steuerzeichen werden vom Steuerwerk interpretiert.
-[X] `if (b > 0 && a/b < 2)` ... ist besser als `if (a/b < 2 && b > 0)` ...
-[ ] Umlaute im Quelltext verursachen Compilezeitfehler.
-[X] `"h\u00F6chstens 6 Zeichen"` ist ein Literal.
-[ ] `Integer.MAX_VALUE++;` verursacht einen Ganzzahlüberlauf.
-[ ] UTF-8 ordnet jedem Zeichen eine Folge von 8 Bytes zu.
-[X] Ganzzahl-Arithmetik ist schneller als Gleitkomma-Arithmetik.
-"""
-
-feedback = """
-Die folgenden Aussagen sind korrekt:
-
-* `if (b > 0 && a/b < 2)` ... ist besser als `if (a/b < 2 && b > 0)` ...
- * *Begründung:* `a/b < 2` ist aufwändiger zu berechnen als `b > 0`. Bei einer Prüfung des Wahrheitswerts einer Konjunktion muss der zweite Term nicht betrachtet werden, wenn der erste falsch ist.
-* `"h\u00F6chstens 6 Zeichen"` ist ein Literal.
- * *Begründung:* Da der String eine konstanten Wert darstellt ist er als Literal zu bezeichnen.
-* Ganzzahl-Arithmetik ist schneller als Gleitkomma-Arithmetik.
- * *Begründung:* Floating Point Arithmetik ist wesentlich aufwändiger als Integer Arithmetik (siehe zum Vergleich: Zweitkomplement und IEE-754)
-"""
\ No newline at end of file
diff --git a/scripts/nur_sterne_sehen.py b/scripts/nur_sterne_sehen.py
deleted file mode 100644
index f9e07c93a0e9ccb9a23888d28ba69db6d0e5841a..0000000000000000000000000000000000000000
--- a/scripts/nur_sterne_sehen.py
+++ /dev/null
@@ -1,43 +0,0 @@
-meta = {
-    'author': 'Jan Maximilian Michal',
-    'title': 'Nur Sterne sehen (I1-ID: cgu8rno0kyg0)',
-    'type': 'single choice',
-    'points': 1, # per correct choice
-}
-
-task = """
-
-Das folgende Programm (nach [Sedgewick/Wayne]) erzeugt als Ausgaben mehrere
-Zeilen mit Ziffern (hier genau vier):
-
-```java
-public class Ruler {
-    public static void main(String[] args) {
-        String ruler1 = "1";                   System.out.println(ruler1);
-        String ruler2 = ruler1 + "2" + ruler1; System.out.println(ruler2);
-        String ruler3 = ruler2 + "3" + ruler2;or System.out.println(ruler3);
-        String ruler4 = ruler3 + "4" + ruler3; System.out.println(ruler4);
-        // usw.
-    }
-}```
-
-Wäre `main` auf genügend Codezeilen nach dem gleichen Schema ergänzt, wieviele
-Zahlen würde bei Ausführung die n-te Ausgabezeile enthalten? """
-
-choices = """
-[ ] [[n]]
-[4] [[2^n−1]]
-[ ] [[2^n]]
-[ ] [[2n+1]]"""
-
-feedback = r"""
-Die erste Zeile ergibt genau die Ausgabe `1`. In jeder folgenden
-Zeile wird die Anzahl der Zahlen verdoppelt und um eine weitere Zahl ergänzt.
-Die Anzahl der Zahlen [[a_n]] im Schritt [[n]] ist daher: [[a_n = 2a_{n-1} +
-1]].
-Als natürlche Folge ergibt sich:
-
-* [[S_n = a_0 + 2a_0 + 4a_0 + \dots + 2^{n-1}a_0 = a_0 (2^n - 1)]]
-
-Weil [[a_0 = 1]] ist [[2^n−1]] die korrekte Antwort.
-"""
\ No newline at end of file
diff --git a/scripts/originale_kopien.py b/scripts/originale_kopien.py
deleted file mode 100644
index 09e87e08c7628d1903b85b3e4fe038c8a8f1e4be..0000000000000000000000000000000000000000
--- a/scripts/originale_kopien.py
+++ /dev/null
@@ -1,40 +0,0 @@
-meta = {
-    'author': 'Jan Maximilian Michal',
-    'title': 'Originale Kopien? (I1-ID: 0c05by80syg0)',
-    'type': 'gap',
-    'points': 0.5, # per correct choice
-}
-
-
-task = """ `a`, `b` sind Variablen vom Typ `char[]` und `c`, `d` sind Variablen
-vom Typ `String`. `a`, `b`, `c` und `d` sind bereits korrekt mit Zeichenfolgen
-der Länge 2 initialisiert (d.h. die jeweiligen Felder/Strings belegen
-Speicherplatz und man kann auf ihre Inhalte zugreifen). Welcher Code ist
-geeignet, um festzustellen, ob die in a und b bzw. in c und d gespeicherten
-Zeichenfolgen gleich sind?
-
-* `if (a == b) ...` [select][ ]geeignet\n[0.5]ungeeignet[/select]
-* `if (a.equals(b)) ...` [select][ ]geeignet\n[0.5]ungeeignet[/select]
-* `if (a[0] == b[0] || a[1] == b[1]) ...` [select][ ]geeignet\n[0.5]ungeeignet[/select]
-* `if (a[0] == b[0] && a[1] == b[1]) ...` [select][0.5]geeignet\n[ ]ungeeignet[/select]
-* `if (c == d) ...` [select][ ]geeignet\n[0.5]ungeeignet[/select]
-* `if (c.equals(d)) ...` [select][0.5]geeignet\n[ ]ungeeignet[/select]
-* `if (c.compareTo(d) == 0) ...` [select][0.5]geeignet\n[ ]ungeeignet[/select]
-* `if (c[0] == d[0] && c[1] == d[1]) ...` [select][ ]geeignet\n[0.5]ungeeignet[/select]
-"""
-
-# Antworten bitte aus drop-down-Menü wählen lassen:
-# Auswahl jeweils geeignet/nicht geeignet
-
-
-feedback = """
-
-Wichtig ist darauf zu achten, dass Objekte vom Typ String spezifische Methoden
-exportieren, die das vergleichen oder bearbeiten von Zeichenketten erlauben.
-Einfache `char[]` Arrays erlauben das nicht.
-
-Da der Objekte vom Typ String jedoch `char` Arrays enthalten ist es möglich
-über Indizierung den Vergleich 'per Hand' durchzuführen.
-
-"""
-
diff --git a/scripts/vermischtes.py b/scripts/vermischtes.py
deleted file mode 100644
index 8e662c692aa5410001ccaef95be2d7fa9c2a722c..0000000000000000000000000000000000000000
--- a/scripts/vermischtes.py
+++ /dev/null
@@ -1,32 +0,0 @@
-meta = {
-    'author': 'Jan Maximilian Michal',
-    'title': 'Vermischtes aus Kapitel 3 (I1-ID: uo93wey0oog0)',
-    'type': 'multiple choice',
-    'points': 0.5,
-}
-
-task = """ Kreuzen Sie alles an, was im weitesten Sinne wahr ist (wahre Aussagen, korrekte Formulierungen, Ausdrücke mit Wert true): """
-
-choices = """
-[X] Formalparameter sind lokale Variablen.
-[X] Die JVM interpretiert Java-Bytecode.
-[X] (false ? true : false) == (true ? false : true)
-[ ] Das rekursive Grundschema lautet: Rekurriere - Finalisiere (falls trivial)
-[ ] Die Java-Laufzeitumgebung beinhaltet Compiler, Klassenbibliotheken und die (JVM) Java Virtual Machine.
-[ ] An Ausdrücke dürfen keine Zuweisungen erfolgen.
-[ ] Methoden mit Signatur int (int) werden mit call-by-reference aufgerufen.
-[ ] (false ? false : true) == (false ? true : false)
-"""
-
-feedback = """
-| Aussage                                                                                                 |  Wert   |   Begründung                                                                                                                                                                                                                                                                                                         |
-|---------------------------------------------------------------------------------------------------------|---------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-| Formalparameter sind lokale Variablen.                                                                  | TRUE    |  Die im Methodenkopf definierten Parameter heißen auch Formalparameter und werden innerhalb der Methode als Variable gebraucht. Tatsächliche Parameter sind die im Programmablauf übergebenen Werte oder Referenzen.                                                                                                 |
-| Die JVM interpretiert Java-Bytecode.                                                                    | TRUE    |  Java-Bytecode ist das Instruction-Set der Java-Virtual-Machine                                                                                                                                                                                                                                                      |
-| (false ? true : false) == (true ? false : true)                                                         | TRUE    |  (false ? true : false) == (true ? false : true) -> false == false -> true                                                                                                                                                                                                                                           |
-| Das rekursive Grundschema lautet: Rekurriere - Finalisiere (falls trivial)                              | FALSE   |  Das rekursive Grundschema lautet: Finalisiere (falls trivial) - Rekurriere                                                                                                                                                                                                                                          |
-| Die Java-Laufzeitumgebung beinhaltet Compiler, Klassenbibliotheken und die (JVM) Java Virtual Machine.  | FALSE   |  Wikipedia: "Allgemein besteht die Laufzeitumgebung aus der Java Virtual Machine (Java VM), die für die Ausführung der Java-Anwendungen verantwortlich ist, einer Programmierschnittstelle (API, für Application and Programming Interface) und weiteren Programmbibliotheken." Ein Compiler gehört nicht dazu.      |
-| An Ausdrücke dürfen keine Zuweisungen erfolgen.                                                         | FALSE   |  Da zum Beispiel x[0] = 1                                                                                                                                                                                                                                                                                            |
-| Methoden mit Signatur int (int) werden mit call-by-reference aufgerufen.                                | FALSE   |  Sämtliche Java Methoden werden mit call-by-value aufgerufen. Eine gute Erklärung zu den Unterschieden finden Sie hier.                                                                                                                                                                                              |
-| (false ? false : true) == (false ? true : false)                                                        | FALSE   |  (false ? false : true) == (false ? true : false) -> true == false -> false                                                                                                                                                                                                                                          |
-"""
diff --git a/scripts/zeilen_sind_anders.py b/scripts/zeilen_sind_anders.py
deleted file mode 100644
index 4aefe5dd25382d10f130e650155dc86b46653626..0000000000000000000000000000000000000000
--- a/scripts/zeilen_sind_anders.py
+++ /dev/null
@@ -1,105 +0,0 @@
-meta = {
-    'author': 'Jan Maximilian Michal',
-    'title': 'Zeilen sind anders, Spalten auch (I1-ID: lhu27691fzg0)',
-    'type': 'gap',
-}
-
-
-gap_1 = """[select]
-[1] int n_ze = m.length;
-[ ] int n_ze = m[0].length;
-[ ] int n_ze = m.length();
-[ ] int n_ze = m[0].length();
-[/select]"""
-
-gap_2 = """[select]
-[ ] int n_sp = m.length();
-[ ] int n_sp = m[0].length();
-[ ] int n_sp = m.length;
-[1] int n_sp = m[0].length;
-[/select]"""
-
-gap_3 = """[select]
-[ ] for (int i = 1; i <= n_ze; i++)
-[1] for (int i = 0; i < n_ze; i++)
-[ ] for (int i = 1; i <= n_sp; i++)
-[ ] for (int i = 0; i < n_sp; i++)
-[/select]"""
-
-gap_4 = """[select]
-[ ] ms[i] = ms[i] + m[j][i]*s[i];
-[ ] ms[i] = ms[i] + m[i][j]*s[i];
-[ ] ms[i] = ms[i] + m[j][i]*s[j];
-[1] ms[i] = ms[i] + m[i][j]*s[j];
-[/select]"""
-
-
-task = """ Folgendes Codefragment soll die Multiplikation eines Zeilenvektors mit einer Matrix sowie einer Matrix mit einem Spaltenvektor realisieren. Wählen Sie die fehlenden Zeilen unten entsprechend aus:
-
-```java
-01: int[][] m = {{ 0, 1, 2, 3},   // Matrix
-02:              { 4, 5, 6, 7},
-03:              {8, 9, 10, 11}};
-04: int[] z = { 12, 13, 14};      // Zeile
-05: int[] s = {15, 16, 17, 18};   // Spalte
-06:
-07: /* CODEZEILE AUSWÄHLEN */     // Zeilenanzahl der Matrix
-08: /* CODEZEILE AUSWÄHLEN */     // Spaltenanzahl der Matrix
-09:
-10: /* 1: Zeile mal Matrix */011: int[] zm = new int[n_sp];
-12: for (int j = 0; j < n_sp; j++) {
-13:     zm[j] = 0;
-14:     /* CODEZEILE AUSWÄHLEN */
-15:         zm[j] = zm[j] + z[i]*m[i][j];
-16: }
-17: /* 2: Matrix mal Spalte */
-18: int[] ms = new int[n_ze];
-19: for (int i = 0; i < n_ze; i++) {
-20:     ms[i] = 0;
-21:     for (int j = 0; j < n_sp; j++)
-22:         /* CODEZEILE AUSWÄHLEN */
-23:
-```
-
-**Zeile 7:**
-%s
-
-**Zeile 8:**
-%s
-
-**Zeile 14:**
-%s
-
-**Zeile 22:**
-%s
-""" % (gap_1, gap_2, gap_3, gap_4)
-
-feedback = """
-
-Der vollständige Code:
-
-```java
-int[][] m = {{ 0, 1, 2, 3},   // Matrix
-             { 4, 5, 6, 7},
-             {8, 9, 10, 11}};
-int[] z = { 12, 13, 14};      // Zeile
-int[] s = {15, 16, 17, 18};   // Spalte
-
-int n_ze = m.length;        // Zeilenanzahl der Matrix
-int n_sp = m[0].length;     // Spaltenanzahl der Matrix
-
-/* 1: Zeile mal Matrix */011: int[] zm = new int[n_sp];
-for (int j = 0; j < n_sp; j++) {
-    zm[j] = 0;
-    for (int i = 0; i < n_ze; i++)
-        zm[j] = zm[j] + z[i]*m[i][j];
-}
-/* 2: Matrix mal Spalte */
-int[] ms = new int[n_ze];
-for (int i = 0; i < n_ze; i++) {
-    ms[i] = 0;
-    for (int j = 0; j < n_sp; j++)
-        ms[i] = ms[i] + m[i][j]*s[j];
-
-```
-"""
\ No newline at end of file
diff --git a/setup.py b/setup.py
new file mode 100644
index 0000000000000000000000000000000000000000..5c6e82979e9ccbdea3fa3e7c33f0d7c7d521b14c
--- /dev/null
+++ b/setup.py
@@ -0,0 +1,24 @@
+# -*- coding: utf-8 -*-
+
+from setuptools import setup, find_packages
+
+
+with open('README.md') as f:
+    readme = f.read()
+
+with open('LICENSE') as f:
+    license = f.read()
+
+setup(
+    name='hallgrim',
+    version='0.1',
+    description='A script generator for the ILIAS platform',
+    long_description=readme,
+    author='Jan Maximilian Michal',
+    author_email='mail-github@jmx.io',
+    url='https://gitlab.gwdg.de/j.michal/ilias-generator',
+    license=license,
+    scripts=['hallgrim/bin/hallgrim'],
+    install_requires=['mistune', 'pygments', 'requests', 'requests_toolbelt'],
+    packages=['hallgrim']
+)