diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md
index 1989e049c4c3c37f7c9ae3f892294716633f36e5..5147222f6ae8c3e6c757fee6c486358c6c9d850f 100644
--- a/DEVELOPMENT.md
+++ b/DEVELOPMENT.md
@@ -2,7 +2,7 @@
 
 ## Setup
 
-* Install python3 and virtualenv
+* Install python3, virtualenv, redis and a database program (postgres, mysql, sqlite does not work with alembic migrations)
 * Create a virtualenv and install the requirements
 
 ```sh
@@ -22,7 +22,7 @@ cp config.py.example config.py
   - Don't forget to enter your database connection
   - And your authentication backend
   - And deactivate everything you do not use
-
+* create the path where PDFs will be stored (`DOCUMENTS_PATH` in config.py)
 * Fill your database
 
 ```sh
diff --git a/config.py.example b/config.py.example
index ee7824736c7246d08ac2f3248fa6fbbe917d3c30..1aa605cbd8a2665a12850e18ec76aeb5ed66bea1 100644
--- a/config.py.example
+++ b/config.py.example
@@ -77,9 +77,10 @@ AUTH_BACKENDS = [
     StaticUserManager(
         users=(
             ("username", "password", ("group1", "group2")),
-            ("testuser", "abc123", ("group1")),
+            ("testuser", "abc123", ("group1",)),
         )
-    )
+    ),
+    PAMManager(),
 ]
 
 OBSOLETION_WARNING = """Please migrate your account!""" # not important
@@ -147,6 +148,7 @@ FONTS = {
 }
 
 # local filesystem path to save compiled and uploaded protocols (and attachments)
+# create this path!
 DOCUMENTS_PATH = "documents"
 
 # keywords indicating private protocol parts
diff --git a/models/database.py b/models/database.py
index a559fd02e3302651ab9f296ed3bf2ee4d4fed64c..49b0635b028a8875a8cc798c3a9422ece1eae284 100644
--- a/models/database.py
+++ b/models/database.py
@@ -611,7 +611,7 @@ class Todo(DatabaseModel):
         return " ".join(parts)
 
     def render_latex(self, current_protocol=None):
-        return r"\textbf{{{}}}: {}: {} -- {}".format(
+        return r"\Todo{{{}}}{{{}}}{{{}}}{{{}}}".format(
             "Neuer Todo" if self.is_new(current_protocol) else "Todo",
             escape_tex(self.who),
             escape_tex(self.description),
diff --git a/protoparser.py b/protoparser.py
index cac3b434d0839225791a635d45b6ad6f93584c86..bee63917caf77d0178d08d90adef684569bcaad7 100644
--- a/protoparser.py
+++ b/protoparser.py
@@ -221,12 +221,10 @@ class Tag:
                     return ""
                 return self.todo.render_latex(current_protocol=protocol)
             elif self.name == "beschluss":
-                parts = [r"\textbf{{Beschluss:}} {}".format(self.decision.content)]
                 if len(self.decision.categories):
-                    parts.append(
-                        r"\textit{{({})}}".format(self.decision.get_categories_str())
-                    )
-                return " ".join(parts)
+                    return r"\Beschluss[{}]{{{}}}".format(self.decision.get_categories_str(),self.decision.content)
+                else:
+                    return r"\Beschluss{{{}}}".format(self.decision.content)
             elif self.name == "footnote":
                 return r"\footnote{{{}}}".format(self.values[0])
             return r"\textbf{{{}:}} {}".format(escape_tex(self.name.capitalize()), escape_tex(";".join(self.values)))
@@ -433,7 +431,10 @@ class Fork(Element):
             else:
                 return "\n".join([escape_tex(name_line), begin_line, content_lines, end_line])
         elif render_type == RenderType.wikitext or render_type == RenderType.dokuwiki:
-            title_line = "{0} {1} {0}".format("=" * (level + 2), name_line)
+            equal_signs = level + 2
+            if render_type == RenderType.dokuwiki:
+                equal_signs = 6 - level
+            title_line = "{0} {1} {0}".format("=" * equal_signs, name_line)
             content_parts = []
             for child in self.children:
                 part = child.render(render_type, show_private, level=level+1, protocol=protocol)
diff --git a/server.py b/server.py
index 61eb7e3853dd079bdb09e9e9795bc8860d15f4f6..eec035d5e969bf3d3a5b2d3d1633dd37ae530cdc 100755
--- a/server.py
+++ b/server.py
@@ -18,6 +18,7 @@ import os
 from datetime import datetime
 import math
 import mimetypes
+import subprocess
 
 import config
 from shared import db, date_filter, datetime_filter, date_filter_long, date_filter_short, time_filter, time_filter_short, user_manager, security_manager, current_user, check_login, login_required, group_required, class_filter, needs_date_test, todostate_name_filter, code_filter, indent_tab_filter
@@ -80,6 +81,18 @@ app.jinja_env.globals.update(max=max)
 app.jinja_env.globals.update(dir=dir)
 app.jinja_env.globals.update(now=datetime.now)
 
+def get_git_revision():
+    gitlab_url = "https://git.fsmpi.rwth-aachen.de/protokollsystem/proto3"
+    commit_hash = subprocess.check_output(["git", "log", "-g", "-1", "--pretty=%H"]).decode("UTF-8").strip()
+    timestamp = int(subprocess.check_output(["git", "log", "-g", "-1", "--pretty=%at"]).strip())
+    commit_date = datetime.fromtimestamp(timestamp)
+    return {"url": gitlab_url, "hash": commit_hash, "date": commit_date}
+
+try:
+    app.jinja_env.globals["git_revision"] = get_git_revision()
+except:
+    pass
+
 # blueprints here
 
 @manager.command
diff --git a/tasks.py b/tasks.py
index b5c4818af2e6dcfc72cb4b93b0fa3a5b4e5c0e1f..28a97703a14de4c61278a4d4dddc595dde1d72bf 100644
--- a/tasks.py
+++ b/tasks.py
@@ -517,14 +517,22 @@ def push_to_dokuwiki(protocol, content, summary):
 
 @celery.task
 def push_to_dokuwiki_async(protocol_id, content, summary):
-    protocol = Protocol.query.filter_by(id=protocol_id).first()
-    with xmlrpc.client.ServerProxy(config.WIKI_API_URL) as proxy:
-        if not proxy.wiki.putPage(protocol.get_wiki_title(),
-            content, {"sum": "Automatisch generiert vom Protokollsystem 3."}):
-            error = protocol.create_error("Pushing to Wiki",
-                "Pushing to Wiki failed." "")
-            db.session.add(error)
-            db.session.commit()
+    with app.app_context():
+        protocol = Protocol.query.filter_by(id=protocol_id).first()
+        with xmlrpc.client.ServerProxy(config.WIKI_API_URL) as proxy:
+            try:
+                if not proxy.wiki.putPage(protocol.get_wiki_title(),
+                    content, {"sum": "Automatisch generiert vom Protokollsystem 3."}):
+                    error = protocol.create_error("Pushing to Wiki",
+                        "Pushing to Wiki failed." "")
+                    db.session.add(error)
+                    db.session.commit()
+            except xmlrpc.client.Error as exception:
+                error = protocol.create_error("Pushing to Wiki",
+                    "XML RPC Exception",
+                    str(exception))
+                db.session.add(error)
+                db.session.commit()
 
 def compile(content, protocol, show_private, maxdepth):
    compile_async.delay(content, protocol.id, show_private=show_private, maxdepth=maxdepth)
@@ -595,19 +603,20 @@ def compile_async(content, protocol_id, show_private=False, use_decision=False,
         except subprocess.SubprocessError:
             log = ""
             total_log_filename = os.path.join(compile_dir, log_filename)
-            if os.path.isfile(total_log_filename):
-                with open(total_log_filename, "r") as log_file:
-                    log = "Log:\n\n" + add_line_numbers(log_file.read())
-            else:
-                log = "Logfile not found."
             total_source_filename = os.path.join(compile_dir, protocol_source_filename)
+            log = ""
             if os.path.isfile(total_source_filename):
                 with open(total_source_filename, "r") as source_file:
-                    log += "\n\nSource:\n\n" + add_line_numbers(source_file.read())
+                    log += "Source:\n\n" + add_line_numbers(source_file.read())
             total_class_filename = os.path.join(compile_dir, protocol_class_filename)
             if os.path.isfile(total_class_filename):
                 with open(total_class_filename, "r") as class_file:
                     log += "\n\nClass:\n\n" + add_line_numbers(class_file.read())
+            if os.path.isfile(total_log_filename):
+                with open(total_log_filename, "r") as log_file:
+                    log += "\n\nLog:\n\n" + add_line_numbers(log_file.read())
+            else:
+                log += "\n\nLogfile not found."
             error = protocol.create_error("Compiling", "Compiling LaTeX failed", log)
             db.session.add(error)
             db.session.commit()
diff --git a/templates/documentation.html b/templates/documentation.html
index 5c6758b5a55867938b6fb45e411f84e2ae5668b8..fd539659aa1c8805ff88fe6d9cd52dd0aadb4c60 100644
--- a/templates/documentation.html
+++ b/templates/documentation.html
@@ -214,6 +214,11 @@
         Optional kann zusätzlich eine Uhrzeit angegeben werden: <code>[sitzung;Datum;Uhrzeit]</code> (z.B. <code>[sitzung;01.01.2018;9:00]</code>).
 
 {% endif %}
+        {% if git_revision %}
+        <h3 id="version">Version</h4>
+        Dieses Protokollsystem nutzt die Software <a href="{{git_revision.url}}">„Protokollsystem 3“</a> in der Version vom <a href="{{git_revision.url}}/commit/{{git_revision.hash}}">{{git_revision.date|datify}}</a>.
+        Alle Änderungen, die seitdem hinzugekommen sind, kannst du <a href="{{git_revision.url}}/compare/{{git_revision.hash}}...master">hier</a> sehen.
+        {% endif %}
     </div>
 </div>
 {% endblock %}
diff --git a/templates/protocol-show.html b/templates/protocol-show.html
index 2faf8783bc6b73ffe9c7a11a2941339a46543057..882700c1e0816c0925c015ef2bdfbf02f72f5d5d 100644
--- a/templates/protocol-show.html
+++ b/templates/protocol-show.html
@@ -26,7 +26,7 @@
                 {% endif %}
                 {% if not protocol.public %}
                     {% if config.ETHERPAD_ACTIVE %}
-                    <a class="btn btn-primary" href="{{url_for("etherpush_protocol", protocol_id=protocol.id)}}"{% if large_time_diff %} onclick="return confirm('Bist du dir sicher, dass du das Template bereits in das Etherpad kopieren willst? Die Sitzung ist erst in {{time_diff.days}} Tagen.');"{% endif %}>Etherpad</a>
+                    <a class="btn btn-primary" href="{{url_for("etherpush_protocol", protocol_id=protocol.id)}}"{% if large_time_diff %} onclick="return confirm('Bist du dir sicher, dass du das Template bereits in das Etherpad kopieren willst? Die Sitzung ist erst in {{time_diff.days}} Tagen.');"{% endif %} target="_blank">Etherpad</a>
                     {% endif %}
                 {% endif %}
                 {% if not protocol.is_done() %}
diff --git a/templates/protocol.dokuwiki b/templates/protocol.dokuwiki
index 24752de15ce2a9ba52a5af4dc9c4a2b4e810ab5c..21574b506ff85924d9ba46ec844cd59d10cba3ac 100644
--- a/templates/protocol.dokuwiki
+++ b/templates/protocol.dokuwiki
@@ -1,10 +1,10 @@
-== Beschlüsse ==
+====== Beschlüsse ======
 <env> if protocol.decisions|length > 0 </env>
     <env> for decision in protocol.decisions </env>
-* <var>decision.content</var>
+  * <var>decision.content</var>
     <env> endfor </env>
 <env> else </env>
-* keine Beschlüsse
+  * keine Beschlüsse
 <env> endif </env>
 
 <env> for top in tree.children </env>
diff --git a/templates/protocol.tex b/templates/protocol.tex
index 206a7510a89280ee30f69a34b4929248acd61487..bc289ba5688c0428d70728a076a696911868b06f 100644
--- a/templates/protocol.tex
+++ b/templates/protocol.tex
@@ -5,7 +5,9 @@
 \usepackage{pdfpages}
 \usepackage{eurosym}
 %\usepackage[utf8]{inputenc}
-\usepackage[pdfborder={0 0 0}]{hyperref}
+\usepackage[hyphens]{url}
+\usepackage[pdfborder={0 0 0},breaklinks=true]{hyperref}
+\def\UrlBreaks{\do\/\do-\do\&\do.\do,\do;\do\_\do?\do\#}
 %\usepackage{ngerman}
 % \usepackage[left]{lineno}
 %\usepackage{footnote}
diff --git a/templates/protokoll2.cls b/templates/protokoll2.cls
index b181f14dd0dbc3b1384f852151bcfad58782a947..75f01685b00022031bcf6a557383ef85b58a0a8b 100644
--- a/templates/protokoll2.cls
+++ b/templates/protokoll2.cls
@@ -1,7 +1,7 @@
 % protokoll.cls -- version 0.1 -- last changed: see mtime of the file ;)
 %
 %
-% Author: Sebastian G�nther <samson@asta.rwth-aachen.de>
+% Author: Sebastian Günther <samson@asta.rwth-aachen.de>
 
 % zuerst mal LaTeX's formalzeug
 \NeedsTeXFormat{LaTeX2e}
@@ -126,7 +126,7 @@
 \renewcommand{\thesubsection}{TOP~\arabic{section}~(\alph{subsection})}
 \newcommand{\TOP}[1]{\section{#1}}
 \newcommand{\unterTOP}[1]{\subsection{#1}}
-% F�rs Inhaltsverzeichnisanpassen
+% Fürs Inhaltsverzeichnisanpassen
 \renewcommand{\l@section}{\@dottedtocline{1}{1.5em}{4em}}
 \renewcommand{\l@subsection}{\@dottedtocline{2}{5.5em}{5.2em}}
 \renewcommand{\contentsname}{Tagesordnung}
@@ -166,7 +166,7 @@
 }%
 {\end{list}}
 
-% Abk�rzungen
+% Abkürzungen
 \newenvironment{Abk}{%
   \begin{list}{}{%
 	Abkürzungen:
@@ -183,7 +183,7 @@
 }%
 {\end{list}}
 
-% Unterschriften f�r eine und zwei Personen
+% Unterschriften für eine und zwei Personen
 \newcommand{\Unterschrift}[2]{
   \vspace*{1.4cm}
   \begin{center}
@@ -250,3 +250,6 @@
 
 \newcommand{\PE}[2]{\textbf{Persönliche Erklärung von #1:}\\\emph{\glqq{}#2\grqq{}}\\}
 
+% Styling der Todo und Beschlusstags im Protokoll
+\newcommand{\Todo}[4]{\textbf{{#1}}: #2: #3 -- #4}
+\newcommand{\Beschluss}[2][\empty]{\textbf{Beschluss:} #2 \def\temp{#1}\ifx\temp\empty\else\textit{(#1)}\fi}
diff --git a/views/forms.py b/views/forms.py
index fe3a2affd485bf0e7d3c6f2a83d2d655e3946bd5..276a8bfbd35920df774d19a51537943c6401fdfa 100644
--- a/views/forms.py
+++ b/views/forms.py
@@ -99,8 +99,13 @@ class IPNetworkField(Field):
                 raise ValueError(self.gettext("Not a valid IP Network: {}".format(str(exc))))
             self.data = ",".join(map(str, result_parts))
 
+class FocusedStringField(StringField):
+    def __call__(self, **kwargs):
+        kwargs['autofocus'] = True
+        return super().__call__(**kwargs)
+
 class LoginForm(FlaskForm):
-    username = StringField("Benutzer", validators=[InputRequired("Bitte gib deinen Benutzernamen ein.")])
+    username = FocusedStringField("Benutzer", validators=[InputRequired("Bitte gib deinen Benutzernamen ein.")])
     password = PasswordField("Passwort", validators=[InputRequired("Bitte gib dein Passwort ein.")])
     permanent = BooleanField("Eingeloggt bleiben?")